use image::{ImageBuffer, Rgb}; use rayon::prelude::*; // Image size. const IMGW: u32 = 1024; const IMGH: u32 = 1024; // Fractal settings. const MAXITER: u32 = IMGW; const MAXITER_F64: f64 = MAXITER as f64; const ESCRAD: f64 = 2.4; fn main() { let w = IMGW as f64; let h = IMGH as f64; // Fractal bounds. let mut width: f64 = 2.0; // Initial frame width let mut xmin: f64 = -1.0; let mut ymin: f64 = -1.0; let target_x = -0.4638686756; let target_y = 0.0723647; let zoom_factor = 1.2; for i in 1..200 { let pxs: Vec = (0..IMGH) .into_par_iter() .flat_map(|y| { let fy = y as f64; (0..IMGW) .into_par_iter() .flat_map(move |x| { let cx = map_range(x as f64, 0.0, w, xmin, xmin + width); let cy = map_range(fy, 0.0, h, ymin, ymin + width); let c = num_complex::Complex::new(cx, cy); // Compute color for each pixel. col_map(esc_time(c)).to_vec() }) .collect::>() }) .collect(); // Create the image from the pixel buffer. let img = ImageBuffer::, _>::from_raw(IMGW, IMGH, pxs).unwrap(); img.save(format!("imgs/{i}.png")).unwrap(); println!("#{i} done."); // Adjust bounds for the next zoom level xmin = target_x - width / 2.0; ymin = target_y - width / 2.0; width /= zoom_factor; // Zoom in by reducing width } } // Maps a value from one range to another. fn map_range(val: f64, imin: f64, imax: f64, omin: f64, omax: f64) -> f64 { omin + (val - imin) * (omax - omin) / (imax - imin) } // Computes the escape time for a given point in the complex plane. fn esc_time(c: num_complex::Complex) -> u32 { let mut z = c; for i in 0..MAXITER { if z.norm() > ESCRAD { return i; } z = (-z).ln() / z.ln(); } MAXITER } // Maps the iteration count to a color. fn col_map(iter: u32) -> [u8; 3] { if iter == MAXITER { [0, 0, 0] // Black for points that never escape. } else { let t = iter as f64 / MAXITER_F64; let c = (t * MAXITER_F64) as u8; [c, c, c] } }