geo_types/geometry/polygon.rs
1use crate::{CoordFloat, CoordNum, LineString, Point, Rect, Triangle};
2use alloc::vec;
3use alloc::vec::Vec;
4use num_traits::{Float, Signed};
5
6/// A bounded two-dimensional area.
7///
8/// A `Polygon`’s outer boundary (_exterior ring_) is represented by a
9/// [`LineString`](LineString). It may contain zero or more holes (_interior rings_), also
10/// represented by `LineString`s.
11///
12/// A `Polygon` can be created with the [`Polygon::new`] constructor or the [`polygon!`][`crate::polygon!`] macro.
13///
14/// # Semantics
15///
16/// The _boundary_ of the polygon is the union of the
17/// boundaries of the exterior and interiors. The interior
18/// is all the points inside the polygon (not on the
19/// boundary).
20///
21/// The `Polygon` structure guarantees that all exterior and interior rings will
22/// be _closed_, such that the first and last `Coord` of each ring has
23/// the same value.
24///
25/// # Validity
26///
27/// - The exterior and interior rings must be valid
28/// `LinearRing`s (see [`LineString`](LineString)).
29///
30/// - No two rings in the boundary may cross, and may
31/// intersect at a `Point` only as a tangent. In other
32/// words, the rings must be distinct, and for every pair of
33/// common points in two of the rings, there must be a
34/// neighborhood (a topological open set) around one that
35/// does not contain the other point.
36///
37/// - The closure of the interior of the `Polygon` must
38/// equal the `Polygon` itself. For instance, the exterior
39/// may not contain a spike.
40///
41/// - The interior of the polygon must be a connected
42/// point-set. That is, any two distinct points in the
43/// interior must admit a curve between these two that lies
44/// in the interior.
45///
46/// Refer to section 6.1.11.1 of the OGC-SFA for a formal
47/// definition of validity. Besides the closed `LineString`
48/// guarantee, the `Polygon` structure does not enforce
49/// validity at this time. For example, it is possible to
50/// construct a `Polygon` that has:
51///
52/// - fewer than 3 coordinates per `LineString` ring
53/// - interior rings that intersect other interior rings
54/// - interior rings that extend beyond the exterior ring
55///
56/// # `LineString` closing operation
57///
58/// Some APIs on `Polygon` result in a closing operation on a `LineString`. The
59/// operation is as follows:
60///
61/// If a `LineString`’s first and last `Coord` have different values, a
62/// new `Coord` will be appended to the `LineString` with a value equal to
63/// the first `Coord`.
64#[derive(Eq, PartialEq, Clone, Hash)]
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66pub struct Polygon<T: CoordNum = f64> {
67 exterior: LineString<T>,
68 interiors: Vec<LineString<T>>,
69}
70
71impl<T: CoordNum> Polygon<T> {
72 /// Create a new `Polygon` with the provided exterior `LineString` ring and
73 /// interior `LineString` rings.
74 ///
75 /// Upon calling `new`, the exterior and interior `LineString` rings [will
76 /// be closed].
77 ///
78 /// [will be closed]: #linestring-closing-operation
79 ///
80 /// # Examples
81 ///
82 /// Creating a `Polygon` with no interior rings:
83 ///
84 /// ```
85 /// use geo_types::{LineString, Polygon};
86 ///
87 /// let polygon = Polygon::new(
88 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
89 /// vec![],
90 /// );
91 /// ```
92 ///
93 /// Creating a `Polygon` with an interior ring:
94 ///
95 /// ```
96 /// use geo_types::{LineString, Polygon};
97 ///
98 /// let polygon = Polygon::new(
99 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
100 /// vec![LineString::from(vec![
101 /// (0.1, 0.1),
102 /// (0.9, 0.9),
103 /// (0.9, 0.1),
104 /// (0.1, 0.1),
105 /// ])],
106 /// );
107 /// ```
108 ///
109 /// If the first and last `Coord`s of the exterior or interior
110 /// `LineString`s no longer match, those `LineString`s [will be closed]:
111 ///
112 /// ```
113 /// use geo_types::{coord, LineString, Polygon};
114 ///
115 /// let mut polygon = Polygon::new(LineString::from(vec![(0., 0.), (1., 1.), (1., 0.)]), vec![]);
116 ///
117 /// assert_eq!(
118 /// polygon.exterior(),
119 /// &LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.),])
120 /// );
121 /// ```
122 pub fn new(mut exterior: LineString<T>, mut interiors: Vec<LineString<T>>) -> Self {
123 exterior.close();
124 for interior in &mut interiors {
125 interior.close();
126 }
127 Self {
128 exterior,
129 interiors,
130 }
131 }
132
133 /// Returns an empty Polygon.
134 ///
135 /// `geo` represents an empty Polygon as one whose exterior is an empty LineString
136 pub fn empty() -> Self {
137 Self::new(LineString::empty(), vec![])
138 }
139
140 /// Consume the `Polygon`, returning the exterior `LineString` ring and
141 /// a vector of the interior `LineString` rings.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// use geo_types::{LineString, Polygon};
147 ///
148 /// let mut polygon = Polygon::new(
149 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
150 /// vec![LineString::from(vec![
151 /// (0.1, 0.1),
152 /// (0.9, 0.9),
153 /// (0.9, 0.1),
154 /// (0.1, 0.1),
155 /// ])],
156 /// );
157 ///
158 /// let (exterior, interiors) = polygon.into_inner();
159 ///
160 /// assert_eq!(
161 /// exterior,
162 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.),])
163 /// );
164 ///
165 /// assert_eq!(
166 /// interiors,
167 /// vec![LineString::from(vec![
168 /// (0.1, 0.1),
169 /// (0.9, 0.9),
170 /// (0.9, 0.1),
171 /// (0.1, 0.1),
172 /// ])]
173 /// );
174 /// ```
175 pub fn into_inner(self) -> (LineString<T>, Vec<LineString<T>>) {
176 (self.exterior, self.interiors)
177 }
178
179 /// Return a reference to the exterior `LineString` ring.
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// use geo_types::{LineString, Polygon};
185 ///
186 /// let exterior = LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]);
187 ///
188 /// let polygon = Polygon::new(exterior.clone(), vec![]);
189 ///
190 /// assert_eq!(polygon.exterior(), &exterior);
191 /// ```
192 pub fn exterior(&self) -> &LineString<T> {
193 &self.exterior
194 }
195
196 /// Execute the provided closure `f`, which is provided with a mutable
197 /// reference to the exterior `LineString` ring.
198 ///
199 /// After the closure executes, the exterior `LineString` [will be closed].
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// use geo_types::{coord, LineString, Polygon};
205 ///
206 /// let mut polygon = Polygon::new(
207 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
208 /// vec![],
209 /// );
210 ///
211 /// polygon.exterior_mut(|exterior| {
212 /// exterior.0[1] = coord! { x: 1., y: 2. };
213 /// });
214 ///
215 /// assert_eq!(
216 /// polygon.exterior(),
217 /// &LineString::from(vec![(0., 0.), (1., 2.), (1., 0.), (0., 0.),])
218 /// );
219 /// ```
220 ///
221 /// If the first and last `Coord`s of the exterior `LineString` no
222 /// longer match, the `LineString` [will be closed]:
223 ///
224 /// ```
225 /// use geo_types::{coord, LineString, Polygon};
226 ///
227 /// let mut polygon = Polygon::new(
228 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
229 /// vec![],
230 /// );
231 ///
232 /// polygon.exterior_mut(|exterior| {
233 /// exterior.0[0] = coord! { x: 0., y: 1. };
234 /// });
235 ///
236 /// assert_eq!(
237 /// polygon.exterior(),
238 /// &LineString::from(vec![(0., 1.), (1., 1.), (1., 0.), (0., 0.), (0., 1.),])
239 /// );
240 /// ```
241 ///
242 /// [will be closed]: #linestring-closing-operation
243 pub fn exterior_mut<F>(&mut self, f: F)
244 where
245 F: FnOnce(&mut LineString<T>),
246 {
247 f(&mut self.exterior);
248 self.exterior.close();
249 }
250
251 /// Fallible alternative to [`exterior_mut`](Polygon::exterior_mut).
252 pub fn try_exterior_mut<F, E>(&mut self, f: F) -> Result<(), E>
253 where
254 F: FnOnce(&mut LineString<T>) -> Result<(), E>,
255 {
256 f(&mut self.exterior)?;
257 self.exterior.close();
258 Ok(())
259 }
260
261 /// Return a slice of the interior `LineString` rings.
262 ///
263 /// # Examples
264 ///
265 /// ```
266 /// use geo_types::{coord, LineString, Polygon};
267 ///
268 /// let interiors = vec![LineString::from(vec![
269 /// (0.1, 0.1),
270 /// (0.9, 0.9),
271 /// (0.9, 0.1),
272 /// (0.1, 0.1),
273 /// ])];
274 ///
275 /// let polygon = Polygon::new(
276 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
277 /// interiors.clone(),
278 /// );
279 ///
280 /// assert_eq!(interiors, polygon.interiors());
281 /// ```
282 pub fn interiors(&self) -> &[LineString<T>] {
283 &self.interiors
284 }
285
286 /// Execute the provided closure `f`, which is provided with a mutable
287 /// reference to the interior `LineString` rings.
288 ///
289 /// After the closure executes, each of the interior `LineString`s [will be
290 /// closed].
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// use geo_types::{coord, LineString, Polygon};
296 ///
297 /// let mut polygon = Polygon::new(
298 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
299 /// vec![LineString::from(vec![
300 /// (0.1, 0.1),
301 /// (0.9, 0.9),
302 /// (0.9, 0.1),
303 /// (0.1, 0.1),
304 /// ])],
305 /// );
306 ///
307 /// polygon.interiors_mut(|interiors| {
308 /// interiors[0].0[1] = coord! { x: 0.8, y: 0.8 };
309 /// });
310 ///
311 /// assert_eq!(
312 /// polygon.interiors(),
313 /// &[LineString::from(vec![
314 /// (0.1, 0.1),
315 /// (0.8, 0.8),
316 /// (0.9, 0.1),
317 /// (0.1, 0.1),
318 /// ])]
319 /// );
320 /// ```
321 ///
322 /// If the first and last `Coord`s of any interior `LineString` no
323 /// longer match, those `LineString`s [will be closed]:
324 ///
325 /// ```
326 /// use geo_types::{coord, LineString, Polygon};
327 ///
328 /// let mut polygon = Polygon::new(
329 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
330 /// vec![LineString::from(vec![
331 /// (0.1, 0.1),
332 /// (0.9, 0.9),
333 /// (0.9, 0.1),
334 /// (0.1, 0.1),
335 /// ])],
336 /// );
337 ///
338 /// polygon.interiors_mut(|interiors| {
339 /// interiors[0].0[0] = coord! { x: 0.1, y: 0.2 };
340 /// });
341 ///
342 /// assert_eq!(
343 /// polygon.interiors(),
344 /// &[LineString::from(vec![
345 /// (0.1, 0.2),
346 /// (0.9, 0.9),
347 /// (0.9, 0.1),
348 /// (0.1, 0.1),
349 /// (0.1, 0.2),
350 /// ])]
351 /// );
352 /// ```
353 ///
354 /// [will be closed]: #linestring-closing-operation
355 pub fn interiors_mut<F>(&mut self, f: F)
356 where
357 F: FnOnce(&mut [LineString<T>]),
358 {
359 f(&mut self.interiors);
360 for interior in &mut self.interiors {
361 interior.close();
362 }
363 }
364
365 /// Fallible alternative to [`interiors_mut`](Self::interiors_mut).
366 pub fn try_interiors_mut<F, E>(&mut self, f: F) -> Result<(), E>
367 where
368 F: FnOnce(&mut [LineString<T>]) -> Result<(), E>,
369 {
370 f(&mut self.interiors)?;
371 for interior in &mut self.interiors {
372 interior.close();
373 }
374 Ok(())
375 }
376
377 /// Add an interior ring to the `Polygon`.
378 ///
379 /// The new `LineString` interior ring [will be closed]:
380 ///
381 /// # Examples
382 ///
383 /// ```
384 /// use geo_types::{coord, LineString, Polygon};
385 ///
386 /// let mut polygon = Polygon::new(
387 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
388 /// vec![],
389 /// );
390 ///
391 /// assert_eq!(polygon.interiors().len(), 0);
392 ///
393 /// polygon.interiors_push(vec![(0.1, 0.1), (0.9, 0.9), (0.9, 0.1)]);
394 ///
395 /// assert_eq!(
396 /// polygon.interiors(),
397 /// &[LineString::from(vec![
398 /// (0.1, 0.1),
399 /// (0.9, 0.9),
400 /// (0.9, 0.1),
401 /// (0.1, 0.1),
402 /// ])]
403 /// );
404 /// ```
405 ///
406 /// [will be closed]: #linestring-closing-operation
407 pub fn interiors_push(&mut self, new_interior: impl Into<LineString<T>>) {
408 let mut new_interior = new_interior.into();
409 new_interior.close();
410 self.interiors.push(new_interior);
411 }
412
413 /// Wrap-around previous-vertex
414 fn previous_vertex(&self, current_vertex: usize) -> usize
415 where
416 T: Float,
417 {
418 (current_vertex + (self.exterior.0.len() - 1) - 1) % (self.exterior.0.len() - 1)
419 }
420
421 /// Count the total number of rings (interior and exterior) in the polygon
422 ///
423 /// # Examples
424 ///
425 /// ```
426 /// use geo_types::{coord, LineString, Polygon};
427 ///
428 /// let polygon = Polygon::new(
429 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
430 /// vec![],
431 /// );
432 ///
433 /// assert_eq!(polygon.num_rings(), 1);
434 ///
435 /// let polygon = Polygon::new(
436 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
437 /// vec![LineString::from(vec![(0.1, 0.1), (0.9, 0.9), (0.9, 0.1)])],
438 /// );
439 ///
440 /// assert_eq!(polygon.num_rings(), 2);
441 /// ```
442 pub fn num_rings(&self) -> usize {
443 self.num_interior_rings() + 1
444 }
445
446 /// Count the number of interior rings in the polygon
447 ///
448 /// # Examples
449 ///
450 /// ```
451 /// use geo_types::{coord, LineString, Polygon};
452 ///
453 /// let polygon = Polygon::new(
454 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
455 /// vec![],
456 /// );
457 ///
458 /// assert_eq!(polygon.num_interior_rings(), 0);
459 ///
460 /// let polygon = Polygon::new(
461 /// LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
462 /// vec![LineString::from(vec![(0.1, 0.1), (0.9, 0.9), (0.9, 0.1)])],
463 /// );
464 ///
465 /// assert_eq!(polygon.num_interior_rings(), 1);
466 /// ```
467 pub fn num_interior_rings(&self) -> usize {
468 self.interiors.len()
469 }
470}
471
472// used to check the sign of a vec of floats
473#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
474enum ListSign {
475 Empty,
476 Positive,
477 Negative,
478 Mixed,
479}
480
481impl<T: CoordFloat + Signed> Polygon<T> {
482 /// Determine whether a Polygon is convex
483 // For each consecutive pair of edges of the polygon (each triplet of points),
484 // compute the z-component of the cross product of the vectors defined by the
485 // edges pointing towards the points in increasing order.
486 // Take the cross product of these vectors
487 // The polygon is convex if the z-components of the cross products are either
488 // all positive or all negative. Otherwise, the polygon is non-convex.
489 // see: http://stackoverflow.com/a/1881201/416626
490 #[deprecated(
491 since = "0.6.1",
492 note = "Please use `geo::is_convex` on `poly.exterior()` instead"
493 )]
494 pub fn is_convex(&self) -> bool {
495 let convex = self
496 .exterior
497 .0
498 .iter()
499 .enumerate()
500 .map(|(idx, _)| {
501 let prev_1 = self.previous_vertex(idx);
502 let prev_2 = self.previous_vertex(prev_1);
503 Point::from(self.exterior[prev_2]).cross_prod(
504 Point::from(self.exterior[prev_1]),
505 Point::from(self.exterior[idx]),
506 )
507 })
508 // accumulate and check cross-product result signs in a single pass
509 // positive implies ccw convexity, negative implies cw convexity
510 // anything else implies non-convexity
511 .fold(ListSign::Empty, |acc, n| match (acc, n.is_positive()) {
512 (ListSign::Empty, true) | (ListSign::Positive, true) => ListSign::Positive,
513 (ListSign::Empty, false) | (ListSign::Negative, false) => ListSign::Negative,
514 _ => ListSign::Mixed,
515 });
516 convex != ListSign::Mixed
517 }
518}
519
520impl<T: CoordNum> From<Rect<T>> for Polygon<T> {
521 fn from(r: Rect<T>) -> Self {
522 Polygon::new(
523 vec![
524 (r.min().x, r.min().y),
525 (r.max().x, r.min().y),
526 (r.max().x, r.max().y),
527 (r.min().x, r.max().y),
528 (r.min().x, r.min().y),
529 ]
530 .into(),
531 Vec::new(),
532 )
533 }
534}
535
536impl<T: CoordNum> From<Triangle<T>> for Polygon<T> {
537 fn from(t: Triangle<T>) -> Self {
538 t.to_polygon()
539 }
540}
541
542#[cfg(any(feature = "approx", test))]
543mod approx_integration {
544 use super::*;
545 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
546
547 impl<T> RelativeEq for Polygon<T>
548 where
549 T: CoordNum + RelativeEq<Epsilon = T>,
550 {
551 #[inline]
552 fn default_max_relative() -> Self::Epsilon {
553 T::default_max_relative()
554 }
555
556 /// Equality assertion within a relative limit.
557 ///
558 /// # Examples
559 ///
560 /// ```
561 /// use geo_types::{Polygon, polygon};
562 ///
563 /// let a: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
564 /// let b: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
565 ///
566 /// approx::assert_relative_eq!(a, b, max_relative=0.1);
567 /// approx::assert_relative_ne!(a, b, max_relative=0.001);
568 /// ```
569 ///
570 fn relative_eq(
571 &self,
572 other: &Self,
573 epsilon: Self::Epsilon,
574 max_relative: Self::Epsilon,
575 ) -> bool {
576 if !self
577 .exterior
578 .relative_eq(&other.exterior, epsilon, max_relative)
579 {
580 return false;
581 }
582
583 if self.interiors.len() != other.interiors.len() {
584 return false;
585 }
586 let mut zipper = self.interiors.iter().zip(other.interiors.iter());
587 zipper.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
588 }
589 }
590
591 impl<T> AbsDiffEq for Polygon<T>
592 where
593 T: CoordNum + AbsDiffEq<Epsilon = T>,
594 {
595 type Epsilon = T;
596
597 #[inline]
598 fn default_epsilon() -> Self::Epsilon {
599 T::default_epsilon()
600 }
601
602 /// Equality assertion with an absolute limit.
603 ///
604 /// # Examples
605 ///
606 /// ```
607 /// use geo_types::{Polygon, polygon};
608 ///
609 /// let a: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
610 /// let b: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
611 ///
612 /// approx::assert_abs_diff_eq!(a, b, epsilon=0.1);
613 /// approx::assert_abs_diff_ne!(a, b, epsilon=0.001);
614 /// ```
615 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
616 if !self.exterior.abs_diff_eq(&other.exterior, epsilon) {
617 return false;
618 }
619
620 if self.interiors.len() != other.interiors.len() {
621 return false;
622 }
623 let mut zipper = self.interiors.iter().zip(other.interiors.iter());
624 zipper.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
625 }
626 }
627
628 impl<T> UlpsEq for Polygon<T>
629 where
630 T: CoordNum + UlpsEq<Epsilon = T>,
631 {
632 fn default_max_ulps() -> u32 {
633 T::default_max_ulps()
634 }
635
636 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
637 if !self.exterior.ulps_eq(&other.exterior, epsilon, max_ulps) {
638 return false;
639 }
640 if self.interiors.len() != other.interiors.len() {
641 return false;
642 }
643 let mut zipper = self.interiors.iter().zip(other.interiors.iter());
644 zipper.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
645 }
646 }
647}
648
649#[cfg(any(
650 feature = "rstar_0_8",
651 feature = "rstar_0_9",
652 feature = "rstar_0_10",
653 feature = "rstar_0_11",
654 feature = "rstar_0_12"
655))]
656macro_rules! impl_rstar_polygon {
657 ($rstar:ident) => {
658 impl<T> $rstar::RTreeObject for Polygon<T>
659 where
660 T: ::num_traits::Float + ::$rstar::RTreeNum,
661 {
662 type Envelope = ::$rstar::AABB<Point<T>>;
663
664 fn envelope(&self) -> Self::Envelope {
665 self.exterior.envelope()
666 }
667 }
668 };
669}
670
671#[cfg(feature = "rstar_0_8")]
672impl_rstar_polygon!(rstar_0_8);
673
674#[cfg(feature = "rstar_0_9")]
675impl_rstar_polygon!(rstar_0_9);
676
677#[cfg(feature = "rstar_0_10")]
678impl_rstar_polygon!(rstar_0_10);
679
680#[cfg(feature = "rstar_0_11")]
681impl_rstar_polygon!(rstar_0_11);
682
683#[cfg(feature = "rstar_0_12")]
684impl_rstar_polygon!(rstar_0_12);
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689 use crate::wkt;
690
691 #[test]
692 fn empty() {
693 let empty = Polygon::<f64>::empty();
694 let empty_2 = wkt! { POLYGON EMPTY };
695 assert_eq!(empty, empty_2);
696 }
697}