PointSampler library (C++)
Loading...
Searching...
No Matches
random_walk_filaments.hpp
Go to the documentation of this file.
1/* Copyright (c) 2025 Otto Link. Distributed under the terms of the GNU General
2 Public License. The full license is in the file LICENSE, distributed with
3 this software. */
4#pragma once
5#include <optional>
6
8
9namespace ps
10{
11
38template <typename T, size_t N>
39std::vector<Point<T, N>> random_walk_filaments(
40 size_t n_filaments,
41 size_t filament_count,
43 const std::array<std::pair<T, T>, N> &ranges,
44 std::optional<unsigned int> seed = std::nullopt,
45 T persistence = T(0.8),
46 T gaussian_sigma = T(0),
47 size_t gaussian_samples = 0,
48 std::vector<T> *p_distances = nullptr) // optional
49// output
50{
51 std::vector<Point<T, N>> points;
53 if (p_distances)
55
56 std::mt19937 gen(seed ? *seed : std::random_device{}());
57 std::uniform_real_distribution<T> uniform(-1, 1);
58 std::normal_distribution<T> normal(0, gaussian_sigma);
59
60 for (size_t f = 0; f < n_filaments; ++f)
61 {
62 // Random starting point
64 for (size_t d = 0; d < N; ++d)
65 p[d] = std::uniform_real_distribution<T>(ranges[d].first, ranges[d].second)(gen);
66
67 // Random initial direction (normalized)
68 std::array<T, N> dir;
69 T norm = 0;
70 for (size_t d = 0; d < N; ++d)
71 {
72 dir[d] = uniform(gen);
73 norm += dir[d] * dir[d];
74 }
75 norm = std::sqrt(norm);
76 for (size_t d = 0; d < N; ++d)
77 dir[d] /= norm;
78
79 for (size_t i = 0; i < filament_count; ++i)
80 {
81 // Always add core filament point
82 points.push_back(p);
83 if (p_distances)
84 p_distances->push_back(T(0));
85
86 // Add Gaussian scatter points (thickness)
87 for (size_t g = 0; g < gaussian_samples; ++g)
88 {
89 Point<T, N> q = p;
90 T dist2 = 0;
91 for (size_t d = 0; d < N; ++d)
92 {
93 T offset = normal(gen);
94 q[d] += offset;
95 dist2 += offset * offset;
96 }
97
98 // Discard points outside the bounding box
99 bool inside = true;
100 for (size_t d = 0; d < N; ++d)
101 {
102 if (q[d] < ranges[d].first || q[d] > ranges[d].second)
103 {
104 inside = false;
105 break;
106 }
107 }
108
109 if (inside)
110 {
111 points.push_back(q);
112 if (p_distances)
113 p_distances->push_back(std::sqrt(dist2));
114 }
115 }
116
117 // Random perturbation
118 std::array<T, N> rnd;
119 T rnd_norm = 0;
120 for (size_t d = 0; d < N; ++d)
121 {
122 rnd[d] = uniform(gen);
123 rnd_norm += rnd[d] * rnd[d];
124 }
125 rnd_norm = std::sqrt(rnd_norm);
126 for (size_t d = 0; d < N; ++d)
127 rnd[d] /= rnd_norm;
128
129 // Blend with persistence
130 for (size_t d = 0; d < N; ++d)
131 dir[d] = persistence * dir[d] + (1 - persistence) * rnd[d];
132
133 // Normalize direction
134 T dnorm = 0;
135 for (size_t d = 0; d < N; ++d)
136 dnorm += dir[d] * dir[d];
137 dnorm = std::sqrt(dnorm);
138 for (size_t d = 0; d < N; ++d)
139 dir[d] /= dnorm;
140
141 // Step forward
142 for (size_t d = 0; d < N; ++d)
143 p[d] += step_size * dir[d];
144 }
145 }
146
147 return points;
148}
149
150} // namespace ps
Definition dbscan_clustering.hpp:11
std::vector< Point< T, N > > random(size_t count, const std::array< std::pair< T, T >, N > &axis_ranges, std::optional< unsigned int > seed=std::nullopt)
Generates a specified number of uniformly distributed random points in N-dimensional space.
Definition random.hpp:66
std::vector< Point< T, N > > random_walk_filaments(size_t n_filaments, size_t filament_count, T step_size, const std::array< std::pair< T, T >, N > &ranges, std::optional< unsigned int > seed=std::nullopt, T persistence=T(0.8), T gaussian_sigma=T(0), size_t gaussian_samples=0, std::vector< T > *p_distances=nullptr)
Generate random walk filaments in N dimensions with optional Gaussian thickness.
Definition random_walk_filaments.hpp:39
A fixed-size N-dimensional point/vector class.
Definition point.hpp:39