Implement a basic Sierpinski Gasket IFS
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
use glam::{vec2, Vec2};
|
||||
use rand::distr::{Distribution, StandardUniform};
|
||||
use rand::{Rng, RngExt};
|
||||
use crate::transform::Transform;
|
||||
|
||||
struct BiUnit;
|
||||
impl Distribution<f32> for BiUnit {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 {
|
||||
rng.sample::<f32, _>(StandardUniform) * 2.0 - 1.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate one step in the chaos game; choose the next transform, apply it,
|
||||
/// and return the resulting point. Also returns the transform index so that
|
||||
/// path-dependent weights (the "Xaos" table in Apophysis) can be chosen
|
||||
/// for the next iteration step.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `weights` - Weights are assumed to be normalized; adding all elements together should return the value 1
|
||||
pub fn step_chaos_game<R: Rng>(
|
||||
point: Vec2,
|
||||
rng: &mut R,
|
||||
transforms: &[Transform],
|
||||
weights: &[f32],
|
||||
) -> (Vec2, u32) {
|
||||
let mut choice_weight = rng.sample::<f32, _>(StandardUniform);
|
||||
let mut transform_index: u32 = 0;
|
||||
|
||||
for weight in weights {
|
||||
choice_weight -= weight;
|
||||
if choice_weight <= 0.0 {
|
||||
break;
|
||||
}
|
||||
|
||||
transform_index += 1;
|
||||
}
|
||||
|
||||
(
|
||||
transforms[transform_index as usize].transform_point(point),
|
||||
transform_index,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct ChaosGame<'a, R: Rng> {
|
||||
current_point: Vec2,
|
||||
rng: &'a mut R,
|
||||
transforms: &'a [Transform],
|
||||
weights: &'a [f32],
|
||||
}
|
||||
|
||||
impl<'a, R: Rng> ChaosGame<'a, R> {
|
||||
pub fn new(rng: &'a mut R, transforms: &'a [Transform], weights: &'a [f32]) -> Self {
|
||||
let current_point = vec2(rng.sample(BiUnit), rng.sample(BiUnit));
|
||||
ChaosGame { current_point, rng, transforms, weights }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Rng> Iterator for ChaosGame<'a, R> {
|
||||
type Item = Vec2;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (next_point, _) = step_chaos_game(self.current_point, self.rng, self.transforms, self.weights);
|
||||
self.current_point = next_point;
|
||||
|
||||
Some(next_point)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user