fix: refactor parts of mandelbrot.rs

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-03-29 20:22:26 -05:00
parent 42c783448e
commit 3d0f2acea3
3 changed files with 73 additions and 44 deletions

View File

@ -1,2 +1,3 @@
pub use crate::mandelbrot::Bounds;
pub use crate::mandelbrot::Mandelbrot;
mod mandelbrot;

View File

@ -1,5 +1,5 @@
use bevy::{prelude::*, render::texture::TextureFormat};
use mandelbrot::Mandelbrot;
use mandelbrot::{Bounds, Mandelbrot};
use std::time::Instant;
fn main() {
@ -88,14 +88,16 @@ fn mandelbrot_render_system(
let z = scale.zoom;
let h = scale.horizontal;
let v = scale.vertical;
let iters = scale.iterations;
let limit = scale.iterations;
let x = ((-2.5 * z) + h, (1.0 * z) + h);
let y = ((-1.0 * z) - v, (1.0 * z) - v);
let bounds = Bounds::new(x, y);
let start = Instant::now();
texture.data.copy_from_slice(fractal.generate_scaled_image(
((-2.5 * z) + h, (1.0 * z) + h),
((-1.0 * z) - v, (1.0 * z) - v),
iters,
));
texture
.data
.copy_from_slice(fractal.scaled_image(bounds, limit));
let _diff = Instant::now() - start;
}
}
@ -109,7 +111,7 @@ fn startup(
mut materials: ResMut<Assets<ColorMaterial>>,
) {
let img_size = Vec2::new(Mandelbrot::width() as f32, Mandelbrot::height() as f32);
let img_buf = Mandelbrot::new().generate_image().to_vec();
let img_buf = Mandelbrot::new().image().to_vec();
let texture_handle = textures.add(Texture::new(
img_size,

View File

@ -1,7 +1,43 @@
use num_complex::Complex;
use rayon::prelude::*;
const MAX_ITERATIONS: u16 = 512;
pub struct Coordinate(usize, usize);
impl Coordinate {
pub fn new(x: usize, y: usize) -> Self {
Self(x, y)
}
pub fn x(&self) -> usize {
self.0
}
pub fn y(&self) -> usize {
self.1
}
}
#[derive(Debug, Clone, Copy)]
pub struct Bounds {
x: (f64, f64),
y: (f64, f64),
}
impl Bounds {
pub const fn new(x: (f64, f64), y: (f64, f64)) -> Self {
Self { x, y }
}
pub fn x(&self) -> (f64, f64) {
self.x
}
pub fn y(&self) -> (f64, f64) {
self.y
}
}
const DEFAULT_MAX_ITERATIONS: u32 = 64;
const DEFAULT_BOUNDS: Bounds = Bounds::new((-2.5, 1.0), (-1.0, 1.0));
#[derive(Debug, Clone)]
pub struct Mandelbrot {
@ -26,33 +62,32 @@ impl Mandelbrot {
Self::IMG_HEIGHT
}
pub fn generate_image(&mut self) -> &[u8] {
pub fn image(&mut self) -> &[u8] {
let max_iters = DEFAULT_MAX_ITERATIONS as f64;
self.texture_buffer
.par_chunks_mut(4)
.enumerate()
.for_each(|(i, buf)| {
let iters = Self::new_escape_time(i, (-2.5, 1.0), (-1.0, 1.0), 64);
let normalized_iters = iters / MAX_ITERATIONS as f64;
let h = 0.5 + (10.0 * normalized_iters);
buf.copy_from_slice(&Self::hsv_to_rgb(h, 0.6, 1.0));
let iters = Self::escape_time(i, DEFAULT_BOUNDS, DEFAULT_MAX_ITERATIONS);
let normalized_iters = iters / max_iters;
let h = normalized_iters * 350.0;
let v = if iters == max_iters { 0.0 } else { 1.0 };
buf.copy_from_slice(&Self::hsv_to_rgb(h, 1.0, v));
});
&self.texture_buffer
}
pub fn generate_scaled_image(
&mut self,
x_bounds: (f64, f64),
y_bounds: (f64, f64),
max_iterations: u32,
) -> &[u8] {
pub fn scaled_image(&mut self, bounds: Bounds, max_iterations: u32) -> &[u8] {
self.texture_buffer
.par_chunks_mut(4)
.enumerate()
.for_each(|(i, buf)| {
let max_iters = max_iterations as f64;
let iters = Self::new_escape_time(i, x_bounds, y_bounds, max_iterations);
let iters = Self::escape_time(i, bounds, max_iterations);
let normalized_iters = iters / max_iters;
let h = normalized_iters * 350.0;
@ -63,17 +98,11 @@ impl Mandelbrot {
&self.texture_buffer
}
fn new_escape_time(
i: usize,
x_bounds: (f64, f64),
y_bounds: (f64, f64),
max_iterations: u32,
) -> f64 {
let px = i % Self::IMG_WIDTH;
let py = i / Self::IMG_WIDTH;
let c = Self::coords_to_complex(px, py, x_bounds, y_bounds);
fn escape_time(i: usize, bounds: Bounds, max_iterations: u32) -> f64 {
let point = Coordinate::new(i % Self::IMG_WIDTH, i / Self::IMG_WIDTH);
let c = Self::coords_to_complex(point, bounds);
Self::new_calc_num_iters(c, max_iterations)
Self::count_iterations(c, max_iterations)
}
#[inline]
@ -108,7 +137,7 @@ impl Mandelbrot {
[r, g, b, a]
}
fn new_calc_num_iters(c: Complex<f64>, max_iterations: u32) -> f64 {
fn count_iterations(c: Complex<f64>, max_iterations: u32) -> f64 {
let mut z: Complex<f64> = Complex::new(0.0, 0.0);
let mut num_iters: u32 = 0;
@ -132,29 +161,26 @@ impl Mandelbrot {
}
}
fn coords_to_complex(
px: usize,
py: usize,
x_bounds: (f64, f64),
y_bounds: (f64, f64),
) -> Complex<f64> {
fn coords_to_complex(point: Coordinate, bounds: Bounds) -> Complex<f64> {
Complex::new(
Self::scale_width(px, x_bounds),
Self::scale_height(py, y_bounds),
Self::scale_width(point.x(), bounds.x()),
Self::scale_height(point.y(), bounds.y()),
)
}
fn scale_width(px: usize, x_bounds: (f64, f64)) -> f64 {
#[inline]
fn scale_width(x: usize, bounds: (f64, f64)) -> f64 {
// const X_MIN: f64 = -2.5;
// const X_MAX: f64 = 1.0;
x_bounds.0 + ((x_bounds.1 - x_bounds.0) * (px as f64 - 0.0)) / Self::IMG_WIDTH as f64 - 0.0
bounds.0 + ((bounds.1 - bounds.0) * (x as f64 - 0.0)) / Self::IMG_WIDTH as f64 - 0.0
}
fn scale_height(py: usize, y_bounds: (f64, f64)) -> f64 {
#[inline]
fn scale_height(y: usize, bounds: (f64, f64)) -> f64 {
// const Y_MIN: f64 = -1.0;
// const Y_MAX: f64 = 1.0;
y_bounds.0 + ((y_bounds.1 - y_bounds.0) * (py as f64 - 0.0)) / Self::IMG_HEIGHT as f64 - 0.0
bounds.0 + ((bounds.1 - bounds.0) * (y as f64 - 0.0)) / Self::IMG_HEIGHT as f64 - 0.0
}
}