glance_core/drawing/
shapes.rs1use super::traits::Drawable;
2use crate::{
3 Result,
4 img::{Image, pixel::Pixel},
5};
6
7pub struct Circle<P: Pixel> {
11 pub position: (usize, usize),
13 pub color: P,
15 pub radius: u32,
17 pub filled: bool,
19 pub thickness: u32,
21}
22
23impl<P> Drawable<P> for Circle<P>
24where
25 P: Pixel,
26{
27 fn draw_on(&self, image: &mut Image<P>) -> Result<()> {
28 let (cx, cy) = (self.position.0 as i32, self.position.1 as i32);
29 let radius = self.radius as i32;
30 let thickness = self.thickness as i32;
31 let dims = image.dimensions();
32
33 let outer_radius = radius + thickness;
34 let outer_radius_sq = outer_radius.pow(2);
35 let inner_radius_sq = radius.pow(2);
36
37 for dy in -outer_radius..outer_radius {
38 for dx in -outer_radius..outer_radius {
39 let nx = cx + dx;
40 let ny = cy + dy;
41
42 if nx < 0 || ny < 0 {
44 continue;
45 }
46
47 let (nx, ny) = (nx as usize, ny as usize);
48 if nx >= dims.0 || ny >= dims.1 {
49 continue;
50 }
51
52 let distance_sq = dx * dx + dy * dy;
53 let draw_pixel = match self.filled {
55 true => distance_sq <= inner_radius_sq,
56 false => distance_sq <= outer_radius_sq && distance_sq >= inner_radius_sq,
57 };
58
59 if draw_pixel {
60 image.set_pixel((nx, ny), self.color)?;
61 }
62 }
63 }
64 Ok(())
65 }
66}
67
68pub struct AABB<P: Pixel> {
72 pub position: (usize, usize),
74 pub size: (usize, usize),
76 pub color: P,
78 pub filled: bool,
80 pub thickness: u32,
82}
83
84impl<P> Drawable<P> for AABB<P>
85where
86 P: Pixel,
87{
88 fn draw_on(&self, image: &mut Image<P>) -> Result<()> {
89 let (cx, cy) = (self.position.0 as i32, self.position.1 as i32);
90 let dims = image.dimensions();
91 let width = self.size.0 as i32;
92 let height = self.size.1 as i32;
93 let thickness = self.thickness as i32;
94
95 let left_x = cx - thickness;
96 let right_x = cx + width + thickness;
97 let top_y = cy - thickness;
98 let bottom_y = cy + height + thickness;
99
100 for x in left_x..right_x {
102 for y in top_y..bottom_y {
103 if x < 0 || y < 0 {
105 continue;
106 }
107
108 let nx = x as usize;
109 let ny = y as usize;
110
111 if nx >= dims.0 || ny >= dims.1 {
112 continue;
113 }
114
115 let on_left_edge = x - left_x <= thickness;
117 let on_right_edge = right_x - x <= thickness;
118 let on_top_edge = y - top_y < thickness;
119 let on_bottom_edge = bottom_y - y <= thickness;
120 let draw_pixel =
121 self.filled || on_left_edge || on_right_edge || on_top_edge || on_bottom_edge;
122
123 if draw_pixel {
124 image.set_pixel((nx, ny), self.color)?;
125 }
126 }
127 }
128
129 Ok(())
130 }
131}
132
133pub struct Line<P: Pixel> {
136 pub start: (usize, usize),
138 pub end: (usize, usize),
140 pub color: P,
142 pub thickness: u32,
144}
145
146impl<P> Drawable<P> for Line<P>
147where
148 P: Pixel,
149{
150 fn draw_on(&self, image: &mut Image<P>) -> Result<()> {
151 let (x0, y0) = self.start;
152 let (x1, y1) = self.end;
153
154 let dims = image.dimensions();
155
156 let x0 = x0 as i32;
157 let y0 = y0 as i32;
158 let x1 = x1 as i32;
159 let y1 = y1 as i32;
160 let thickness = self.thickness as i32;
161 let half_thickness = thickness / 2;
162
163 let dx = (x1 - x0).abs();
165 let dy = -(y1 - y0).abs();
166 let sx = if x0 < x1 { 1 } else { -1 };
168 let sy = if y0 < y1 { 1 } else { -1 };
169 let mut err = dx + dy;
170 let mut x = x0;
171 let mut y = y0;
172
173 loop {
174 for tx in -half_thickness..=half_thickness {
175 for ty in -half_thickness..=half_thickness {
176 let nx = x + tx;
177 let ny = y + ty;
178
179 if nx < 0 || ny < 0 {
181 continue;
182 }
183
184 let (nx, ny) = (nx as usize, ny as usize);
185 if nx >= dims.0 || ny >= dims.1 {
186 continue;
187 }
188
189 image.set_pixel((nx, ny), self.color)?;
190 }
191 }
192
193 if x == x1 && y == y1 {
195 break;
196 }
197
198 let err_twice = 2 * err;
199 if err_twice >= dy {
200 err += dy;
201 x += sx;
202 }
203 if err_twice <= dx {
204 err += dx;
205 y += sy;
206 }
207 }
208
209 Ok(())
210 }
211}