poisson2d/algorithm/
bridson.rs1use glam::Vec2;
2use rand::distributions::Uniform;
3use rand::Rng;
4use rand_distr::StandardNormal;
5use sphere::sphere_volume;
6
7use crate::algorithm::{Algorithm, Creator};
8use crate::utils::*;
9use crate::Builder;
10
11#[derive(Debug, Clone, Copy)]
14pub struct Bridson;
15
16impl Creator for Bridson {
17 type Algo = Algo;
18
19 fn create(poisson: &Builder) -> Self::Algo {
20 Algo {
21 grid: Grid::new(poisson.radius, poisson.poisson_type),
22 active_samples: vec![],
23 outside: vec![],
24 success: 0,
25 }
26 }
27}
28
29pub struct Algo {
31 grid: Grid,
32 active_samples: Vec<Vec2>,
33 outside: Vec<Vec2>,
34 success: usize,
35}
36
37impl Algorithm for Algo {
38 fn next<R>(&mut self, poisson: &mut Builder, rng: &mut R) -> Option<mint::Vector2<f32>>
39 where
40 R: Rng,
41 {
42 while !self.active_samples.is_empty() {
43 let index = rng.sample(Uniform::new(0, self.active_samples.len()));
44 let cur = self.active_samples[index].clone();
45 for _ in 0..30 {
46 let min = 2.0 * poisson.radius;
47 let max = 4.0 * poisson.radius;
48 let sample = cur.clone() + random_point_annulus(rng, min, max).into();
49 if (0..2)
50 .map(|n| sample[n])
51 .all(|c| 0.0 <= c && c < 1.0)
52 {
53 let index = sample_to_index(&sample, self.grid.side());
54 if self.insert_if_valid(poisson, index, sample.clone()) {
55 return Some(sample.into());
56 }
57 }
58 }
59 self.active_samples.swap_remove(index);
60 }
61 while self.success == 0 {
62 let cell = rng.sample(Uniform::new(0, self.grid.cells()));
63 let index: Vec2 = decode(cell, self.grid.side()).expect(
64 "Because we are decoding random index within grid \
65 this should work.",
66 );
67 let sample = choose_random_sample(rng, &self.grid, index.clone(), 0);
68 if self.insert_if_valid(poisson, index, sample.clone()) {
69 return Some(sample.into());
70 }
71 }
72 None
73 }
74
75 fn size_hint(&self, poisson: &Builder) -> (usize, Option<usize>) {
76 let upper = if self.grid.cells() > self.success {
78 self.grid.cells() - self.success
79 } else {
80 0
81 };
82 let spacing = self.grid.cell();
85 let grid_volume = (upper as f32) * spacing.powi(2);
86 let sphere_volume = sphere_volume(2.0 * poisson.radius, 2);
87 let lower: f32 = grid_volume / sphere_volume;
88 let mut lower = lower.floor() as usize;
89 if lower > 0 {
90 lower -= 1;
91 }
92 (lower, Some(upper))
93 }
94
95 fn restrict(&mut self, sample: mint::Vector2<f32>) {
96 let sample: Vec2 = sample.into();
97 self.success += 1;
98 let index = sample_to_index(&sample, self.grid.side());
99 if let Some(g) = self.grid.get_mut(index) {
100 g.push(sample);
101 } else {
102 self.outside.push(sample);
103 }
104 }
105
106 fn stays_legal(&self, poisson: &Builder, sample: mint::Vector2<f32>) -> bool {
107 let sample: Vec2 = sample.into();
108 let index = sample_to_index(&sample, self.grid.side());
109 is_disk_free(&self.grid, poisson, index, 0, sample.clone(), &self.outside)
110 }
111}
112
113impl Algo {
114 fn insert_if_valid(&mut self, poisson: &mut Builder, index: Vec2, sample: Vec2) -> bool {
115 if is_disk_free(
116 &self.grid,
117 poisson,
118 index.clone(),
119 0,
120 sample.clone(),
121 &self.outside,
122 ) {
123 self.active_samples.push(sample.clone());
124 self.grid
125 .get_mut(index)
126 .expect("Because the sample is in [0, 1), indexing it should work.")
127 .push(sample);
128 self.success += 1;
129 true
130 } else {
131 false
132 }
133 }
134}
135
136fn random_point_annulus<R>(rand: &mut R, min: f32, max: f32) -> Vec2
137where
138 R: Rng,
139{
140 loop {
141 let mut result = Vec2::zero();
142 for n in 0..2 {
143 result[n] = rand.sample(StandardNormal);
144 }
145 let result = result.normalize() * rand.gen::<f32>() * max;
146 if result.length() >= min {
147 return result;
148 }
149 }
150}
151
152#[test]
153fn random_point_annulus_does_not_generate_outside_annulus() {
154 use rand::{rngs::SmallRng, SeedableRng};
155 let mut rng = SmallRng::seed_from_u64(42);
156 for _ in 0..10000 {
157 let result = random_point_annulus(&mut rng, 1.0, 2.0);
158 assert!(result.length() >= 1.0);
159 assert!(result.length() <= 2.0);
160 }
161}
162
163#[test]
164fn random_point_annulus_generates_all_quadrants() {
165 use rand::{rngs::SmallRng, SeedableRng};
166 let mut rng = SmallRng::seed_from_u64(42);
167 let (mut top_left, mut top_right, mut bottom_left, mut bottom_right) =
168 (false, false, false, false);
169 for _ in 0..10000 {
170 let result = random_point_annulus(&mut rng, 1.0, 2.0);
171 if result.y() < 0.0 {
172 if result.x() < 0.0 {
173 bottom_left = true;
174 } else {
175 bottom_right = true;
176 }
177 } else {
178 if result.x() < 0.0 {
179 top_left = true;
180 } else {
181 top_right = true;
182 }
183 }
184 }
185 assert!(top_left);
186 assert!(top_right);
187 assert!(bottom_left);
188 assert!(bottom_right);
189}