aboutsummaryrefslogtreecommitdiff
path: root/src/bitmap.rs
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-13 17:24:21 +0000
committerAkshay <[email protected]>2021-03-13 17:24:21 +0000
commitef37a6552a71f86eb1e393b61a3bbb5d81815783 (patch)
treed5f3fb74756508941f2d36960b60d52ecf2d52de /src/bitmap.rs
parent4b4ebe84d2cfbb8b0ddf7b678c5fe4cff53e5089 (diff)
factor out line and circle drawing into bitmap
Diffstat (limited to 'src/bitmap.rs')
-rw-r--r--src/bitmap.rs103
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 @@
1use std::convert::{From, Into, TryFrom}; 1use std::{
2 convert::{From, Into, TryFrom},
3 ops::Sub,
4};
2 5
3#[derive(Debug)] 6#[derive(Debug)]
4pub struct Pixmap<T> { 7pub 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
184fn 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}