shapefile/record/
polygon.rs

1//! Module with the definition of Polygon, PolygonM, PolygonZ
2use 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/// Rings composing a Polygon
23///
24/// `Inner` rings define holes in polygons.
25///
26/// In shapefile, the point ordering is what is used to know if
27/// a ring is an outer or inner one:
28/// - **Outer** ring => points in clockwise order
29/// - **Inner** ring => points in counter-clockwise order
30///
31/// # Note
32///
33/// Rings you get access from a [`GenericPolygon`] will always have its points ordered
34/// according to its type (outer, inner).
35///
36/// But `PolygonRing`s you create won't be reordered until you move them into
37/// a [`GenericPolygon`].
38///
39///
40/// # Example
41///
42/// ```
43/// use shapefile::{PolygonRing, Polygon, Point};
44/// // Here the points are not in the correct order to be an Outer ring for a shapefile
45/// let mut points = vec![
46///     Point::new(-12.0, 6.0),
47///     Point::new(-12.0, -6.0),
48///     Point::new(12.0, -6.0),
49///     Point::new(12.0, 6.0),
50///     Point::new(-12.0, 6.0),
51/// ];
52///
53/// let mut reversed_points = points.clone();
54/// reversed_points.reverse();
55///
56/// let ring = PolygonRing::Outer(points);
57/// assert_ne!(ring.points(), reversed_points.as_slice());
58/// assert_eq!(ring[0], Point::new(-12.0, 6.0));
59///
60/// // Now the points will be reversed
61/// let polygon = Polygon::new(ring);
62/// assert_eq!(polygon.rings()[0].points(), reversed_points.as_slice());
63/// ```
64///
65/// [`GenericPolygon`]: struct.GenericPolygon.html
66#[derive(Debug, Clone, PartialEq)]
67pub enum PolygonRing<PointType> {
68    /// The outer ring of a polygon.
69    Outer(Vec<PointType>),
70    /// Defines a hole in a polygon
71    Inner(Vec<PointType>),
72}
73
74impl<PointType> PolygonRing<PointType> {
75    /// Returns the number of points inside the ring
76    ///
77    /// # Example
78    ///
79    /// ```
80    /// use shapefile::{PolygonRing, Point};
81    /// let ring = PolygonRing::Inner(vec![
82    ///     Point::new(-12.0, 6.0),
83    ///     Point::new(-12.0, -6.0),
84    ///     Point::new(12.0, -6.0),
85    ///     Point::new(12.0, 6.0),
86    ///     Point::new(-12.0, 6.0),
87    /// ]);
88    /// assert_eq!(ring.len(), 5);
89    /// ```
90    #[inline]
91    pub fn len(&self) -> usize {
92        self.points().len()
93    }
94
95    /// Returns whether the rings contains any points
96    #[inline]
97    pub fn is_empty(&self) -> bool {
98        self.points().is_empty()
99    }
100
101    /// Returns a non-mutable slice to the points inside the ring
102    ///
103    /// ```
104    /// use shapefile::{PolygonRing, Point};
105    /// let ring = PolygonRing::Inner(vec![
106    ///     Point::new(-12.0, 6.0),
107    ///     Point::new(-12.0, -6.0),
108    ///     Point::new(12.0, -6.0),
109    ///     Point::new(12.0, 6.0),
110    ///     Point::new(-12.0, 6.0),
111    /// ]);
112    /// assert_eq!(ring.points()[2], Point::new(12.0, -6.0));
113    /// ```
114    #[inline]
115    pub fn points(&self) -> &[PointType] {
116        match self {
117            PolygonRing::Outer(points) => points,
118            PolygonRing::Inner(points) => points,
119        }
120    }
121
122    /// Consumes the ring and returns its points
123    #[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// TODO a Polygon is a connected sequence of 4 or more points
190/// Generic struct to create Polygon; PolygonM, PolygonZ
191///
192/// Polygons can have multiple parts (or rings)
193///
194/// To create a polygon with only one part use [`new`].
195///
196/// To create a polygon with multiple rings use [`with_rings`].
197///
198/// # Notes
199/// - A Polygon ring is a connected sequence of 4 or more points
200///   **(this is not checked)**
201/// - Polygon's rings MUST be closed (the first and last points MUST be the same) (p 13/34)
202///   **(this is done by the constructors if you do not do it yourself)**
203/// - The order of rings is not significant (p 13/34)
204/// - A polygon may have multiple [`Outer`] rings (p12/34)
205///
206///
207/// # geo-types
208///
209/// shapefile's Polygons can be converted to geo-types's `MultiPolygon<f64>`,
210/// but not geo-types's Polygon<f64> as they only allow polygons with one outer ring.
211///
212/// geo-types's `Polygon<f64>` and `MultiPolygon<f64>` can be converted to shapefile's Polygon
213///
214/// ```
215/// # #[cfg(feature = "geo-types")]
216/// # fn main() -> Result<(), shapefile::Error>{
217/// let mut polygons = shapefile::read_shapes_as::<_, shapefile::PolygonM>("tests/data/polygonm.shp")?;
218/// let geo_polygon: geo_types::MultiPolygon<f64> = polygons.pop().unwrap().into();
219/// let polygon = shapefile::PolygonZ::from(geo_polygon);
220/// # Ok(())
221/// # }
222/// # #[cfg(not(feature = "geo-types"))]
223/// # fn main() {}
224/// ```
225///
226/// [`new`]: #method.new
227/// [`with_rings`]: #method.with_rings
228/// [`Outer`]: enum.PolygonRing.html#variant.Outer
229#[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    /// Creates a polygon with only one ring
240    ///
241    /// The ring will be closed if it is not
242    /// (shapefiles requires the first and last point to be equal)
243    ///
244    /// The ring points may be reordered to match their type
245    /// (see [`PolygonRing`])
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use shapefile::{PolygonRing, PointZ, PolygonZ, NO_DATA};
251    /// let ring = PolygonRing::Outer(vec![
252    ///     PointZ::new(0.0, 0.0, 0.0, NO_DATA),
253    ///     PointZ::new(0.0, 1.0, 0.0, NO_DATA),
254    ///     PointZ::new(1.0, 1.0, 0.0, NO_DATA),
255    ///     PointZ::new(1.0, 0.0, 0.0, NO_DATA),
256    /// ]);
257    /// let poly = PolygonZ::new(ring);
258    /// assert_eq!(poly.rings()[0].points().first(), poly.rings()[0].points().last());
259    /// ```
260    ///
261    /// [`PolygonRing`]: enum.PolygonRing.html
262    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    /// Creates a polygon with multiple rings
273    ///
274    /// The ring will be closed if it is not
275    /// (shapefiles requires the first and last point to be equal)
276    ///
277    /// The ring points may be reordered to match their type
278    /// (see [`PolygonRing`])
279    ///
280    ///
281    /// # Example
282    ///
283    /// ```
284    /// use shapefile::{PolygonRing, Point, Polygon};
285    /// let polygon = Polygon::with_rings(vec![
286    ///     PolygonRing::Outer(vec![
287    ///         Point::new(-120.0, 60.0),
288    ///         Point::new(-120.0, -60.0),
289    ///         Point::new(120.0, -60.0),
290    ///         Point::new(120.0, 60.0),
291    ///         Point::new(-120.0, 60.0),
292    ///     ]),
293    ///     PolygonRing::Inner(vec![
294    ///          Point::new(-60.0, 30.0),
295    ///          Point::new(60.0, 30.0),
296    ///          Point::new(60.0, -30.0),
297    ///          Point::new(-60.0, -30.0),
298    ///          Point::new(-60.0, 30.0),
299    ///     ]),
300    /// ]);
301    ///
302    /// assert_eq!(polygon.rings().len(), 2);
303    /// ```
304    ///
305    /// [`PolygonRing`]: enum.PolygonRing.html
306    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    /// Returns the bounding box associated to the polygon
318    #[inline]
319    pub fn bbox(&self) -> &GenericBBox<PointType> {
320        &self.bbox
321    }
322
323    /// Returns the rings of the polygon
324    #[inline]
325    pub fn rings(&self) -> &[PolygonRing<PointType>] {
326        &self.rings
327    }
328
329    /// Returns the ring as index
330    ///
331    /// # Example
332    ///
333    /// ```
334    /// use shapefile::{polygon, NO_DATA};
335    ///
336    /// let polygon = polygon!{
337    ///     Outer(
338    ///         (0.0, 0.0, 0.0, NO_DATA),
339    ///         (0.0, 1.0, 0.0, NO_DATA),
340    ///         (1.0, 1.0, 0.0, NO_DATA),
341    ///         (1.0, 0.0, 0.0, NO_DATA),
342    ///     )
343    /// };
344    ///
345    /// assert_eq!( polygon.ring(0).is_some(), true);
346    /// assert_eq!(polygon.ring(1), None);
347    /// ```
348    #[inline]
349    pub fn ring(&self, index: usize) -> Option<&PolygonRing<PointType>> {
350        self.rings.get(index)
351    }
352
353    /// Consumes the shape and returns the rings
354    #[inline]
355    pub fn into_inner(self) -> Vec<PolygonRing<PointType>> {
356        self.rings
357    }
358
359    /// Returns the sum of points of all the rings
360    #[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
379/*
380 * Polygon
381*/
382/// Specialization of the `GenericPolygon` struct to represent a `Polygon` shape
383/// ( collection of [Point](../point/struct.Point.html))
384pub 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>(); // num parts
409        size += size_of::<i32>(); //num points
410        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
433/*
434 * PolygonM
435 */
436
437/// Specialization of the `GenericPolygon` struct to represent a `PolygonM` shape
438/// ( collection of [PointM](../point/struct.PointM.html))
439pub 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>(); // num parts
464        size += size_of::<i32>(); //num points
465        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
493/*
494 * PolygonZ
495 */
496
497/// Specialization of the `GenericPolygon` struct to represent a `PolygonZ` shape
498/// ( collection of [PointZ](../point/struct.PointZ.html))
499pub 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>(); // num parts
524        size += size_of::<i32>(); //num points
525        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                        // This is the strange (?) case: inner ring without a previous outer ring
590                        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}