Skip to main content

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}