turtle_svg/draw/
drawing.rs

1use svg::{node::element::{Rectangle, Line}, Document};
2
3use crate::{
4    color::{Color, ColorSvg},
5    size::Size,
6    draw::pen::Pen,
7    position::{Distance, Pos}
8};
9
10struct DrawingLine {
11    color: Color,
12    thickness: f64,
13    x1: f64,
14    y1: f64,
15    x2: f64,
16    y2: f64
17}
18
19/// Drawing position
20pub type DrawingPos = Pos<f64>;
21
22/// The drawing contains
23pub struct Drawing {
24    size: Size,
25    bg: Color,
26    lines: Vec<DrawingLine>,
27    center: DrawingPos
28}
29
30impl Default for Drawing {
31    fn default() -> Self {
32        Self {
33            size: (800., 600.).into(),
34            bg: Color::default(),
35            lines: Vec::new(),
36            center: (0., 0.).into()
37        }
38    }
39}
40
41impl Drawing {
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    /// Move the pen in a direction
47    fn go(
48        &mut self,
49        pen: &mut Pen,
50        distance: Distance,
51        f: &dyn Fn(&mut Pen, Distance)
52    ) {
53        let (x1, y1) = pen.position.into();
54
55        f(pen, distance);
56        
57        let (x2, y2) = pen.position.into();
58        let line = DrawingLine {
59            color: pen.color,
60            thickness: pen.thickness,
61            x1,
62            y1,
63            x2,
64            y2,
65        };
66        
67        // Add the line to the 'history'
68        self.lines.push(line);
69    }
70
71    /// Move by `distance` forward from `pen` with the same angle
72    pub fn forward(&mut self, pen: &mut Pen, distance: Distance) {
73        self.go(pen, distance, &Pen::forward)
74    }
75
76    /// Move by `distance` backward from `pen` with the same angle
77    pub fn backward(&mut self, pen: &mut Pen, distance: Distance) {
78        self.go(pen, distance, &Pen::backward)
79    }
80
81    /// Change the background color
82    pub fn set_background_color<C: Into<Color>>(&mut self, color: C) {
83        self.bg = color.into();
84    }
85
86    /// Change the drawing size
87    pub fn set_size<S: Into<Size>>(&mut self, size: S) {
88        self.size = size.into();
89    }
90
91    /// Centering the drawing
92    pub fn set_center<P: Into<DrawingPos>>(&mut self, positon: P) {
93        self.center = positon.into();
94    }
95
96    /// Parse `self.composer` and write lines into a file at `path`
97    pub fn save_svg(&mut self, path: &str) {
98        // Background
99        let background_color: ColorSvg = self.bg.into(); 
100        let background = Rectangle::new()
101            .set("fill", background_color)
102            .set("height", "100%")
103            .set("width", "100%");
104        
105        // Document
106        let viewbox = (0, 0, self.size.w, self.size.h);
107
108        let mut document = Document::new()
109            .set("viewBox", viewbox)
110            .add(background);
111
112        // Distance to reach the center
113        let dx = (self.size.w / 2.) - self.center.0;
114        let dy = (self.size.h / 2.) - self.center.1;
115
116        for line in &self.lines {
117            let color: ColorSvg = line.color.into();
118            let node = Line::new()
119                .set("stroke", color)
120                .set("stroke-width", line.thickness)
121                .set("x1", line.x1 + dx)
122                .set("y1", line.y1 + dy)
123                .set("x2", line.x2 + dx)
124                .set("y2", line.y2 + dy);
125
126            document = document.add(node);
127        }
128
129        // Save the document as a SVG file
130        svg::save(path, &document).unwrap();
131    }
132}