rustvision/shapes/
line.rs

1//! Lines in 2D.
2
3use crate::{color::Color, image::Image, vec::Vec2d};
4
5use super::Shape;
6
7/// Struct for representing a line in 2D space with a given color.
8#[derive(Default, Debug, Clone, Copy, PartialEq)]
9pub struct Line {
10    start: Vec2d,
11    end: Vec2d,
12    color: Color,
13}
14
15impl Line {
16    /// Create a new line with given start and end point.
17    pub fn new(start: Vec2d, end: Vec2d) -> Self {
18        Self {
19            start,
20            end,
21            ..Default::default()
22        }
23    }
24
25    /// Add a color to this line.
26    pub fn with_color(mut self, color: Color) -> Self {
27        self.color = color;
28        self
29    }
30}
31
32impl Shape for Line {
33    fn draw(&self, img: &mut Image) {
34        // Some quick algorithms for drawing fancy lines
35        let p0 = self.start;
36        let p1 = self.end;
37
38        let x0 = p0.x as i64;
39        let y0 = p0.y as i64;
40
41        let x1 = p1.x as i64;
42        let y1 = p1.y as i64;
43
44        let dx = (x1 - x0).abs();
45        let dy = (y1 - y0).abs();
46
47        let sx = (x1 - x0).signum();
48        let sy = (y1 - y0).signum();
49
50        let mut x = x0;
51        let mut y = y0;
52
53        if dx >= dy {
54            let mut e = 2 * dy - dx;
55
56            while x != x1 || y != y1 {
57                img.set(x as usize, y as usize, &self.color);
58
59                x += sx;
60                if e <= 0 {
61                    e += 2 * dy;
62                } else {
63                    y += sy;
64                    e += 2 * dy - 2 * dx;
65                }
66            }
67        } else {
68            let mut e = 2 * dx - dy;
69
70            while x != x1 || y != y1 {
71                img.set(x as usize, y as usize, &self.color);
72
73                y += sy;
74                if e <= 0 {
75                    e += 2 * dx;
76                } else {
77                    x += sx;
78                    e += 2 * dx - 2 * dy;
79                }
80            }
81        }
82        img.set(x as usize, y as usize, &self.color);
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::{rgb, vec2};
90
91    #[test]
92    fn test_line_new() {
93        let start = vec2![10.0, 20.0];
94        let end = vec2![15.0, 10.0];
95        assert_eq!(
96            Line::new(start, end),
97            Line {
98                start,
99                end,
100                color: Color::default()
101            }
102        );
103    }
104
105    #[test]
106    fn test_line_with_color() {
107        let start = vec2![10.0, 20.0];
108        let end = vec2![15.0, 10.0];
109        let color = rgb!(255, 42, 17);
110        assert_eq!(
111            Line::new(start, end).with_color(color),
112            Line { start, end, color }
113        );
114    }
115}