plotters_unsable/drawing/
backend.rs1use crate::style::{Color, FontDesc, FontError, Mixable};
2use std::error::Error;
3
4pub type BackendCoord = (i32, i32);
6
7#[derive(Debug)]
9pub enum DrawingErrorKind<E: Error> {
10 DrawingError(E),
12 FontError(FontError),
14}
15
16impl<E: Error> std::fmt::Display for DrawingErrorKind<E> {
17 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
18 match self {
19 DrawingErrorKind::DrawingError(e) => write!(fmt, "Drawing backend error: {}", e),
20 DrawingErrorKind::FontError(e) => write!(fmt, "Font loading error: {}", e),
21 }
22 }
23}
24
25impl<E: Error> Error for DrawingErrorKind<E> {}
26
27pub trait BackendStyle {
29 type ColorType: Color;
31
32 fn as_color(&self) -> &Self::ColorType;
34 }
36
37impl<T: Color> BackendStyle for T {
38 type ColorType = T;
39 fn as_color(&self) -> &T {
40 self
41 }
42}
43
44pub trait DrawingBackend {
52 type ErrorType: Error;
54
55 fn get_size(&self) -> (u32, u32);
57
58 fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
60
61 fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
67
68 fn draw_pixel<S: Color>(
72 &mut self,
73 point: BackendCoord,
74 color: &S,
75 ) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
76
77 fn draw_line<S: BackendStyle>(
82 &mut self,
83 mut from: BackendCoord,
84 mut to: BackendCoord,
85 style: &S,
86 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
87 if style.as_color().alpha() == 0.0 {
88 return Ok(());
89 }
90
91 let steep = (from.0 - to.0).abs() < (from.1 - to.1).abs();
92
93 if steep {
94 from = (from.1, from.0);
95 to = (to.1, to.0);
96 }
97
98 let (from, to) = if from.0 > to.0 {
99 (to, from)
100 } else {
101 (from, to)
102 };
103
104 let grad = f64::from(to.1 - from.1) / f64::from(to.0 - from.0);
105
106 let mut put_pixel = |(x, y): BackendCoord, b: f64| {
107 if steep {
108 self.draw_pixel((y, x), &style.as_color().mix(b))
109 } else {
110 self.draw_pixel((x, y), &style.as_color().mix(b))
111 }
112 };
113
114 let mut y = f64::from(from.1);
115
116 for x in from.0..=to.0 {
117 put_pixel((x, y as i32), 1.0 + y.floor() - y)?;
118 put_pixel((x, y as i32 + 1), y - y.floor())?;
119
120 y += grad;
121 }
122
123 Ok(())
124 }
125
126 fn draw_rect<S: BackendStyle>(
132 &mut self,
133 upper_left: BackendCoord,
134 bottom_right: BackendCoord,
135 style: &S,
136 fill: bool,
137 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
138 if style.as_color().alpha() == 0.0 {
139 return Ok(());
140 }
141 let (upper_left, bottom_right) = (
142 (
143 upper_left.0.min(bottom_right.0),
144 upper_left.1.min(bottom_right.1),
145 ),
146 (
147 upper_left.0.max(bottom_right.0),
148 upper_left.1.max(bottom_right.1),
149 ),
150 );
151
152 if fill {
153 if bottom_right.0 - upper_left.0 < bottom_right.1 - upper_left.1 {
154 for x in upper_left.0..=bottom_right.0 {
155 self.draw_line((x, upper_left.1), (x, bottom_right.1), style)?;
156 }
157 } else {
158 for y in upper_left.1..=bottom_right.1 {
159 self.draw_line((upper_left.0, y), (bottom_right.0, y), style)?;
160 }
161 }
162 } else {
163 self.draw_line(
164 (upper_left.0, upper_left.1),
165 (upper_left.0, bottom_right.1),
166 style,
167 )?;
168 self.draw_line(
169 (upper_left.0, upper_left.1),
170 (bottom_right.0, upper_left.1),
171 style,
172 )?;
173 self.draw_line(
174 (bottom_right.0, bottom_right.1),
175 (upper_left.0, bottom_right.1),
176 style,
177 )?;
178 self.draw_line(
179 (bottom_right.0, bottom_right.1),
180 (bottom_right.0, upper_left.1),
181 style,
182 )?;
183 }
184 Ok(())
185 }
186
187 fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
191 &mut self,
192 path: I,
193 style: &S,
194 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
195 if style.as_color().alpha() == 0.0 {
196 return Ok(());
197 }
198
199 let mut begin: Option<BackendCoord> = None;
200 for end in path.into_iter() {
201 if let Some(begin) = begin {
202 self.draw_line(begin, end, style)?;
203 }
204 begin = Some(end);
205 }
206 Ok(())
207 }
208
209 fn draw_circle<S: BackendStyle>(
215 &mut self,
216 center: BackendCoord,
217 radius: u32,
218 style: &S,
219 fill: bool,
220 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
221 if style.as_color().alpha() == 0.0 {
222 return Ok(());
223 }
224
225 let min = (f64::from(radius) * (1.0 - (2f64).sqrt() / 2.0)).ceil() as i32;
226 let max = (f64::from(radius) * (1.0 + (2f64).sqrt() / 2.0)).floor() as i32;
227
228 let range = min..=max;
229
230 let (up, down) = (
231 range.start() + center.1 - radius as i32,
232 range.end() + center.1 - radius as i32,
233 );
234
235 for dy in range {
236 let dy = dy - radius as i32;
237 let y = center.1 + dy;
238
239 let lx = (f64::from(radius) * f64::from(radius)
240 - (f64::from(dy) * f64::from(dy)).max(1e-5))
241 .sqrt();
242
243 let left = center.0 - lx.floor() as i32;
244 let right = center.0 + lx.floor() as i32;
245
246 let v = lx - lx.floor();
247
248 let x = center.0 + dy;
249 let top = center.1 - lx.floor() as i32;
250 let bottom = center.1 + lx.floor() as i32;
251
252 if fill {
253 self.draw_line((left, y), (right, y), style)?;
254 self.draw_line((x, top), (x, up), style)?;
255 self.draw_line((x, down), (x, bottom), style)?;
256 } else {
257 self.draw_pixel((left, y), &style.as_color().mix(1.0 - v))?;
258 self.draw_pixel((right, y), &style.as_color().mix(1.0 - v))?;
259
260 self.draw_pixel((x, top), &style.as_color().mix(1.0 - v))?;
261 self.draw_pixel((x, bottom), &style.as_color().mix(1.0 - v))?;
262 }
263
264 self.draw_pixel((left - 1, y), &style.as_color().mix(v))?;
265 self.draw_pixel((right + 1, y), &style.as_color().mix(v))?;
266 self.draw_pixel((x, top - 1), &style.as_color().mix(v))?;
267 self.draw_pixel((x, bottom + 1), &style.as_color().mix(v))?;
268 }
269
270 Ok(())
271 }
272
273 fn draw_text<'a, C: Color>(
279 &mut self,
280 text: &str,
281 font: &FontDesc<'a>,
282 pos: BackendCoord,
283 color: &C,
284 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
285 if color.alpha() == 0.0 {
286 return Ok(());
287 }
288
289 match font.draw(text, (pos.0, pos.1), |x, y, v| {
290 self.draw_pixel((x as i32, y as i32), &color.mix(f64::from(v)))
291 }) {
292 Ok(drawing_result) => drawing_result,
293 Err(font_error) => Err(DrawingErrorKind::FontError(font_error)),
294 }
295 }
296}