fenris_geometry/
polytope.rs1use crate::{HalfPlane, Line2d, LineSegment2d, SimplePolygon2d, Triangle, Triangle2d};
2use fenris_traits::Real;
3use itertools::Itertools;
4use nalgebra::{Point2, Scalar, Unit, Vector2};
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8pub struct ConcavePolygonError;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct ConvexPolygon<T>
12where
13 T: Scalar,
14{
15 vertices: Vec<Point2<T>>,
18}
19
20impl<T> From<LineSegment2d<T>> for ConvexPolygon<T>
21where
22 T: Scalar,
23{
24 fn from(segment: LineSegment2d<T>) -> Self {
25 ConvexPolygon::from_vertices(vec![segment.start().clone(), segment.end().clone()])
26 }
27}
28
29impl<T> ConvexPolygon<T>
30where
31 T: Scalar,
32{
33 pub fn from_vertices(vertices: Vec<Point2<T>>) -> ConvexPolygon<T> {
38 Self { vertices }
39 }
40
41 pub fn vertices(&self) -> &[Point2<T>] {
42 &self.vertices
43 }
44
45 pub fn num_edges(&self) -> usize {
49 self.vertices().len()
50 }
51
52 pub fn edges(&self) -> impl Iterator<Item = (&Point2<T>, &Point2<T>)> {
53 let num_vertices = self.vertices().len();
54 self.vertices()
55 .iter()
56 .cycle()
57 .take(num_vertices + 1)
58 .tuple_windows()
59 }
60
61 pub fn is_empty(&self) -> bool {
62 self.vertices.is_empty()
63 }
64
65 pub fn is_point(&self) -> bool {
66 self.vertices.len() == 1
67 }
68
69 pub fn is_line_segment(&self) -> bool {
70 self.vertices.len() == 2
71 }
72}
73
74impl<T> ConvexPolygon<T>
75where
76 T: Real,
77{
78 pub fn half_planes<'a>(&'a self) -> impl Iterator<Item = HalfPlane<T>> + 'a {
86 self.edges().filter_map(|(v1, v2)| {
87 if v1 != v2 {
88 let edge_dir = v2 - v1;
89 let edge_normal = Vector2::new(edge_dir.y, -edge_dir.x);
90 Some(HalfPlane::from_point_and_normal(*v1, Unit::new_normalize(edge_normal)))
91 } else {
92 None
93 }
94 })
95 }
96
97 pub fn contains_point(&self, point: &Point2<T>) -> bool {
99 if self.is_point() {
100 self.vertices.first().unwrap() == point
101 } else if self.is_line_segment() {
102 unimplemented!()
103 } else {
104 self.half_planes()
105 .all(|half_plane| half_plane.contains_point(point))
106 }
107 }
108
109 pub fn intersect_halfplane(&self, half_plane: &HalfPlane<T>) -> ConvexPolygon<T> {
115 let mut new_vertices = Vec::new();
116
117 if self.vertices.len() == 1 {
119 let first = self.vertices().first().unwrap();
120 if half_plane.contains_point(first) {
121 new_vertices.push(first.clone());
122 }
123 } else {
124 for (v1, v2) in self.edges() {
125 let v1_contained = half_plane.contains_point(v1);
126 let v2_contained = half_plane.contains_point(v2);
127 if v1_contained {
128 new_vertices.push(v1.clone());
129 }
130
131 if (v1_contained && !v2_contained) || (!v1_contained && v2_contained) {
132 let dir = (v2 - v1).normalize();
134 let intersection_point = half_plane
135 .surface()
136 .intersect(&Line2d::from_point_and_dir(v1.clone(), dir))
137 .expect(
138 "We already know that the line must intersect the edge, \
139 so this should work unless we have some ugly numerical \
140 artifacts.",
141 );
142
143 new_vertices.push(intersection_point);
144 }
145 }
146 }
147
148 ConvexPolygon::from_vertices(new_vertices)
149 }
150
151 pub fn intersect_polygon(&self, other: &ConvexPolygon<T>) -> Self {
153 if self.is_point() || other.is_point() {
155 unimplemented!()
156 } else if self.is_line_segment() {
157 let segment = LineSegment2d::from_end_points(self.vertices[0], self.vertices[1]);
158 segment
159 .intersect_polygon(other)
160 .map(|segment| ConvexPolygon::from_vertices(vec![*segment.start(), *segment.end()]))
161 .unwrap_or_else(|| ConvexPolygon::from_vertices(Vec::new()))
162 } else if other.is_line_segment() {
163 other.intersect_polygon(self)
164 } else {
165 let mut result = self.clone();
166 for half_plane in other.half_planes() {
167 result = result.intersect_halfplane(&half_plane);
168 }
169 result
170 }
171 }
172
173 pub fn triangulate<'a>(&'a self) -> impl Iterator<Item = Triangle2d<T>> + 'a {
176 self.edges()
177 .take(self.num_edges().saturating_sub(1))
180 .skip(1)
181 .map(move |(a, b)| Triangle([*self.vertices.first().unwrap(), *a, *b]))
182 }
183
184 pub fn triangulate_into_vec(&self) -> Vec<Triangle2d<T>> {
185 self.triangulate().collect()
186 }
187}
188
189impl<T> From<ConvexPolygon<T>> for SimplePolygon2d<T>
190where
191 T: Scalar,
192{
193 fn from(poly: ConvexPolygon<T>) -> Self {
194 SimplePolygon2d::from_vertices(poly.vertices)
195 }
196}