three_d/renderer/geometry/
line.rs

1use crate::renderer::*;
2
3///
4/// A rectangle 2D geometry which can be rendered using a camera created by [Camera::new_2d].
5///
6pub struct Line {
7    mesh: Mesh,
8    pixel0: PhysicalPoint,
9    pixel1: PhysicalPoint,
10    thickness: f32,
11}
12
13impl Line {
14    ///
15    /// Constructs a new line geometry.
16    ///
17    pub fn new(
18        context: &Context,
19        pixel0: impl Into<PhysicalPoint>,
20        pixel1: impl Into<PhysicalPoint>,
21        thickness: f32,
22    ) -> Self {
23        let mut mesh = CpuMesh::square();
24        mesh.transform(Mat4::from_scale(0.5) * Mat4::from_translation(vec3(1.0, 0.0, 0.0)))
25            .unwrap();
26        let mut line = Self {
27            mesh: Mesh::new(context, &mesh),
28            pixel0: pixel0.into(),
29            pixel1: pixel1.into(),
30            thickness,
31        };
32        line.update();
33        line
34    }
35
36    /// Get one of the end points of the line.
37    pub fn end_point0(&self) -> PhysicalPoint {
38        self.pixel0
39    }
40
41    /// Get one of the end points of the line.
42    pub fn end_point1(&self) -> PhysicalPoint {
43        self.pixel1
44    }
45
46    ///
47    /// Change the two end points of the line.
48    /// The pixel coordinates must be in physical pixels, where (viewport.x, viewport.y) indicate the top left corner of the viewport
49    /// and (viewport.x + viewport.width, viewport.y + viewport.height) indicate the bottom right corner.
50    ///
51    pub fn set_endpoints(
52        &mut self,
53        pixel0: impl Into<PhysicalPoint>,
54        pixel1: impl Into<PhysicalPoint>,
55    ) {
56        self.pixel0 = pixel0.into();
57        self.pixel1 = pixel1.into();
58        self.update();
59    }
60
61    /// Set the line thickness.
62    pub fn set_thickness(&mut self, thickness: f32) {
63        self.thickness = thickness;
64        self.update();
65    }
66
67    fn update(&mut self) {
68        let dx = self.pixel1.x - self.pixel0.x;
69        let dy = self.pixel1.y - self.pixel0.y;
70        let length = (dx * dx + dy * dy).sqrt();
71        let c = dx / length;
72        let s = dy / length;
73        let rot = Mat3::new(c, s, 0.0, -s, c, 0.0, 0.0, 0.0, 1.0);
74        self.mesh.set_transformation_2d(
75            Mat3::from_translation(self.pixel0.into())
76                * rot
77                * Mat3::from_nonuniform_scale(length, self.thickness),
78        );
79    }
80}
81
82impl<'a> IntoIterator for &'a Line {
83    type Item = &'a dyn Geometry;
84    type IntoIter = std::iter::Once<&'a dyn Geometry>;
85
86    fn into_iter(self) -> Self::IntoIter {
87        std::iter::once(self)
88    }
89}
90
91use std::ops::Deref;
92impl Deref for Line {
93    type Target = Mesh;
94    fn deref(&self) -> &Self::Target {
95        &self.mesh
96    }
97}
98
99impl std::ops::DerefMut for Line {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.mesh
102    }
103}
104
105impl Geometry for Line {
106    impl_geometry_body!(deref);
107
108    fn animate(&mut self, time: f32) {
109        self.mesh.animate(time)
110    }
111}