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