Path Manipulation

General path manipulation can be performed on the Polygon type. We can construct a Polygon from any type implementing Iterator<Item=P2>, which Ngon does.

let square = Polygon::from(Ngon::square(world.center(), 200.));
canvas.paint(Filled(square));

Polygon provides an iterator over its vertices we can use to manipulate them, and build a new polygon. In this code we use that to distort the polygon by sampling Fbm noise with time as the z position:

let fbm = Fbm::new().set_seed(world.seed as u32);
let shift_by_timed_noise = |v| {
    let sample_point = P3::new(v.x, v.y, ctx.time.as_secs_f32().sin() / 5.);
    let t = fbm.noise(sample_point) * 60.;
    v.translate(V2::new(t, t))
};

let square = Polygon::from(Ngon::square(world.center(), 200.));
let square = Polygon::from(square.vertices().map(shift_by_timed_noise));

Further, we can iteratively subdivide and apply this same distortion to make more interesting shapes:

let fbm = Fbm::new().set_seed(world.seed as u32);
let shift_by_timed_noise = |(v, strength): (P2, f32)| {
    let sample_point =
        P3::new(v.x / 100., v.y / 100., ctx.time.as_secs_f32().sin() / 2.);
    let t = fbm.noise(sample_point) * strength;
    v.translate(V2::new(t, t))
};

let square = Polygon::from(Ngon::square(world.center(), 200.));
let initial_strength = 15.;
let splotches =
    std::iter::successors(Some((square, initial_strength)), |(shape, strength)| {
        let next_strength = strength / 1.5;
        let next_shape = Polygon::from(
            shape
                .clone()
                .subdivide()
                .vertices()
                .map(|v| (v, *strength))
                .map(shift_by_timed_noise),
        );
        
        Some((next_shape, next_strength))
    })
    .map(|(s, _)| s);

for splotch in splotches.skip(8).take(1) {
    canvas.paint(Filled(splotch));
}

Last updated