geo_types/geometry/
triangle.rs1use crate::{polygon, Coord, CoordNum, Line, Point, Polygon};
2use core::cmp::Ordering;
3
4#[derive(Copy, Clone, Hash, Eq, PartialEq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct Triangle<T: CoordNum = f64>(pub Coord<T>, pub Coord<T>, pub Coord<T>);
14
15impl<T: CoordNum> Triangle<T> {
16 pub fn new(v1: Coord<T>, v2: Coord<T>, v3: Coord<T>) -> Self {
18 let orientation = Point::from(v1).cross_prod(v2.into(), v3.into());
20 match orientation.partial_cmp(&T::zero()) {
21 Some(Ordering::Greater) => Self(v1, v2, v3),
22 Some(Ordering::Less) => Self(v3, v2, v1),
23 _ => Self(v1, v2, v3),
25 }
26 }
27
28 pub fn to_array(&self) -> [Coord<T>; 3] {
29 [self.0, self.1, self.2]
30 }
31
32 pub fn to_lines(&self) -> [Line<T>; 3] {
33 [
34 Line::new(self.0, self.1),
35 Line::new(self.1, self.2),
36 Line::new(self.2, self.0),
37 ]
38 }
39
40 pub fn to_polygon(self) -> Polygon<T> {
66 polygon![self.0, self.1, self.2, self.0]
67 }
68}
69
70impl<IC: Into<Coord<T>> + Copy, T: CoordNum> From<[IC; 3]> for Triangle<T> {
71 fn from(array: [IC; 3]) -> Self {
72 Self(array[0].into(), array[1].into(), array[2].into())
73 }
74}
75
76#[cfg(any(feature = "approx", test))]
77mod approx_integration {
78 use super::*;
79 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
80
81 impl<T> RelativeEq for Triangle<T>
82 where
83 T: CoordNum + RelativeEq<Epsilon = T>,
84 {
85 #[inline]
86 fn default_max_relative() -> Self::Epsilon {
87 T::default_max_relative()
88 }
89
90 #[inline]
104 fn relative_eq(
105 &self,
106 other: &Self,
107 epsilon: Self::Epsilon,
108 max_relative: Self::Epsilon,
109 ) -> bool {
110 if !self.0.relative_eq(&other.0, epsilon, max_relative) {
111 return false;
112 }
113 if !self.1.relative_eq(&other.1, epsilon, max_relative) {
114 return false;
115 }
116 if !self.2.relative_eq(&other.2, epsilon, max_relative) {
117 return false;
118 }
119
120 true
121 }
122 }
123
124 impl<T> AbsDiffEq for Triangle<T>
125 where
126 T: CoordNum + AbsDiffEq<Epsilon = T>,
127 {
128 type Epsilon = T;
129
130 #[inline]
131 fn default_epsilon() -> Self::Epsilon {
132 T::default_epsilon()
133 }
134
135 #[inline]
149 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
150 if !self.0.abs_diff_eq(&other.0, epsilon) {
151 return false;
152 }
153 if !self.1.abs_diff_eq(&other.1, epsilon) {
154 return false;
155 }
156 if !self.2.abs_diff_eq(&other.2, epsilon) {
157 return false;
158 }
159
160 true
161 }
162 }
163
164 impl<T> UlpsEq for Triangle<T>
165 where
166 T: CoordNum + UlpsEq<Epsilon = T>,
167 {
168 fn default_max_ulps() -> u32 {
169 T::default_max_ulps()
170 }
171
172 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
173 if !self.0.ulps_eq(&other.0, epsilon, max_ulps) {
174 return false;
175 }
176 if !self.1.ulps_eq(&other.1, epsilon, max_ulps) {
177 return false;
178 }
179 if !self.2.ulps_eq(&other.2, epsilon, max_ulps) {
180 return false;
181 }
182 true
183 }
184 }
185}
186
187#[cfg(any(
188 feature = "rstar_0_8",
189 feature = "rstar_0_9",
190 feature = "rstar_0_10",
191 feature = "rstar_0_11",
192 feature = "rstar_0_12"
193))]
194macro_rules! impl_rstar_triangle {
195 ($rstar:ident) => {
196 impl<T> ::$rstar::RTreeObject for Triangle<T>
197 where
198 T: ::num_traits::Float + ::$rstar::RTreeNum,
199 {
200 type Envelope = ::$rstar::AABB<Point<T>>;
201
202 fn envelope(&self) -> Self::Envelope {
203 let bounding_rect =
204 crate::private_utils::get_bounding_rect(self.to_array()).unwrap();
205 ::$rstar::AABB::from_corners(bounding_rect.min().into(), bounding_rect.max().into())
206 }
207 }
208 };
209}
210
211#[cfg(feature = "rstar_0_8")]
212impl_rstar_triangle!(rstar_0_8);
213
214#[cfg(feature = "rstar_0_9")]
215impl_rstar_triangle!(rstar_0_9);
216
217#[cfg(feature = "rstar_0_10")]
218impl_rstar_triangle!(rstar_0_10);
219
220#[cfg(feature = "rstar_0_11")]
221impl_rstar_triangle!(rstar_0_11);
222
223#[cfg(feature = "rstar_0_12")]
224impl_rstar_triangle!(rstar_0_12);