Skip to content

Instantly share code, notes, and snippets.

@wchargin
Created October 11, 2023 20:16
Show Gist options
  • Save wchargin/fddc5a325e8f2e133dae521b080d7cbb to your computer and use it in GitHub Desktop.
Save wchargin/fddc5a325e8f2e133dae521b080d7cbb to your computer and use it in GitHub Desktop.
dump flow fields before and after disturbances
diff --git a/src/art.rs b/src/art.rs
index bcba7e0..1d99457 100644
--- a/src/art.rs
+++ b/src/art.rs
@@ -548,10 +548,84 @@ impl FlowField {
} => Self::raw_circular(*circularity, *direction, *rotation, traits.version, rng),
};
let disturbances = Disturbance::build(traits, rng);
+ ff.dump(&[], "flowfield0_initial.png").unwrap();
+ ff.dump(&disturbances, "flowfield1_disturbances.png")
+ .unwrap();
ff.adjust(&disturbances);
+ ff.dump(&disturbances, "flowfield2_disturbed.png").unwrap();
+ ff.dump(&[], "flowfield3_disturbed_clean.png").unwrap();
+ panic!("goodbye");
ff
}
+ fn dump(&self, disturbances: &[Disturbance], to: &str) -> anyhow::Result<()> {
+ let mut dt = DrawTarget::new(VIRTUAL_W as i32, VIRTUAL_H as i32);
+ dt.clear(Rgb(200.0, 200.0, 200.0).to_solid_source());
+ // The flow field is dense; only show every `n`th point on each axis.
+ let step = 6;
+ for (x, col) in self.0.iter().enumerate().step_by(step) {
+ for (y, theta) in col.iter().enumerate().step_by(step) {
+ let mut pb = PathBuilder::new();
+ let half_length = SPC as f32 * step as f32 * 0.5;
+ let (x, y) = (x as f32 * SPC as f32, y as f32 * SPC as f32);
+ let (cos, sin) = (theta.cos() as f32, theta.sin() as f32);
+ pb.move_to(x - cos * half_length, y - sin * half_length);
+ pb.line_to(x + cos * half_length, y + sin * half_length);
+ let path = pb.finish();
+
+ let mut total_disturbance = 0.0;
+ for d in disturbances {
+ let dist = dist(d.center, (x as f64, y as f64));
+ let theta_adjust = rescale(dist, (0.0, d.radius), (d.theta, 0.0));
+ total_disturbance += theta_adjust;
+ }
+ total_disturbance = (-total_disturbance / std::f64::consts::TAU).rem_euclid(1.0);
+ // Color `total_disturbance` based on how close it is to `base` (on S^1 topology).
+ let redblue = |base: f64| -> u8 {
+ let mut diff = (total_disturbance - base).abs();
+ if diff > 0.5 {
+ diff = 1.0 - diff;
+ }
+ let fac = (diff * 4.0 - 0.5).clamp(0.0, 1.0);
+ (fac * 512.0).clamp(0.0, 255.0) as u8
+ };
+ let color = Source::Solid(SolidSource {
+ r: redblue(7.0 / 8.0),
+ g: 0,
+ b: redblue(1.0 / 8.0),
+ a: 255,
+ });
+
+ let mut style = StrokeStyle::default();
+ style.width = 4.0;
+ dt.stroke(&path, &color, &style, &DrawOptions::new());
+ }
+ }
+ for d in disturbances {
+ let mut pb = PathBuilder::new();
+ pb.arc(
+ d.center.0 as f32,
+ d.center.1 as f32,
+ d.radius as f32,
+ 0.0,
+ std::f32::consts::TAU,
+ );
+ let path = pb.finish();
+ let theta_rel = (d.theta * 100.0).clamp(-255.0, 255.0);
+ let color = Source::Solid(SolidSource {
+ r: theta_rel.max(0.0) as u8,
+ g: 0,
+ b: -theta_rel.min(0.0) as u8,
+ a: theta_rel.abs() as u8,
+ });
+ let mut style = StrokeStyle::default();
+ style.width = 4.0;
+ dt.stroke(&path, &color, &style, &DrawOptions::new());
+ }
+ dt.write_png(to)?;
+ Ok(())
+ }
+
fn constant_flow_field(theta: f64) -> Box<[[f64; FLOW_FIELD_ROWS]; FLOW_FIELD_COLS]> {
let vec_of_arrays = vec![[theta; FLOW_FIELD_ROWS]; FLOW_FIELD_COLS];
let slice_of_arrays = vec_of_arrays.into_boxed_slice();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment