geo-offset 0.4.0

Add margin and padding to geometric shapes
Documentation
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};

#[allow(dead_code)]
pub static POLYGONE_POLYLINE: Lazy<geo_types::GeometryCollection<f64>> = Lazy::new(|| {
    let data = include_str!("fixtures/polygon_polyline.json");
    let feature_collection: FeatureCollection = serde_json::from_str(&data).unwrap();
    feature_collection.into()
});

#[allow(dead_code)]
pub static DEMO: Lazy<geo_types::GeometryCollection<f64>> = Lazy::new(|| {
    let data = include_str!("fixtures/demo.json");
    let feature_collection: FeatureCollection = serde_json::from_str(&data).unwrap();
    feature_collection.into()
});

#[allow(dead_code)]
pub static DEMO_WITH_OFFSET: Lazy<geo_types::GeometryCollection<f64>> = Lazy::new(|| {
    let data = include_str!("fixtures/demo_with_offset.json");
    let feature_collection: FeatureCollection = serde_json::from_str(&data).unwrap();
    feature_collection.into()
});

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct FeatureCollection {
    pub features: Vec<Feature>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Feature {
    pub geometry: Geometry,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum Geometry {
    Polygon(Polygon),
    LineString(LineString),
    Point(Point),
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Polygon {
    pub coordinates: Vec<Vec<(f64, f64)>>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct LineString {
    pub coordinates: Vec<(f64, f64)>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Point {
    pub coordinates: (f64, f64),
}

impl From<FeatureCollection> for geo_types::GeometryCollection<f64> {
    fn from(feature_collection: FeatureCollection) -> Self {
        Self(
            feature_collection
                .features
                .iter()
                .map(|feature| geo_types::Geometry::from(feature.clone()))
                .collect(),
        )
    }
}

impl From<Feature> for geo_types::Geometry<f64> {
    fn from(feature: Feature) -> Self {
        feature.geometry.into()
    }
}

impl From<Geometry> for geo_types::Geometry<f64> {
    fn from(geometry: Geometry) -> Self {
        match geometry {
            Geometry::Polygon(polygon) => {
                let polygon: geo_types::Polygon<f64> = polygon.into();
                polygon.into()
            }
            Geometry::LineString(line_string) => {
                let line_string: geo_types::LineString<f64> = line_string.into();
                line_string.into()
            }
            Geometry::Point(point) => {
                let point: geo_types::Point<f64> = point.into();
                point.into()
            }
        }
    }
}

impl From<Polygon> for geo_types::Polygon<f64> {
    fn from(polygon: Polygon) -> Self {
        Self::new(
            polygon
                .coordinates
                .get(0)
                .cloned()
                .unwrap_or_default()
                .into_iter()
                .map(geo_types::Coord::from)
                .collect::<Vec<_>>()
                .into(),
            polygon
                .coordinates
                .iter()
                .skip(1)
                .map(|interior| {
                    interior
                        .iter()
                        .cloned()
                        .map(geo_types::Coord::from)
                        .collect::<Vec<_>>()
                        .into()
                })
                .collect(),
        )
    }
}

impl From<LineString> for geo_types::LineString<f64> {
    fn from(line_string: LineString) -> Self {
        Self(
            line_string
                .coordinates
                .iter()
                .map(|coordinate| geo_types::Coord::from(*coordinate))
                .collect(),
        )
    }
}

impl From<Point> for geo_types::Point<f64> {
    fn from(point: Point) -> Self {
        Self::from(point.coordinates)
    }
}

impl From<geo_types::GeometryCollection<f64>> for FeatureCollection {
    fn from(geometry_collection: geo_types::GeometryCollection<f64>) -> Self {
        Self {
            features: geometry_collection
                .into_iter()
                .flat_map(|geometry| FeatureCollection::from(geometry).features)
                .collect(),
        }
    }
}

impl From<geo_types::Geometry<f64>> for FeatureCollection {
    fn from(geometry: geo_types::Geometry<f64>) -> Self {
        match geometry {
            geo_types::Geometry::Polygon(polygon) => {
                let polygon: Polygon = polygon.into();
                Self {
                    features: vec![Feature {
                        geometry: Geometry::Polygon(polygon),
                    }],
                }
            }
            geo_types::Geometry::LineString(line_string) => {
                let line_string: LineString = line_string.into();
                Self {
                    features: vec![Feature {
                        geometry: Geometry::LineString(line_string),
                    }],
                }
            }
            geo_types::Geometry::Point(point) => {
                let point: Point = point.into();
                Self {
                    features: vec![Feature {
                        geometry: Geometry::Point(point),
                    }],
                }
            }
            geo_types::Geometry::MultiPolygon(multi_polygon) => multi_polygon.into(),
            _ => unimplemented!(),
        }
    }
}

impl From<geo_types::MultiPolygon<f64>> for FeatureCollection {
    fn from(multi_polygon: geo_types::MultiPolygon<f64>) -> Self {
        Self {
            features: multi_polygon
                .into_iter()
                .map(|polygon| Feature {
                    geometry: Geometry::Polygon(polygon.into()),
                })
                .collect(),
        }
    }
}

impl From<geo_types::Polygon<f64>> for Polygon {
    fn from(polygon: geo_types::Polygon<f64>) -> Self {
        Self {
            coordinates: vec![polygon
                .exterior()
                .clone()
                .into_iter()
                .map(|coords| (coords.x, coords.y))
                .collect()],
        }
    }
}

impl From<geo_types::LineString<f64>> for LineString {
    fn from(line_string: geo_types::LineString<f64>) -> Self {
        Self {
            coordinates: line_string
                .points()
                .map(|coords| (coords.x(), coords.y()))
                .collect(),
        }
    }
}

impl From<geo_types::Point<f64>> for Point {
    fn from(point: geo_types::Point<f64>) -> Self {
        Self {
            coordinates: (point.x(), point.y()),
        }
    }
}