From 71c6b5bfbe9c4dea20b9332c20233bd2af3c9ad8 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 26 Oct 2024 13:29:44 -0400 Subject: [PATCH 01/20] initial direct approach --- src/geo_traits_to_wkt.rs | 3 + src/lib.rs | 1 + src/to_wkt/geo_trait_impl.rs | 326 +++++++++++++++++++++++++++++++ src/{to_wkt.rs => to_wkt/mod.rs} | 2 + src/types/coord.rs | 10 +- src/types/linestring.rs | 14 +- src/types/multilinestring.rs | 19 +- src/types/multipoint.rs | 15 +- src/types/point.rs | 19 +- src/types/polygon.rs | 19 +- 10 files changed, 344 insertions(+), 84 deletions(-) create mode 100644 src/geo_traits_to_wkt.rs create mode 100644 src/to_wkt/geo_trait_impl.rs rename src/{to_wkt.rs => to_wkt/mod.rs} (98%) diff --git a/src/geo_traits_to_wkt.rs b/src/geo_traits_to_wkt.rs new file mode 100644 index 0000000..b5e1efd --- /dev/null +++ b/src/geo_traits_to_wkt.rs @@ -0,0 +1,3 @@ +use geo_traits::GeometryTrait; + +// pub fn to_wkt(g: &impl GeometryTrait) -> diff --git a/src/lib.rs b/src/lib.rs index 130d20a..606304f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,6 +112,7 @@ pub use crate::to_wkt::ToWkt; #[cfg(feature = "geo-types")] #[deprecated(note = "renamed module to `wkt::geo_types_from_wkt`")] pub mod conversion; +pub mod geo_traits_to_wkt; #[cfg(feature = "geo-types")] pub mod geo_types_from_wkt; #[cfg(feature = "geo-types")] diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs new file mode 100644 index 0000000..a151423 --- /dev/null +++ b/src/to_wkt/geo_trait_impl.rs @@ -0,0 +1,326 @@ +use core::fmt; +use std::fmt::Write; + +use geo_traits::{ + CoordTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, + PointTrait, PolygonTrait, +}; +use geo_types::CoordNum; + +use crate::WktNum; + +pub fn coord_to_wkt, W: Write>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + match g.dim() { + geo_traits::Dimensions::Xy => { + write!(f, "{} {}", g.x(), g.y())?; + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Xym => { + write!(f, "{} {} {}", g.x(), g.y(), g.nth_unchecked(2))?; + } + geo_traits::Dimensions::Xyzm => { + write!( + f, + "{} {} {} {}", + g.x(), + g.y(), + g.nth_unchecked(2), + g.nth_unchecked(3) + )?; + } + geo_traits::Dimensions::Unknown(_) => todo!(), + }; + + Ok(()) +} + +pub fn point_to_wkt, W: Write>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = g.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("POINT"), + geo_traits::Dimensions::Xyz => f.write_str("POINT Z"), + geo_traits::Dimensions::Xym => f.write_str("POINT M"), + geo_traits::Dimensions::Xyzm => f.write_str("POINT ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + if let Some(coord) = g.coord() { + f.write_char('(')?; + coord_to_wkt(&coord, f)?; + f.write_char(')')?; + Ok(()) + } else { + f.write_str(" EMPTY") + } +} + +pub fn linestring_to_wkt< + T: CoordNum + WktNum + fmt::Display, + G: LineStringTrait, + W: Write, +>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = g.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("LINESTRING"), + geo_traits::Dimensions::Xyz => f.write_str("LINESTRING Z"), + geo_traits::Dimensions::Xym => f.write_str("LINESTRING M"), + geo_traits::Dimensions::Xyzm => f.write_str("LINESTRING ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + if g.num_coords() == 0 { + f.write_str(" EMPTY") + } else { + // add_coords(linestring.coords(), f)?; + let strings = g + .coords() + .map(|c| { + let mut s = String::new(); + coord_to_wkt(&c, &mut s)?; + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join(","); + write!(f, "({})", strings) + } +} + +pub fn polygon_to_wkt, W: Write>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = g.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("POLYGON"), + geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), + geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), + geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + if let Some(exterior) = g.exterior() { + let exterior_string = exterior + .coords() + .map(|c| { + let mut s = String::new(); + coord_to_wkt(&c, &mut s)?; + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join(","); + + if g.num_interiors() == 0 { + write!(f, "({})", exterior_string) + } else { + let interior_string = g + .interiors() + .map(|ring| { + let s = ring + .coords() + .map(|c| { + let mut s = String::new(); + coord_to_wkt(&c, &mut s)?; + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join(","); + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join("),("); + write!(f, "({},({}))", exterior_string, interior_string) + } + } else { + f.write_str(" EMPTY") + } +} + +pub fn multipoint_to_wkt< + T: CoordNum + WktNum + fmt::Display, + G: MultiPointTrait, + W: Write, +>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = g.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("MULTIPOINT"), + geo_traits::Dimensions::Xyz => f.write_str("MULTIPOINT Z"), + geo_traits::Dimensions::Xym => f.write_str("MULTIPOINT M"), + geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOINT ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + if g.num_points() == 0 { + f.write_str(" EMPTY") + } else { + let strings = g + .points() + .map(|c| { + let mut s = String::new(); + // Assume no empty points within this MultiPoint + coord_to_wkt(&c.coord().unwrap(), &mut s)?; + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join(","); + write!(f, "({})", strings) + } +} + +pub fn multilinestring_to_wkt< + T: CoordNum + WktNum + fmt::Display, + G: MultiLineStringTrait, + W: Write, +>( + g: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = g.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("MULTILINESTRING"), + geo_traits::Dimensions::Xyz => f.write_str("MULTILINESTRING Z"), + geo_traits::Dimensions::Xym => f.write_str("MULTILINESTRING M"), + geo_traits::Dimensions::Xyzm => f.write_str("MULTILINESTRING ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + + if g.num_line_strings() == 0 { + f.write_str(" EMPTY") + } else { + let strings = g + .line_strings() + .map(|ring| { + let s = ring + .coords() + .map(|c| { + let mut s = String::new(); + coord_to_wkt(&c, &mut s)?; + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join(","); + Ok(s) + }) + .collect::, std::fmt::Error>>()? + .join("),("); + write!(f, "({})", strings) + } +} + +// pub fn multipolygon_to_wkt< +// T: CoordNum + WktNum + fmt::Display, +// G: MultiPolygonTrait, +// W: Write, +// >( +// g: &G, +// f: &mut W, +// ) -> Result<(), std::fmt::Error> { +// let dim = g.dim(); +// // Write prefix +// match dim { +// geo_traits::Dimensions::Xy => f.write_str("MULTIPOLYGON"), +// geo_traits::Dimensions::Xyz => f.write_str("MULTIPOLYGON Z"), +// geo_traits::Dimensions::Xym => f.write_str("MULTIPOLYGON M"), +// geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOLYGON ZM"), +// geo_traits::Dimensions::Unknown(_) => todo!(), +// }?; + +// if g.num_polygons() == 0 { +// f.write_str(" EMPTY") +// } else { +// let strings = g +// .polygons() +// .map(|polygon| { +// let exterior = polygon.exterior().unwrap(); +// let exterior_string = exterior +// .coords() +// .map(|c| { +// let mut s = String::new(); +// coord_to_wkt(&c, &mut s)?; +// Ok(s) +// }) +// .collect::, std::fmt::Error>>()? +// .join(","); + +// if polygon.num_interiors() == 0 { +// write!(f, "({})", exterior_string) +// } else { +// let interior_string = polygon +// .interiors() +// .map(|ring| { +// let s = ring +// .coords() +// .map(|c| { +// let mut s = String::new(); +// coord_to_wkt(&c, &mut s)?; +// Ok(s) +// }) +// .collect::, std::fmt::Error>>()? +// .join(","); +// Ok(s) +// }) +// .collect::, std::fmt::Error>>()? +// .join("),("); +// write!(f, "({},({}))", exterior_string, interior_string) +// }; +// Ok(s) +// }) +// .collect::, std::fmt::Error>>()? +// .join("),("); +// write!(f, "({})", strings) +// } +// } + +fn add_coord, W: Write>( + coord: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + match coord.dim().size() { + 2 => write!(f, "{} {}", coord.x(), coord.y()), + 3 => { + write!(f, "{} {} {}", coord.x(), coord.y(), coord.nth_unchecked(2)) + } + 4 => { + write!( + f, + "{} {} {} {}", + coord.x(), + coord.y(), + coord.nth_unchecked(2), + coord.nth_unchecked(3) + ) + } + size => panic!("Unexpected dimension for coordinate: {}", size), + } +} + +fn add_coords>( + mut coords: impl ExactSizeIterator, + f: &mut W, +) -> Result<(), std::fmt::Error> { + f.write_char('(')?; + + if let Some(first_coord) = coords.next() { + add_coord(&first_coord, f)?; + + for coord in coords { + f.write_char(',')?; + add_coord(&coord, f)?; + } + } + + f.write_char(')')?; + + Ok(()) +} diff --git a/src/to_wkt.rs b/src/to_wkt/mod.rs similarity index 98% rename from src/to_wkt.rs rename to src/to_wkt/mod.rs index 8219d5c..f2cd73f 100644 --- a/src/to_wkt.rs +++ b/src/to_wkt/mod.rs @@ -1,5 +1,7 @@ use crate::{Wkt, WktNum}; +pub mod geo_trait_impl; + /// A trait for converting values to WKT pub trait ToWkt where diff --git a/src/types/coord.rs b/src/types/coord.rs index dcf4be0..9640e08 100644 --- a/src/types/coord.rs +++ b/src/types/coord.rs @@ -14,6 +14,7 @@ use geo_traits::CoordTrait; +use crate::to_wkt::geo_trait_impl::coord_to_wkt; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, WktNum}; @@ -36,14 +37,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "{} {}", self.x, self.y)?; - if let Some(z) = self.z { - write!(f, " {}", z)?; - } - if let Some(m) = self.m { - write!(f, " {}", m)?; - } - Ok(()) + coord_to_wkt(self, f) } } diff --git a/src/types/linestring.rs b/src/types/linestring.rs index 0285ae9..9f8e450 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -14,6 +14,7 @@ use geo_traits::{CoordTrait, LineStringTrait}; +use crate::to_wkt::geo_trait_impl::linestring_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; @@ -48,18 +49,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("LINESTRING EMPTY") - } else { - let strings = self - .0 - .iter() - .map(|c| format!("{}", c)) - .collect::>() - .join(","); - - write!(f, "LINESTRING({})", strings) - } + linestring_to_wkt(self, f) } } diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index cded706..f712de4 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -14,6 +14,7 @@ use geo_traits::{LineStringTrait, MultiLineStringTrait}; +use crate::to_wkt::geo_trait_impl::multilinestring_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; @@ -38,23 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("MULTILINESTRING EMPTY") - } else { - let strings = self - .0 - .iter() - .map(|l| { - l.0.iter() - .map(|c| format!("{} {}", c.x, c.y)) - .collect::>() - .join(",") - }) - .collect::>() - .join("),("); - - write!(f, "MULTILINESTRING(({}))", strings) - } + multilinestring_to_wkt(self, f) } } diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index 7c8968e..ae176a7 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -14,6 +14,7 @@ use geo_traits::{MultiPointTrait, PointTrait}; +use crate::to_wkt::geo_trait_impl::multipoint_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::point::Point; use crate::types::Dimension; @@ -38,19 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("MULTIPOINT EMPTY") - } else { - let strings = self - .0 - .iter() - .filter_map(|p| p.0.as_ref()) - .map(|c| format!("({} {})", c.x, c.y)) - .collect::>() - .join(","); - - write!(f, "MULTIPOINT({})", strings) - } + multipoint_to_wkt(self, f) } } diff --git a/src/types/point.rs b/src/types/point.rs index 0d2e5ab..3f9f0fd 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -14,6 +14,7 @@ use geo_traits::{CoordTrait, PointTrait}; +use crate::to_wkt::geo_trait_impl::point_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; @@ -38,23 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.0 { - Some(ref coord) => { - let mut lrs = String::new(); - if coord.z.is_some() { - lrs += "Z"; - } - if coord.m.is_some() { - lrs += "M"; - } - if !lrs.is_empty() { - lrs = " ".to_string() + &lrs; - } - - write!(f, "POINT{}({})", lrs, coord) - } - None => f.write_str("POINT EMPTY"), - } + point_to_wkt(self, f) } } diff --git a/src/types/polygon.rs b/src/types/polygon.rs index 77e3be4..fcaa320 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -14,6 +14,7 @@ use geo_traits::{LineStringTrait, PolygonTrait}; +use crate::to_wkt::geo_trait_impl::polygon_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; @@ -38,23 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("POLYGON EMPTY") - } else { - let strings = self - .0 - .iter() - .map(|l| { - l.0.iter() - .map(|c| format!("{} {}", c.x, c.y)) - .collect::>() - .join(",") - }) - .collect::>() - .join("),("); - - write!(f, "POLYGON(({}))", strings) - } + polygon_to_wkt(self, f) } } From afd4305549b52199c7fc24403594dce69308ad09 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 26 Oct 2024 14:06:12 -0400 Subject: [PATCH 02/20] WKT writer using geo traits --- src/geo_traits_to_wkt.rs | 3 - src/lib.rs | 12 +- src/to_wkt/geo_trait_impl.rs | 430 ++++++++++++++++++-------------- src/types/coord.rs | 7 +- src/types/geometrycollection.rs | 14 +- src/types/multilinestring.rs | 4 +- src/types/multipoint.rs | 4 +- src/types/multipolygon.rs | 24 +- 8 files changed, 260 insertions(+), 238 deletions(-) delete mode 100644 src/geo_traits_to_wkt.rs diff --git a/src/geo_traits_to_wkt.rs b/src/geo_traits_to_wkt.rs deleted file mode 100644 index b5e1efd..0000000 --- a/src/geo_traits_to_wkt.rs +++ /dev/null @@ -1,3 +0,0 @@ -use geo_traits::GeometryTrait; - -// pub fn to_wkt(g: &impl GeometryTrait) -> diff --git a/src/lib.rs b/src/lib.rs index 606304f..05e2482 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,6 +86,7 @@ use geo_traits::{ }; use num_traits::{Float, Num, NumCast}; +use crate::to_wkt::geo_trait_impl::geometry_to_wkt; use crate::tokenizer::{PeekableTokens, Token, Tokens}; use crate::types::{ Dimension, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, @@ -112,7 +113,6 @@ pub use crate::to_wkt::ToWkt; #[cfg(feature = "geo-types")] #[deprecated(note = "renamed module to `wkt::geo_types_from_wkt`")] pub mod conversion; -pub mod geo_traits_to_wkt; #[cfg(feature = "geo-types")] pub mod geo_types_from_wkt; #[cfg(feature = "geo-types")] @@ -360,15 +360,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - Wkt::Point(point) => point.fmt(f), - Wkt::LineString(linestring) => linestring.fmt(f), - Wkt::Polygon(polygon) => polygon.fmt(f), - Wkt::MultiPoint(multipoint) => multipoint.fmt(f), - Wkt::MultiLineString(multilinstring) => multilinstring.fmt(f), - Wkt::MultiPolygon(multipolygon) => multipolygon.fmt(f), - Wkt::GeometryCollection(geometrycollection) => geometrycollection.fmt(f), - } + geometry_to_wkt(self, f) } } diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index a151423..4720186 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -2,38 +2,33 @@ use core::fmt; use std::fmt::Write; use geo_traits::{ - CoordTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, - PointTrait, PolygonTrait, + CoordTrait, GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, + MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, }; use geo_types::CoordNum; use crate::WktNum; -pub fn coord_to_wkt, W: Write>( - g: &G, - f: &mut W, -) -> Result<(), std::fmt::Error> { - match g.dim() { - geo_traits::Dimensions::Xy => { - write!(f, "{} {}", g.x(), g.y())?; - } - geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Xym => { - write!(f, "{} {} {}", g.x(), g.y(), g.nth_unchecked(2))?; - } - geo_traits::Dimensions::Xyzm => { - write!( - f, - "{} {} {} {}", - g.x(), - g.y(), - g.nth_unchecked(2), - g.nth_unchecked(3) - )?; - } - geo_traits::Dimensions::Unknown(_) => todo!(), - }; +/// The physical size of the coordinate dimension +/// +/// This is used so that we don't have to call `.dim()` on **every** coordinate. We infer it once +/// from the `geo_traits::Dimensions` and then pass it to each coordinate. +#[derive(Clone, Copy)] +pub(crate) enum PhysicalCoordinateDimension { + Two, + Three, + Four, +} - Ok(()) +impl From for PhysicalCoordinateDimension { + fn from(value: geo_traits::Dimensions) -> Self { + match value.size() { + 2 => Self::Two, + 3 => Self::Three, + 4 => Self::Four, + size => panic!("Unexpected dimension for coordinate: {}", size), + } + } } pub fn point_to_wkt, W: Write>( @@ -49,9 +44,10 @@ pub fn point_to_wkt, W geo_traits::Dimensions::Xyzm => f.write_str("POINT ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; + let size = PhysicalCoordinateDimension::from(dim); if let Some(coord) = g.coord() { f.write_char('(')?; - coord_to_wkt(&coord, f)?; + add_coord(&coord, f, size)?; f.write_char(')')?; Ok(()) } else { @@ -64,10 +60,10 @@ pub fn linestring_to_wkt< G: LineStringTrait, W: Write, >( - g: &G, + linestring: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { - let dim = g.dim(); + let dim = linestring.dim(); // Write prefix match dim { geo_traits::Dimensions::Xy => f.write_str("LINESTRING"), @@ -76,28 +72,19 @@ pub fn linestring_to_wkt< geo_traits::Dimensions::Xyzm => f.write_str("LINESTRING ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; - if g.num_coords() == 0 { + let size = PhysicalCoordinateDimension::from(dim); + if linestring.num_coords() == 0 { f.write_str(" EMPTY") } else { - // add_coords(linestring.coords(), f)?; - let strings = g - .coords() - .map(|c| { - let mut s = String::new(); - coord_to_wkt(&c, &mut s)?; - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join(","); - write!(f, "({})", strings) + add_coord_sequence(linestring.coords(), f, size) } } pub fn polygon_to_wkt, W: Write>( - g: &G, + polygon: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { - let dim = g.dim(); + let dim = polygon.dim(); // Write prefix match dim { geo_traits::Dimensions::Xy => f.write_str("POLYGON"), @@ -106,52 +93,35 @@ pub fn polygon_to_wkt f.write_str("POLYGON ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; - if let Some(exterior) = g.exterior() { - let exterior_string = exterior - .coords() - .map(|c| { - let mut s = String::new(); - coord_to_wkt(&c, &mut s)?; - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join(","); - - if g.num_interiors() == 0 { - write!(f, "({})", exterior_string) + let size = PhysicalCoordinateDimension::from(dim); + if let Some(exterior) = polygon.exterior() { + if exterior.num_coords() != 0 { + f.write_str(" (")?; + add_coord_sequence(exterior.coords(), f, size)?; + + for interior in polygon.interiors() { + f.write_char(',')?; + add_coord_sequence(interior.coords(), f, size)?; + } + + f.write_char(')') } else { - let interior_string = g - .interiors() - .map(|ring| { - let s = ring - .coords() - .map(|c| { - let mut s = String::new(); - coord_to_wkt(&c, &mut s)?; - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join(","); - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join("),("); - write!(f, "({},({}))", exterior_string, interior_string) + f.write_str(" EMPTY") } } else { f.write_str(" EMPTY") } } -pub fn multipoint_to_wkt< +pub fn multi_point_to_wkt< T: CoordNum + WktNum + fmt::Display, G: MultiPointTrait, W: Write, >( - g: &G, + multipoint: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { - let dim = g.dim(); + let dim = multipoint.dim(); // Write prefix match dim { geo_traits::Dimensions::Xy => f.write_str("MULTIPOINT"), @@ -160,32 +130,40 @@ pub fn multipoint_to_wkt< geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOINT ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; - if g.num_points() == 0 { - f.write_str(" EMPTY") + let size = PhysicalCoordinateDimension::from(dim); + + let mut points = multipoint.points(); + + // Note: This is largely copied from `add_coord_sequence`, because `multipoint.points()` + // yields a sequence of Point, not Coord. + if let Some(first_point) = points.next() { + f.write_char('(')?; + + // Assume no empty points within this MultiPoint + add_coord(&first_point.coord().unwrap(), f, size)?; + + for point in points { + f.write_char(',')?; + add_coord(&point.coord().unwrap(), f, size)?; + } + + f.write_char(')')?; } else { - let strings = g - .points() - .map(|c| { - let mut s = String::new(); - // Assume no empty points within this MultiPoint - coord_to_wkt(&c.coord().unwrap(), &mut s)?; - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join(","); - write!(f, "({})", strings) + f.write_str(" EMPTY")?; } + + Ok(()) } -pub fn multilinestring_to_wkt< +pub fn multi_linestring_to_wkt< T: CoordNum + WktNum + fmt::Display, G: MultiLineStringTrait, W: Write, >( - g: &G, + multilinestring: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { - let dim = g.dim(); + let dim = multilinestring.dim(); // Write prefix match dim { geo_traits::Dimensions::Xy => f.write_str("MULTILINESTRING"), @@ -194,104 +172,180 @@ pub fn multilinestring_to_wkt< geo_traits::Dimensions::Xyzm => f.write_str("MULTILINESTRING ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; + let size = PhysicalCoordinateDimension::from(dim); + let mut line_strings = multilinestring.line_strings(); + if let Some(first_linestring) = line_strings.next() { + f.write_str("(")?; + add_coord_sequence(first_linestring.coords(), f, size)?; - if g.num_line_strings() == 0 { - f.write_str(" EMPTY") + for linestring in line_strings { + f.write_char(',')?; + add_coord_sequence(linestring.coords(), f, size)?; + } + + f.write_char(')')?; + } else { + f.write_str(" EMPTY")?; + }; + + Ok(()) +} + +pub fn multi_polygon_to_wkt< + T: CoordNum + WktNum + fmt::Display, + G: MultiPolygonTrait, + W: Write, +>( + multipolygon: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = multipolygon.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("MULTILINESTRING"), + geo_traits::Dimensions::Xyz => f.write_str("MULTILINESTRING Z"), + geo_traits::Dimensions::Xym => f.write_str("MULTILINESTRING M"), + geo_traits::Dimensions::Xyzm => f.write_str("MULTILINESTRING ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + let size = PhysicalCoordinateDimension::from(dim); + + let mut polygons = multipolygon.polygons(); + + if let Some(first_polygon) = polygons.next() { + f.write_str(" ((")?; + + add_coord_sequence(first_polygon.exterior().unwrap().coords(), f, size)?; + for interior in first_polygon.interiors() { + f.write_char(',')?; + add_coord_sequence(interior.coords(), f, size)?; + } + + for polygon in polygons { + f.write_str("),(")?; + + add_coord_sequence(polygon.exterior().unwrap().coords(), f, size)?; + for interior in polygon.interiors() { + f.write_char(',')?; + add_coord_sequence(interior.coords(), f, size)?; + } + } + + f.write_str("))")?; + } else { + f.write_str(" EMPTY")?; + }; + + Ok(()) +} + +/// Create geometry to WKT representation. + +pub fn geometry_to_wkt, W: Write>( + geometry: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + match geometry.as_type() { + geo_traits::GeometryType::Point(point) => point_to_wkt(point, f), + geo_traits::GeometryType::LineString(linestring) => linestring_to_wkt(linestring, f), + geo_traits::GeometryType::Polygon(polygon) => polygon_to_wkt(polygon, f), + geo_traits::GeometryType::MultiPoint(multi_point) => multi_point_to_wkt(multi_point, f), + geo_traits::GeometryType::MultiLineString(mls) => multi_linestring_to_wkt(mls, f), + geo_traits::GeometryType::MultiPolygon(multi_polygon) => { + multi_polygon_to_wkt(multi_polygon, f) + } + geo_traits::GeometryType::GeometryCollection(gc) => geometry_collection_to_wkt(gc, f), + geo_traits::GeometryType::Rect(rect) => rect_to_wkt(rect, f), + geo_traits::GeometryType::Triangle(_) => todo!(), + geo_traits::GeometryType::Line(_) => todo!(), + } +} + +pub fn geometry_collection_to_wkt< + T: CoordNum + WktNum + fmt::Display, + G: GeometryCollectionTrait, + W: Write, +>( + gc: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = gc.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("GEOMETRYCOLLECTION"), + geo_traits::Dimensions::Xyz => f.write_str("GEOMETRYCOLLECTION Z"), + geo_traits::Dimensions::Xym => f.write_str("GEOMETRYCOLLECTION M"), + geo_traits::Dimensions::Xyzm => f.write_str("GEOMETRYCOLLECTION ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + let mut geometries = gc.geometries(); + + if let Some(first_geometry) = geometries.next() { + f.write_str(" (")?; + + geometry_to_wkt(&first_geometry, f)?; + for geom in geometries { + f.write_char(',')?; + geometry_to_wkt(&geom, f)?; + } + + f.write_char(')')?; } else { - let strings = g - .line_strings() - .map(|ring| { - let s = ring - .coords() - .map(|c| { - let mut s = String::new(); - coord_to_wkt(&c, &mut s)?; - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join(","); - Ok(s) - }) - .collect::, std::fmt::Error>>()? - .join("),("); - write!(f, "({})", strings) + f.write_str(" EMPTY")?; } + Ok(()) } -// pub fn multipolygon_to_wkt< -// T: CoordNum + WktNum + fmt::Display, -// G: MultiPolygonTrait, -// W: Write, -// >( -// g: &G, -// f: &mut W, -// ) -> Result<(), std::fmt::Error> { -// let dim = g.dim(); -// // Write prefix -// match dim { -// geo_traits::Dimensions::Xy => f.write_str("MULTIPOLYGON"), -// geo_traits::Dimensions::Xyz => f.write_str("MULTIPOLYGON Z"), -// geo_traits::Dimensions::Xym => f.write_str("MULTIPOLYGON M"), -// geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOLYGON ZM"), -// geo_traits::Dimensions::Unknown(_) => todo!(), -// }?; - -// if g.num_polygons() == 0 { -// f.write_str(" EMPTY") -// } else { -// let strings = g -// .polygons() -// .map(|polygon| { -// let exterior = polygon.exterior().unwrap(); -// let exterior_string = exterior -// .coords() -// .map(|c| { -// let mut s = String::new(); -// coord_to_wkt(&c, &mut s)?; -// Ok(s) -// }) -// .collect::, std::fmt::Error>>()? -// .join(","); - -// if polygon.num_interiors() == 0 { -// write!(f, "({})", exterior_string) -// } else { -// let interior_string = polygon -// .interiors() -// .map(|ring| { -// let s = ring -// .coords() -// .map(|c| { -// let mut s = String::new(); -// coord_to_wkt(&c, &mut s)?; -// Ok(s) -// }) -// .collect::, std::fmt::Error>>()? -// .join(","); -// Ok(s) -// }) -// .collect::, std::fmt::Error>>()? -// .join("),("); -// write!(f, "({},({}))", exterior_string, interior_string) -// }; -// Ok(s) -// }) -// .collect::, std::fmt::Error>>()? -// .join("),("); -// write!(f, "({})", strings) -// } -// } - -fn add_coord, W: Write>( +pub fn rect_to_wkt, W: Write>( + _rect: &G, + _f: &mut W, +) -> Result<(), std::fmt::Error> { + todo!() + + // let dim = rect.dim(); + // // Write prefix + // match dim { + // geo_traits::Dimensions::Xy => f.write_str("POLYGON"), + // geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), + // geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), + // geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), + // geo_traits::Dimensions::Unknown(_) => todo!(), + // }?; + + // let size = PhysicalCoordinateDimension::from(dim); + + // // A rect cannot be empty + // let min = rect.min(); + // let max = rect.max(); + + // match rect.dim() { + // 2 => writer.write_fmt(format_args!( + // " ({0} {1},{2} {1},{2} {3},{0} {3},{0} {1})", + // lower.x(), + // lower.y(), + // upper.x(), + // upper.y(), + // ))?, + // 3 => todo!("cube as polygon / linestring / multipoint?"), + + // _ => unimplemented!(), + // }; +} + +/// Write a single coordinate to the writer. +/// +/// Will not include any start or end `()` characters. +pub(crate) fn add_coord, W: Write>( coord: &G, f: &mut W, + size: PhysicalCoordinateDimension, ) -> Result<(), std::fmt::Error> { - match coord.dim().size() { - 2 => write!(f, "{} {}", coord.x(), coord.y()), - 3 => { + match size { + PhysicalCoordinateDimension::Two => write!(f, "{} {}", coord.x(), coord.y()), + PhysicalCoordinateDimension::Three => { write!(f, "{} {} {}", coord.x(), coord.y(), coord.nth_unchecked(2)) } - 4 => { + PhysicalCoordinateDimension::Four => { write!( f, "{} {} {} {}", @@ -301,26 +355,32 @@ fn add_coord, W: Write coord.nth_unchecked(3) ) } - size => panic!("Unexpected dimension for coordinate: {}", size), } } -fn add_coords>( +/// Includes the `()` characters to start and end this sequence. +/// +/// E.g. it will write: +/// ```notest +/// (1 2, 3 4, 5 6) +/// ``` +/// for a coordinate sequence with three coordinates. +fn add_coord_sequence>( mut coords: impl ExactSizeIterator, f: &mut W, + size: PhysicalCoordinateDimension, ) -> Result<(), std::fmt::Error> { f.write_char('(')?; if let Some(first_coord) = coords.next() { - add_coord(&first_coord, f)?; + add_coord(&first_coord, f, size)?; for coord in coords { f.write_char(',')?; - add_coord(&coord, f)?; + add_coord(&coord, f, size)?; } } f.write_char(')')?; - Ok(()) } diff --git a/src/types/coord.rs b/src/types/coord.rs index 9640e08..c064ccc 100644 --- a/src/types/coord.rs +++ b/src/types/coord.rs @@ -14,7 +14,7 @@ use geo_traits::CoordTrait; -use crate::to_wkt::geo_trait_impl::coord_to_wkt; +use crate::to_wkt::geo_trait_impl::add_coord; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, WktNum}; @@ -37,7 +37,10 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - coord_to_wkt(self, f) + f.write_str("(")?; + add_coord(self, f, self.dim().into())?; + f.write_str(")")?; + Ok(()) } } diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index 06fabdf..fbb7df6 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -14,6 +14,7 @@ use geo_traits::{GeometryCollectionTrait, GeometryTrait}; +use crate::to_wkt::geo_trait_impl::geometry_collection_to_wkt; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, Wkt, WktNum}; @@ -37,18 +38,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("GEOMETRYCOLLECTION EMPTY") - } else { - let strings = self - .0 - .iter() - .map(|geometry| format!("{}", geometry)) - .collect::>() - .join(","); - - write!(f, "GEOMETRYCOLLECTION({})", strings) - } + geometry_collection_to_wkt(self, f) } } diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index f712de4..65bb412 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -14,7 +14,7 @@ use geo_traits::{LineStringTrait, MultiLineStringTrait}; -use crate::to_wkt::geo_trait_impl::multilinestring_to_wkt; +use crate::to_wkt::geo_trait_impl::multi_linestring_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - multilinestring_to_wkt(self, f) + multi_linestring_to_wkt(self, f) } } diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index ae176a7..01ee23e 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -14,7 +14,7 @@ use geo_traits::{MultiPointTrait, PointTrait}; -use crate::to_wkt::geo_trait_impl::multipoint_to_wkt; +use crate::to_wkt::geo_trait_impl::multi_point_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::point::Point; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - multipoint_to_wkt(self, f) + multi_point_to_wkt(self, f) } } diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index bce47c2..8a81418 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -14,6 +14,7 @@ use geo_traits::{MultiPolygonTrait, PolygonTrait}; +use crate::to_wkt::geo_trait_impl::multi_polygon_to_wkt; use crate::tokenizer::PeekableTokens; use crate::types::polygon::Polygon; use crate::types::Dimension; @@ -38,28 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.0.is_empty() { - f.write_str("MULTIPOLYGON EMPTY") - } else { - let strings = self - .0 - .iter() - .map(|p| { - p.0.iter() - .map(|l| { - l.0.iter() - .map(|c| format!("{} {}", c.x, c.y)) - .collect::>() - .join(",") - }) - .collect::>() - .join("),(") - }) - .collect::>() - .join(")),(("); - - write!(f, "MULTIPOLYGON((({})))", strings) - } + multi_polygon_to_wkt(self, f) } } From f351816fbe6a391ff9182b67862d42c8cb85fcdc Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 26 Oct 2024 14:20:13 -0400 Subject: [PATCH 03/20] fix tests --- src/to_wkt/geo_trait_impl.rs | 20 +++++------ src/types/coord.rs | 67 ------------------------------------ 2 files changed, 10 insertions(+), 77 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 4720186..e4c08c5 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -96,7 +96,7 @@ pub fn polygon_to_wkt f.write_str("MULTILINESTRING"), - geo_traits::Dimensions::Xyz => f.write_str("MULTILINESTRING Z"), - geo_traits::Dimensions::Xym => f.write_str("MULTILINESTRING M"), - geo_traits::Dimensions::Xyzm => f.write_str("MULTILINESTRING ZM"), + geo_traits::Dimensions::Xy => f.write_str("MULTIPOLYGON"), + geo_traits::Dimensions::Xyz => f.write_str("MULTIPOLYGON Z"), + geo_traits::Dimensions::Xym => f.write_str("MULTIPOLYGON M"), + geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOLYGON ZM"), geo_traits::Dimensions::Unknown(_) => todo!(), }?; let size = PhysicalCoordinateDimension::from(dim); @@ -213,7 +213,7 @@ pub fn multi_polygon_to_wkt< let mut polygons = multipolygon.polygons(); if let Some(first_polygon) = polygons.next() { - f.write_str(" ((")?; + f.write_str("((")?; add_coord_sequence(first_polygon.exterior().unwrap().coords(), f, size)?; for interior in first_polygon.interiors() { @@ -281,7 +281,7 @@ pub fn geometry_collection_to_wkt< let mut geometries = gc.geometries(); if let Some(first_geometry) = geometries.next() { - f.write_str(" (")?; + f.write_str("(")?; geometry_to_wkt(&first_geometry, f)?; for geom in geometries { diff --git a/src/types/coord.rs b/src/types/coord.rs index c064ccc..8fe319f 100644 --- a/src/types/coord.rs +++ b/src/types/coord.rs @@ -14,11 +14,9 @@ use geo_traits::CoordTrait; -use crate::to_wkt::geo_trait_impl::add_coord; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, WktNum}; -use std::fmt; use std::str::FromStr; #[derive(Clone, Debug, Default, PartialEq)] @@ -32,18 +30,6 @@ where pub m: Option, } -impl fmt::Display for Coord -where - T: WktNum + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.write_str("(")?; - add_coord(self, f, self.dim().into())?; - f.write_str(")")?; - Ok(()) - } -} - impl FromTokens for Coord where T: WktNum + FromStr + Default, @@ -188,56 +174,3 @@ impl CoordTrait for &Coord { } } } - -#[cfg(test)] -mod tests { - use super::Coord; - - #[test] - fn write_2d_coord() { - let coord = Coord { - x: 10.1, - y: 20.2, - z: None, - m: None, - }; - - assert_eq!("10.1 20.2", format!("{}", coord)); - } - - #[test] - fn write_3d_coord() { - let coord = Coord { - x: 10.1, - y: 20.2, - z: Some(-30.3), - m: None, - }; - - assert_eq!("10.1 20.2 -30.3", format!("{}", coord)); - } - - #[test] - fn write_2d_coord_with_linear_referencing_system() { - let coord = Coord { - x: 10.1, - y: 20.2, - z: None, - m: Some(10.), - }; - - assert_eq!("10.1 20.2 10", format!("{}", coord)); - } - - #[test] - fn write_3d_coord_with_linear_referencing_system() { - let coord = Coord { - x: 10.1, - y: 20.2, - z: Some(-30.3), - m: Some(10.), - }; - - assert_eq!("10.1 20.2 -30.3 10", format!("{}", coord)); - } -} From 63b13243568470d6da5a44fcc9fe7b903aa53eea Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 26 Oct 2024 14:34:25 -0400 Subject: [PATCH 04/20] update bench --- benches/write.rs | 28 +++++++++++++++++++++++++++- src/lib.rs | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/benches/write.rs b/benches/write.rs index 50f5356..b413127 100644 --- a/benches/write.rs +++ b/benches/write.rs @@ -64,5 +64,31 @@ fn geo_write_wkt(c: &mut criterion::Criterion) { }); } -criterion_group!(benches, wkt_to_string, geo_to_wkt_string, geo_write_wkt); +fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { + c.bench_function("geo: write small wkt using trait", |bencher| { + let s = include_str!("./small.wkt"); + let w = wkt::Wkt::::from_str(s).unwrap(); + let g = geo_types::Geometry::try_from(w).unwrap(); + bencher.iter(|| { + wkt::to_wkt::geo_trait_impl::geometry_to_wkt(&g, &mut String::new()).unwrap(); + }); + }); + + c.bench_function("geo: write big wkt using trait", |bencher| { + let s = include_str!("./big.wkt"); + let w = wkt::Wkt::::from_str(s).unwrap(); + let g = geo_types::Geometry::try_from(w).unwrap(); + bencher.iter(|| { + wkt::to_wkt::geo_trait_impl::geometry_to_wkt(&g, &mut String::new()).unwrap(); + }); + }); +} + +criterion_group!( + benches, + wkt_to_string, + geo_to_wkt_string, + geo_write_wkt, + geo_write_wkt_as_trait +); criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index 05e2482..105cc48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ use crate::types::{ Polygon, }; -mod to_wkt; +pub mod to_wkt; mod tokenizer; /// `WKT` primitive types and collections From 599c68fc3dd09b1800bf5378ae01a0c1737d285a Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 29 Oct 2024 15:35:04 -0400 Subject: [PATCH 05/20] Fix implementation for rect, triangle, line --- src/to_wkt/geo_trait_impl.rs | 134 +++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 37 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index e4c08c5..16be8b3 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -2,11 +2,13 @@ use core::fmt; use std::fmt::Write; use geo_traits::{ - CoordTrait, GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, - MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, + CoordTrait, GeometryCollectionTrait, GeometryTrait, LineStringTrait, LineTrait, + MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, + TriangleTrait, }; use geo_types::CoordNum; +use crate::types::{Coord, LineString, Polygon}; use crate::WktNum; /// The physical size of the coordinate dimension @@ -256,8 +258,8 @@ pub fn geometry_to_wkt geometry_collection_to_wkt(gc, f), geo_traits::GeometryType::Rect(rect) => rect_to_wkt(rect, f), - geo_traits::GeometryType::Triangle(_) => todo!(), - geo_traits::GeometryType::Line(_) => todo!(), + geo_traits::GeometryType::Triangle(triangle) => triangle_to_wkt(triangle, f), + geo_traits::GeometryType::Line(line) => line_to_wkt(line, f), } } @@ -296,40 +298,98 @@ pub fn geometry_collection_to_wkt< Ok(()) } +fn rect_to_polygon>( + rect: &G, +) -> Polygon { + let min_coord = rect.min(); + let max_coord = rect.max(); + + // Note: Even if the rect has more than 2 dimensions, we omit the other dimensions when + // converting to a Polygon. + let coords = vec![ + Coord { + x: min_coord.x(), + y: min_coord.y(), + z: None, + m: None, + }, + Coord { + x: min_coord.x(), + y: max_coord.y(), + z: None, + m: None, + }, + Coord { + x: max_coord.x(), + y: max_coord.y(), + z: None, + m: None, + }, + Coord { + x: max_coord.x(), + y: min_coord.y(), + z: None, + m: None, + }, + Coord { + x: min_coord.x(), + y: min_coord.y(), + z: None, + m: None, + }, + ]; + let ring = LineString(coords); + Polygon(vec![ring]) +} + pub fn rect_to_wkt, W: Write>( - _rect: &G, - _f: &mut W, + rect: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let polygon = rect_to_polygon(rect); + polygon_to_wkt(&polygon, f) +} + +pub fn triangle_to_wkt, W: Write>( + triangle: &G, + f: &mut W, ) -> Result<(), std::fmt::Error> { - todo!() - - // let dim = rect.dim(); - // // Write prefix - // match dim { - // geo_traits::Dimensions::Xy => f.write_str("POLYGON"), - // geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), - // geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), - // geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), - // geo_traits::Dimensions::Unknown(_) => todo!(), - // }?; - - // let size = PhysicalCoordinateDimension::from(dim); - - // // A rect cannot be empty - // let min = rect.min(); - // let max = rect.max(); - - // match rect.dim() { - // 2 => writer.write_fmt(format_args!( - // " ({0} {1},{2} {1},{2} {3},{0} {3},{0} {1})", - // lower.x(), - // lower.y(), - // upper.x(), - // upper.y(), - // ))?, - // 3 => todo!("cube as polygon / linestring / multipoint?"), - - // _ => unimplemented!(), - // }; + let dim = triangle.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("POLYGON"), + geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), + geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), + geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + let size = PhysicalCoordinateDimension::from(dim); + f.write_str("(")?; + + let coords_iter = triangle + .coords() + .into_iter() + .chain(std::iter::once(triangle.first())); + add_coord_sequence(coords_iter, f, size)?; + + f.write_char(')') +} + +pub fn line_to_wkt, W: Write>( + line: &G, + f: &mut W, +) -> Result<(), std::fmt::Error> { + let dim = line.dim(); + // Write prefix + match dim { + geo_traits::Dimensions::Xy => f.write_str("LINESTRING"), + geo_traits::Dimensions::Xyz => f.write_str("LINESTRING Z"), + geo_traits::Dimensions::Xym => f.write_str("LINESTRING M"), + geo_traits::Dimensions::Xyzm => f.write_str("LINESTRING ZM"), + geo_traits::Dimensions::Unknown(_) => todo!(), + }?; + let size = PhysicalCoordinateDimension::from(dim); + add_coord_sequence(line.coords().into_iter(), f, size) } /// Write a single coordinate to the writer. @@ -366,7 +426,7 @@ pub(crate) fn add_coord>( - mut coords: impl ExactSizeIterator, + mut coords: impl Iterator, f: &mut W, size: PhysicalCoordinateDimension, ) -> Result<(), std::fmt::Error> { From e04b751a63f6f4c760362afbd0400741693faca3 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 30 Oct 2024 15:56:55 -0400 Subject: [PATCH 06/20] shorten name --- benches/write.rs | 4 +-- src/lib.rs | 4 +-- src/to_wkt/geo_trait_impl.rs | 48 ++++++++++++++++----------------- src/types/geometrycollection.rs | 4 +-- src/types/linestring.rs | 4 +-- src/types/multilinestring.rs | 4 +-- src/types/multipoint.rs | 4 +-- src/types/multipolygon.rs | 4 +-- src/types/point.rs | 4 +-- src/types/polygon.rs | 4 +-- 10 files changed, 42 insertions(+), 42 deletions(-) diff --git a/benches/write.rs b/benches/write.rs index b413127..e5f38c8 100644 --- a/benches/write.rs +++ b/benches/write.rs @@ -70,7 +70,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::geo_trait_impl::geometry_to_wkt(&g, &mut String::new()).unwrap(); + wkt::to_wkt::geo_trait_impl::write_geometry(&g, &mut String::new()).unwrap(); }); }); @@ -79,7 +79,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::geo_trait_impl::geometry_to_wkt(&g, &mut String::new()).unwrap(); + wkt::to_wkt::geo_trait_impl::write_geometry(&g, &mut String::new()).unwrap(); }); }); } diff --git a/src/lib.rs b/src/lib.rs index 105cc48..e34cdad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ use geo_traits::{ }; use num_traits::{Float, Num, NumCast}; -use crate::to_wkt::geo_trait_impl::geometry_to_wkt; +use crate::to_wkt::geo_trait_impl::write_geometry; use crate::tokenizer::{PeekableTokens, Token, Tokens}; use crate::types::{ Dimension, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, @@ -360,7 +360,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - geometry_to_wkt(self, f) + write_geometry(self, f) } } diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 16be8b3..6b3d252 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -33,7 +33,7 @@ impl From for PhysicalCoordinateDimension { } } -pub fn point_to_wkt, W: Write>( +pub fn write_point, W: Write>( g: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -57,7 +57,7 @@ pub fn point_to_wkt, W } } -pub fn linestring_to_wkt< +pub fn write_linestring< T: CoordNum + WktNum + fmt::Display, G: LineStringTrait, W: Write, @@ -82,7 +82,7 @@ pub fn linestring_to_wkt< } } -pub fn polygon_to_wkt, W: Write>( +pub fn write_polygon, W: Write>( polygon: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -115,7 +115,7 @@ pub fn polygon_to_wkt, W: Write, @@ -157,7 +157,7 @@ pub fn multi_point_to_wkt< Ok(()) } -pub fn multi_linestring_to_wkt< +pub fn write_multi_linestring< T: CoordNum + WktNum + fmt::Display, G: MultiLineStringTrait, W: Write, @@ -193,7 +193,7 @@ pub fn multi_linestring_to_wkt< Ok(()) } -pub fn multi_polygon_to_wkt< +pub fn write_multi_polygon< T: CoordNum + WktNum + fmt::Display, G: MultiPolygonTrait, W: Write, @@ -243,27 +243,27 @@ pub fn multi_polygon_to_wkt< /// Create geometry to WKT representation. -pub fn geometry_to_wkt, W: Write>( +pub fn write_geometry, W: Write>( geometry: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { match geometry.as_type() { - geo_traits::GeometryType::Point(point) => point_to_wkt(point, f), - geo_traits::GeometryType::LineString(linestring) => linestring_to_wkt(linestring, f), - geo_traits::GeometryType::Polygon(polygon) => polygon_to_wkt(polygon, f), - geo_traits::GeometryType::MultiPoint(multi_point) => multi_point_to_wkt(multi_point, f), - geo_traits::GeometryType::MultiLineString(mls) => multi_linestring_to_wkt(mls, f), + geo_traits::GeometryType::Point(point) => write_point(point, f), + geo_traits::GeometryType::LineString(linestring) => write_linestring(linestring, f), + geo_traits::GeometryType::Polygon(polygon) => write_polygon(polygon, f), + geo_traits::GeometryType::MultiPoint(multi_point) => write_multi_point(multi_point, f), + geo_traits::GeometryType::MultiLineString(mls) => write_multi_linestring(mls, f), geo_traits::GeometryType::MultiPolygon(multi_polygon) => { - multi_polygon_to_wkt(multi_polygon, f) + write_multi_polygon(multi_polygon, f) } - geo_traits::GeometryType::GeometryCollection(gc) => geometry_collection_to_wkt(gc, f), - geo_traits::GeometryType::Rect(rect) => rect_to_wkt(rect, f), - geo_traits::GeometryType::Triangle(triangle) => triangle_to_wkt(triangle, f), - geo_traits::GeometryType::Line(line) => line_to_wkt(line, f), + geo_traits::GeometryType::GeometryCollection(gc) => write_geometry_collection(gc, f), + geo_traits::GeometryType::Rect(rect) => write_rect(rect, f), + geo_traits::GeometryType::Triangle(triangle) => write_triangle(triangle, f), + geo_traits::GeometryType::Line(line) => write_line(line, f), } } -pub fn geometry_collection_to_wkt< +pub fn write_geometry_collection< T: CoordNum + WktNum + fmt::Display, G: GeometryCollectionTrait, W: Write, @@ -285,10 +285,10 @@ pub fn geometry_collection_to_wkt< if let Some(first_geometry) = geometries.next() { f.write_str("(")?; - geometry_to_wkt(&first_geometry, f)?; + write_geometry(&first_geometry, f)?; for geom in geometries { f.write_char(',')?; - geometry_to_wkt(&geom, f)?; + write_geometry(&geom, f)?; } f.write_char(')')?; @@ -342,15 +342,15 @@ fn rect_to_polygon>( Polygon(vec![ring]) } -pub fn rect_to_wkt, W: Write>( +pub fn write_rect, W: Write>( rect: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { let polygon = rect_to_polygon(rect); - polygon_to_wkt(&polygon, f) + write_polygon(&polygon, f) } -pub fn triangle_to_wkt, W: Write>( +pub fn write_triangle, W: Write>( triangle: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -375,7 +375,7 @@ pub fn triangle_to_wkt, W: Write>( +pub fn write_line, W: Write>( line: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index fbb7df6..11858c0 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -14,7 +14,7 @@ use geo_traits::{GeometryCollectionTrait, GeometryTrait}; -use crate::to_wkt::geo_trait_impl::geometry_collection_to_wkt; +use crate::to_wkt::geo_trait_impl::write_geometry_collection; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, Wkt, WktNum}; @@ -38,7 +38,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - geometry_collection_to_wkt(self, f) + write_geometry_collection(self, f) } } diff --git a/src/types/linestring.rs b/src/types/linestring.rs index 9f8e450..dd978cf 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -14,7 +14,7 @@ use geo_traits::{CoordTrait, LineStringTrait}; -use crate::to_wkt::geo_trait_impl::linestring_to_wkt; +use crate::to_wkt::geo_trait_impl::write_linestring; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; @@ -49,7 +49,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - linestring_to_wkt(self, f) + write_linestring(self, f) } } diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index 65bb412..d32988c 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -14,7 +14,7 @@ use geo_traits::{LineStringTrait, MultiLineStringTrait}; -use crate::to_wkt::geo_trait_impl::multi_linestring_to_wkt; +use crate::to_wkt::geo_trait_impl::write_multi_linestring; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - multi_linestring_to_wkt(self, f) + write_multi_linestring(self, f) } } diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index 01ee23e..ee7ea95 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -14,7 +14,7 @@ use geo_traits::{MultiPointTrait, PointTrait}; -use crate::to_wkt::geo_trait_impl::multi_point_to_wkt; +use crate::to_wkt::geo_trait_impl::write_multi_point; use crate::tokenizer::PeekableTokens; use crate::types::point::Point; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - multi_point_to_wkt(self, f) + write_multi_point(self, f) } } diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index 8a81418..f501954 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -14,7 +14,7 @@ use geo_traits::{MultiPolygonTrait, PolygonTrait}; -use crate::to_wkt::geo_trait_impl::multi_polygon_to_wkt; +use crate::to_wkt::geo_trait_impl::write_multi_polygon; use crate::tokenizer::PeekableTokens; use crate::types::polygon::Polygon; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - multi_polygon_to_wkt(self, f) + write_multi_polygon(self, f) } } diff --git a/src/types/point.rs b/src/types/point.rs index 3f9f0fd..dda3f6c 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -14,7 +14,7 @@ use geo_traits::{CoordTrait, PointTrait}; -use crate::to_wkt::geo_trait_impl::point_to_wkt; +use crate::to_wkt::geo_trait_impl::write_point; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - point_to_wkt(self, f) + write_point(self, f) } } diff --git a/src/types/polygon.rs b/src/types/polygon.rs index fcaa320..c2bb7c9 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -14,7 +14,7 @@ use geo_traits::{LineStringTrait, PolygonTrait}; -use crate::to_wkt::geo_trait_impl::polygon_to_wkt; +use crate::to_wkt::geo_trait_impl::write_polygon; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - polygon_to_wkt(self, f) + write_polygon(self, f) } } From f3434f5283d070f1accd64cd1bd09303f0f0547c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 30 Oct 2024 16:14:48 -0400 Subject: [PATCH 07/20] expose via `wkt::to_wkt` mod --- benches/write.rs | 4 ++-- src/lib.rs | 2 +- src/to_wkt/geo_trait_impl.rs | 4 ++-- src/to_wkt/mod.rs | 8 +++++++- src/types/geometrycollection.rs | 2 +- src/types/linestring.rs | 2 +- src/types/multilinestring.rs | 2 +- src/types/multipoint.rs | 2 +- src/types/multipolygon.rs | 2 +- src/types/point.rs | 2 +- src/types/polygon.rs | 2 +- 11 files changed, 19 insertions(+), 13 deletions(-) diff --git a/benches/write.rs b/benches/write.rs index e5f38c8..60040d6 100644 --- a/benches/write.rs +++ b/benches/write.rs @@ -70,7 +70,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::geo_trait_impl::write_geometry(&g, &mut String::new()).unwrap(); + wkt::to_wkt::write_geometry(&g, &mut String::new()).unwrap(); }); }); @@ -79,7 +79,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::geo_trait_impl::write_geometry(&g, &mut String::new()).unwrap(); + wkt::to_wkt::write_geometry(&g, &mut String::new()).unwrap(); }); }); } diff --git a/src/lib.rs b/src/lib.rs index e34cdad..eeb75cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ use geo_traits::{ }; use num_traits::{Float, Num, NumCast}; -use crate::to_wkt::geo_trait_impl::write_geometry; +use crate::to_wkt::write_geometry; use crate::tokenizer::{PeekableTokens, Token, Tokens}; use crate::types::{ Dimension, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 6b3d252..78e89e8 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -16,7 +16,7 @@ use crate::WktNum; /// This is used so that we don't have to call `.dim()` on **every** coordinate. We infer it once /// from the `geo_traits::Dimensions` and then pass it to each coordinate. #[derive(Clone, Copy)] -pub(crate) enum PhysicalCoordinateDimension { +enum PhysicalCoordinateDimension { Two, Three, Four, @@ -395,7 +395,7 @@ pub fn write_line, W: W /// Write a single coordinate to the writer. /// /// Will not include any start or end `()` characters. -pub(crate) fn add_coord, W: Write>( +fn add_coord, W: Write>( coord: &G, f: &mut W, size: PhysicalCoordinateDimension, diff --git a/src/to_wkt/mod.rs b/src/to_wkt/mod.rs index f2cd73f..3581c8b 100644 --- a/src/to_wkt/mod.rs +++ b/src/to_wkt/mod.rs @@ -1,6 +1,12 @@ use crate::{Wkt, WktNum}; -pub mod geo_trait_impl; +mod geo_trait_impl; + +pub use geo_trait_impl::{ + write_geometry, write_geometry_collection, write_line, write_linestring, + write_multi_linestring, write_multi_point, write_multi_polygon, write_point, write_polygon, + write_rect, write_triangle, +}; /// A trait for converting values to WKT pub trait ToWkt diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index 11858c0..dc760f5 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -14,7 +14,7 @@ use geo_traits::{GeometryCollectionTrait, GeometryTrait}; -use crate::to_wkt::geo_trait_impl::write_geometry_collection; +use crate::to_wkt::write_geometry_collection; use crate::tokenizer::{PeekableTokens, Token}; use crate::types::Dimension; use crate::{FromTokens, Wkt, WktNum}; diff --git a/src/types/linestring.rs b/src/types/linestring.rs index dd978cf..476ffca 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -14,7 +14,7 @@ use geo_traits::{CoordTrait, LineStringTrait}; -use crate::to_wkt::geo_trait_impl::write_linestring; +use crate::to_wkt::write_linestring; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index d32988c..adbe517 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -14,7 +14,7 @@ use geo_traits::{LineStringTrait, MultiLineStringTrait}; -use crate::to_wkt::geo_trait_impl::write_multi_linestring; +use crate::to_wkt::write_multi_linestring; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index ee7ea95..1aef9cc 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -14,7 +14,7 @@ use geo_traits::{MultiPointTrait, PointTrait}; -use crate::to_wkt::geo_trait_impl::write_multi_point; +use crate::to_wkt::write_multi_point; use crate::tokenizer::PeekableTokens; use crate::types::point::Point; use crate::types::Dimension; diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index f501954..cf2e413 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -14,7 +14,7 @@ use geo_traits::{MultiPolygonTrait, PolygonTrait}; -use crate::to_wkt::geo_trait_impl::write_multi_polygon; +use crate::to_wkt::write_multi_polygon; use crate::tokenizer::PeekableTokens; use crate::types::polygon::Polygon; use crate::types::Dimension; diff --git a/src/types/point.rs b/src/types/point.rs index dda3f6c..342c6fe 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -14,7 +14,7 @@ use geo_traits::{CoordTrait, PointTrait}; -use crate::to_wkt::geo_trait_impl::write_point; +use crate::to_wkt::write_point; use crate::tokenizer::PeekableTokens; use crate::types::coord::Coord; use crate::types::Dimension; diff --git a/src/types/polygon.rs b/src/types/polygon.rs index c2bb7c9..8101cd6 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -14,7 +14,7 @@ use geo_traits::{LineStringTrait, PolygonTrait}; -use crate::to_wkt::geo_trait_impl::write_polygon; +use crate::to_wkt::write_polygon; use crate::tokenizer::PeekableTokens; use crate::types::linestring::LineString; use crate::types::Dimension; From 6b57a1cdc714b709a3fdc338fb9c304ed31e87ed Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 23 Nov 2024 16:17:01 +0000 Subject: [PATCH 08/20] update for geo-traits 0.2 --- src/to_wkt/geo_trait_impl.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 78e89e8..5b54a5b 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -403,7 +403,11 @@ fn add_coord, W: Write match size { PhysicalCoordinateDimension::Two => write!(f, "{} {}", coord.x(), coord.y()), PhysicalCoordinateDimension::Three => { - write!(f, "{} {} {}", coord.x(), coord.y(), coord.nth_unchecked(2)) + // Safety: + // We've validated that there are three dimensions + write!(f, "{} {} {}", coord.x(), coord.y(), unsafe { + coord.nth_unchecked(2) + }) } PhysicalCoordinateDimension::Four => { write!( @@ -411,8 +415,12 @@ fn add_coord, W: Write "{} {} {} {}", coord.x(), coord.y(), - coord.nth_unchecked(2), - coord.nth_unchecked(3) + // Safety: + // We've validated that there are four dimensions + unsafe { coord.nth_unchecked(2) }, + // Safety: + // We've validated that there are four dimensions + unsafe { coord.nth_unchecked(3) } ) } } From 9b23f7b28cf470e7cdb8931d2fc963d5a094283f Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 25 Nov 2024 15:48:33 -0500 Subject: [PATCH 09/20] fix compile --- src/to_wkt/geo_trait_impl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 5b54a5b..726f584 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -6,6 +6,7 @@ use geo_traits::{ MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, TriangleTrait, }; +#[cfg(feature = "geo-types")] use geo_types::CoordNum; use crate::types::{Coord, LineString, Polygon}; From 447be533e0a76188ca499eb8a0c74fc4e8a0f823 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 25 Nov 2024 15:51:56 -0500 Subject: [PATCH 10/20] Remove CoordNum bound --- src/to_wkt/geo_trait_impl.rs | 44 ++++++++++++------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 726f584..af1a63b 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -6,8 +6,6 @@ use geo_traits::{ MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, TriangleTrait, }; -#[cfg(feature = "geo-types")] -use geo_types::CoordNum; use crate::types::{Coord, LineString, Polygon}; use crate::WktNum; @@ -34,7 +32,7 @@ impl From for PhysicalCoordinateDimension { } } -pub fn write_point, W: Write>( +pub fn write_point, W: Write>( g: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -58,11 +56,7 @@ pub fn write_point, W: } } -pub fn write_linestring< - T: CoordNum + WktNum + fmt::Display, - G: LineStringTrait, - W: Write, ->( +pub fn write_linestring, W: Write>( linestring: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -83,7 +77,7 @@ pub fn write_linestring< } } -pub fn write_polygon, W: Write>( +pub fn write_polygon, W: Write>( polygon: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -116,11 +110,7 @@ pub fn write_polygon } } -pub fn write_multi_point< - T: CoordNum + WktNum + fmt::Display, - G: MultiPointTrait, - W: Write, ->( +pub fn write_multi_point, W: Write>( multipoint: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -159,7 +149,7 @@ pub fn write_multi_point< } pub fn write_multi_linestring< - T: CoordNum + WktNum + fmt::Display, + T: WktNum + fmt::Display, G: MultiLineStringTrait, W: Write, >( @@ -194,11 +184,7 @@ pub fn write_multi_linestring< Ok(()) } -pub fn write_multi_polygon< - T: CoordNum + WktNum + fmt::Display, - G: MultiPolygonTrait, - W: Write, ->( +pub fn write_multi_polygon, W: Write>( multipolygon: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -244,7 +230,7 @@ pub fn write_multi_polygon< /// Create geometry to WKT representation. -pub fn write_geometry, W: Write>( +pub fn write_geometry, W: Write>( geometry: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -265,7 +251,7 @@ pub fn write_geometry, W: Write, >( @@ -299,9 +285,7 @@ pub fn write_geometry_collection< Ok(()) } -fn rect_to_polygon>( - rect: &G, -) -> Polygon { +fn rect_to_polygon>(rect: &G) -> Polygon { let min_coord = rect.min(); let max_coord = rect.max(); @@ -343,7 +327,7 @@ fn rect_to_polygon>( Polygon(vec![ring]) } -pub fn write_rect, W: Write>( +pub fn write_rect, W: Write>( rect: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -351,7 +335,7 @@ pub fn write_rect, W: W write_polygon(&polygon, f) } -pub fn write_triangle, W: Write>( +pub fn write_triangle, W: Write>( triangle: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -376,7 +360,7 @@ pub fn write_triangle, W: Write>( +pub fn write_line, W: Write>( line: &G, f: &mut W, ) -> Result<(), std::fmt::Error> { @@ -396,7 +380,7 @@ pub fn write_line, W: W /// Write a single coordinate to the writer. /// /// Will not include any start or end `()` characters. -fn add_coord, W: Write>( +fn add_coord, W: Write>( coord: &G, f: &mut W, size: PhysicalCoordinateDimension, @@ -434,7 +418,7 @@ fn add_coord, W: Write /// (1 2, 3 4, 5 6) /// ``` /// for a coordinate sequence with three coordinates. -fn add_coord_sequence>( +fn add_coord_sequence>( mut coords: impl Iterator, f: &mut W, size: PhysicalCoordinateDimension, From d5e4bfd89077a0ca5e3d494a7ed4f00729fa1d18 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 14:01:07 -0500 Subject: [PATCH 11/20] Add error enum --- src/error.rs | 24 ++++++ src/lib.rs | 6 +- src/to_wkt/geo_trait_impl.rs | 155 +++++++++++++++++++++++------------ 3 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..23a6228 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,24 @@ +use core::fmt; + +use thiserror::Error; + +#[derive(Error, Debug)] +/// WKT to [`geo_types`] conversions errors +pub enum Error { + // #[error("The WKT Point was empty, but geo_type::Points cannot be empty")] + // RectWriter, + #[error("Only defined dimensions and undefined dimensions of 2, 3, or 4 are supported.")] + UnknownDimension, + /// Wrapper around `[std::fmt::Error]` + #[error(transparent)] + FmtError(#[from] std::fmt::Error), +} + +impl From for fmt::Error { + fn from(value: Error) -> Self { + match value { + Error::FmtError(err) => err, + _ => std::fmt::Error, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b418444..3d6122b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,8 @@ use crate::types::{ pub mod to_wkt; mod tokenizer; +/// Error variant for this crate +pub mod error; /// `WKT` primitive types and collections pub mod types; @@ -106,8 +108,6 @@ pub use infer_type::infer_type; #[cfg(feature = "geo-types")] extern crate geo_types; -extern crate thiserror; - pub use crate::to_wkt::ToWkt; #[cfg(feature = "geo-types")] @@ -360,7 +360,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_geometry(self, f) + Ok(write_geometry(self, f)?) } } diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index af1a63b..01bee9f 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -7,6 +7,7 @@ use geo_traits::{ TriangleTrait, }; +use crate::error::Error; use crate::types::{Coord, LineString, Polygon}; use crate::WktNum; @@ -35,15 +36,17 @@ impl From for PhysicalCoordinateDimension { pub fn write_point, W: Write>( g: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), Error> { let dim = g.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("POINT"), - geo_traits::Dimensions::Xyz => f.write_str("POINT Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => f.write_str("POINT"), + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => f.write_str("POINT Z"), geo_traits::Dimensions::Xym => f.write_str("POINT M"), - geo_traits::Dimensions::Xyzm => f.write_str("POINT ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("POINT ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); if let Some(coord) = g.coord() { @@ -52,26 +55,32 @@ pub fn write_point, W: Write>( f.write_char(')')?; Ok(()) } else { - f.write_str(" EMPTY") + Ok(f.write_str(" EMPTY")?) } } pub fn write_linestring, W: Write>( linestring: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = linestring.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("LINESTRING"), - geo_traits::Dimensions::Xyz => f.write_str("LINESTRING Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("LINESTRING") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("LINESTRING Z") + } geo_traits::Dimensions::Xym => f.write_str("LINESTRING M"), - geo_traits::Dimensions::Xyzm => f.write_str("LINESTRING ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("LINESTRING ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); if linestring.num_coords() == 0 { - f.write_str(" EMPTY") + Ok(f.write_str(" EMPTY")?) } else { add_coord_sequence(linestring.coords(), f, size) } @@ -80,15 +89,19 @@ pub fn write_linestring, W: pub fn write_polygon, W: Write>( polygon: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = polygon.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("POLYGON"), - geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => f.write_str("POLYGON"), + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("POLYGON Z") + } geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), - geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("POLYGON ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); if let Some(exterior) = polygon.exterior() { @@ -101,27 +114,33 @@ pub fn write_polygon, W: Write> add_coord_sequence(interior.coords(), f, size)?; } - f.write_char(')') + Ok(f.write_char(')')?) } else { - f.write_str(" EMPTY") + Ok(f.write_str(" EMPTY")?) } } else { - f.write_str(" EMPTY") + Ok(f.write_str(" EMPTY")?) } } pub fn write_multi_point, W: Write>( multipoint: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = multipoint.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("MULTIPOINT"), - geo_traits::Dimensions::Xyz => f.write_str("MULTIPOINT Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("MULTIPOINT") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("MULTIPOINT Z") + } geo_traits::Dimensions::Xym => f.write_str("MULTIPOINT M"), - geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOINT ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("MULTIPOINT ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); @@ -155,15 +174,21 @@ pub fn write_multi_linestring< >( multilinestring: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = multilinestring.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("MULTILINESTRING"), - geo_traits::Dimensions::Xyz => f.write_str("MULTILINESTRING Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("MULTILINESTRING") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("MULTILINESTRING Z") + } geo_traits::Dimensions::Xym => f.write_str("MULTILINESTRING M"), - geo_traits::Dimensions::Xyzm => f.write_str("MULTILINESTRING ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("MULTILINESTRING ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); let mut line_strings = multilinestring.line_strings(); @@ -187,15 +212,21 @@ pub fn write_multi_linestring< pub fn write_multi_polygon, W: Write>( multipolygon: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = multipolygon.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("MULTIPOLYGON"), - geo_traits::Dimensions::Xyz => f.write_str("MULTIPOLYGON Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("MULTIPOLYGON") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("MULTIPOLYGON Z") + } geo_traits::Dimensions::Xym => f.write_str("MULTIPOLYGON M"), - geo_traits::Dimensions::Xyzm => f.write_str("MULTIPOLYGON ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("MULTIPOLYGON ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); @@ -233,7 +264,7 @@ pub fn write_multi_polygon pub fn write_geometry, W: Write>( geometry: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { match geometry.as_type() { geo_traits::GeometryType::Point(point) => write_point(point, f), geo_traits::GeometryType::LineString(linestring) => write_linestring(linestring, f), @@ -257,15 +288,21 @@ pub fn write_geometry_collection< >( gc: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = gc.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("GEOMETRYCOLLECTION"), - geo_traits::Dimensions::Xyz => f.write_str("GEOMETRYCOLLECTION Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("GEOMETRYCOLLECTION") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("GEOMETRYCOLLECTION Z") + } geo_traits::Dimensions::Xym => f.write_str("GEOMETRYCOLLECTION M"), - geo_traits::Dimensions::Xyzm => f.write_str("GEOMETRYCOLLECTION ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("GEOMETRYCOLLECTION ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let mut geometries = gc.geometries(); @@ -330,7 +367,7 @@ fn rect_to_polygon>(rect: &G) -> P pub fn write_rect, W: Write>( rect: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let polygon = rect_to_polygon(rect); write_polygon(&polygon, f) } @@ -338,15 +375,19 @@ pub fn write_rect, W: Write>( pub fn write_triangle, W: Write>( triangle: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = triangle.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("POLYGON"), - geo_traits::Dimensions::Xyz => f.write_str("POLYGON Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => f.write_str("POLYGON"), + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("POLYGON Z") + } geo_traits::Dimensions::Xym => f.write_str("POLYGON M"), - geo_traits::Dimensions::Xyzm => f.write_str("POLYGON ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("POLYGON ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); f.write_str("(")?; @@ -357,21 +398,27 @@ pub fn write_triangle, W: Writ .chain(std::iter::once(triangle.first())); add_coord_sequence(coords_iter, f, size)?; - f.write_char(')') + Ok(f.write_char(')')?) } pub fn write_line, W: Write>( line: &G, f: &mut W, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { let dim = line.dim(); // Write prefix match dim { - geo_traits::Dimensions::Xy => f.write_str("LINESTRING"), - geo_traits::Dimensions::Xyz => f.write_str("LINESTRING Z"), + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + f.write_str("LINESTRING") + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + f.write_str("LINESTRING Z") + } geo_traits::Dimensions::Xym => f.write_str("LINESTRING M"), - geo_traits::Dimensions::Xyzm => f.write_str("LINESTRING ZM"), - geo_traits::Dimensions::Unknown(_) => todo!(), + geo_traits::Dimensions::Xyzm | geo_traits::Dimensions::Unknown(4) => { + f.write_str("LINESTRING ZM") + } + geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); add_coord_sequence(line.coords().into_iter(), f, size) @@ -422,7 +469,7 @@ fn add_coord_sequence>( mut coords: impl Iterator, f: &mut W, size: PhysicalCoordinateDimension, -) -> Result<(), std::fmt::Error> { +) -> Result<(), crate::error::Error> { f.write_char('(')?; if let Some(first_coord) = coords.next() { From 5bda2dc94cca127a125327bdeca248636bb8459d Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 14:07:01 -0500 Subject: [PATCH 12/20] Update writing rect --- src/error.rs | 4 ++-- src/to_wkt/geo_trait_impl.rs | 30 ++++++++++++++++-------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/error.rs b/src/error.rs index 23a6228..4907ba5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,8 +5,8 @@ use thiserror::Error; #[derive(Error, Debug)] /// WKT to [`geo_types`] conversions errors pub enum Error { - // #[error("The WKT Point was empty, but geo_type::Points cannot be empty")] - // RectWriter, + #[error("Only 2D input is supported when writing Rect to WKT.")] + RectUnsupportedDimension, #[error("Only defined dimensions and undefined dimensions of 2, 3, or 4 are supported.")] UnknownDimension, /// Wrapper around `[std::fmt::Error]` diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 01bee9f..eb46be0 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -8,7 +8,7 @@ use geo_traits::{ }; use crate::error::Error; -use crate::types::{Coord, LineString, Polygon}; +use crate::types::Coord; use crate::WktNum; /// The physical size of the coordinate dimension @@ -322,13 +322,21 @@ pub fn write_geometry_collection< Ok(()) } -fn rect_to_polygon>(rect: &G) -> Polygon { +pub fn write_rect, W: Write>( + rect: &G, + f: &mut W, +) -> Result<(), crate::error::Error> { + // Write prefix and error if not 2D + match rect.dim() { + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => f.write_str("POLYGON"), + _ => return Err(Error::RectUnsupportedDimension), + }?; + let min_coord = rect.min(); let max_coord = rect.max(); - // Note: Even if the rect has more than 2 dimensions, we omit the other dimensions when - // converting to a Polygon. - let coords = vec![ + // We need to construct the five points of the rect that make up the exterior Polygon + let coords = [ Coord { x: min_coord.x(), y: min_coord.y(), @@ -360,16 +368,10 @@ fn rect_to_polygon>(rect: &G) -> P m: None, }, ]; - let ring = LineString(coords); - Polygon(vec![ring]) -} -pub fn write_rect, W: Write>( - rect: &G, - f: &mut W, -) -> Result<(), crate::error::Error> { - let polygon = rect_to_polygon(rect); - write_polygon(&polygon, f) + f.write_str("(")?; + add_coord_sequence(coords.iter(), f, PhysicalCoordinateDimension::Two)?; + Ok(f.write_char(')')?) } pub fn write_triangle, W: Write>( From 96666da3f02ff7a09994ca166051b6c0eadc856c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 14:07:49 -0500 Subject: [PATCH 13/20] fix compile --- src/types/geometrycollection.rs | 2 +- src/types/linestring.rs | 2 +- src/types/multilinestring.rs | 2 +- src/types/multipoint.rs | 2 +- src/types/multipolygon.rs | 2 +- src/types/point.rs | 2 +- src/types/polygon.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index 9d06760..20b1536 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -38,7 +38,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_geometry_collection(self, f) + Ok(write_geometry_collection(self, f)?) } } diff --git a/src/types/linestring.rs b/src/types/linestring.rs index 94c8065..f67a856 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -49,7 +49,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_linestring(self, f) + Ok(write_linestring(self, f)?) } } diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index a9a3716..f197695 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_multi_linestring(self, f) + Ok(write_multi_linestring(self, f)?) } } diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index 3ff0870..40f0d17 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_multi_point(self, f) + Ok(write_multi_point(self, f)?) } } diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index f89183c..647416f 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_multi_polygon(self, f) + Ok(write_multi_polygon(self, f)?) } } diff --git a/src/types/point.rs b/src/types/point.rs index 342c6fe..10b3def 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_point(self, f) + Ok(write_point(self, f)?) } } diff --git a/src/types/polygon.rs b/src/types/polygon.rs index 3fd0a24..fa53a5a 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_polygon(self, f) + Ok(write_polygon(self, f)?) } } From 9760faf089a0134c58cdd05bddc0a9f3768ce484 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 14:09:26 -0500 Subject: [PATCH 14/20] update comment --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 4907ba5..670ce0a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,8 +2,8 @@ use core::fmt; use thiserror::Error; +/// Generic errors for WKT writing and reading #[derive(Error, Debug)] -/// WKT to [`geo_types`] conversions errors pub enum Error { #[error("Only 2D input is supported when writing Rect to WKT.")] RectUnsupportedDimension, From f140289e10726cb6ea0771846fbb045b42cb06a4 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:10:12 -0500 Subject: [PATCH 15/20] Use core::fmt --- src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 670ce0a..8c02d7e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,14 +11,14 @@ pub enum Error { UnknownDimension, /// Wrapper around `[std::fmt::Error]` #[error(transparent)] - FmtError(#[from] std::fmt::Error), + FmtError(#[from] core::fmt::Error), } impl From for fmt::Error { fn from(value: Error) -> Self { match value { Error::FmtError(err) => err, - _ => std::fmt::Error, + _ => core::fmt::Error, } } } From f4af2cf093743e0094161913de4437f702014e49 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:11:10 -0500 Subject: [PATCH 16/20] standardize on std::fmt --- src/error.rs | 6 +++--- src/to_wkt/geo_trait_impl.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8c02d7e..d34ee29 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use core::fmt; +use std::fmt; use thiserror::Error; @@ -11,14 +11,14 @@ pub enum Error { UnknownDimension, /// Wrapper around `[std::fmt::Error]` #[error(transparent)] - FmtError(#[from] core::fmt::Error), + FmtError(#[from] std::fmt::Error), } impl From for fmt::Error { fn from(value: Error) -> Self { match value { Error::FmtError(err) => err, - _ => core::fmt::Error, + _ => std::fmt::Error, } } } diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index eb46be0..5f10991 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -1,4 +1,4 @@ -use core::fmt; +use std::fmt; use std::fmt::Write; use geo_traits::{ From 11d209c3c4458a4a8c8ed44ad1f4fc188216464b Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:12:02 -0500 Subject: [PATCH 17/20] Use `Error` instead of `std::error::Error` --- src/to_wkt/geo_trait_impl.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 5f10991..6be4d56 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -62,7 +62,7 @@ pub fn write_point, W: Write>( pub fn write_linestring, W: Write>( linestring: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = linestring.dim(); // Write prefix match dim { @@ -89,7 +89,7 @@ pub fn write_linestring, W: pub fn write_polygon, W: Write>( polygon: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = polygon.dim(); // Write prefix match dim { @@ -126,7 +126,7 @@ pub fn write_polygon, W: Write> pub fn write_multi_point, W: Write>( multipoint: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = multipoint.dim(); // Write prefix match dim { @@ -174,7 +174,7 @@ pub fn write_multi_linestring< >( multilinestring: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = multilinestring.dim(); // Write prefix match dim { @@ -212,7 +212,7 @@ pub fn write_multi_linestring< pub fn write_multi_polygon, W: Write>( multipolygon: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = multipolygon.dim(); // Write prefix match dim { @@ -264,7 +264,7 @@ pub fn write_multi_polygon pub fn write_geometry, W: Write>( geometry: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { match geometry.as_type() { geo_traits::GeometryType::Point(point) => write_point(point, f), geo_traits::GeometryType::LineString(linestring) => write_linestring(linestring, f), @@ -288,7 +288,7 @@ pub fn write_geometry_collection< >( gc: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = gc.dim(); // Write prefix match dim { @@ -325,7 +325,7 @@ pub fn write_geometry_collection< pub fn write_rect, W: Write>( rect: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { // Write prefix and error if not 2D match rect.dim() { geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => f.write_str("POLYGON"), @@ -377,7 +377,7 @@ pub fn write_rect, W: Write>( pub fn write_triangle, W: Write>( triangle: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = triangle.dim(); // Write prefix match dim { @@ -406,7 +406,7 @@ pub fn write_triangle, W: Writ pub fn write_line, W: Write>( line: &G, f: &mut W, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { let dim = line.dim(); // Write prefix match dim { @@ -471,7 +471,7 @@ fn add_coord_sequence>( mut coords: impl Iterator, f: &mut W, size: PhysicalCoordinateDimension, -) -> Result<(), crate::error::Error> { +) -> Result<(), Error> { f.write_char('(')?; if let Some(first_coord) = coords.next() { From 6f49994efe654148dd28b87be83784873d880056 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:12:37 -0500 Subject: [PATCH 18/20] add_coord -> write_coord --- src/to_wkt/geo_trait_impl.rs | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 6be4d56..686ebea 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -51,7 +51,7 @@ pub fn write_point, W: Write>( let size = PhysicalCoordinateDimension::from(dim); if let Some(coord) = g.coord() { f.write_char('(')?; - add_coord(&coord, f, size)?; + write_coord(&coord, f, size)?; f.write_char(')')?; Ok(()) } else { @@ -82,7 +82,7 @@ pub fn write_linestring, W: if linestring.num_coords() == 0 { Ok(f.write_str(" EMPTY")?) } else { - add_coord_sequence(linestring.coords(), f, size) + write_coord_sequence(linestring.coords(), f, size) } } @@ -107,11 +107,11 @@ pub fn write_polygon, W: Write> if let Some(exterior) = polygon.exterior() { if exterior.num_coords() != 0 { f.write_str("(")?; - add_coord_sequence(exterior.coords(), f, size)?; + write_coord_sequence(exterior.coords(), f, size)?; for interior in polygon.interiors() { f.write_char(',')?; - add_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(interior.coords(), f, size)?; } Ok(f.write_char(')')?) @@ -146,17 +146,17 @@ pub fn write_multi_point, W: let mut points = multipoint.points(); - // Note: This is largely copied from `add_coord_sequence`, because `multipoint.points()` + // Note: This is largely copied from `write_coord_sequence`, because `multipoint.points()` // yields a sequence of Point, not Coord. if let Some(first_point) = points.next() { f.write_str("((")?; // Assume no empty points within this MultiPoint - add_coord(&first_point.coord().unwrap(), f, size)?; + write_coord(&first_point.coord().unwrap(), f, size)?; for point in points { f.write_str("),(")?; - add_coord(&point.coord().unwrap(), f, size)?; + write_coord(&point.coord().unwrap(), f, size)?; } f.write_str("))")?; @@ -194,11 +194,11 @@ pub fn write_multi_linestring< let mut line_strings = multilinestring.line_strings(); if let Some(first_linestring) = line_strings.next() { f.write_str("(")?; - add_coord_sequence(first_linestring.coords(), f, size)?; + write_coord_sequence(first_linestring.coords(), f, size)?; for linestring in line_strings { f.write_char(',')?; - add_coord_sequence(linestring.coords(), f, size)?; + write_coord_sequence(linestring.coords(), f, size)?; } f.write_char(')')?; @@ -235,19 +235,19 @@ pub fn write_multi_polygon if let Some(first_polygon) = polygons.next() { f.write_str("((")?; - add_coord_sequence(first_polygon.exterior().unwrap().coords(), f, size)?; + write_coord_sequence(first_polygon.exterior().unwrap().coords(), f, size)?; for interior in first_polygon.interiors() { f.write_char(',')?; - add_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(interior.coords(), f, size)?; } for polygon in polygons { f.write_str("),(")?; - add_coord_sequence(polygon.exterior().unwrap().coords(), f, size)?; + write_coord_sequence(polygon.exterior().unwrap().coords(), f, size)?; for interior in polygon.interiors() { f.write_char(',')?; - add_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(interior.coords(), f, size)?; } } @@ -370,7 +370,7 @@ pub fn write_rect, W: Write>( ]; f.write_str("(")?; - add_coord_sequence(coords.iter(), f, PhysicalCoordinateDimension::Two)?; + write_coord_sequence(coords.iter(), f, PhysicalCoordinateDimension::Two)?; Ok(f.write_char(')')?) } @@ -398,7 +398,7 @@ pub fn write_triangle, W: Writ .coords() .into_iter() .chain(std::iter::once(triangle.first())); - add_coord_sequence(coords_iter, f, size)?; + write_coord_sequence(coords_iter, f, size)?; Ok(f.write_char(')')?) } @@ -423,13 +423,13 @@ pub fn write_line, W: Write>( geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); - add_coord_sequence(line.coords().into_iter(), f, size) + write_coord_sequence(line.coords().into_iter(), f, size) } /// Write a single coordinate to the writer. /// /// Will not include any start or end `()` characters. -fn add_coord, W: Write>( +fn write_coord, W: Write>( coord: &G, f: &mut W, size: PhysicalCoordinateDimension, @@ -467,7 +467,7 @@ fn add_coord, W: Write>( /// (1 2, 3 4, 5 6) /// ``` /// for a coordinate sequence with three coordinates. -fn add_coord_sequence>( +fn write_coord_sequence>( mut coords: impl Iterator, f: &mut W, size: PhysicalCoordinateDimension, @@ -475,11 +475,11 @@ fn add_coord_sequence>( f.write_char('(')?; if let Some(first_coord) = coords.next() { - add_coord(&first_coord, f, size)?; + write_coord(&first_coord, f, size)?; for coord in coords { f.write_char(',')?; - add_coord(&coord, f, size)?; + write_coord(&coord, f, size)?; } } From aee9ab30591bb97716bbdf0aaca4844623a3f126 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:17:07 -0500 Subject: [PATCH 19/20] Inline impl Write --- src/to_wkt/geo_trait_impl.rs | 60 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 686ebea..3e0ec5e 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -33,9 +33,9 @@ impl From for PhysicalCoordinateDimension { } } -pub fn write_point, W: Write>( +pub fn write_point>( g: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = g.dim(); // Write prefix @@ -59,9 +59,9 @@ pub fn write_point, W: Write>( } } -pub fn write_linestring, W: Write>( +pub fn write_linestring>( linestring: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = linestring.dim(); // Write prefix @@ -86,9 +86,9 @@ pub fn write_linestring, W: } } -pub fn write_polygon, W: Write>( +pub fn write_polygon>( polygon: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = polygon.dim(); // Write prefix @@ -123,9 +123,9 @@ pub fn write_polygon, W: Write> } } -pub fn write_multi_point, W: Write>( +pub fn write_multi_point>( multipoint: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = multipoint.dim(); // Write prefix @@ -167,13 +167,9 @@ pub fn write_multi_point, W: Ok(()) } -pub fn write_multi_linestring< - T: WktNum + fmt::Display, - G: MultiLineStringTrait, - W: Write, ->( +pub fn write_multi_linestring>( multilinestring: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = multilinestring.dim(); // Write prefix @@ -209,9 +205,9 @@ pub fn write_multi_linestring< Ok(()) } -pub fn write_multi_polygon, W: Write>( +pub fn write_multi_polygon>( multipolygon: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = multipolygon.dim(); // Write prefix @@ -261,9 +257,9 @@ pub fn write_multi_polygon /// Create geometry to WKT representation. -pub fn write_geometry, W: Write>( +pub fn write_geometry>( geometry: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { match geometry.as_type() { geo_traits::GeometryType::Point(point) => write_point(point, f), @@ -281,13 +277,9 @@ pub fn write_geometry, W: Writ } } -pub fn write_geometry_collection< - T: WktNum + fmt::Display, - G: GeometryCollectionTrait, - W: Write, ->( +pub fn write_geometry_collection>( gc: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = gc.dim(); // Write prefix @@ -322,9 +314,9 @@ pub fn write_geometry_collection< Ok(()) } -pub fn write_rect, W: Write>( +pub fn write_rect>( rect: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { // Write prefix and error if not 2D match rect.dim() { @@ -374,9 +366,9 @@ pub fn write_rect, W: Write>( Ok(f.write_char(')')?) } -pub fn write_triangle, W: Write>( +pub fn write_triangle>( triangle: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = triangle.dim(); // Write prefix @@ -403,9 +395,9 @@ pub fn write_triangle, W: Writ Ok(f.write_char(')')?) } -pub fn write_line, W: Write>( +pub fn write_line>( line: &G, - f: &mut W, + f: &mut impl Write, ) -> Result<(), Error> { let dim = line.dim(); // Write prefix @@ -429,9 +421,9 @@ pub fn write_line, W: Write>( /// Write a single coordinate to the writer. /// /// Will not include any start or end `()` characters. -fn write_coord, W: Write>( +fn write_coord>( coord: &G, - f: &mut W, + f: &mut impl Write, size: PhysicalCoordinateDimension, ) -> Result<(), std::fmt::Error> { match size { @@ -467,9 +459,9 @@ fn write_coord, W: Write>( /// (1 2, 3 4, 5 6) /// ``` /// for a coordinate sequence with three coordinates. -fn write_coord_sequence>( +fn write_coord_sequence>( mut coords: impl Iterator, - f: &mut W, + f: &mut impl Write, size: PhysicalCoordinateDimension, ) -> Result<(), Error> { f.write_char('(')?; From 6ab501c4ef3f9b1c70fa4012d7f1671a1cbb742f Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 26 Nov 2024 15:21:23 -0500 Subject: [PATCH 20/20] reorder writer param --- benches/write.rs | 4 +- src/lib.rs | 2 +- src/to_wkt/geo_trait_impl.rs | 84 ++++++++++++++++----------------- src/types/geometrycollection.rs | 2 +- src/types/linestring.rs | 2 +- src/types/multilinestring.rs | 2 +- src/types/multipoint.rs | 2 +- src/types/multipolygon.rs | 2 +- src/types/point.rs | 2 +- src/types/polygon.rs | 2 +- 10 files changed, 52 insertions(+), 52 deletions(-) diff --git a/benches/write.rs b/benches/write.rs index 60040d6..f46c0ab 100644 --- a/benches/write.rs +++ b/benches/write.rs @@ -70,7 +70,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::write_geometry(&g, &mut String::new()).unwrap(); + wkt::to_wkt::write_geometry(&mut String::new(), &g).unwrap(); }); }); @@ -79,7 +79,7 @@ fn geo_write_wkt_as_trait(c: &mut criterion::Criterion) { let w = wkt::Wkt::::from_str(s).unwrap(); let g = geo_types::Geometry::try_from(w).unwrap(); bencher.iter(|| { - wkt::to_wkt::write_geometry(&g, &mut String::new()).unwrap(); + wkt::to_wkt::write_geometry(&mut String::new(), &g).unwrap(); }); }); } diff --git a/src/lib.rs b/src/lib.rs index 3d6122b..d0c6680 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_geometry(self, f)?) + Ok(write_geometry(f, self)?) } } diff --git a/src/to_wkt/geo_trait_impl.rs b/src/to_wkt/geo_trait_impl.rs index 3e0ec5e..b6ec9a1 100644 --- a/src/to_wkt/geo_trait_impl.rs +++ b/src/to_wkt/geo_trait_impl.rs @@ -34,8 +34,8 @@ impl From for PhysicalCoordinateDimension { } pub fn write_point>( - g: &G, f: &mut impl Write, + g: &G, ) -> Result<(), Error> { let dim = g.dim(); // Write prefix @@ -51,7 +51,7 @@ pub fn write_point>( let size = PhysicalCoordinateDimension::from(dim); if let Some(coord) = g.coord() { f.write_char('(')?; - write_coord(&coord, f, size)?; + write_coord(f, &coord, size)?; f.write_char(')')?; Ok(()) } else { @@ -60,8 +60,8 @@ pub fn write_point>( } pub fn write_linestring>( - linestring: &G, f: &mut impl Write, + linestring: &G, ) -> Result<(), Error> { let dim = linestring.dim(); // Write prefix @@ -82,13 +82,13 @@ pub fn write_linestring>( if linestring.num_coords() == 0 { Ok(f.write_str(" EMPTY")?) } else { - write_coord_sequence(linestring.coords(), f, size) + write_coord_sequence(f, linestring.coords(), size) } } pub fn write_polygon>( - polygon: &G, f: &mut impl Write, + polygon: &G, ) -> Result<(), Error> { let dim = polygon.dim(); // Write prefix @@ -107,11 +107,11 @@ pub fn write_polygon>( if let Some(exterior) = polygon.exterior() { if exterior.num_coords() != 0 { f.write_str("(")?; - write_coord_sequence(exterior.coords(), f, size)?; + write_coord_sequence(f, exterior.coords(), size)?; for interior in polygon.interiors() { f.write_char(',')?; - write_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(f, interior.coords(), size)?; } Ok(f.write_char(')')?) @@ -124,8 +124,8 @@ pub fn write_polygon>( } pub fn write_multi_point>( - multipoint: &G, f: &mut impl Write, + multipoint: &G, ) -> Result<(), Error> { let dim = multipoint.dim(); // Write prefix @@ -152,11 +152,11 @@ pub fn write_multi_point>( f.write_str("((")?; // Assume no empty points within this MultiPoint - write_coord(&first_point.coord().unwrap(), f, size)?; + write_coord(f, &first_point.coord().unwrap(), size)?; for point in points { f.write_str("),(")?; - write_coord(&point.coord().unwrap(), f, size)?; + write_coord(f, &point.coord().unwrap(), size)?; } f.write_str("))")?; @@ -168,8 +168,8 @@ pub fn write_multi_point>( } pub fn write_multi_linestring>( - multilinestring: &G, f: &mut impl Write, + multilinestring: &G, ) -> Result<(), Error> { let dim = multilinestring.dim(); // Write prefix @@ -190,11 +190,11 @@ pub fn write_multi_linestring>( - multipolygon: &G, f: &mut impl Write, + multipolygon: &G, ) -> Result<(), Error> { let dim = multipolygon.dim(); // Write prefix @@ -231,19 +231,19 @@ pub fn write_multi_polygon if let Some(first_polygon) = polygons.next() { f.write_str("((")?; - write_coord_sequence(first_polygon.exterior().unwrap().coords(), f, size)?; + write_coord_sequence(f, first_polygon.exterior().unwrap().coords(), size)?; for interior in first_polygon.interiors() { f.write_char(',')?; - write_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(f, interior.coords(), size)?; } for polygon in polygons { f.write_str("),(")?; - write_coord_sequence(polygon.exterior().unwrap().coords(), f, size)?; + write_coord_sequence(f, polygon.exterior().unwrap().coords(), size)?; for interior in polygon.interiors() { f.write_char(',')?; - write_coord_sequence(interior.coords(), f, size)?; + write_coord_sequence(f, interior.coords(), size)?; } } @@ -258,28 +258,28 @@ pub fn write_multi_polygon /// Create geometry to WKT representation. pub fn write_geometry>( - geometry: &G, f: &mut impl Write, + geometry: &G, ) -> Result<(), Error> { match geometry.as_type() { - geo_traits::GeometryType::Point(point) => write_point(point, f), - geo_traits::GeometryType::LineString(linestring) => write_linestring(linestring, f), - geo_traits::GeometryType::Polygon(polygon) => write_polygon(polygon, f), - geo_traits::GeometryType::MultiPoint(multi_point) => write_multi_point(multi_point, f), - geo_traits::GeometryType::MultiLineString(mls) => write_multi_linestring(mls, f), + geo_traits::GeometryType::Point(point) => write_point(f, point), + geo_traits::GeometryType::LineString(linestring) => write_linestring(f, linestring), + geo_traits::GeometryType::Polygon(polygon) => write_polygon(f, polygon), + geo_traits::GeometryType::MultiPoint(multi_point) => write_multi_point(f, multi_point), + geo_traits::GeometryType::MultiLineString(mls) => write_multi_linestring(f, mls), geo_traits::GeometryType::MultiPolygon(multi_polygon) => { - write_multi_polygon(multi_polygon, f) + write_multi_polygon(f, multi_polygon) } - geo_traits::GeometryType::GeometryCollection(gc) => write_geometry_collection(gc, f), - geo_traits::GeometryType::Rect(rect) => write_rect(rect, f), - geo_traits::GeometryType::Triangle(triangle) => write_triangle(triangle, f), - geo_traits::GeometryType::Line(line) => write_line(line, f), + geo_traits::GeometryType::GeometryCollection(gc) => write_geometry_collection(f, gc), + geo_traits::GeometryType::Rect(rect) => write_rect(f, rect), + geo_traits::GeometryType::Triangle(triangle) => write_triangle(f, triangle), + geo_traits::GeometryType::Line(line) => write_line(f, line), } } pub fn write_geometry_collection>( - gc: &G, f: &mut impl Write, + gc: &G, ) -> Result<(), Error> { let dim = gc.dim(); // Write prefix @@ -301,10 +301,10 @@ pub fn write_geometry_collection>( - rect: &G, f: &mut impl Write, + rect: &G, ) -> Result<(), Error> { // Write prefix and error if not 2D match rect.dim() { @@ -362,13 +362,13 @@ pub fn write_rect>( ]; f.write_str("(")?; - write_coord_sequence(coords.iter(), f, PhysicalCoordinateDimension::Two)?; + write_coord_sequence(f, coords.iter(), PhysicalCoordinateDimension::Two)?; Ok(f.write_char(')')?) } pub fn write_triangle>( - triangle: &G, f: &mut impl Write, + triangle: &G, ) -> Result<(), Error> { let dim = triangle.dim(); // Write prefix @@ -390,14 +390,14 @@ pub fn write_triangle>( .coords() .into_iter() .chain(std::iter::once(triangle.first())); - write_coord_sequence(coords_iter, f, size)?; + write_coord_sequence(f, coords_iter, size)?; Ok(f.write_char(')')?) } pub fn write_line>( - line: &G, f: &mut impl Write, + line: &G, ) -> Result<(), Error> { let dim = line.dim(); // Write prefix @@ -415,15 +415,15 @@ pub fn write_line>( geo_traits::Dimensions::Unknown(_) => return Err(Error::UnknownDimension), }?; let size = PhysicalCoordinateDimension::from(dim); - write_coord_sequence(line.coords().into_iter(), f, size) + write_coord_sequence(f, line.coords().into_iter(), size) } /// Write a single coordinate to the writer. /// /// Will not include any start or end `()` characters. fn write_coord>( - coord: &G, f: &mut impl Write, + coord: &G, size: PhysicalCoordinateDimension, ) -> Result<(), std::fmt::Error> { match size { @@ -460,18 +460,18 @@ fn write_coord>( /// ``` /// for a coordinate sequence with three coordinates. fn write_coord_sequence>( - mut coords: impl Iterator, f: &mut impl Write, + mut coords: impl Iterator, size: PhysicalCoordinateDimension, ) -> Result<(), Error> { f.write_char('(')?; if let Some(first_coord) = coords.next() { - write_coord(&first_coord, f, size)?; + write_coord(f, &first_coord, size)?; for coord in coords { f.write_char(',')?; - write_coord(&coord, f, size)?; + write_coord(f, &coord, size)?; } } diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index 20b1536..04e3606 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -38,7 +38,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_geometry_collection(self, f)?) + Ok(write_geometry_collection(f, self)?) } } diff --git a/src/types/linestring.rs b/src/types/linestring.rs index f67a856..248771e 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -49,7 +49,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_linestring(self, f)?) + Ok(write_linestring(f, self)?) } } diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index f197695..bad491c 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_multi_linestring(self, f)?) + Ok(write_multi_linestring(f, self)?) } } diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index 40f0d17..b189afa 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_multi_point(self, f)?) + Ok(write_multi_point(f, self)?) } } diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index 647416f..e9e2619 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_multi_polygon(self, f)?) + Ok(write_multi_polygon(f, self)?) } } diff --git a/src/types/point.rs b/src/types/point.rs index 10b3def..b610612 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_point(self, f)?) + Ok(write_point(f, self)?) } } diff --git a/src/types/polygon.rs b/src/types/polygon.rs index fa53a5a..b55a3ec 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -39,7 +39,7 @@ where T: WktNum + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Ok(write_polygon(self, f)?) + Ok(write_polygon(f, self)?) } }