fenris_geometry/primitives/
quad.rs1use crate::{
2 AxisAlignedBoundingBox2d, BoundedGeometry, ConvexPolygon3d, Distance, SimplePolygon2d, Triangle, Triangle2d,
3};
4use fenris_traits::Real;
5use itertools::izip;
6use nalgebra::{Point2, Point3, Scalar, U2};
7
8#[derive(Debug, Copy, Clone, PartialEq)]
9pub struct Quad3d<T: Scalar> {
10 vertices: [Point3<T>; 4],
11}
12
13impl<T: Scalar> Quad3d<T> {
14 pub fn from_vertices(vertices: [Point3<T>; 4]) -> Self {
15 Self { vertices }
16 }
17}
18
19impl<'a, T> ConvexPolygon3d<'a, T> for Quad3d<T>
20where
21 T: Scalar,
22{
23 fn num_vertices(&self) -> usize {
24 4
25 }
26
27 fn get_vertex(&self, index: usize) -> Option<Point3<T>> {
28 self.vertices.get(index).cloned()
29 }
30}
31
32impl<T> BoundedGeometry<T> for Quad2d<T>
33where
34 T: Real,
35{
36 type Dimension = U2;
37
38 fn bounding_box(&self) -> AxisAlignedBoundingBox2d<T> {
39 AxisAlignedBoundingBox2d::from_points(&self.0).expect("Triangle always has > 0 vertices")
40 }
41}
42
43#[derive(Debug, Copy, Clone, PartialEq, Eq)]
44pub struct Quad2d<T: Scalar>(pub [Point2<T>; 4]);
47
48impl<T> Quad2d<T>
49where
50 T: Real,
51{
52 pub fn concave_corner(&self) -> Option<usize> {
54 for i in 0..4 {
55 let x_next = self.0[(i + 2) % 4];
56 let x_curr = self.0[(i + 1) % 4];
57 let x_prev = self.0[(i + 1) % 4];
58
59 let a = x_next - x_curr;
60 let b = x_prev - x_curr;
61 if a.perp(&b) < T::zero() {
64 return Some(i + 1);
65 }
66 }
67
68 None
69 }
70
71 pub fn split_into_triangle_connectivities(&self) -> ([usize; 3], [usize; 3]) {
77 if let Some(concave_corner_index) = self.concave_corner() {
78 let i = concave_corner_index;
79 let triangle1 = [(i + 2) % 4, (i + 3) % 4, (i + 0) % 4];
80 let triangle2 = [(i + 2) % 4, (i + 0) % 4, (i + 1) % 4];
81 (triangle1, triangle2)
82 } else {
83 let triangle1 = [0, 1, 2];
85 let triangle2 = [0, 2, 3];
86 (triangle1, triangle2)
87 }
88 }
89
90 pub fn split_into_triangles(&self) -> (Triangle2d<T>, Triangle2d<T>) {
91 let (conn1, conn2) = self.split_into_triangle_connectivities();
92 let mut vertices1 = [Point2::origin(); 3];
93 let mut vertices2 = [Point2::origin(); 3];
94
95 for (v, idx) in izip!(&mut vertices1, &conn1) {
96 *v = self.0[*idx];
97 }
98
99 for (v, idx) in izip!(&mut vertices2, &conn2) {
100 *v = self.0[*idx];
101 }
102
103 let tri1 = Triangle(vertices1);
104 let tri2 = Triangle(vertices2);
105
106 (tri1, tri2)
107 }
108
109 pub fn area(&self) -> T {
110 let (tri1, tri2) = self.split_into_triangles();
111 tri1.area() + tri2.area()
112 }
113}
114
115impl<T> Distance<T, Point2<T>> for Quad2d<T>
116where
117 T: Real,
118{
119 fn distance(&self, point: &Point2<T>) -> T {
120 SimplePolygon2d::from_vertices(self.0.to_vec()).distance(point)
122 }
123}