graphics/
line.rs

1//! Draw Line
2
3use crate::{
4    math::{Matrix2d, Scalar},
5    triangulation, types,
6    types::{Color, Radius, Resolution},
7    DrawState, Graphics,
8};
9
10/// The shape of the line
11#[derive(Copy, Clone)]
12pub enum Shape {
13    /// Square edges
14    Square,
15    /// Round edges
16    Round,
17    /// Round edges with specified resolution
18    RoundWithResolution(Resolution),
19    /// Bevel edges
20    Bevel,
21}
22
23impl Shape {
24    /// Gets the round resolution of the shape.
25    fn resolution(&self) -> u32 {
26        use Shape::*;
27
28        match self {
29            Square => 2,
30            Bevel => 3,
31            Round => 64,
32            RoundWithResolution(n) => *n,
33        }
34    }
35}
36
37/// A colored line with a default border radius
38#[derive(Copy, Clone)]
39pub struct Line {
40    /// The line color
41    pub color: Color,
42    /// The line radius
43    pub radius: Radius,
44    /// The line shape
45    pub shape: Shape,
46}
47
48impl Line {
49    /// Creates a new line
50    pub fn new(color: Color, radius: Radius) -> Line {
51        Line {
52            color,
53            radius,
54            shape: Shape::Square,
55        }
56    }
57
58    /// Creates a new line
59    pub fn new_round(color: Color, radius: Radius) -> Line {
60        Line {
61            color,
62            radius,
63            shape: Shape::Round,
64        }
65    }
66
67    /// Sets color.
68    pub fn color(mut self, value: Color) -> Self {
69        self.color = value;
70        self
71    }
72
73    /// Sets radius.
74    pub fn radius(mut self, value: Radius) -> Self {
75        self.radius = value;
76        self
77    }
78
79    /// Sets width.
80    pub fn width(mut self, value: types::Width) -> Self {
81        self.radius = 0.5 * value;
82        self
83    }
84
85    /// Sets shape.
86    pub fn shape(mut self, value: Shape) -> Self {
87        self.shape = value;
88        self
89    }
90
91    /// Draws line using default method between points.
92    #[inline(always)]
93    pub fn draw_from_to<P: Into<types::Vec2d>, G>(
94        &self,
95        from: P,
96        to: P,
97        draw_state: &DrawState,
98        transform: Matrix2d,
99        g: &mut G,
100    ) where
101        G: Graphics,
102    {
103        let from: types::Vec2d = from.into();
104        let to: types::Vec2d = to.into();
105        g.line(
106            self,
107            [from[0], from[1], to[0], to[1]],
108            draw_state,
109            transform,
110        );
111    }
112
113    /// Draws line using default method.
114    #[inline(always)]
115    pub fn draw<L: Into<types::Line>, G>(
116        &self,
117        line: L,
118        draw_state: &DrawState,
119        transform: Matrix2d,
120        g: &mut G,
121    ) where
122        G: Graphics,
123    {
124        g.line(self, line, draw_state, transform);
125    }
126
127    /// Draws line using triangulation.
128    pub fn draw_tri<L: Into<types::Line>, G>(
129        &self,
130        line: L,
131        draw_state: &DrawState,
132        transform: Matrix2d,
133        g: &mut G,
134    ) where
135        G: Graphics,
136    {
137        let line = line.into();
138        g.tri_list(draw_state, &self.color, |f| {
139            triangulation::with_round_border_line_tri_list(
140                self.shape.resolution(),
141                transform,
142                line,
143                self.radius,
144                |vertices| f(vertices),
145            )
146        });
147    }
148
149    /// Draws an arrow
150    ///
151    /// Head size is the sides of the triangle
152    /// between the arrow hooks and the line
153    pub fn draw_arrow<L: Into<types::Line>, G>(
154        &self,
155        line: L,
156        head_size: Scalar,
157        draw_state: &DrawState,
158        transform: Matrix2d,
159        g: &mut G,
160    ) where
161        G: Graphics,
162    {
163        use crate::Transformed;
164
165        let line = line.into();
166        self.draw(line, draw_state, transform, g);
167        let diff = [line[2] - line[0], line[3] - line[1]];
168        let arrow_head = transform.trans(line[2], line[3]).orient(diff[0], diff[1]);
169        self.draw([-head_size, head_size, 0.0, 0.0], draw_state, arrow_head, g);
170        self.draw(
171            [-head_size, -head_size, 0.0, 0.0],
172            draw_state,
173            arrow_head,
174            g,
175        );
176    }
177}
178
179#[cfg(test)]
180mod test {
181    use super::*;
182
183    #[test]
184    fn test_line() {
185        use crate::Colored;
186
187        let _line = Line::new([0.0; 4], 3.0)
188            .color([1.0; 4])
189            .radius(3.0)
190            .shape(Shape::Round)
191            .hue_deg(1.0);
192    }
193}