use image::{ImageBuffer, Luma};
use indicatif::{ProgressBar, ProgressStyle};
use nalgebra::{Vector2, vector};
use polydf::{NearestOptions, nearest_t_within};
fn curve(t: f32) -> Vector2<f32> {
let s = 0.04 * t.sqrt() + 5.0;
let theta = s.sin();
let (st, ct) = theta.sin_cos();
vector![t * ct, t * st]
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let width: u32 = 512;
let height: u32 = 512;
let x_min = 0.0f32;
let x_max = 500_000.0f32; let y_min = -250_000.0f32; let y_max = 250_000.0f32;
let threshold = 15000.0f32;
let t_range = 0.0f32..=x_max;
let speed_upper_bound = Some(16.0f32);
let opts = NearestOptions {
samples: 150,
..Default::default()
};
let mut img: ImageBuffer<Luma<u8>, Vec<u8>> = ImageBuffer::new(width, height);
let sx = if width > 1 {
(x_max - x_min) / (width - 1) as f32
} else {
0.0
};
let sy = if height > 1 {
(y_max - y_min) / (height - 1) as f32
} else {
0.0
};
let pb = ProgressBar::new(height as u64);
pb.set_style(
ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} rows ({eta})",
)
.unwrap()
.progress_chars("#>-"),
);
for y in 0..height {
let wy = y_min + (y as f32) * sy;
for x in 0..width {
let wx = x_min + (x as f32) * sx;
let p = vector![wx, wy];
let lum = match nearest_t_within(
p,
curve,
t_range.clone(),
threshold,
speed_upper_bound,
opts,
) {
None => 255u8, Some(res) => {
let d = res.distance;
((d / threshold).clamp(0.0, 1.0) * 255.0).round() as u8
}
};
img.put_pixel(x, height - 1 - y, Luma([lum]));
}
pb.inc(1);
}
pb.finish_with_message("render complete");
img.save("wave.png")?;
eprintln!("Wrote wave.png");
Ok(())
}