1use super::io::MultiPartShapeWriter;
3use super::polyline::GenericPolyline;
4use super::traits::{GrowablePoint, HasXY, ShrinkablePoint};
5use super::{
6 close_points_if_not_already, ring_type_from_points_ordering, ConcreteReadableShape, EsriShape,
7 GenericBBox, RingType, WritableShape,
8};
9use super::{Error, ShapeType};
10use super::{HasShapeType, Point};
11use super::{PointM, PointZ};
12use super::{Polyline, PolylineM, PolylineZ};
13use core::fmt;
14use std::io::{Read, Write};
15use std::mem::size_of;
16
17#[cfg(feature = "geo-types")]
18use geo_types::{Coordinate, LineString};
19use std::ops::Index;
20use std::slice::SliceIndex;
21
22#[derive(Debug, Clone, PartialEq)]
67pub enum PolygonRing<PointType> {
68 Outer(Vec<PointType>),
70 Inner(Vec<PointType>),
72}
73
74impl<PointType> PolygonRing<PointType> {
75 #[inline]
91 pub fn len(&self) -> usize {
92 self.points().len()
93 }
94
95 #[inline]
97 pub fn is_empty(&self) -> bool {
98 self.points().is_empty()
99 }
100
101 #[inline]
115 pub fn points(&self) -> &[PointType] {
116 match self {
117 PolygonRing::Outer(points) => points,
118 PolygonRing::Inner(points) => points,
119 }
120 }
121
122 #[inline]
124 pub fn into_inner(self) -> Vec<PointType> {
125 match self {
126 PolygonRing::Outer(points) => points,
127 PolygonRing::Inner(points) => points,
128 }
129 }
130
131 #[inline]
132 fn points_vec_mut(&mut self) -> &mut Vec<PointType> {
133 match self {
134 PolygonRing::Outer(points) => points,
135 PolygonRing::Inner(points) => points,
136 }
137 }
138}
139
140impl<PointType> AsRef<[PointType]> for PolygonRing<PointType> {
141 fn as_ref(&self) -> &[PointType] {
142 self.points()
143 }
144}
145
146impl<PointType> PolygonRing<PointType>
147where
148 PointType: Copy + PartialEq + HasXY,
149{
150 fn close_and_reorder(&mut self) {
151 self.close_if_not_already_closed();
152 self.correctly_order_points();
153 }
154
155 fn close_if_not_already_closed(&mut self) {
156 close_points_if_not_already(self.points_vec_mut())
157 }
158
159 fn correctly_order_points(&mut self) {
160 let points = self.points_vec_mut();
161 let actual_ring_type = super::ring_type_from_points_ordering(points);
162 match (self, actual_ring_type) {
163 (PolygonRing::Outer(points), RingType::InnerRing)
164 | (PolygonRing::Inner(points), RingType::OuterRing) => {
165 points.reverse();
166 }
167 _ => {}
168 }
169 }
170}
171
172impl<PointType, I: SliceIndex<[PointType]>> Index<I> for PolygonRing<PointType> {
173 type Output = I::Output;
174
175 fn index(&self, index: I) -> &Self::Output {
176 Index::index(self.points(), index)
177 }
178}
179
180impl<PointType: HasXY> From<Vec<PointType>> for PolygonRing<PointType> {
181 fn from(p: Vec<PointType>) -> Self {
182 match ring_type_from_points_ordering(&p) {
183 RingType::OuterRing => PolygonRing::Outer(p),
184 RingType::InnerRing => PolygonRing::Inner(p),
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq)]
230pub struct GenericPolygon<PointType> {
231 bbox: GenericBBox<PointType>,
232 rings: Vec<PolygonRing<PointType>>,
233}
234
235impl<PointType> GenericPolygon<PointType>
236where
237 PointType: ShrinkablePoint + GrowablePoint + PartialEq + HasXY + Copy,
238{
239 pub fn new(mut ring: PolygonRing<PointType>) -> Self {
263 ring.close_and_reorder();
264 Self::with_rings(vec![ring])
265 }
266}
267
268impl<PointType> GenericPolygon<PointType>
269where
270 PointType: GrowablePoint + ShrinkablePoint + PartialEq + HasXY + Copy,
271{
272 pub fn with_rings(mut rings: Vec<PolygonRing<PointType>>) -> Self {
307 rings.iter_mut().for_each(PolygonRing::close_and_reorder);
308 let mut bbox = GenericBBox::<PointType>::from_points(rings[0].points());
309 for ring in &rings[1..] {
310 bbox.grow_from_points(ring.points());
311 }
312 Self { bbox, rings }
313 }
314}
315
316impl<PointType> GenericPolygon<PointType> {
317 #[inline]
319 pub fn bbox(&self) -> &GenericBBox<PointType> {
320 &self.bbox
321 }
322
323 #[inline]
325 pub fn rings(&self) -> &[PolygonRing<PointType>] {
326 &self.rings
327 }
328
329 #[inline]
349 pub fn ring(&self, index: usize) -> Option<&PolygonRing<PointType>> {
350 self.rings.get(index)
351 }
352
353 #[inline]
355 pub fn into_inner(self) -> Vec<PolygonRing<PointType>> {
356 self.rings
357 }
358
359 #[inline]
361 pub fn total_point_count(&self) -> usize {
362 self.rings.iter().map(|ring| ring.len()).sum()
363 }
364}
365
366impl<PointType: HasXY> From<GenericPolyline<PointType>> for GenericPolygon<PointType> {
367 fn from(polyline: GenericPolyline<PointType>) -> Self {
368 let mut rings = Vec::<PolygonRing<PointType>>::with_capacity(polyline.parts.len());
369 for part in polyline.parts {
370 rings.push(PolygonRing::from(part))
371 }
372 Self {
373 bbox: polyline.bbox,
374 rings,
375 }
376 }
377}
378
379pub type Polygon = GenericPolygon<Point>;
385
386impl fmt::Display for Polygon {
387 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
388 write!(f, "Polygon({} rings)", self.rings.len())
389 }
390}
391
392impl HasShapeType for Polygon {
393 fn shapetype() -> ShapeType {
394 ShapeType::Polygon
395 }
396}
397
398impl ConcreteReadableShape for Polygon {
399 fn read_shape_content<T: Read>(source: &mut T, record_size: i32) -> Result<Self, Error> {
400 Polyline::read_shape_content(source, record_size).map(Polygon::from)
401 }
402}
403
404impl WritableShape for Polygon {
405 fn size_in_bytes(&self) -> usize {
406 let mut size = 0_usize;
407 size += size_of::<f64>() * 4;
408 size += size_of::<i32>(); size += size_of::<i32>(); size += size_of::<i32>() * self.rings.len();
411 size += 2 * size_of::<f64>() * self.total_point_count();
412 size
413 }
414
415 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error> {
416 let parts_iter = self.rings().iter().map(|ring| ring.points());
417 let writer = MultiPartShapeWriter::new(&self.bbox, parts_iter, dest);
418 writer.write_point_shape()?;
419 Ok(())
420 }
421}
422
423impl EsriShape for Polygon {
424 fn x_range(&self) -> [f64; 2] {
425 self.bbox.x_range()
426 }
427
428 fn y_range(&self) -> [f64; 2] {
429 self.bbox.y_range()
430 }
431}
432
433pub type PolygonM = GenericPolygon<PointM>;
440
441impl fmt::Display for PolygonM {
442 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
443 write!(f, "PolygonM({} rings)", self.rings.len())
444 }
445}
446
447impl HasShapeType for PolygonM {
448 fn shapetype() -> ShapeType {
449 ShapeType::PolygonM
450 }
451}
452
453impl ConcreteReadableShape for PolygonM {
454 fn read_shape_content<T: Read>(source: &mut T, record_size: i32) -> Result<Self, Error> {
455 PolylineM::read_shape_content(source, record_size).map(PolygonM::from)
456 }
457}
458
459impl WritableShape for PolygonM {
460 fn size_in_bytes(&self) -> usize {
461 let mut size = 0_usize;
462 size += size_of::<f64>() * 4;
463 size += size_of::<i32>(); size += size_of::<i32>(); size += size_of::<i32>() * self.rings.len();
466 size += 3 * size_of::<f64>() * self.total_point_count();
467 size += 2 * size_of::<f64>();
468 size
469 }
470
471 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error> {
472 let parts_iter = self.rings().iter().map(|ring| ring.points());
473 let writer = MultiPartShapeWriter::new(&self.bbox, parts_iter, dest);
474 writer.write_point_m_shape()?;
475 Ok(())
476 }
477}
478
479impl EsriShape for PolygonM {
480 fn x_range(&self) -> [f64; 2] {
481 self.bbox.x_range()
482 }
483
484 fn y_range(&self) -> [f64; 2] {
485 self.bbox.y_range()
486 }
487
488 fn m_range(&self) -> [f64; 2] {
489 self.bbox.m_range()
490 }
491}
492
493pub type PolygonZ = GenericPolygon<PointZ>;
500
501impl fmt::Display for PolygonZ {
502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503 write!(f, "PolygonZ({} rings)", self.rings.len())
504 }
505}
506
507impl HasShapeType for PolygonZ {
508 fn shapetype() -> ShapeType {
509 ShapeType::PolygonZ
510 }
511}
512
513impl ConcreteReadableShape for PolygonZ {
514 fn read_shape_content<T: Read>(source: &mut T, record_size: i32) -> Result<Self, Error> {
515 PolylineZ::read_shape_content(source, record_size).map(PolygonZ::from)
516 }
517}
518
519impl WritableShape for PolygonZ {
520 fn size_in_bytes(&self) -> usize {
521 let mut size = 0_usize;
522 size += size_of::<f64>() * 4;
523 size += size_of::<i32>(); size += size_of::<i32>(); size += size_of::<i32>() * self.rings.len();
526 size += 4 * size_of::<f64>() * self.total_point_count();
527 size += 2 * size_of::<f64>();
528 size += 2 * size_of::<f64>();
529 size
530 }
531
532 fn write_to<T: Write>(&self, dest: &mut T) -> Result<(), Error> {
533 let parts_iter = self.rings().iter().map(|ring| ring.points());
534 let writer = MultiPartShapeWriter::new(&self.bbox, parts_iter, dest);
535 writer.write_point_z_shape()?;
536 Ok(())
537 }
538}
539
540impl EsriShape for PolygonZ {
541 fn x_range(&self) -> [f64; 2] {
542 self.bbox.x_range()
543 }
544
545 fn y_range(&self) -> [f64; 2] {
546 self.bbox.y_range()
547 }
548
549 fn z_range(&self) -> [f64; 2] {
550 self.bbox.z_range()
551 }
552
553 fn m_range(&self) -> [f64; 2] {
554 self.bbox.m_range()
555 }
556}
557
558#[cfg(feature = "geo-types")]
559impl<PointType> From<GenericPolygon<PointType>> for geo_types::MultiPolygon<f64>
560where
561 PointType: ShrinkablePoint + GrowablePoint + Copy,
562 geo_types::Coordinate<f64>: From<PointType>,
563{
564 fn from(p: GenericPolygon<PointType>) -> Self {
565 let mut last_poly = None;
566 let mut polygons = Vec::<geo_types::Polygon<f64>>::new();
567 for ring in p.rings {
568 match ring {
569 PolygonRing::Outer(points) => {
570 let exterior = points
571 .into_iter()
572 .map(Coordinate::<f64>::from)
573 .collect::<Vec<Coordinate<f64>>>();
574
575 if let Some(poly) = last_poly.take() {
576 polygons.push(poly);
577 }
578 last_poly = Some(geo_types::Polygon::new(LineString::from(exterior), vec![]))
579 }
580 PolygonRing::Inner(points) => {
581 let interior = points
582 .into_iter()
583 .map(Coordinate::<f64>::from)
584 .collect::<Vec<Coordinate<f64>>>();
585
586 if let Some(poly) = last_poly.as_mut() {
587 poly.interiors_push(interior);
588 } else {
589 polygons.push(geo_types::Polygon::<f64>::new(
591 LineString::<f64>::from(Vec::<Coordinate<f64>>::new()),
592 vec![LineString::from(interior)],
593 ));
594 }
595 }
596 }
597 }
598 if let Some(poly) = last_poly.take() {
599 polygons.push(poly);
600 }
601 polygons.into()
602 }
603}
604
605#[cfg(feature = "geo-types")]
606impl<PointType> From<geo_types::Polygon<f64>> for GenericPolygon<PointType>
607where
608 PointType: From<geo_types::Coordinate<f64>>
609 + GrowablePoint
610 + ShrinkablePoint
611 + PartialEq
612 + HasXY
613 + Copy,
614{
615 fn from(polygon: geo_types::Polygon<f64>) -> Self {
616 let (outer, inners) = polygon.into_inner();
617 let mut rings = Vec::<PolygonRing<PointType>>::with_capacity(inners.len() + 1);
618
619 rings.push(PolygonRing::Outer(
620 outer.0.into_iter().map(PointType::from).collect(),
621 ));
622 for inner in inners {
623 rings.push(PolygonRing::Inner(
624 inner.0.into_iter().map(PointType::from).collect(),
625 ));
626 }
627 Self::with_rings(rings)
628 }
629}
630
631#[cfg(feature = "geo-types")]
632impl<PointType> From<geo_types::MultiPolygon<f64>> for GenericPolygon<PointType>
633where
634 PointType: HasXY
635 + From<geo_types::Coordinate<f64>>
636 + GrowablePoint
637 + ShrinkablePoint
638 + PartialEq
639 + HasXY
640 + Copy,
641{
642 fn from(multi_polygon: geo_types::MultiPolygon<f64>) -> Self {
643 let mut all_rings = Vec::<PolygonRing<PointType>>::new();
644 for polygon in multi_polygon {
645 let mut rings = GenericPolygon::<PointType>::from(polygon).into_inner();
646 all_rings.append(&mut rings);
647 }
648 Self::with_rings(all_rings)
649 }
650}
651
652#[cfg(test)]
653#[cfg(feature = "geo-types")]
654mod test_geo_types {
655 use super::*;
656 #[test]
657 fn shapefile_polygon_to_geotypes_polygon() {
658 let simple_polygon = Polygon::new(PolygonRing::Outer(vec![
659 Point::new(-1.1, -1.01),
660 Point::new(-1.2, 1.02),
661 Point::new(1.3, 1.03),
662 Point::new(1.4, -1.04),
663 Point::new(-1.1, -1.01),
664 ]));
665
666 let converted_multipolygon = geo_types::MultiPolygon::<f64>::from(simple_polygon);
667
668 let converted_polygon = converted_multipolygon.into_iter().next().unwrap();
669
670 let expected_geotypes_polygon = geo_types::Polygon::new(
671 LineString::from(vec![
672 (-1.1, -1.01),
673 (-1.2, 1.02),
674 (1.3, 1.03),
675 (1.4, -1.04),
676 (-1.1, -1.01),
677 ]),
678 vec![],
679 );
680
681 assert_eq!(converted_polygon, expected_geotypes_polygon);
682 }
683
684 #[test]
685 fn shapefile_polygon_to_geotypes_polygon_auto_close() {
686 let simple_polygon = Polygon::new(PolygonRing::Outer(vec![
687 Point::new(-1.1, -1.01),
688 Point::new(-1.2, 1.02),
689 Point::new(1.3, 1.03),
690 Point::new(1.4, -1.04),
691 ]));
692
693 let converted_polygon = geo_types::MultiPolygon::<f64>::from(simple_polygon);
694
695 let converted_polygon = converted_polygon.into_iter().next().unwrap();
696
697 let (geotypes_exterior, _) = converted_polygon.into_inner();
698
699 assert_eq!(
700 geotypes_exterior,
701 LineString::from(vec![
702 (-1.1, -1.01),
703 (-1.2, 1.02),
704 (1.3, 1.03),
705 (1.4, -1.04),
706 (-1.1, -1.01)
707 ])
708 );
709 }
710
711 #[test]
712 fn geotypes_polygon_to_shapefile_polygon() {
713 let geotypes_polygon = geo_types::Polygon::new(
714 LineString::from(vec![
715 (-1.1, -1.01),
716 (-1.2, 1.02),
717 (1.3, 1.03),
718 (1.4, -1.04),
719 (-1.1, -1.01),
720 ]),
721 vec![],
722 );
723
724 let converted_polygon = Polygon::from(geotypes_polygon);
725
726 let expected_polygon = Polygon::new(PolygonRing::Outer(vec![
727 Point::new(-1.1, -1.01),
728 Point::new(-1.2, 1.02),
729 Point::new(1.3, 1.03),
730 Point::new(1.4, -1.04),
731 Point::new(-1.1, -1.01),
732 ]));
733
734 assert_eq!(converted_polygon, expected_polygon);
735 }
736
737 #[test]
738 fn shapefile_polygon_to_geotypes_polygon_with_inner_ring() {
739 let one_ring_polygon = Polygon::with_rings(vec![
740 PolygonRing::Outer(vec![
741 Point::new(-1.1, -1.01),
742 Point::new(-1.2, 1.02),
743 Point::new(1.3, 1.03),
744 Point::new(1.4, -1.04),
745 Point::new(-1.1, -1.01),
746 ]),
747 PolygonRing::Inner(vec![
748 Point::new(-0.51, -0.501),
749 Point::new(0.54, -0.504),
750 Point::new(0.53, 0.503),
751 Point::new(-0.52, 0.502),
752 Point::new(-0.51, -0.501),
753 ]),
754 ]);
755
756 let converted_multipolygon = geo_types::MultiPolygon::<f64>::from(one_ring_polygon);
757
758 let converted_polygon = converted_multipolygon.into_iter().next().unwrap();
759
760 let expected_geotypes_polygon = geo_types::Polygon::new(
761 LineString::from(vec![
762 (-1.1, -1.01),
763 (-1.2, 1.02),
764 (1.3, 1.03),
765 (1.4, -1.04),
766 (-1.1, -1.01),
767 ]),
768 vec![LineString::from(vec![
769 (-0.51, -0.501),
770 (0.54, -0.504),
771 (0.53, 0.503),
772 (-0.52, 0.502),
773 (-0.51, -0.501),
774 ])],
775 );
776
777 assert_eq!(converted_polygon, expected_geotypes_polygon);
778 }
779
780 #[test]
781 fn geotypes_polygon_to_shapefile_polygon_inner_ring() {
782 let geotypes_polygon = geo_types::Polygon::new(
783 LineString::from(vec![
784 (-1.1, -1.01),
785 (-1.2, 1.02),
786 (1.3, 1.03),
787 (1.4, -1.04),
788 (-1.1, -1.01),
789 ]),
790 vec![LineString::from(vec![
791 (-0.51, -0.501),
792 (-0.52, 0.502),
793 (0.53, 0.503),
794 (0.54, -0.504),
795 (-0.51, -0.501),
796 ])],
797 );
798
799 let converted_polygon = Polygon::from(geotypes_polygon);
800
801 let expected_polygon = Polygon::with_rings(vec![
802 PolygonRing::Outer(vec![
803 Point::new(-1.1, -1.01),
804 Point::new(-1.2, 1.02),
805 Point::new(1.3, 1.03),
806 Point::new(1.4, -1.04),
807 Point::new(-1.1, -1.01),
808 ]),
809 PolygonRing::Inner(vec![
810 Point::new(-0.51, -0.501),
811 Point::new(0.54, -0.504),
812 Point::new(0.53, 0.503),
813 Point::new(-0.52, 0.502),
814 Point::new(-0.51, -0.501),
815 ]),
816 ]);
817
818 assert_eq!(converted_polygon, expected_polygon);
819 }
820}