From 3f711f0be5ad3b434fcfdebf2388b1c036f87b9f Mon Sep 17 00:00:00 2001 From: TudbuT Date: Mon, 9 Feb 2026 17:57:28 +0100 Subject: [PATCH] more operations, fixes, improvements --- src/assist.rs | 25 ------------------ src/canvas.rs | 14 +++++----- src/lib.rs | 66 ++++++++++++++++++++++++++-------------------- src/ops/area.rs | 12 ++++----- src/ops/axial.rs | 10 +++---- src/ops/map.rs | 2 +- src/ops/stretch.rs | 4 +-- src/pixel.rs | 30 ++++++++++----------- src/pixfn.rs | 12 ++++----- src/polar_math.rs | 46 ++++++++++++++++++++++++++++++++ 10 files changed, 125 insertions(+), 96 deletions(-) delete mode 100644 src/assist.rs create mode 100644 src/polar_math.rs diff --git a/src/assist.rs b/src/assist.rs deleted file mode 100644 index f1a6d4b..0000000 --- a/src/assist.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::f32::consts::*; - -use crate::Canvas; - -pub fn polar(x: f32, y: f32, meta: Canvas) -> (f32, f32) { - let x = x - 0.5; - let y = y - 0.5; - let r = (x * x + y * y).sqrt(); - let mut phi = f32::atan2(y, x) + PI / 2.; - phi = phi.rem_euclid(TAU); - (r * 2. / corner_distance(meta), phi / TAU) -} - -pub fn axial(r: f32, phi: f32, meta: Canvas) -> (f32, f32) { - let phi = phi * TAU - PI / 2.; - let r = r / 2. * corner_distance(meta); - let x = r * phi.cos(); - let y = r * phi.sin(); - (x + 0.5, y + 0.5) -} - -fn corner_distance(meta: Canvas) -> f32 { - let corner_distance = (meta.width * meta.width + meta.height * meta.height).sqrt(); - corner_distance / meta.width.max(meta.height) -} diff --git a/src/canvas.rs b/src/canvas.rs index 43f898a..c7645e9 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -2,8 +2,8 @@ use crate::{ImgSyn, pixel::Pixel}; #[derive(Clone, Copy, PartialEq)] pub struct Canvas { - pub width: f32, - pub height: f32, + pub width: f64, + pub height: f64, pub default_px: Pixel, } @@ -13,7 +13,7 @@ pub struct PaintedCanvas { } impl Canvas { - pub fn new(width: f32, height: f32, default_px: Pixel) -> Self { + pub fn new(width: f64, height: f64, default_px: Pixel) -> Self { Self { width, height, @@ -23,7 +23,7 @@ impl Canvas { } impl ImgSyn for Canvas { - fn getpx(&self, _meta: Canvas, _x: f32, _y: f32) -> Pixel { + fn getpx(&self, _meta: Canvas, _x: f64, _y: f64) -> Pixel { self.default_px } } @@ -32,10 +32,10 @@ impl PaintedCanvas { pub fn new(meta @ Canvas { width, height, .. }: Canvas, function: impl ImgSyn) -> Self { Self { array: (0..height as u32) - .map(|y| y as f32 / height) + .map(|y| y as f64 / height) .map(|y| { (0..width as u32) - .map(|x| x as f32 / width) + .map(|x| x as f64 / width) .map(|x| function.getpx(meta, x, y)) .collect() }) @@ -52,7 +52,7 @@ impl PaintedCanvas { } impl ImgSyn for PaintedCanvas { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> Pixel { + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> Pixel { // float coords -> int coords let x = (x * meta.width).round() as usize; let y = (y * meta.height).round() as usize; diff --git a/src/lib.rs b/src/lib.rs index ac35104..3e7420e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ -pub mod assist; mod canvas; mod ops; mod pixel; mod pixfn; +pub mod polar_math; pub use canvas::*; pub use pixel::*; @@ -14,11 +14,11 @@ use crate::ops::{ }; pub trait ImgSynPixFn: Clone { - fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T; + fn run(&self, meta: Canvas, x: f64, y: f64, pixel: Pixel) -> T; } pub trait ImgSyn: Clone { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> Pixel; + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> Pixel; fn map>(self, f: F) -> ImgSynMap { ImgSynMap(self, f) } @@ -31,10 +31,10 @@ pub trait ImgSyn: Clone { } fn mapped_rect) -> ImgB>( self, - begin_x: f32, - begin_y: f32, - size_x: f32, - size_y: f32, + begin_x: f64, + begin_y: f64, + size_x: f64, + size_y: f64, f: F, ) -> ImgSynRect { let rect = (begin_x, begin_y, size_x, size_y); @@ -42,10 +42,10 @@ pub trait ImgSyn: Clone { } fn add_image( self, - begin_x: f32, - begin_y: f32, - size_x: f32, - size_y: f32, + begin_x: f64, + begin_y: f64, + size_x: f64, + size_y: f64, img: ImgB, ) -> ImgSynRect { let rect = (begin_x, begin_y, size_x, size_y); @@ -70,7 +70,7 @@ pub trait ImgSyn: Clone { fn axial(self) -> ImgSynPolar { ImgSynPolar(self) } - fn stretched_by(self, x: f32, y: f32) -> ImgSynStretched { + fn stretched_by(self, x: f64, y: f64) -> ImgSynStretched { ImgSynStretched(self, (x, y)) } fn paint(self, meta: Canvas) -> PaintedCanvas { @@ -99,7 +99,7 @@ pub trait ImgSyn: Clone { mod test { use std::fs; - use crate::{Canvas, ImgSyn, PixFnFloat, Pixel}; + use crate::{Canvas, ImgSyn, PixFnFloat, Pixel, polar_math::distance_from_circle}; #[test] fn test() { @@ -108,7 +108,7 @@ mod test { "test.png", canvas .polar() - .map(|_, y: f32, pix: Pixel| pix.with_r((y - 0.5).abs() * 2.)) + .map(|_, y: f64, pix: Pixel| pix.with_r((y - 0.5).abs() * 2.)) .map(|_, y, pix: Pixel| pix.with_b(y)) .axial() .map(PixFnFloat(|_, _, y, pix| pix.with_g(y))) @@ -118,7 +118,7 @@ mod test { ) .area(PixFnFloat(|_, _, _, px| px.g > 0.8 && px.r < 0.3), |img| { img.polar() - .map(PixFnFloat(|_, x, y, pix| pix.with_r(x).with_b(1. - y))) + .map(PixFnFloat(|_, x, _, pix| pix.with_r(x).with_b(0.0))) .axial() }) .mapped_rect(0.3, 0.3, 0.4, 0.4, |img| { @@ -145,30 +145,38 @@ mod test { "graph.png", canvas .add_image( - 0.1, - 0.0, + 0.07, + 0.03, 0.9, 0.9, Canvas::new(900., 900., Pixel::new_black()).map_area( - |x, y, _| x < 0.7 || y > 0.3, + |x, y, _| distance_from_circle(x, y, 1.0, 0.0, 0.5, 1.0, 1.0) > 0.0, |x, y, px: Pixel| px.with_r(x).with_g(1. - y), ), ) .map_area( |x, y, _| { - let t = 0.004; - (0.1 - t..0.1 + t).contains(&x) || (0.9 - t..0.9 + t).contains(&y) + let xc = 0.07; + let yc = 0.93; + let t = 0.003; + (xc - t..=xc + t).contains(&x) && y >= 0.03 + || (yc - t..=yc + t).contains(&y) && x <= 0.97 + }, + |x, y, px: Pixel| { + if (1. + x - y) % 0.03 <= 0.02 { + px.with_rgb(1.0, 0.0, 0.5) + } else { + px.with_rgb(1.0, 1.0, 0.0) + } }, - |_, _, px: Pixel| px.with_rgb(1.0, 0.0, 0.0), ) - .mapped_rect(0.05, 0.90, 0.05, 0.05, |img| { - img.polar() - .map_area( - |r: f32, phi, _| (r - 0.3).abs() < 0.04, - |_, _, px: Pixel| px.with_rgb_of(0.0), - ) - .axial() - .stretched_by(1.0, 1.5) + .mapped_rect(0.02, 0.93, 0.05, 0.05, |img| { + img.map_area( + |x: f64, y: f64, _| { + distance_from_circle(x, y, 0.6, 0.5, 0.2, 1.0, 1.4).abs() < 0.03 + }, + |_, _, px: Pixel| px.with_rgb_of(0.0), + ) }) .paint(canvas) .png(canvas), diff --git a/src/ops/area.rs b/src/ops/area.rs index 335331e..6118049 100644 --- a/src/ops/area.rs +++ b/src/ops/area.rs @@ -13,7 +13,7 @@ where C: ImgSynPixFn, F: ImgSynPixFn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { let px = self.0.getpx(meta, x, y); if !self.1.run(meta, x, y, px) { return px; @@ -35,7 +35,7 @@ where ImgB: ImgSyn, C: ImgSynPixFn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { let px = self.0.getpx(meta, x, y); if !self.2.run(meta, x, y, px) { return px; @@ -48,7 +48,7 @@ where pub struct ImgSynRect( pub(crate) Prev, pub(crate) ImgB, - pub(crate) (f32, f32, f32, f32), + pub(crate) (f64, f64, f64, f64), ); impl ImgSyn for ImgSynRect @@ -56,7 +56,7 @@ where Prev: ImgSyn, ImgB: ImgSyn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { let px = self.0.getpx(meta, x, y); let (startx, starty, sizex, sizey) = self.2; if x < startx || y < starty { @@ -74,13 +74,13 @@ where } #[derive(Clone, Copy)] -pub struct ImgSynUnmapRect(pub(crate) Prev, pub(crate) (f32, f32, f32, f32)); +pub struct ImgSynUnmapRect(pub(crate) Prev, pub(crate) (f64, f64, f64, f64)); impl ImgSyn for ImgSynUnmapRect where Prev: ImgSyn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { let (startx, starty, sizex, sizey) = self.1; self.0.getpx( Canvas::new(meta.width / sizex, meta.height / sizey, meta.default_px), diff --git a/src/ops/axial.rs b/src/ops/axial.rs index 4e3f689..b215051 100644 --- a/src/ops/axial.rs +++ b/src/ops/axial.rs @@ -1,6 +1,6 @@ use crate::{ Canvas, ImgSyn, - assist::{axial, polar}, + polar_math::{axial, polar}, }; #[derive(Clone, Copy)] @@ -10,8 +10,8 @@ impl ImgSyn for ImgSynAxial where Prev: ImgSyn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { - let (x, y) = axial(x, y, meta); + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { + let (x, y) = axial(x, y); self.0.getpx(meta, x, y) } } @@ -22,8 +22,8 @@ impl ImgSyn for ImgSynPolar where Prev: ImgSyn, { - fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel { - let (x, y) = polar(x, y, meta); + fn getpx(&self, meta: Canvas, x: f64, y: f64) -> crate::Pixel { + let (x, y) = polar(x, y); self.0.getpx(meta, x, y) } } diff --git a/src/ops/map.rs b/src/ops/map.rs index 6127d29..459026f 100644 --- a/src/ops/map.rs +++ b/src/ops/map.rs @@ -4,7 +4,7 @@ use crate::{ImgSyn, ImgSynPixFn, Pixel}; pub struct ImgSynMap>(pub(crate) Prev, pub(crate) F); impl> ImgSyn for ImgSynMap { - fn getpx(&self, meta: crate::Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: crate::Canvas, x: f64, y: f64) -> crate::Pixel { self.1.run(meta, x, y, self.0.getpx(meta, x, y)) } } diff --git a/src/ops/stretch.rs b/src/ops/stretch.rs index b43d81f..d59361a 100644 --- a/src/ops/stretch.rs +++ b/src/ops/stretch.rs @@ -1,10 +1,10 @@ use crate::ImgSyn; #[derive(Clone, Copy)] -pub struct ImgSynStretched(pub(crate) Prev, pub(crate) (f32, f32)); +pub struct ImgSynStretched(pub(crate) Prev, pub(crate) (f64, f64)); impl ImgSyn for ImgSynStretched { - fn getpx(&self, meta: crate::Canvas, x: f32, y: f32) -> crate::Pixel { + fn getpx(&self, meta: crate::Canvas, x: f64, y: f64) -> crate::Pixel { self.0.getpx( meta, x / self.1.0 - 0.5 / self.1.0 + 0.5, diff --git a/src/pixel.rs b/src/pixel.rs index 0ac37c0..4868f3a 100644 --- a/src/pixel.rs +++ b/src/pixel.rs @@ -1,9 +1,9 @@ #[derive(Clone, Copy, PartialEq)] pub struct Pixel { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, + pub r: f64, + pub g: f64, + pub b: f64, + pub a: f64, } impl Pixel { @@ -33,26 +33,26 @@ impl Pixel { } } - pub fn of(r: f32, g: f32, b: f32, a: f32) -> Pixel { + pub fn of(r: f64, g: f64, b: f64, a: f64) -> Pixel { Self { r, g, b, a } } - pub fn with_r(self, x: f32) -> Pixel { + pub fn with_r(self, x: f64) -> Pixel { Self { r: x, ..self } } - pub fn with_g(self, x: f32) -> Pixel { + pub fn with_g(self, x: f64) -> Pixel { Self { g: x, ..self } } - pub fn with_b(self, x: f32) -> Pixel { + pub fn with_b(self, x: f64) -> Pixel { Self { b: x, ..self } } - pub fn with_a(self, x: f32) -> Pixel { + pub fn with_a(self, x: f64) -> Pixel { Self { a: x, ..self } } - pub fn with_rgb(self, r: f32, g: f32, b: f32) -> Pixel { + pub fn with_rgb(self, r: f64, g: f64, b: f64) -> Pixel { Self { r, g, b, ..self } } - pub fn with_rgb_of(self, x: f32) -> Pixel { + pub fn with_rgb_of(self, x: f64) -> Pixel { Self { r: x, g: x, @@ -65,19 +65,19 @@ impl Pixel { f(self) } - pub fn map_r(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + pub fn map_r(mut self, f: impl FnOnce(f64) -> f64) -> Pixel { self.r = f(self.r); self } - pub fn map_g(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + pub fn map_g(mut self, f: impl FnOnce(f64) -> f64) -> Pixel { self.r = f(self.r); self } - pub fn map_b(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + pub fn map_b(mut self, f: impl FnOnce(f64) -> f64) -> Pixel { self.r = f(self.r); self } - pub fn map_a(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + pub fn map_a(mut self, f: impl FnOnce(f64) -> f64) -> Pixel { self.r = f(self.r); self } diff --git a/src/pixfn.rs b/src/pixfn.rs index 83ad80a..3c98fe4 100644 --- a/src/pixfn.rs +++ b/src/pixfn.rs @@ -6,7 +6,7 @@ impl ImgSynPixFn for PixFnInt where F: (Fn(Canvas, u32, u32, Pixel) -> T) + Copy, { - fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T { + fn run(&self, meta: Canvas, x: f64, y: f64, pixel: Pixel) -> T { self.0( meta, (x * meta.width).round() as u32, @@ -17,21 +17,21 @@ where } #[derive(Clone, Copy)] -pub struct PixFnFloat T) + Copy>(pub F); +pub struct PixFnFloat T) + Copy>(pub F); impl ImgSynPixFn for PixFnFloat where - F: (Fn(Canvas, f32, f32, Pixel) -> T) + Copy, + F: (Fn(Canvas, f64, f64, Pixel) -> T) + Copy, { - fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T { + fn run(&self, meta: Canvas, x: f64, y: f64, pixel: Pixel) -> T { self.0(meta, x, y, pixel) } } impl ImgSynPixFn for F where - F: (Fn(f32, f32, Pixel) -> T) + Copy, + F: (Fn(f64, f64, Pixel) -> T) + Copy, { - fn run(&self, _meta: Canvas, x: f32, y: f32, px: Pixel) -> T { + fn run(&self, _meta: Canvas, x: f64, y: f64, px: Pixel) -> T { self(x, y, px) } } diff --git a/src/polar_math.rs b/src/polar_math.rs new file mode 100644 index 0000000..bd473f6 --- /dev/null +++ b/src/polar_math.rs @@ -0,0 +1,46 @@ +use std::f64::consts::*; + +use crate::Canvas; + +pub fn polar(x: f64, y: f64) -> (f64, f64) { + let x = x - 0.5; + let y = y - 0.5; + let r = (x * x + y * y).sqrt(); + let mut phi = f64::atan2(y, x) + PI / 2.; + phi = phi.rem_euclid(TAU); + (r * 2. / SQRT_2, phi / TAU) +} + +pub fn axial(r: f64, phi: f64) -> (f64, f64) { + let phi = phi * TAU - PI / 2.; + let r = r / 2. * SQRT_2; + let x = r * phi.cos(); + let y = r * phi.sin(); + (x + 0.5, y + 0.5) +} + +/// rotates polar coordinates (phi @ 0..1), n=1.0 ~ 360° +pub fn polar_rotate(phi: f64, n: f64) -> f64 { + (phi + n).rem_euclid(1.0) +} + +pub fn distance_from_circle( + x: f64, + y: f64, + circle_x: f64, + circle_y: f64, + radius: f64, + xstretch: f64, + ystretch: f64, +) -> f64 { + let xdiff = (x - circle_x) / xstretch; + let ydiff = (y - circle_y) / ystretch; + let r = (xdiff * xdiff + ydiff * ydiff).sqrt(); + + r - radius +} + +pub fn relative_corner_distance(meta: Canvas) -> f64 { + let corner_distance = (meta.width * meta.width + meta.height * meta.height).sqrt(); + corner_distance / meta.width.max(meta.height) +}