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>(
14 #[deprecated(
15 since = "0.7.19",
16 note = "Use Triangle::new for construction and triangle.v1() to retrieve the value."
17 )]
18 pub Coord<T>,
19 #[deprecated(
20 since = "0.7.19",
21 note = "Use Triangle::new for construction and triangle.v2() to retrieve the value."
22 )]
23 pub Coord<T>,
24 #[deprecated(
25 since = "0.7.19",
26 note = "Use Triangle::new for construction and triangle.v3() to retrieve the value."
27 )]
28 pub Coord<T>,
29);
30
31#[allow(deprecated)]
32impl<T: CoordNum> Triangle<T> {
33 pub fn new(v1: Coord<T>, v2: Coord<T>, v3: Coord<T>) -> Self {
38 let orientation = Point::from(v1).cross_prod(v2.into(), v3.into());
40 match orientation.partial_cmp(&T::zero()) {
41 Some(Ordering::Greater) => Self(v1, v2, v3),
42 Some(Ordering::Less) => Self(v3, v2, v1),
43 _ => Self(v1, v2, v3),
45 }
46 }
47
48 pub fn unchecked_winding(v1: Coord<T>, v2: Coord<T>, v3: Coord<T>) -> Self {
56 Self(v1, v2, v3)
57 }
58
59 pub fn v1(&self) -> Coord<T> {
61 self.0
62 }
63
64 pub fn v2(&self) -> Coord<T> {
66 self.1
67 }
68
69 pub fn v3(&self) -> Coord<T> {
71 self.2
72 }
73
74 pub fn to_array(&self) -> [Coord<T>; 3] {
75 [self.0, self.1, self.2]
76 }
77
78 pub fn to_lines(&self) -> [Line<T>; 3] {
79 [
80 Line::new(self.0, self.1),
81 Line::new(self.1, self.2),
82 Line::new(self.2, self.0),
83 ]
84 }
85
86 pub fn to_polygon(self) -> Polygon<T> {
112 polygon![self.0, self.1, self.2, self.0]
113 }
114}
115
116impl<IC: Into<Coord<T>> + Copy, T: CoordNum> From<[IC; 3]> for Triangle<T> {
117 fn from(array: [IC; 3]) -> Self {
118 Self::new(array[0].into(), array[1].into(), array[2].into())
119 }
120}
121
122#[cfg(any(feature = "approx", test))]
123mod approx_integration {
124 use super::*;
125 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
126
127 impl<T> RelativeEq for Triangle<T>
128 where
129 T: CoordNum + RelativeEq<Epsilon = T>,
130 {
131 #[inline]
132 fn default_max_relative() -> Self::Epsilon {
133 T::default_max_relative()
134 }
135
136 #[inline]
150 fn relative_eq(
151 &self,
152 other: &Self,
153 epsilon: Self::Epsilon,
154 max_relative: Self::Epsilon,
155 ) -> bool {
156 if !self.v1().relative_eq(&other.v1(), epsilon, max_relative) {
157 return false;
158 }
159 if !self.v2().relative_eq(&other.v2(), epsilon, max_relative) {
160 return false;
161 }
162 if !self.v3().relative_eq(&other.v3(), epsilon, max_relative) {
163 return false;
164 }
165
166 true
167 }
168 }
169
170 impl<T> AbsDiffEq for Triangle<T>
171 where
172 T: CoordNum + AbsDiffEq<Epsilon = T>,
173 {
174 type Epsilon = T;
175
176 #[inline]
177 fn default_epsilon() -> Self::Epsilon {
178 T::default_epsilon()
179 }
180
181 #[inline]
195 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
196 if !self.v1().abs_diff_eq(&other.v1(), epsilon) {
197 return false;
198 }
199 if !self.v2().abs_diff_eq(&other.v2(), epsilon) {
200 return false;
201 }
202 if !self.v3().abs_diff_eq(&other.v3(), epsilon) {
203 return false;
204 }
205
206 true
207 }
208 }
209
210 impl<T> UlpsEq for Triangle<T>
211 where
212 T: CoordNum + UlpsEq<Epsilon = T>,
213 {
214 fn default_max_ulps() -> u32 {
215 T::default_max_ulps()
216 }
217
218 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
219 if !self.v1().ulps_eq(&other.v1(), epsilon, max_ulps) {
220 return false;
221 }
222 if !self.v2().ulps_eq(&other.v2(), epsilon, max_ulps) {
223 return false;
224 }
225 if !self.v3().ulps_eq(&other.v3(), epsilon, max_ulps) {
226 return false;
227 }
228 true
229 }
230 }
231}
232
233#[cfg(any(
234 feature = "rstar_0_8",
235 feature = "rstar_0_9",
236 feature = "rstar_0_10",
237 feature = "rstar_0_11",
238 feature = "rstar_0_12"
239))]
240macro_rules! impl_rstar_triangle {
241 ($rstar:ident) => {
242 impl<T> ::$rstar::RTreeObject for Triangle<T>
243 where
244 T: ::num_traits::Float + ::$rstar::RTreeNum,
245 {
246 type Envelope = ::$rstar::AABB<Point<T>>;
247
248 fn envelope(&self) -> Self::Envelope {
249 let bounding_rect =
250 crate::private_utils::get_bounding_rect(self.to_array()).unwrap();
251 ::$rstar::AABB::from_corners(bounding_rect.min().into(), bounding_rect.max().into())
252 }
253 }
254 };
255}
256
257#[cfg(feature = "rstar_0_8")]
258impl_rstar_triangle!(rstar_0_8);
259
260#[cfg(feature = "rstar_0_9")]
261impl_rstar_triangle!(rstar_0_9);
262
263#[cfg(feature = "rstar_0_10")]
264impl_rstar_triangle!(rstar_0_10);
265
266#[cfg(feature = "rstar_0_11")]
267impl_rstar_triangle!(rstar_0_11);
268
269#[cfg(feature = "rstar_0_12")]
270impl_rstar_triangle!(rstar_0_12);