diff options
Diffstat (limited to 'src/bitmap.rs')
-rw-r--r-- | src/bitmap.rs | 103 |
1 files changed, 102 insertions, 1 deletions
diff --git a/src/bitmap.rs b/src/bitmap.rs index 01a39d9..8ff311b 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use std::convert::{From, Into, TryFrom}; | 1 | use std::{ |
2 | convert::{From, Into, TryFrom}, | ||
3 | ops::Sub, | ||
4 | }; | ||
2 | 5 | ||
3 | #[derive(Debug)] | 6 | #[derive(Debug)] |
4 | pub struct Pixmap<T> { | 7 | pub struct Pixmap<T> { |
@@ -59,6 +62,7 @@ where | |||
59 | data, | 62 | data, |
60 | } | 63 | } |
61 | } | 64 | } |
65 | |||
62 | pub fn new_with(width: u32, height: u32, start: T) -> Self { | 66 | pub fn new_with(width: u32, height: u32, start: T) -> Self { |
63 | let data = vec![start; (width * height) as usize]; | 67 | let data = vec![start; (width * height) as usize]; |
64 | Pixmap { | 68 | Pixmap { |
@@ -67,18 +71,22 @@ where | |||
67 | data, | 71 | data, |
68 | } | 72 | } |
69 | } | 73 | } |
74 | |||
70 | pub fn is_inside<P: Into<MapPoint>>(&self, pt: P) -> bool { | 75 | pub fn is_inside<P: Into<MapPoint>>(&self, pt: P) -> bool { |
71 | let MapPoint { x, y } = pt.into(); | 76 | let MapPoint { x, y } = pt.into(); |
72 | x < self.width && y < self.height | 77 | x < self.width && y < self.height |
73 | } | 78 | } |
79 | |||
74 | pub fn idx<P: Into<MapPoint>>(&self, pt: P) -> usize { | 80 | pub fn idx<P: Into<MapPoint>>(&self, pt: P) -> usize { |
75 | let MapPoint { x, y } = pt.into(); | 81 | let MapPoint { x, y } = pt.into(); |
76 | (y * self.width + x) as usize | 82 | (y * self.width + x) as usize |
77 | } | 83 | } |
84 | |||
78 | pub fn get<P: Into<MapPoint>>(&self, pt: P) -> T { | 85 | pub fn get<P: Into<MapPoint>>(&self, pt: P) -> T { |
79 | let idx = self.idx(pt); | 86 | let idx = self.idx(pt); |
80 | self.data[idx] | 87 | self.data[idx] |
81 | } | 88 | } |
89 | |||
82 | pub fn set<P: Into<MapPoint>>(&mut self, pt: P, new_val: T) -> T { | 90 | pub fn set<P: Into<MapPoint>>(&mut self, pt: P, new_val: T) -> T { |
83 | let pt = pt.into(); | 91 | let pt = pt.into(); |
84 | let old_val = self.get(pt); | 92 | let old_val = self.get(pt); |
@@ -86,4 +94,97 @@ where | |||
86 | self.data[idx] = new_val; | 94 | self.data[idx] = new_val; |
87 | old_val | 95 | old_val |
88 | } | 96 | } |
97 | |||
98 | pub fn get_circle<P: Into<MapPoint>>(&self, center: P, radius: u32) -> Vec<MapPoint> { | ||
99 | let mut circle: Vec<(i64, i64)> = vec![]; | ||
100 | let MapPoint { x, y } = center.into(); | ||
101 | let x = x as i64; | ||
102 | let y = y as i64; | ||
103 | let (mut dx, mut dy, mut err) = (radius as i64, 0i64, 1 - radius as i64); | ||
104 | while dx >= dy { | ||
105 | circle.push((x + dx, y + dy)); | ||
106 | circle.push((x - dx, y + dy)); | ||
107 | circle.push((x + dx, y - dy)); | ||
108 | circle.push((x - dx, y - dy)); | ||
109 | circle.push((x + dy, y + dx)); | ||
110 | circle.push((x - dy, y + dx)); | ||
111 | circle.push((x + dy, y - dx)); | ||
112 | circle.push((x - dy, y - dx)); | ||
113 | dy = dy + 1; | ||
114 | if err < 0 { | ||
115 | err = err + 2 * dy + 1; | ||
116 | } else { | ||
117 | dx -= 1; | ||
118 | err += 2 * (dy - dx) + 1; | ||
119 | } | ||
120 | } | ||
121 | for xi in 0..radius as i64 { | ||
122 | for yi in 0..radius as i64 { | ||
123 | if xi.pow(2) + yi.pow(2) < (radius as i64).pow(2) { | ||
124 | circle.push((x + xi, y + yi)); | ||
125 | circle.push((x - xi, y + yi)); | ||
126 | circle.push((x + xi, y - yi)); | ||
127 | circle.push((x - xi, y - yi)); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | circle | ||
132 | .into_iter() | ||
133 | .flat_map(|pt| MapPoint::try_from(pt)) | ||
134 | .filter(|&pt| self.is_inside(pt)) | ||
135 | .collect() | ||
136 | } | ||
137 | |||
138 | pub fn get_line<P: Into<MapPoint>>(&self, start: P, end: P) -> Vec<MapPoint> { | ||
139 | let MapPoint { x: x1, y: y1 } = start.into(); | ||
140 | let MapPoint { x: x2, y: y2 } = end.into(); | ||
141 | let mut coordinates = vec![]; | ||
142 | let dx = abs_difference(x1, x2) as i64; | ||
143 | let dy = abs_difference(y1, y2) as i64; | ||
144 | let sx = { | ||
145 | if x1 < x2 { | ||
146 | 1 | ||
147 | } else { | ||
148 | -1 | ||
149 | } | ||
150 | }; | ||
151 | let sy = { | ||
152 | if y1 < y2 { | ||
153 | 1 | ||
154 | } else { | ||
155 | -1 | ||
156 | } | ||
157 | }; | ||
158 | let mut err: i64 = dx - dy; | ||
159 | let mut current_x = x1 as i64; | ||
160 | let mut current_y = y1 as i64; | ||
161 | loop { | ||
162 | coordinates.push((current_x, current_y)); | ||
163 | if current_x == x2 as i64 && current_y == y2 as i64 { | ||
164 | break; | ||
165 | } | ||
166 | let e2 = 2 * err; | ||
167 | if e2 > -dy { | ||
168 | err -= dy; | ||
169 | current_x += sx; | ||
170 | } | ||
171 | if e2 < dx { | ||
172 | err += dx; | ||
173 | current_y += sy; | ||
174 | } | ||
175 | } | ||
176 | coordinates | ||
177 | .into_iter() | ||
178 | .flat_map(|pt| MapPoint::try_from(pt)) | ||
179 | .filter(|&pt| self.is_inside(pt)) | ||
180 | .collect() | ||
181 | } | ||
182 | } | ||
183 | |||
184 | fn abs_difference<T: Sub<Output = T> + Ord>(x: T, y: T) -> T { | ||
185 | if x < y { | ||
186 | y - x | ||
187 | } else { | ||
188 | x - y | ||
189 | } | ||
89 | } | 190 | } |