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}