From c7039f0fc2d49dd0501db8f201e66a915d189ac1 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 14 Mar 2021 12:35:34 +0530 Subject: add symmetry options --- src/app.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++------ src/bitmap.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/app.rs b/src/app.rs index bcc9c3a..13f8732 100644 --- a/src/app.rs +++ b/src/app.rs @@ -38,6 +38,12 @@ struct Grid { color: Color, } +#[derive(Debug, Default, Copy, Clone)] +struct Symmetry { + x: Option, + y: Option, +} + impl Grid { fn new() -> Self { Self { @@ -99,6 +105,44 @@ impl<'ctx> AppState<'ctx> { self.grid.enabled = !self.grid.enabled; } + fn cycle_symmetry(&mut self) { + let Symmetry { x, y } = self.symmetry; + self.symmetry = match (x, y) { + (None, None) => Symmetry { + x: Some(self.width() / 2), + y: None, + }, + (_, None) => Symmetry { + x: None, + y: Some(self.height() / 2), + }, + (None, y) => Symmetry { + x: Some(self.width() / 2), + y, + }, + (Some(_), Some(_)) => Symmetry { x: None, y: None }, + } + } + + fn apply_symmetry(&self, figure: &[MapPoint]) -> Vec { + let Symmetry { x, y } = self.symmetry; + match (x, y) { + (None, None) => vec![], + (Some(line), None) => self.pixmap.mirror_figure(figure, line, Axis::X), + (None, Some(line)) => self.pixmap.mirror_figure(figure, line, Axis::Y), + (Some(x), Some(y)) => { + let along_x = self.pixmap.mirror_figure(figure, x, Axis::X); + let along_y = self.pixmap.mirror_figure(figure, y, Axis::Y); + let reflected = self.pixmap.reflect_figure(figure, (x, y).into()); + along_x + .into_iter() + .chain(along_y) + .chain(reflected) + .collect() + } + } + } + fn paint_point>( &mut self, center: P, @@ -106,21 +150,24 @@ impl<'ctx> AppState<'ctx> { ) -> Result, ()> { let radius = self.brush_size as u32; let center = self.idx_at_coord(center).ok_or(())?; - let mut circle_modify_record = vec![]; - for point in self.pixmap.get_circle(center, radius) { + let mut modify_record = vec![]; + let circle = self.pixmap.get_circle(center, radius); + let sym_circle = self.apply_symmetry(&circle); + for point in circle.into_iter().chain(sym_circle) { let old_val = self.pixmap.set(point, val); - circle_modify_record.push(ModifyRecord::new(point, old_val, val)); + modify_record.push(ModifyRecord::new(point, old_val, val)); } - Ok(circle_modify_record) + Ok(modify_record) } fn paint_line>(&mut self, start: P, end: P) -> Result, ()> { let start = self.idx_at_coord(start).ok_or(())?; let end = self.idx_at_coord(end).ok_or(())?; - let line_coords = self.pixmap.get_line(start, end); + let line = self.pixmap.get_line(start, end); + let sym_line = self.apply_symmetry(&line); let mut line_modify_record = vec![]; let val = self.active_color; - for point in line_coords { + for point in line.into_iter().chain(sym_line) { let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32); for c in circle_around_point { let old_val = self.pixmap.set(c, val); @@ -292,7 +339,6 @@ impl<'ctx> AppState<'ctx> { self.canvas.present(); let mut event_pump = self.context.event_pump().unwrap(); - 'running: loop { let mouse = event_pump.mouse_state(); for event in event_pump.poll_iter() { diff --git a/src/bitmap.rs b/src/bitmap.rs index 8ff311b..726e0a2 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -1,6 +1,6 @@ use std::{ convert::{From, Into, TryFrom}, - ops::Sub, + ops::{Add, Sub}, }; #[derive(Debug)] @@ -50,6 +50,56 @@ impl TryFrom<(i64, i64)> for MapPoint { } } +impl Add for MapPoint { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + MapPoint { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + +impl Sub for MapPoint { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + MapPoint { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Axis { + X, + Y, +} + +impl MapPoint { + #[inline] + pub fn scale(self, c: u32) -> MapPoint { + MapPoint { + x: self.x * c, + y: self.y * c, + } + } + + #[inline] + pub fn mirror_about(self, line: u32, axis: Axis) -> MapPoint { + let MapPoint { x, y } = self; + match axis { + Axis::X => MapPoint { x, y: 2 * line - y }, + Axis::Y => MapPoint { x: 2 * line - x, y }, + } + } + + #[inline] + pub fn reflect(self, around: MapPoint) -> MapPoint { + around.scale(2) - self + } +} + impl Pixmap where T: Copy + Clone + Default, @@ -179,6 +229,22 @@ where .filter(|&pt| self.is_inside(pt)) .collect() } + + pub fn mirror_figure(&self, figure: &[MapPoint], line: u32, axis: Axis) -> Vec { + figure + .iter() + .map(|pt| pt.mirror_about(line, axis)) + .filter(|&pt| self.is_inside(pt)) + .collect() + } + + pub fn reflect_figure(&self, figure: &[MapPoint], around: MapPoint) -> Vec { + figure + .iter() + .map(|pt| pt.reflect(around)) + .filter(|&pt| self.is_inside(pt)) + .collect() + } } fn abs_difference + Ord>(x: T, y: T) -> T { -- cgit v1.2.3