transforms appear to work correctly
This commit is contained in:
5
TODO.adoc
Normal file
5
TODO.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
= TODOs
|
||||
|
||||
- Improve deep zoom precision
|
||||
* https://mathr.co.uk/blog/2021-05-14_deep_zoom_theory_and_practice.html)
|
||||
|
||||
10
src/lib.rs
10
src/lib.rs
@@ -24,7 +24,7 @@ pub struct Args {
|
||||
pub transform: Vec<String>
|
||||
}
|
||||
|
||||
pub type Float = f32;
|
||||
pub type Float = f64;
|
||||
pub type Point = Complex<Float>;
|
||||
use num::complex::Complex;
|
||||
pub type Transform = [(Point, Point); 3];
|
||||
@@ -56,7 +56,7 @@ pub struct Config {
|
||||
|
||||
|
||||
impl Config {
|
||||
fn render_point(&self, (base, delta): (Point, Point)) -> f32 {
|
||||
fn render_point(&self, (base, delta): (Point, Point)) -> Float {
|
||||
const ESCAPE: Float = 2.;
|
||||
const ESCAPE2: Float = ESCAPE * ESCAPE;
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Config {
|
||||
|(iter, val)|
|
||||
iter as Float + 1. - val.norm().ln().ln() / ESCAPE.ln()
|
||||
);
|
||||
result as f32
|
||||
result as Float
|
||||
}
|
||||
|
||||
pub fn render_image(&self) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
|
||||
@@ -86,8 +86,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_palette(val: f32) -> image::Rgb<u8> {
|
||||
let magnitude = f32::clamp(val * 255., 0., 255.) as u8;
|
||||
pub fn map_palette(val: Float) -> image::Rgb<u8> {
|
||||
let magnitude = Float::clamp(val * 255., 0., 255.) as u8;
|
||||
image::Rgb([magnitude, magnitude, magnitude])
|
||||
}
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
|
||||
86
src/main.rs
86
src/main.rs
@@ -1,8 +1,9 @@
|
||||
// extern crate mandelia;
|
||||
use eframe::{CreationContext, Frame, Result};
|
||||
use egui::Context;
|
||||
use egui::load::SizedTexture;
|
||||
use image::EncodableLayout;
|
||||
|
||||
use mandelia::Float;
|
||||
fn main() -> eframe::Result {
|
||||
// mandelia::main()
|
||||
|
||||
@@ -69,17 +70,18 @@ impl App {
|
||||
}
|
||||
|
||||
fn add_transform(&mut self, xf: mandelia::transform::Type) {
|
||||
self.tx_mat *= mandelia::transform::MTransform::from(xf);
|
||||
self.tx_mat = mandelia::transform::MTransform::from(xf) * self.tx_mat;
|
||||
self.update_transform();
|
||||
}
|
||||
|
||||
fn mk_adjuster(&mut self, ui: &mut egui::Ui, label: &str, mut action: impl FnMut(f32) -> mandelia::transform::Type) {
|
||||
if ui.button("-").clicked() {
|
||||
fn mk_adjuster(&mut self, ui: &mut egui::Ui, label: &str, key_dec: egui::Key, key_inc: egui::Key, mut action: impl Fn(Float) -> mandelia::transform::Type) {
|
||||
let (dn, up) = ui.ctx().input(|is| (is.key_pressed(key_dec), is.key_pressed(key_inc)));
|
||||
if ui.button(format!("- ({})", key_dec.symbol_or_name())).clicked() || dn {
|
||||
self.add_transform(action(-1.));
|
||||
}
|
||||
|
||||
ui.centered_and_justified(|ui| {ui.label(label);});
|
||||
if ui.button("+").clicked() {
|
||||
if ui.button(format!("+ ({})", key_inc.symbol_or_name())).clicked() || up {
|
||||
self.add_transform(action(1.));
|
||||
}
|
||||
ui.end_row();
|
||||
@@ -108,34 +110,82 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
// transform functions
|
||||
fn mk_translation(axis: u8) -> impl Fn(Float) -> mandelia::transform::Type {
|
||||
move |amt| mandelia::transform::Type::Translation(axis, amt / 100.)
|
||||
}
|
||||
|
||||
fn mk_rotation(a0: u8, a1: u8) -> impl Fn(Float) -> mandelia::transform::Type {
|
||||
move |amt| mandelia::transform::Type::Rotation(a0, a1, amt)
|
||||
}
|
||||
|
||||
fn mk_scale(scale: Float) -> mandelia::transform::Type {
|
||||
mandelia::transform::Type::Scale(1. + scale / 4.)
|
||||
}
|
||||
|
||||
enum JumpMode {
|
||||
Mandelbrot,
|
||||
Julia,
|
||||
Origin,
|
||||
}
|
||||
|
||||
impl eframe::App for App {
|
||||
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
|
||||
if let Some(jump_mode) = ctx.input(|is| {
|
||||
if is.key_pressed(egui::Key::Num0) {
|
||||
Some(JumpMode::Origin)
|
||||
} else if is.key_pressed(egui::Key::Num1) {
|
||||
Some(JumpMode::Mandelbrot)
|
||||
} else if is.key_pressed(egui::Key::Num2) {
|
||||
Some(JumpMode::Julia)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
use mandelia::transform::Type;
|
||||
match jump_mode {
|
||||
JumpMode::Mandelbrot => {
|
||||
self.reset_transform();
|
||||
self.add_transform(Type::CoordSwap(0, 2));
|
||||
self.add_transform(Type::CoordSwap(1, 3));
|
||||
},
|
||||
JumpMode::Julia => {
|
||||
self.reset_transform();
|
||||
self.add_transform(Type::Translation(0, 0.31));
|
||||
self.add_transform(Type::Translation(1, 0.31));
|
||||
}
|
||||
JumpMode::Origin => {
|
||||
self.reset_transform();
|
||||
}
|
||||
}
|
||||
};
|
||||
egui::SidePanel::left("nav").show(ctx, |ui| {
|
||||
use mandelia::transform::Type;
|
||||
use egui::Key;
|
||||
egui::Grid::new("nav_grid")
|
||||
.num_columns(3)
|
||||
.show(ui, |ui| {
|
||||
self.mk_adjuster(ui, "base x", |delta| Type::Translation(0, delta));
|
||||
self.mk_adjuster(ui, "base y", |delta| Type::Translation(1, delta));
|
||||
self.mk_adjuster(ui, "delta x", |delta| Type::Translation(2, delta));
|
||||
self.mk_adjuster(ui, "delta y", |delta| Type::Translation(3, delta));
|
||||
self.mk_adjuster(ui, "base x", Key::A, Key::D, mk_translation(0));
|
||||
self.mk_adjuster(ui, "base y", Key::S, Key::W, mk_translation(1));
|
||||
self.mk_adjuster(ui, "delta x", Key::J, Key::L, mk_translation(2));
|
||||
self.mk_adjuster(ui, "delta y", Key::K, Key::I, mk_translation(3));
|
||||
|
||||
self.mk_adjuster(ui, "scale", |scale| Type::Scale(scale));
|
||||
self.mk_adjuster(ui, "scale", Key::OpenBracket, Key::CloseBracket, mk_scale);
|
||||
|
||||
self.mk_adjuster(ui, "xy", |delta| Type::Rotation(0, 1, delta));
|
||||
self.mk_adjuster(ui, "XY", |delta| Type::Rotation(2, 3, delta));
|
||||
self.mk_adjuster(ui, "xX", |delta| Type::Rotation(0, 2, delta));
|
||||
self.mk_adjuster(ui, "yY", |delta| Type::Rotation(1, 3, delta));
|
||||
self.mk_adjuster(ui, "xY", |delta| Type::Rotation(0, 3, delta));
|
||||
self.mk_adjuster(ui, "Xy", |delta| Type::Rotation(1, 2, delta));
|
||||
self.mk_adjuster(ui, "xy", Key::Q, Key::E, mk_rotation(0, 1));
|
||||
self.mk_adjuster(ui, "XY", Key::U, Key::O, mk_rotation(2, 3));
|
||||
self.mk_adjuster(ui, "xX", Key::F, Key::G, mk_rotation(0, 2));
|
||||
self.mk_adjuster(ui, "yY", Key::R, Key::T, mk_rotation(1, 3));
|
||||
self.mk_adjuster(ui, "xY", Key::Z, Key::X, mk_rotation(0, 3));
|
||||
self.mk_adjuster(ui, "Xy", Key::N, Key::M, mk_rotation(1, 2));
|
||||
})
|
||||
});
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let size = ui.available_size();
|
||||
let base_size = ui.available_size();
|
||||
let size = base_size * ui.pixels_per_point();
|
||||
let size = [size.x as usize, size.y as usize];
|
||||
self.update_texture(size);
|
||||
ui.add(egui::Image::from_texture(&self.texture));
|
||||
ui.add(egui::Image::from_texture(SizedTexture::new(&self.texture, base_size)));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ pub type MTransform = nalgebra::Matrix5<Float>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Type {
|
||||
Rotation(u8, u8, f32),
|
||||
Translation(u8, f32),
|
||||
Rotation(u8, u8, Float),
|
||||
Translation(u8, Float),
|
||||
CoordSwap(u8, u8),
|
||||
Scale(f32),
|
||||
Scale(Float),
|
||||
}
|
||||
|
||||
impl From<Type> for MTransform {
|
||||
@@ -43,7 +43,9 @@ impl From<Type> for MTransform {
|
||||
m
|
||||
}
|
||||
Type::Scale(delta) => {
|
||||
MTransform::identity() / delta
|
||||
let mut xf = MTransform::identity() / delta;
|
||||
xf[(4,4)] = 1.;
|
||||
xf
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +68,7 @@ fn parse_axis(c: char) -> Option<u8> {
|
||||
/// TODO: replace this with a nom parser
|
||||
pub fn parse_step(s: &str) -> Option<Type> {
|
||||
if let Some(r) = s.strip_prefix("z") {
|
||||
return f32::from_str_radix(r, 10).ok().map(Type::Scale);
|
||||
return Float::from_str_radix(r, 10).ok().map(Type::Scale);
|
||||
}
|
||||
if s.len() < 2 {
|
||||
return None;
|
||||
@@ -85,11 +87,11 @@ pub fn parse_step(s: &str) -> Option<Type> {
|
||||
if axis0 == axis1 {
|
||||
return None;
|
||||
}
|
||||
let val = f32::from_str_radix(chars.as_str().trim(), 10).ok()?;
|
||||
let val = Float::from_str_radix(chars.as_str().trim(), 10).ok()?;
|
||||
Type::Rotation(axis0, axis1, val)
|
||||
}
|
||||
'0' ..= '9' => {
|
||||
let val = f32::from_str_radix(chars.as_str().trim(), 10).ok()?;
|
||||
let val = Float::from_str_radix(chars.as_str().trim(), 10).ok()?;
|
||||
Type::Translation(axis0, val)
|
||||
}
|
||||
_ => return None,
|
||||
|
||||
Reference in New Issue
Block a user