maker_panel/features/
triangle.rs

1use geo::{Coordinate, MultiPolygon};
2use std::fmt;
3
4/// A triangular region with sharp edges.
5#[derive(Debug, Clone)]
6pub struct Triangle<U = super::Unit> {
7    right_angle: bool,
8    triangle: geo::Triangle<f64>,
9    inner: U,
10}
11
12impl Triangle {
13    /// Constructs a new triangle using the provided corners.
14    pub fn new(c1: Coordinate<f64>, c2: Coordinate<f64>, c3: Coordinate<f64>) -> Self {
15        Self {
16            right_angle: false,
17            triangle: geo::Triangle(c1, c2, c3),
18            inner: super::Unit,
19        }
20    }
21
22    /// Constructs a right-angle triangle, centered at the origin and
23    /// with the given width and height.
24    pub fn right_angle(width: f64, height: f64) -> Self {
25        Self {
26            right_angle: true,
27            triangle: geo::Triangle(
28                Coordinate {
29                    x: -width / 2.,
30                    y: -height / 2.,
31                },
32                Coordinate {
33                    x: -width / 2.,
34                    y: height / 2.,
35                },
36                Coordinate {
37                    x: width / 2.,
38                    y: height / 2.,
39                },
40            ),
41            inner: super::Unit,
42        }
43    }
44}
45
46impl<U: super::InnerFeature + Clone + std::fmt::Debug> Triangle<U> {
47    /// Constructs a triangle surrounding the inner feature. The
48    /// origin of the inner feature will match the centeroid of the
49    /// triangle.
50    pub fn with_inner(inner: U) -> Self {
51        let c1: Coordinate<f64> = [-1f64, -1f64].into();
52        let c2: Coordinate<f64> = [-1f64, 1f64].into();
53        let c3: Coordinate<f64> = [1f64, 1f64].into();
54        let triangle = geo::Triangle(c1, c2, c3);
55        Self {
56            right_angle: true,
57            triangle,
58            inner,
59        }
60    }
61
62    /// Returns a new right-angle triangle around the provided center.
63    pub fn dimensions(mut self, center: Coordinate<f64>, width: f64, height: f64) -> Self {
64        let triangle = geo::Triangle(
65            center
66                + Coordinate {
67                    x: -width / 2.,
68                    y: -height / 2.,
69                },
70            center
71                + Coordinate {
72                    x: -width / 2.,
73                    y: height / 2.,
74                },
75            center
76                + Coordinate {
77                    x: width / 2.,
78                    y: height / 2.,
79                },
80        );
81        self.inner.translate(center);
82        Self {
83            triangle,
84            right_angle: true,
85            inner: self.inner,
86        }
87    }
88
89    /// Returns a new triangle using the provided points. The inner feature will
90    /// be translated to the centeroid of the triangle.
91    pub fn bounds(mut self, c1: Coordinate<f64>, c2: Coordinate<f64>, c3: Coordinate<f64>) -> Self {
92        use geo::algorithm::centroid::Centroid;
93        let triangle = geo::Triangle(c1, c2, c3);
94        self.inner
95            .translate(triangle.to_polygon().centroid().unwrap().into());
96        Self {
97            triangle,
98            right_angle: false,
99            inner: self.inner,
100        }
101    }
102}
103
104impl<U: super::InnerFeature> fmt::Display for Triangle<U> {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        write!(
107            f,
108            "triangle({:?}, U = {})",
109            self.triangle.to_array(),
110            self.inner
111        )
112    }
113}
114
115impl<U: super::InnerFeature + Clone + std::fmt::Debug> super::Feature for Triangle<U> {
116    fn name(&self) -> &'static str {
117        "triangle"
118    }
119
120    fn edge_union(&self) -> Option<MultiPolygon<f64>> {
121        Some(self.triangle.clone().to_polygon().into())
122    }
123
124    fn translate(&mut self, v: Coordinate<f64>) {
125        use geo::algorithm::translate::Translate;
126        self.triangle.translate_inplace(v.x, v.y);
127        self.inner.translate(v);
128    }
129
130    fn interior(&self) -> Vec<super::InnerAtom> {
131        self.inner.atoms()
132    }
133}