1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
#![allow(unused_variables, dead_code)] extern crate euclid; pub mod backend; mod util; pub mod svg; use backend::{Command, DrawOptions}; use euclid::TypedPoint2D; use std::ops::{Deref, DerefMut}; pub struct Canvas<T> { backend: T, } impl<T> Deref for Canvas<T> { type Target = T; fn deref(&self) -> &T { &self.backend } } impl<T> DerefMut for Canvas<T> { fn deref_mut(&mut self) -> &mut T { &mut self.backend } } impl<T: backend::DrawBackend> Canvas<T> { pub fn new(t: T) -> Canvas<T> { Canvas { backend: t } } fn write_closed_polygon<I, K>(&mut self, i: I) -> Result<(), T::Error> where I: IntoIterator<Item = TypedPoint2D<f32, K>> { let mut i = i.into_iter(); if let Some(point) = i.next() { self.backend.apply(Command::MoveTo { x: point.x as f64, y: point.y as f64, })?; for point in i { self.backend.apply(Command::LineTo { x: point.x as f64, y: point.y as f64, })?; } } Ok(()) } pub fn draw_line<S: Into<f64>>(&mut self, start: (S, S), end: (S, S), draw_options: Option<DrawOptions>) -> Result<(), T::Error> { self.backend .apply(Command::StartShape(draw_options.unwrap_or(DrawOptions::default())))?; self.backend.apply(Command::MoveTo { x: start.0.into(), y: start.1.into(), })?; self.backend.apply(Command::LineTo { x: end.0.into(), y: end.1.into(), })?; self.backend.apply(Command::EndShape)?; Ok(()) } pub fn draw_lines<I: IntoIterator<Item = (S, S)>, S: Into<f64>>(&mut self, points: I, draw_options: Option<DrawOptions>) -> Result<(), T::Error> { let mut points = points.into_iter(); let (first, second) = match (points.next(), points.next()) { (Some(f), Some(s)) => (f, s), _ => return Ok(()), }; self.backend .apply(Command::StartShape(draw_options.unwrap_or(DrawOptions::default())))?; self.backend.apply(Command::MoveTo { x: first.0.into(), y: first.1.into(), })?; self.backend.apply(Command::LineTo { x: second.0.into(), y: second.1.into(), })?; for r in points { self.backend .apply(Command::LineTo { x: r.0.into(), y: r.1.into() })?; } self.backend.apply(Command::EndShape)?; Ok(()) } pub fn draw_closed_polygon<I, K>(&mut self, points: I, options: DrawOptions) -> Result<(), T::Error> where I: IntoIterator<Item = TypedPoint2D<f32, K>> { let mut points = points.into_iter().collect::<Vec<_>>(); if !util::is_clockwise(&points[..]) { points.reverse(); } self.backend.apply(Command::StartShape(options))?; self.write_closed_polygon(points)?; self.backend.apply(Command::CloseShape) } pub fn draw_holy_polygon<'a, I1, I2, K: 'static>(&mut self, additive: I1, subtractive: I2, options: DrawOptions) -> Result<(), T::Error> where I1: IntoIterator<Item = Vec<TypedPoint2D<f32, K>>>, I2: IntoIterator<Item = Vec<TypedPoint2D<f32, K>>>, { self.backend.apply(Command::StartShape(options))?; for outline in additive { let iter = outline.iter().cloned().chain(Some(outline[0])); if util::is_clockwise(&outline) { self.write_closed_polygon(iter)?; } else { self.write_closed_polygon(iter.rev())?; } } for outline in subtractive { let iter = outline.iter().cloned().chain(Some(outline[0])); if util::is_clockwise(&outline) { self.write_closed_polygon(iter.rev())?; } else { self.write_closed_polygon(iter)?; } } self.backend.apply(Command::EndShape) } pub fn close(self) -> Result<(), T::Error> { self.backend.close() } }