diff --git a/src/io/wkt/mod.rs b/src/io/wkt/mod.rs index 1077754f..c9134a0e 100644 --- a/src/io/wkt/mod.rs +++ b/src/io/wkt/mod.rs @@ -1 +1,2 @@ pub mod reader; +pub mod writer; diff --git a/src/io/wkt/writer/mod.rs b/src/io/wkt/writer/mod.rs new file mode 100644 index 00000000..a48c8cde --- /dev/null +++ b/src/io/wkt/writer/mod.rs @@ -0,0 +1 @@ +mod scalar; diff --git a/src/io/wkt/writer/scalar.rs b/src/io/wkt/writer/scalar.rs new file mode 100644 index 00000000..9a7a3973 --- /dev/null +++ b/src/io/wkt/writer/scalar.rs @@ -0,0 +1,135 @@ +#![allow(dead_code)] +use geo::CoordFloat; + +use crate::geo_traits::{ + CoordTrait, GeometryCollectionTrait, GeometryTrait, GeometryType, LineStringTrait, + MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, +}; + +fn coord_to_wkt(coord: &impl CoordTrait) -> wkt::types::Coord { + let mut out = wkt::types::Coord { + x: coord.x(), + y: coord.y(), + z: None, + m: None, + }; + if coord.dim() == 3 { + out.z = Some(coord.nth_unchecked(2)); + } + out +} + +fn point_to_wkt(point: &impl PointTrait) -> wkt::types::Point { + if point.x().is_nan() && point.y().is_nan() { + return wkt::types::Point(None); + } + + let mut coord = wkt::types::Coord { + x: point.x(), + y: point.y(), + z: None, + m: None, + }; + if point.dim() == 3 { + coord.z = Some(point.nth_unchecked(2)); + } + wkt::types::Point(Some(coord)) +} + +fn line_string_to_wkt( + line_string: &impl LineStringTrait, +) -> wkt::types::LineString { + wkt::types::LineString( + line_string + .coords() + .map(|coord| coord_to_wkt(&coord)) + .collect(), + ) +} + +fn polygon_to_wkt(polygon: &impl PolygonTrait) -> wkt::types::Polygon { + let mut rings = vec![]; + if let Some(exterior) = polygon.exterior() { + rings.push(line_string_to_wkt(&exterior)); + } + polygon + .interiors() + .for_each(|interior| rings.push(line_string_to_wkt(&interior))); + wkt::types::Polygon(rings) +} + +fn multi_point_to_wkt( + multi_point: &impl MultiPointTrait, +) -> wkt::types::MultiPoint { + wkt::types::MultiPoint( + multi_point + .points() + .map(|point| point_to_wkt(&point)) + .collect(), + ) +} + +fn multi_line_string_to_wkt( + multi_line_string: &impl MultiLineStringTrait, +) -> wkt::types::MultiLineString { + wkt::types::MultiLineString( + multi_line_string + .lines() + .map(|line| line_string_to_wkt(&line)) + .collect(), + ) +} + +fn multi_polygon_to_wkt( + multi_polygon: &impl MultiPolygonTrait, +) -> wkt::types::MultiPolygon { + wkt::types::MultiPolygon( + multi_polygon + .polygons() + .map(|polygon| polygon_to_wkt(&polygon)) + .collect(), + ) +} + +/// Convert any Rect to a [`geo::Rect`]. +/// +/// Only the first two dimensions will be kept. +fn rect_to_wkt(_rect: &impl RectTrait) -> wkt::types::Polygon { + todo!() + // Need to create custom coords for a polygon box, see + // https://github.com/georust/geo/blob/68f80f851879dd58f146aae47dc2feeea6c83230/geo-types/src/geometry/rect.rs#L217-L225 +} + +/// Convert any Geometry to a [`geo::Geometry`]. +/// +/// Only the first two dimensions will be kept. +fn geometry_to_wkt(geometry: &impl GeometryTrait) -> wkt::Wkt { + match geometry.as_type() { + GeometryType::Point(geom) => wkt::Wkt::Point(point_to_wkt(geom)), + GeometryType::LineString(geom) => wkt::Wkt::LineString(line_string_to_wkt(geom)), + GeometryType::Polygon(geom) => wkt::Wkt::Polygon(polygon_to_wkt(geom)), + GeometryType::MultiPoint(geom) => wkt::Wkt::MultiPoint(multi_point_to_wkt(geom)), + GeometryType::MultiLineString(geom) => { + wkt::Wkt::MultiLineString(multi_line_string_to_wkt(geom)) + } + GeometryType::MultiPolygon(geom) => wkt::Wkt::MultiPolygon(multi_polygon_to_wkt(geom)), + GeometryType::GeometryCollection(geom) => { + wkt::Wkt::GeometryCollection(geometry_collection_to_wkt(geom)) + } + GeometryType::Rect(geom) => wkt::Wkt::Polygon(rect_to_wkt(geom)), + } +} + +/// Convert any GeometryCollection to a [`geo::GeometryCollection`]. +/// +/// Only the first two dimensions will be kept. +fn geometry_collection_to_wkt( + geometry_collection: &impl GeometryCollectionTrait, +) -> wkt::types::GeometryCollection { + wkt::types::GeometryCollection( + geometry_collection + .geometries() + .map(|geometry| geometry_to_wkt(&geometry)) + .collect(), + ) +}