Merge branch 'master' of ssh://ssh.paoda.moe:31059/paoda/mandelbrot into bevy0.4
This commit is contained in:
commit
b86f6549d3
|
@ -5,7 +5,7 @@ name: default
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
image: rust:1.49
|
image: rust:latest
|
||||||
commands:
|
commands:
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get install -y libasound2-dev
|
- apt-get install -y libasound2-dev
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,6 +7,6 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.4"
|
bevy = "^0.4"
|
||||||
num-complex = "0.3"
|
num-complex = "^0.4"
|
||||||
rayon = "1.5"
|
rayon = "^1.5"
|
||||||
|
|
56
README.md
56
README.md
|
@ -3,34 +3,46 @@
|
||||||
An interactive interface where you can navigate the Mandelbrot Set.
|
An interactive interface where you can navigate the Mandelbrot Set.
|
||||||
|
|
||||||
### Controls
|
### Controls
|
||||||
<kbd>W</kbd> - Up
|
|
||||||
<br />
|
|
||||||
<kbd>A</kbd> - Left
|
|
||||||
<br />
|
|
||||||
<kbd>S</kbd> - Down
|
|
||||||
<br />
|
|
||||||
<kbd>D</kbd> - Right
|
|
||||||
|
|
||||||
<kbd>Q</kbd> Zoom Out
|
#### 2D Movement
|
||||||
<br />
|
Key | Action
|
||||||
<kbd>E</kbd> Zoom In
|
--- | ---
|
||||||
|
<kbd>W</kbd> | Up
|
||||||
|
<kbd>A</kbd> | Left
|
||||||
|
<kbd>S</kbd> | Down
|
||||||
|
<kbd>D</kbd> | Right
|
||||||
|
|
||||||
|
#### Zoom
|
||||||
|
Key | Action
|
||||||
|
--- | ---
|
||||||
|
<kbd>Q</kbd> | Zoom Out
|
||||||
|
<kbd>E</kbd> | Zoom In
|
||||||
|
|
||||||
|
#### 2D and Zoom Scale
|
||||||
|
Key | Action
|
||||||
|
--- | ---
|
||||||
|
<kbd>R</kbd> | Increase Scale
|
||||||
|
<kbd>F</kbd> | Decrease Scale
|
||||||
|
|
||||||
|
#### Mandelbrot Iteration Limit (Max 512 by default)
|
||||||
|
Key | Action
|
||||||
|
--- | ---
|
||||||
|
<kbd>T</kbd> | Increment by a factor of 2
|
||||||
|
<kbd>G</kbd> | Decrement by a factor of 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Build Instructions
|
### Build Instructions
|
||||||
Due to my current configuration (which is one that prioritizes quick development), Bevy requires
|
You can build the program with `cargo build`, or `cargo build --release` on stable.
|
||||||
some dependencies in order to build this project. These dependencies are `clang`, `lld`, and `llvm`.
|
|
||||||
|
|
||||||
Also, this program requires Rust Nightly (as of 2020-11-26)
|
|
||||||
|
|
||||||
Once done, you can build the program with `cargo build`, or `cargo build --release`
|
|
||||||
|
|
||||||
### Run Instructions
|
### Run Instructions
|
||||||
You can either execut the compiled binary, or use cargo and run `cargo run --release`
|
You can either execute the compiled binary, or use `cargo run --release`
|
||||||
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
* Make Zooming feel more natural (where you zoom to is fixed, and not centered)
|
- [x] Make Zooming feel more natural (where you zoom to is fixed, and not centred)
|
||||||
* Make the amount of iterations done when calculating the Mandelbrot set configurable
|
- [x] Make the amount of iterations done when calculating the Mandelbrot set configurable
|
||||||
* preferrably with a keybind
|
- [x] Add smooth colouring
|
||||||
* Add smooth colouring
|
<!-- * Maybe look into histograms? -->
|
||||||
* Maybe look into histograms?
|
- [ ] Zoom with the Mouse?
|
||||||
|
- [ ] Automatically change scale? Remove the need for the user to deal with the Scale modifier
|
|
@ -1,2 +1,7 @@
|
||||||
|
pub use crate::mandelbrot::Bounds;
|
||||||
pub use crate::mandelbrot::Mandelbrot;
|
pub use crate::mandelbrot::Mandelbrot;
|
||||||
|
|
||||||
|
pub const TEXTURE_WIDTH: usize = 1280;
|
||||||
|
pub const TEXTURE_HEIGHT: usize = 720;
|
||||||
|
|
||||||
mod mandelbrot;
|
mod mandelbrot;
|
||||||
|
|
90
src/main.rs
90
src/main.rs
|
@ -1,6 +1,6 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::texture::{Extent3d, TextureDimension, TextureFormat};
|
use bevy::render::texture::{Extent3d, TextureDimension, TextureFormat};
|
||||||
use mandelbrot::Mandelbrot;
|
use mandelbrot::{Bounds, Mandelbrot, TEXTURE_HEIGHT, TEXTURE_WIDTH};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -8,58 +8,60 @@ fn main() {
|
||||||
App::build()
|
App::build()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(startup.system())
|
.add_startup_system(startup.system())
|
||||||
.add_resource(SpriteScale::default())
|
.add_resource(TextureOptions::default())
|
||||||
.add_system(mandelbrot_render_system.system())
|
.add_system(mandelbrot_render_system.system())
|
||||||
.add_system(transform_mandelbrot_system.system())
|
.add_system(transform_mandelbrot_system.system())
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SpriteScale {
|
struct TextureOptions {
|
||||||
zoom: f64,
|
zoom: f64,
|
||||||
horiz: f64,
|
horizontal: f64,
|
||||||
verti: f64,
|
vertical: f64,
|
||||||
step: f64,
|
step: f64,
|
||||||
iterations: u32,
|
iteration_limit: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpriteScale {
|
impl Default for TextureOptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
zoom: 1.0,
|
zoom: 1.0,
|
||||||
horiz: 0.0,
|
horizontal: 0.0,
|
||||||
verti: 0.0,
|
vertical: 0.0,
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
iterations: 64,
|
iteration_limit: 64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_mandelbrot_system(input: Res<Input<KeyCode>>, mut scale: ResMut<SpriteScale>) {
|
fn transform_mandelbrot_system(input: Res<Input<KeyCode>>, mut scale: ResMut<TextureOptions>) {
|
||||||
|
// Zoom: E to Zoom In, Q to Zoom Out
|
||||||
|
// Horizontal Movement: D to move right, A to move left
|
||||||
|
// Vertical Movement: W to move up, S to move Down
|
||||||
|
// R to increase the steps taken by zoom, horizontal movement, and vertical movement
|
||||||
|
// T to increase the Iteration Limit, G to decrease the iteration limit
|
||||||
let zoom = input.pressed(KeyCode::Q) as i8 - input.pressed(KeyCode::E) as i8;
|
let zoom = input.pressed(KeyCode::Q) as i8 - input.pressed(KeyCode::E) as i8;
|
||||||
let horizontal = input.pressed(KeyCode::D) as i8 - input.pressed(KeyCode::A) as i8;
|
let horizontal = input.pressed(KeyCode::D) as i8 - input.pressed(KeyCode::A) as i8;
|
||||||
let vertical = input.pressed(KeyCode::W) as i8 - input.pressed(KeyCode::S) as i8;
|
let vertical = input.pressed(KeyCode::W) as i8 - input.pressed(KeyCode::S) as i8;
|
||||||
let step_mod = input.pressed(KeyCode::R) as i8 - input.pressed(KeyCode::F) as i8;
|
let step_change = input.pressed(KeyCode::R) as i8 - input.pressed(KeyCode::F) as i8;
|
||||||
let iter_mod = input.pressed(KeyCode::T) as i8 - input.pressed(KeyCode::G) as i8;
|
let limit_change = input.just_pressed(KeyCode::T) as i8 - input.just_pressed(KeyCode::G) as i8;
|
||||||
|
|
||||||
scale.step += (scale.step / 10.0) * step_mod as f64;
|
scale.step += (scale.step / 10.0) * step_change as f64;
|
||||||
scale.verti += scale.step * vertical as f64;
|
scale.vertical += scale.step * vertical as f64;
|
||||||
scale.horiz += scale.step * horizontal as f64;
|
scale.horizontal += scale.step * horizontal as f64;
|
||||||
scale.zoom += scale.step * zoom as f64;
|
scale.zoom += scale.step * zoom as f64;
|
||||||
|
|
||||||
if iter_mod == 1 {
|
if limit_change == 1 {
|
||||||
scale.iterations += (scale.step * 100.0) as u32;
|
scale.iteration_limit *= 2;
|
||||||
|
|
||||||
if scale.iterations > 512 {
|
if scale.iteration_limit > 512 {
|
||||||
scale.iterations = 512;
|
scale.iteration_limit = 512;
|
||||||
}
|
}
|
||||||
} else if iter_mod == -1 {
|
} else if limit_change == -1 {
|
||||||
let step = (scale.step * 100.0) as u32;
|
scale.iteration_limit /= 2;
|
||||||
let diff = scale.iterations as i64 - step as i64;
|
|
||||||
|
|
||||||
if diff < 32 {
|
if scale.iteration_limit < 32 {
|
||||||
scale.iterations = 32;
|
scale.iteration_limit = 32;
|
||||||
} else {
|
|
||||||
scale.iterations -= step;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +77,7 @@ fn transform_mandelbrot_system(input: Res<Input<KeyCode>>, mut scale: ResMut<Spr
|
||||||
fn mandelbrot_render_system(
|
fn mandelbrot_render_system(
|
||||||
materials: Res<Assets<ColorMaterial>>,
|
materials: Res<Assets<ColorMaterial>>,
|
||||||
mut textures: ResMut<Assets<Texture>>,
|
mut textures: ResMut<Assets<Texture>>,
|
||||||
scale: Res<SpriteScale>,
|
scale: Res<TextureOptions>,
|
||||||
mut query: Query<(&mut Mandelbrot, &Handle<ColorMaterial>)>,
|
mut query: Query<(&mut Mandelbrot, &Handle<ColorMaterial>)>,
|
||||||
) {
|
) {
|
||||||
for (mut fractal, handle) in query.iter_mut() {
|
for (mut fractal, handle) in query.iter_mut() {
|
||||||
|
@ -83,20 +85,23 @@ fn mandelbrot_render_system(
|
||||||
if let Some(texture_handle) = &material.texture {
|
if let Some(texture_handle) = &material.texture {
|
||||||
if let Some(texture) = textures.get_mut(texture_handle) {
|
if let Some(texture) = textures.get_mut(texture_handle) {
|
||||||
let z = scale.zoom;
|
let z = scale.zoom;
|
||||||
let h = scale.horiz;
|
let h = scale.horizontal;
|
||||||
let v = scale.verti;
|
let v = scale.vertical;
|
||||||
let iters = scale.iterations;
|
let limit = scale.iteration_limit;
|
||||||
|
|
||||||
let buf = fractal.generate_scaled_image(
|
let x = ((-2.5 * z) + h, (1.0 * z) + h);
|
||||||
((-2.5 * z) + h, (1.0 * z) + h),
|
let y = ((-1.0 * z) - v, (1.0 * z) - v);
|
||||||
((-1.0 * z) - v, (1.0 * z) - v),
|
let bounds = Bounds::new(x, y);
|
||||||
iters,
|
|
||||||
);
|
let start = Instant::now();
|
||||||
|
|
||||||
// FIXME: This will not work due to https://github.com/bevyengine/bevy/issues/1161
|
// FIXME: This will not work due to https://github.com/bevyengine/bevy/issues/1161
|
||||||
// The workaround involves "getting a mutable borrow of the ColorMaterial you use to display the Texture"
|
// The workaround involves "getting a mutable borrow of the ColorMaterial you use to display the Texture"
|
||||||
// according to @FrancoisM#2474, a developer of Bevy on Discord
|
// according to @FrancoisM#2474, a developer of Bevy on Discord
|
||||||
texture.data.copy_from_slice(buf);
|
texture
|
||||||
|
.data
|
||||||
|
.copy_from_slice(fractal.scaled_image(bounds, limit));
|
||||||
|
let _diff = Instant::now() - start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,14 +113,13 @@ fn startup(
|
||||||
mut textures: ResMut<Assets<Texture>>,
|
mut textures: ResMut<Assets<Texture>>,
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
) {
|
) {
|
||||||
let img_size = Extent3d::new(Mandelbrot::width() as u32, Mandelbrot::height() as u32, 1);
|
let texture_size = Extent3d::new(TEXTURE_WIDTH as u32, TEXTURE_HEIGHT as u32, 1);
|
||||||
let dimension = TextureDimension::D2;
|
let texture_data = Mandelbrot::new().image().to_vec();
|
||||||
let img_buf = Mandelbrot::new().generate_image().to_vec();
|
|
||||||
|
|
||||||
let texture_handle = textures.add(Texture::new(
|
let texture_handle = textures.add(Texture::new(
|
||||||
img_size,
|
texture_size,
|
||||||
dimension,
|
TextureDimension::D2,
|
||||||
img_buf,
|
texture_data,
|
||||||
TextureFormat::Rgba8UnormSrgb,
|
TextureFormat::Rgba8UnormSrgb,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -1,79 +1,98 @@
|
||||||
|
use crate::{TEXTURE_HEIGHT, TEXTURE_WIDTH};
|
||||||
use num_complex::Complex;
|
use num_complex::Complex;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
const MAX_ITERATIONS: u16 = 512;
|
const DEFAULT_ITERATION_LIMIT: u32 = 64;
|
||||||
|
const DEFAULT_BOUNDS: Bounds = Bounds::new((-2.5, 1.0), (-1.0, 1.0));
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Mandelbrot {
|
pub struct Mandelbrot {
|
||||||
texture_buffer: Vec<u8>,
|
frame_buffer: Box<[u8; (TEXTURE_WIDTH * TEXTURE_HEIGHT) * 4]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mandelbrot {
|
impl Mandelbrot {
|
||||||
const IMG_WIDTH: usize = 1280;
|
|
||||||
const IMG_HEIGHT: usize = 720;
|
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Mandelbrot {
|
Mandelbrot {
|
||||||
texture_buffer: vec![0; (Self::IMG_WIDTH * Self::IMG_HEIGHT) * 4],
|
frame_buffer: Box::new([0; (TEXTURE_WIDTH * TEXTURE_HEIGHT) * 4]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width() -> usize {
|
pub fn image(&mut self) -> &[u8] {
|
||||||
Self::IMG_WIDTH
|
let limit_f64 = DEFAULT_ITERATION_LIMIT as f64;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height() -> usize {
|
self.frame_buffer
|
||||||
Self::IMG_HEIGHT
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_image(&mut self) -> &[u8] {
|
|
||||||
self.texture_buffer
|
|
||||||
.par_chunks_mut(4)
|
.par_chunks_mut(4)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, buf)| {
|
.for_each(|(i, buf)| {
|
||||||
let iters = Self::new_escape_time(i, (-2.5, 1.0), (-1.0, 1.0), 64);
|
let iterations = Self::escape_time(i, DEFAULT_BOUNDS, DEFAULT_ITERATION_LIMIT);
|
||||||
let normalized_iters = iters / MAX_ITERATIONS as f64;
|
let normalized_iters = iterations / limit_f64;
|
||||||
let h = 0.5 + (10.0 * normalized_iters);
|
|
||||||
buf.copy_from_slice(&Self::hsv_to_rgb(h, 0.6, 1.0));
|
|
||||||
});
|
|
||||||
|
|
||||||
&self.texture_buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_scaled_image(
|
|
||||||
&mut self,
|
|
||||||
x_bounds: (f64, f64),
|
|
||||||
y_bounds: (f64, f64),
|
|
||||||
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 normalized_iters = iters / max_iters;
|
|
||||||
|
|
||||||
let h = normalized_iters * 350.0;
|
let h = normalized_iters * 350.0;
|
||||||
let v = if iters == max_iters { 0.0 } else { 1.0 };
|
let v = if iterations == limit_f64 { 0.0 } else { 1.0 };
|
||||||
|
buf.copy_from_slice(&Self::hsv_to_rgb(h, 1.0, v));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.frame_buffer.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scaled_image(&mut self, bounds: Bounds, limit: u32) -> &[u8] {
|
||||||
|
self.frame_buffer
|
||||||
|
.par_chunks_mut(4)
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, buf)| {
|
||||||
|
let limit_f64 = limit as f64;
|
||||||
|
|
||||||
|
let iterations = Self::escape_time(i, bounds, limit);
|
||||||
|
let normalized_iters = iterations / limit_f64;
|
||||||
|
|
||||||
|
let h = normalized_iters * 350.0;
|
||||||
|
let v = if iterations == limit_f64 { 0.0 } else { 1.0 };
|
||||||
buf.copy_from_slice(&Self::hsv_to_rgb(h, 1.0, v))
|
buf.copy_from_slice(&Self::hsv_to_rgb(h, 1.0, v))
|
||||||
});
|
});
|
||||||
|
|
||||||
&self.texture_buffer
|
self.frame_buffer.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_escape_time(
|
fn escape_time(i: usize, bounds: Bounds, iteration_limit: u32) -> f64 {
|
||||||
i: usize,
|
let point = Coordinate::new(i % TEXTURE_WIDTH, i / TEXTURE_WIDTH);
|
||||||
x_bounds: (f64, f64),
|
let c = Self::coords_to_complex(point, bounds);
|
||||||
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);
|
|
||||||
|
|
||||||
Self::new_calc_num_iters(c, max_iterations)
|
Self::count_iterations(c, iteration_limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -108,53 +127,50 @@ impl Mandelbrot {
|
||||||
[r, g, b, a]
|
[r, g, b, a]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_calc_num_iters(c: Complex<f64>, max_iterations: u32) -> f64 {
|
fn count_iterations(c: Complex<f64>, maximum: u32) -> f64 {
|
||||||
let mut z: Complex<f64> = Complex::new(0.0, 0.0);
|
let mut z: Complex<f64> = Complex::new(0.0, 0.0);
|
||||||
let mut num_iters: u32 = 0;
|
let mut count: u32 = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if z.norm_sqr() > 4.0 {
|
if z.norm_sqr() > 4.0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if num_iters >= max_iterations {
|
if count >= maximum {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
z = (z * z) + c;
|
z = (z * z) + c;
|
||||||
num_iters += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if num_iters < max_iterations {
|
if count < maximum {
|
||||||
(num_iters as f64 + 1.0) - z.norm().ln().ln() / 2f64.ln()
|
(count as f64 + 1.0) - z.norm().ln().ln() / 2f64.ln()
|
||||||
} else {
|
} else {
|
||||||
num_iters as f64
|
count as f64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coords_to_complex(
|
fn coords_to_complex(point: Coordinate, bounds: Bounds) -> Complex<f64> {
|
||||||
px: usize,
|
|
||||||
py: usize,
|
|
||||||
x_bounds: (f64, f64),
|
|
||||||
y_bounds: (f64, f64),
|
|
||||||
) -> Complex<f64> {
|
|
||||||
Complex::new(
|
Complex::new(
|
||||||
Self::scale_width(px, x_bounds),
|
Self::scale_width(point.x(), bounds.x()),
|
||||||
Self::scale_height(py, y_bounds),
|
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_MIN: f64 = -2.5;
|
||||||
// const X_MAX: f64 = 1.0;
|
// 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)) / TEXTURE_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_MIN: f64 = -1.0;
|
||||||
// const Y_MAX: 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)) / TEXTURE_HEIGHT as f64 - 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue