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
#![allow(unused_variables, dead_code)]

pub mod backend;
mod util;
pub mod svg;

use backend::{DrawOptions, Command};

pub struct Canvas<T> {
    backend: T
}

impl <T: backend::DrawBackend> Canvas<T> {
    pub fn new(t: T) -> Canvas<T> {
        Canvas {
            backend: t
        }
    }

    fn write_closed_polygon<I>(&mut self, mut i: I) -> Result<(), T::Error>
    where I: Iterator<Item=(f64, f64)>{
        if let Some((x, y)) = i.next() {
            self.backend.apply(Command::MoveTo{x, y})?;
            for (x, y) in i {
                self.backend.apply(Command::LineTo{x, y})?;
            }
        }
        Ok(())
    }

    pub fn draw_closed_polygon(&mut self, points: &[(f64, f64)], options: DrawOptions) -> Result<(), T::Error> {
        if points.len() == 0 { return Ok(()); }

        self.backend.apply(Command::StartShape(options))?;
        if util::is_clockwise(points) {
            self.write_closed_polygon(points.into_iter().cloned())?;
        } else {
            self.write_closed_polygon(points.into_iter().cloned().rev())?;
        }
        self.backend.apply(Command::CloseShape)
    }

    pub fn draw_holy_polygon<'a, I1, I2>(&mut self, additive: I1, subtractive: I2, options: DrawOptions) -> Result<(), T::Error>
    where I1: IntoIterator<Item=&'a[(f64, f64)]>, I2: IntoIterator<Item=&'a[(f64, f64)]> {
        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()
    }
}