1use crate::model::common::{
2 ApplyTransform, ComputeEnvelope, IterGeometries, Triangulate, Triangulation,
3};
4use crate::model::geometry::primitives::{
5 AbstractRingKind, AbstractSurface, AsAbstractSurface, AsAbstractSurfaceMut,
6};
7use crate::model::geometry::refs::AbstractGeometryKindRef;
8use crate::model::geometry::{DirectPosition, Envelope};
9use crate::util::plane::Plane;
10use crate::util::triangulate::triangulate;
11use crate::{
12 Error, impl_abstract_surface_mut_traits, impl_abstract_surface_traits, impl_has_geometry_type,
13};
14use nalgebra::{Isometry3, Rotation3, Scale3, Transform3, Vector3};
15use rayon::prelude::*;
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct Polygon {
19 pub abstract_surface: AbstractSurface,
20 exterior: Option<AbstractRingKind>,
21 interior: Vec<AbstractRingKind>,
22}
23
24impl Polygon {
25 pub fn new(
26 exterior: Option<AbstractRingKind>,
27 interior: impl IntoIterator<Item = AbstractRingKind>,
28 ) -> Result<Self, Error> {
29 Ok(Self {
30 abstract_surface: AbstractSurface::default(),
31 exterior,
32 interior: interior.into_iter().collect(),
33 })
34 }
35
36 pub fn from_abstract_surface(
37 abstract_surface: AbstractSurface,
38 exterior: Option<AbstractRingKind>,
39 interior: impl IntoIterator<Item = AbstractRingKind>,
40 ) -> Self {
41 Self {
42 abstract_surface,
43 exterior,
44 interior: interior.into_iter().collect(),
45 }
46 }
47
48 pub fn exterior(&self) -> Option<&AbstractRingKind> {
49 self.exterior.as_ref()
50 }
51
52 pub fn set_exterior(&mut self, exterior: AbstractRingKind) {
53 self.exterior = Some(exterior);
54 }
55
56 pub fn set_exterior_opt(&mut self, exterior: Option<AbstractRingKind>) {
57 self.exterior = exterior;
58 }
59
60 pub fn clear_exterior(&mut self) {
61 self.exterior = None;
62 }
63
64 pub fn interior(&self) -> &[AbstractRingKind] {
65 &self.interior
66 }
67
68 pub fn set_interior(&mut self, interior: Vec<AbstractRingKind>) {
69 self.interior = interior;
70 }
71
72 pub fn push_interior(&mut self, ring: AbstractRingKind) {
73 self.interior.push(ring);
74 }
75
76 pub fn extend_interiors(&mut self, rings: impl IntoIterator<Item = AbstractRingKind>) {
77 self.interior.extend(rings);
78 }
79}
80
81impl AsAbstractSurface for Polygon {
82 fn abstract_surface(&self) -> &AbstractSurface {
83 &self.abstract_surface
84 }
85}
86
87impl AsAbstractSurfaceMut for Polygon {
88 fn abstract_surface_mut(&mut self) -> &mut AbstractSurface {
89 &mut self.abstract_surface
90 }
91}
92
93impl_abstract_surface_traits!(Polygon);
94impl_abstract_surface_mut_traits!(Polygon);
95impl_has_geometry_type!(Polygon, Polygon);
96
97impl Polygon {
98 fn normal(&self) -> Vector3<f64> {
101 let mut enclosed_boundary_points =
102 self.exterior().expect("should be there").points().to_vec();
103 let first = enclosed_boundary_points
104 .first()
105 .copied()
106 .expect("should be there");
107 enclosed_boundary_points.push(first);
108
109 let mut normal = Vector3::new(0.0, 0.0, 0.0);
110 for current_point_pair in enclosed_boundary_points.windows(2) {
111 let current_first_point: Vector3<f64> = current_point_pair[0].into();
112 let current_second_point: Vector3<f64> = current_point_pair[1].into();
113
114 normal += (current_first_point - current_second_point)
115 .cross(&(current_first_point + current_second_point));
116 }
117
118 normal.normalize()
119 }
120
121 pub fn plane_equation(&self) -> Plane {
122 let envelope = self.compute_envelope().expect("should have envelope");
123 Plane::new(*envelope.lower_corner(), self.normal())
124 }
125
126 pub fn area_3d(&self) -> Result<f64, Error> {
132 let exterior = self
133 .exterior
134 .as_ref()
135 .ok_or(Error::MissingExteriorRing)?
136 .area_3d();
137 let holes = self.interior.iter().map(|r| r.area_3d()).sum::<f64>();
138
139 Ok(exterior - holes)
140 }
141
142 pub fn points(&self) -> Vec<&DirectPosition> {
143 let mut all_points = Vec::new();
144 if let Some(exterior) = &self.exterior {
145 all_points.extend(exterior.points());
146 }
147 for ring in &self.interior {
148 all_points.extend(ring.points());
149 }
150
151 all_points
152 }
153}
154
155impl ApplyTransform for Polygon {
156 fn apply_transform(&mut self, transform: Transform3<f64>) {
157 if let Some(exterior) = &mut self.exterior {
158 exterior.apply_transform(transform);
159 }
160 self.interior
161 .par_iter_mut()
162 .for_each(|p| p.apply_transform(transform));
163 }
164
165 fn apply_isometry(&mut self, isometry: Isometry3<f64>) {
166 if let Some(exterior) = &mut self.exterior {
167 exterior.apply_isometry(isometry);
168 }
169 self.interior
170 .par_iter_mut()
171 .for_each(|p| p.apply_isometry(isometry));
172 }
173
174 fn apply_translation(&mut self, vector: Vector3<f64>) {
175 if let Some(exterior) = &mut self.exterior {
176 exterior.apply_translation(vector);
177 }
178 self.interior
179 .par_iter_mut()
180 .for_each(|p| p.apply_translation(vector));
181 }
182
183 fn apply_rotation(&mut self, rotation: Rotation3<f64>) {
184 if let Some(exterior) = &mut self.exterior {
185 exterior.apply_rotation(rotation);
186 }
187 self.interior
188 .par_iter_mut()
189 .for_each(|p| p.apply_rotation(rotation));
190 }
191
192 fn apply_scale(&mut self, scale: Scale3<f64>) {
193 if let Some(exterior) = &mut self.exterior {
194 exterior.apply_scale(scale);
195 }
196 self.interior
197 .par_iter_mut()
198 .for_each(|p| p.apply_scale(scale));
199 }
200}
201
202impl ComputeEnvelope for Polygon {
203 fn compute_envelope(&self) -> Option<Envelope> {
204 if let Some(exterior) = &self.exterior
205 && let Some(e) = exterior.compute_envelope()
206 {
207 return Some(e);
208 }
209
210 let envelopes = self
211 .interior
212 .iter()
213 .filter_map(|x| x.compute_envelope())
214 .collect::<Vec<_>>();
215
216 Envelope::from_envelopes(&envelopes)
217 }
218}
219
220impl Triangulate for Polygon {
221 fn triangulate(&self) -> Result<Triangulation, Error> {
222 let surface = triangulate(self.exterior.clone(), self.interior.to_vec())?;
223 Ok(Triangulation::new(surface, Vec::new()))
224 }
225}
226
227impl IterGeometries for Polygon {
228 fn iter_geometries(&self) -> Box<dyn Iterator<Item = AbstractGeometryKindRef<'_>> + '_> {
229 Box::new(
230 std::iter::once(self.into())
231 .chain(
232 self.exterior
233 .as_ref()
234 .into_iter()
235 .flat_map(|x| x.iter_geometries()),
236 )
237 .chain(self.interior.iter().flat_map(|x| x.iter_geometries())),
238 )
239 }
240}
241
242#[cfg(test)]
243mod test {
244 use super::*;
245 use crate::model::geometry::DirectPosition;
246 use crate::model::geometry::primitives::{AbstractRingKind, AsSurface, LinearRing};
247 use nalgebra::Vector3;
248
249 #[test]
250 fn area_3d_unit_square() {
251 let ring = LinearRing::new([
252 DirectPosition::new(0.0, 0.0, 1.0).unwrap(),
253 DirectPosition::new(1.0, 0.0, 1.0).unwrap(),
254 DirectPosition::new(1.0, 1.0, 1.0).unwrap(),
255 DirectPosition::new(0.0, 1.0, 1.0).unwrap(),
256 ])
257 .unwrap();
258 let polygon = Polygon::new(Some(AbstractRingKind::LinearRing(ring)), []).unwrap();
259 assert!((polygon.area_3d().expect("has exterior ring") - 1.0).abs() < 1e-10);
260 }
261
262 #[test]
263 fn area_3d_with_hole() {
264 let exterior = LinearRing::new([
266 DirectPosition::new(0.0, 0.0, 0.0).unwrap(),
267 DirectPosition::new(4.0, 0.0, 0.0).unwrap(),
268 DirectPosition::new(4.0, 4.0, 0.0).unwrap(),
269 DirectPosition::new(0.0, 4.0, 0.0).unwrap(),
270 ])
271 .unwrap();
272 let hole = LinearRing::new([
273 DirectPosition::new(1.0, 1.0, 0.0).unwrap(),
274 DirectPosition::new(2.0, 1.0, 0.0).unwrap(),
275 DirectPosition::new(2.0, 2.0, 0.0).unwrap(),
276 DirectPosition::new(1.0, 2.0, 0.0).unwrap(),
277 ])
278 .unwrap();
279 let polygon = Polygon::new(
280 Some(AbstractRingKind::LinearRing(exterior)),
281 vec![AbstractRingKind::LinearRing(hole)],
282 )
283 .unwrap();
284 assert!((polygon.area_3d().expect("has exterior ring") - 15.0).abs() < 1e-10);
285 }
286
287 #[test]
288 fn area_3d_no_exterior_ring() {
289 let polygon = Polygon::new(None, []).unwrap();
290 assert_eq!(polygon.area_3d(), Err(Error::MissingExteriorRing));
291 }
292
293 #[test]
294 fn triangulate_no_exterior_ring() {
295 let polygon = Polygon::new(None, []).unwrap();
296 assert_eq!(
297 polygon.triangulate().err(),
298 Some(Error::MissingExteriorRing)
299 );
300 }
301
302 #[test]
303 fn basic_normal_vector() {
304 let point_a = DirectPosition::new(0.0, 0.0, 1.0).unwrap();
305 let point_b = DirectPosition::new(1.0, 0.0, 1.0).unwrap();
306 let point_c = DirectPosition::new(1.0, 1.0, 1.0).unwrap();
307 let point_d = DirectPosition::new(0.0, 1.0, 1.0).unwrap();
308 let linear_ring = LinearRing::new([point_a, point_b, point_c, point_d]).unwrap();
309 let linear_ring = AbstractRingKind::LinearRing(linear_ring);
310 let polygon = Polygon::new(Some(linear_ring), []).unwrap();
311 let normal = polygon.normal();
312
313 assert_eq!(normal, Vector3::new(0.0, 0.0, 1.0));
314 }
315
316 #[test]
317 fn basic_plane_equation() {
318 let point_a = DirectPosition::new(0.0, 0.0, 1.0).unwrap();
319 let point_b = DirectPosition::new(1.0, 0.0, 1.0).unwrap();
320 let point_c = DirectPosition::new(1.0, 1.0, 1.0).unwrap();
321 let point_d = DirectPosition::new(0.0, 1.0, 1.0).unwrap();
322 let linear_ring = LinearRing::new([point_a, point_b, point_c, point_d]).unwrap();
323 let linear_ring = AbstractRingKind::LinearRing(linear_ring);
324 let polygon = Polygon::new(Some(linear_ring), []).unwrap();
325 let plane_equation = polygon.plane_equation();
326
327 assert_eq!(
328 plane_equation.point,
329 DirectPosition::new(0.0, 0.0, 1.0).unwrap()
330 );
331 assert_eq!(plane_equation.normal(), Vector3::new(0.0, 0.0, 1.0));
332 }
333
334 #[test]
335 fn test_polygon_triangulation() {
336 let linear_ring_exterior = LinearRing::new([
337 DirectPosition::new(0.0, 0.0, 0.0).expect("should work"),
338 DirectPosition::new(1.0, 0.0, 0.0).expect("should work"),
339 DirectPosition::new(1.0, 1.0, 2.0).expect("should work"),
340 DirectPosition::new(0.0, 1.0, 2.0).expect("should work"),
341 ])
342 .expect("should work");
343 let linear_ring_exterior = AbstractRingKind::LinearRing(linear_ring_exterior);
344
345 let polygon = Polygon::new(Some(linear_ring_exterior), vec![]).expect("should work");
346 let triangulation = polygon.triangulate().expect("should work");
347 assert_eq!(triangulation.surface().patches_len(), 2);
348 }
349
350 #[test]
351 fn test_polygon_with_interior_triangulation() {
352 let linear_ring_exterior = LinearRing::new([
355 DirectPosition::new(0.0, 0.0, 0.0).expect("should work"),
356 DirectPosition::new(2.0, 0.0, 0.0).expect("should work"),
357 DirectPosition::new(2.0, 2.0, 4.0).expect("should work"),
358 DirectPosition::new(0.0, 2.0, 4.0).expect("should work"),
359 ])
360 .expect("should work");
361 let linear_ring_interior = LinearRing::new([
362 DirectPosition::new(0.5, 0.5, 1.0).expect("should work"),
363 DirectPosition::new(0.5, 1.5, 3.0).expect("should work"),
364 DirectPosition::new(1.5, 1.5, 3.0).expect("should work"),
365 DirectPosition::new(1.5, 0.5, 1.0).expect("should work"),
366 ])
367 .expect("should work");
368
369 let polygon = Polygon::new(
370 Some(AbstractRingKind::LinearRing(linear_ring_exterior)),
371 vec![AbstractRingKind::LinearRing(linear_ring_interior)],
372 )
373 .expect("should work");
374 let triangulation = polygon.triangulate().expect("should work");
375
376 let expected = 3.0 * 5.0_f64.sqrt();
377 assert!(triangulation.skipped().is_empty());
378 assert!((triangulation.surface().area_3d().expect("should work") - expected).abs() < 1e-10);
379 assert!((polygon.area_3d().expect("should work") - expected).abs() < 1e-10);
380 }
381}