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