1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//! # Poisson disk sampling
//!
//! Generates a sampling of points in [0, 1)<sup>2</sup> where:
//!
//! * Sample points fill the space uniformly.
//! * Sample points stay a given minimum distance apart.
//!
//! This is equivalent to uniformly filling a unit square with non-overlapping
//! disks of equal radius, where the radius is half the minimum distance.
//!
//! Due to their blue noise properties, Poisson disk samplings can be used for
//! object placement in procedural texture/world generation, digital stippling,
//! sampling in rendering, or (re)meshing.
//!
//! # Examples
//!
//! Generate a non-tiling Poisson disk sampling in [0, 1)<sup>2</sup> with disk radius 0.1
//! using a slower but more accurate algorithm.
//!
//! ````rust
//! use poisson2d::{Builder, Type, algorithm};
//! use rand::SeedableRng;
//! use rand::rngs::SmallRng;
//!
//! fn main() {
//!     let poisson =
//!         Builder::with_radius(0.1, Type::Normal)
//!             .build(SmallRng::from_entropy(), algorithm::Ebeida);
//!     let samples = poisson.generate();
//!     println!("{:?}", samples);
//! }
//! ````
//!
//! Generate a tiling Poisson disk sampling in [0, 1)<sup>2</sup> with approximately 100 samples
//! and relative disk radius 0.9 using a faster but less accurate algorithm.
//!
//! ````rust
//! # use poisson2d::{Builder, Type, algorithm};
//! # use rand::SeedableRng;
//! # use rand::rngs::SmallRng;
//!
//! fn main() {
//!     let poisson =
//!         Builder::with_samples(100, 0.9, Type::Periodic)
//!             .build(SmallRng::from_entropy(), algorithm::Bridson);
//!     for sample in poisson {
//!         println!("{:?}", sample)
//!     }
//! }
//! ````

use std::marker::PhantomData;

use rand::Rng;

use crate::algorithm::{Algorithm, Creator};
use crate::utils::math::calc_radius;

pub mod algorithm;
mod utils;

/// Enum for determining the type of Poisson disk sampling.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Type {
    /// Acts like there is void all around the space placing no restrictions to sides.
    Normal,
    /// Makes the space wrap around on edges allowing tiling of the generated Poisson disk sampling.
    Periodic,
}

impl Default for Type {
    fn default() -> Type {
        Type::Normal
    }
}

/// Builder for the generator.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Builder {
    radius: f32,
    poisson_type: Type,
}

impl Builder {
    /// New Builder with type of distribution and radius specified.
    /// The radius should be in (0, √2 / 2]
    pub fn with_radius(radius: f32, poisson_type: Type) -> Self {
        assert!(0.0 < radius && radius <= 2f32.sqrt() / 2.0);
        Builder {
            radius,
            poisson_type,
        }
    }

    /// New Builder with type of distribution and relative radius specified.
    /// The relative radius should be in (0, 1]
    pub fn with_relative_radius(relative: f32, poisson_type: Type) -> Self {
        assert!(0.0 < relative && relative <= 1.0);
        Builder {
            radius: relative * 2f32.sqrt() / 2.0,
            poisson_type,
        }
    }

    /// New Builder with type of distribution, approximate amount of samples and relative radius specified.
    /// The amount of samples should be larger than 0.
    /// The relative radius should be in (0, 1].
    pub fn with_samples(samples: usize, relative: f32, poisson_type: Type) -> Self {
        Builder {
            radius: calc_radius(samples, relative, poisson_type),
            poisson_type,
        }
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f32 {
        self.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson_type
    }

    /// Builds generator with random number generator and algorithm specified.
    pub fn build<R, A>(self, rng: R, _algo: A) -> Generator<R, A>
    where
        R: Rng,
        A: Creator,
    {
        Generator::new(self, rng)
    }
}

/// Generates a Poisson disk sampling in a [0, 1)<sup>2</sup> area.
#[derive(Clone, Debug)]
pub struct Generator<R, A>
where
    R: Rng,
    A: Creator,
{
    poisson: Builder,
    rng: R,
    _algo: PhantomData<A>,
}

impl<R, A> Generator<R, A>
where
    R: Rng,
    A: Creator,
{
    fn new(poisson: Builder, rng: R) -> Self {
        Generator {
            rng,
            poisson,
            _algo: PhantomData,
        }
    }

    /// Sets the radius of the generator.
    pub fn set_radius(&mut self, radius: f32) {
        assert!(0.0 < radius && radius <= 2f32.sqrt() / 2.0);
        self.poisson.radius = radius;
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f32 {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }

    /// Generates a Poisson disk sampling.
    pub fn generate(self) -> Vec<mint::Vector2<f32>> {
        self.into_iter().collect()
    }
}

impl<R, A> IntoIterator for Generator<R, A>
where
    R: Rng,
    A: Creator,
{
    type Item = mint::Vector2<f32>;
    type IntoIter = PoissonIter<R, A::Algo>;

    fn into_iter(self) -> Self::IntoIter {
        PoissonIter {
            rng: self.rng,
            algo: A::create(&self.poisson),
            poisson: self.poisson,
        }
    }
}

/// Iterator for generating a Poisson disk sampling.
#[derive(Clone)]
pub struct PoissonIter<R, A>
where
    R: Rng,
    A: Algorithm,
{
    poisson: Builder,
    rng: R,
    algo: A,
}

impl<R, A> Iterator for PoissonIter<R, A>
where
    R: Rng,
    A: Algorithm,
{
    type Item = mint::Vector2<f32>;

    fn next(&mut self) -> Option<Self::Item> {
        self.algo.next(&mut self.poisson, &mut self.rng)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<R, A> PoissonIter<R, A>
where
    R: Rng,
    A: Algorithm,
{
    /// Returns the radius of the generator.
    pub fn radius(&self) -> f32 {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }

    /// Restricts the poisson algorithm with arbitrary sample.
    pub fn restrict(&mut self, value: mint::Vector2<f32>) {
        self.algo.restrict(value);
    }

    /// Checks legality of sample for current distribution.
    pub fn stays_legal(&self, value: mint::Vector2<f32>) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}