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));}