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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
#![allow(unused_variables, dead_code)] extern crate euclid; pub mod backend; mod util; pub mod svg; use euclid::TypedPoint2D; use backend::{Command, DrawOptions}; 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)) -> Result<(), T::Error> { self.backend .apply(Command::StartShape(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, ) -> 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(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() } }