aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs60
-rw-r--r--src/bitmap.rs68
2 files changed, 120 insertions, 8 deletions
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 {
38 color: Color, 38 color: Color,
39} 39}
40 40
41#[derive(Debug, Default, Copy, Clone)]
42struct Symmetry {
43 x: Option<u32>,
44 y: Option<u32>,
45}
46
41impl Grid { 47impl Grid {
42 fn new() -> Self { 48 fn new() -> Self {
43 Self { 49 Self {
@@ -99,6 +105,44 @@ impl<'ctx> AppState<'ctx> {
99 self.grid.enabled = !self.grid.enabled; 105 self.grid.enabled = !self.grid.enabled;
100 } 106 }
101 107
108 fn cycle_symmetry(&mut self) {
109 let Symmetry { x, y } = self.symmetry;
110 self.symmetry = match (x, y) {
111 (None, None) => Symmetry {
112 x: Some(self.width() / 2),
113 y: None,
114 },
115 (_, None) => Symmetry {
116 x: None,
117 y: Some(self.height() / 2),
118 },
119 (None, y) => Symmetry {
120 x: Some(self.width() / 2),
121 y,
122 },
123 (Some(_), Some(_)) => Symmetry { x: None, y: None },
124 }
125 }
126
127 fn apply_symmetry(&self, figure: &[MapPoint]) -> Vec<MapPoint> {
128 let Symmetry { x, y } = self.symmetry;
129 match (x, y) {
130 (None, None) => vec![],
131 (Some(line), None) => self.pixmap.mirror_figure(figure, line, Axis::X),
132 (None, Some(line)) => self.pixmap.mirror_figure(figure, line, Axis::Y),
133 (Some(x), Some(y)) => {
134 let along_x = self.pixmap.mirror_figure(figure, x, Axis::X);
135 let along_y = self.pixmap.mirror_figure(figure, y, Axis::Y);
136 let reflected = self.pixmap.reflect_figure(figure, (x, y).into());
137 along_x
138 .into_iter()
139 .chain(along_y)
140 .chain(reflected)
141 .collect()
142 }
143 }
144 }
145
102 fn paint_point<P: Into<Point>>( 146 fn paint_point<P: Into<Point>>(
103 &mut self, 147 &mut self,
104 center: P, 148 center: P,
@@ -106,21 +150,24 @@ impl<'ctx> AppState<'ctx> {
106 ) -> Result<Vec<ModifyRecord>, ()> { 150 ) -> Result<Vec<ModifyRecord>, ()> {
107 let radius = self.brush_size as u32; 151 let radius = self.brush_size as u32;
108 let center = self.idx_at_coord(center).ok_or(())?; 152 let center = self.idx_at_coord(center).ok_or(())?;
109 let mut circle_modify_record = vec![]; 153 let mut modify_record = vec![];
110 for point in self.pixmap.get_circle(center, radius) { 154 let circle = self.pixmap.get_circle(center, radius);
155 let sym_circle = self.apply_symmetry(&circle);
156 for point in circle.into_iter().chain(sym_circle) {
111 let old_val = self.pixmap.set(point, val); 157 let old_val = self.pixmap.set(point, val);
112 circle_modify_record.push(ModifyRecord::new(point, old_val, val)); 158 modify_record.push(ModifyRecord::new(point, old_val, val));
113 } 159 }
114 Ok(circle_modify_record) 160 Ok(modify_record)
115 } 161 }
116 162
117 fn paint_line<P: Into<Point>>(&mut self, start: P, end: P) -> Result<Vec<ModifyRecord>, ()> { 163 fn paint_line<P: Into<Point>>(&mut self, start: P, end: P) -> Result<Vec<ModifyRecord>, ()> {
118 let start = self.idx_at_coord(start).ok_or(())?; 164 let start = self.idx_at_coord(start).ok_or(())?;
119 let end = self.idx_at_coord(end).ok_or(())?; 165 let end = self.idx_at_coord(end).ok_or(())?;
120 let line_coords = self.pixmap.get_line(start, end); 166 let line = self.pixmap.get_line(start, end);
167 let sym_line = self.apply_symmetry(&line);
121 let mut line_modify_record = vec![]; 168 let mut line_modify_record = vec![];
122 let val = self.active_color; 169 let val = self.active_color;
123 for point in line_coords { 170 for point in line.into_iter().chain(sym_line) {
124 let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32); 171 let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32);
125 for c in circle_around_point { 172 for c in circle_around_point {
126 let old_val = self.pixmap.set(c, val); 173 let old_val = self.pixmap.set(c, val);
@@ -292,7 +339,6 @@ impl<'ctx> AppState<'ctx> {
292 self.canvas.present(); 339 self.canvas.present();
293 340
294 let mut event_pump = self.context.event_pump().unwrap(); 341 let mut event_pump = self.context.event_pump().unwrap();
295
296 'running: loop { 342 'running: loop {
297 let mouse = event_pump.mouse_state(); 343 let mouse = event_pump.mouse_state();
298 for event in event_pump.poll_iter() { 344 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 @@
1use std::{ 1use std::{
2 convert::{From, Into, TryFrom}, 2 convert::{From, Into, TryFrom},
3 ops::Sub, 3 ops::{Add, Sub},
4}; 4};
5 5
6#[derive(Debug)] 6#[derive(Debug)]
@@ -50,6 +50,56 @@ impl TryFrom<(i64, i64)> for MapPoint {
50 } 50 }
51} 51}
52 52
53impl Add for MapPoint {
54 type Output = Self;
55 fn add(self, rhs: Self) -> Self::Output {
56 MapPoint {
57 x: self.x + rhs.x,
58 y: self.y + rhs.y,
59 }
60 }
61}
62
63impl Sub for MapPoint {
64 type Output = Self;
65 fn sub(self, rhs: Self) -> Self::Output {
66 MapPoint {
67 x: self.x - rhs.x,
68 y: self.y - rhs.y,
69 }
70 }
71}
72
73#[derive(Debug, Copy, Clone)]
74pub enum Axis {
75 X,
76 Y,
77}
78
79impl MapPoint {
80 #[inline]
81 pub fn scale(self, c: u32) -> MapPoint {
82 MapPoint {
83 x: self.x * c,
84 y: self.y * c,
85 }
86 }
87
88 #[inline]
89 pub fn mirror_about(self, line: u32, axis: Axis) -> MapPoint {
90 let MapPoint { x, y } = self;
91 match axis {
92 Axis::X => MapPoint { x, y: 2 * line - y },
93 Axis::Y => MapPoint { x: 2 * line - x, y },
94 }
95 }
96
97 #[inline]
98 pub fn reflect(self, around: MapPoint) -> MapPoint {
99 around.scale(2) - self
100 }
101}
102
53impl<T> Pixmap<T> 103impl<T> Pixmap<T>
54where 104where
55 T: Copy + Clone + Default, 105 T: Copy + Clone + Default,
@@ -179,6 +229,22 @@ where
179 .filter(|&pt| self.is_inside(pt)) 229 .filter(|&pt| self.is_inside(pt))
180 .collect() 230 .collect()
181 } 231 }
232
233 pub fn mirror_figure(&self, figure: &[MapPoint], line: u32, axis: Axis) -> Vec<MapPoint> {
234 figure
235 .iter()
236 .map(|pt| pt.mirror_about(line, axis))
237 .filter(|&pt| self.is_inside(pt))
238 .collect()
239 }
240
241 pub fn reflect_figure(&self, figure: &[MapPoint], around: MapPoint) -> Vec<MapPoint> {
242 figure
243 .iter()
244 .map(|pt| pt.reflect(around))
245 .filter(|&pt| self.is_inside(pt))
246 .collect()
247 }
182} 248}
183 249
184fn abs_difference<T: Sub<Output = T> + Ord>(x: T, y: T) -> T { 250fn abs_difference<T: Sub<Output = T> + Ord>(x: T, y: T) -> T {