From 24ec61afeeffc5b1efa0bf3d7de04aa0791cf7ff Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 1 May 2022 23:13:54 +0200 Subject: [PATCH 01/22] Add experimental event API --- geozero/src/bbox.rs | 185 ++++++++ geozero/src/chaining.rs | 189 +++++++++ geozero/src/events.rs | 679 ++++++++++++++++++++++++++++++ geozero/src/geometry_processor.rs | 2 +- geozero/src/lib.rs | 3 + 5 files changed, 1057 insertions(+), 1 deletion(-) create mode 100644 geozero/src/bbox.rs create mode 100644 geozero/src/chaining.rs create mode 100644 geozero/src/events.rs diff --git a/geozero/src/bbox.rs b/geozero/src/bbox.rs new file mode 100644 index 00000000..5c62b0f8 --- /dev/null +++ b/geozero/src/bbox.rs @@ -0,0 +1,185 @@ +use crate::error::Result; +use crate::GeomProcessor; + +#[derive(Clone, PartialEq, Debug)] +/// Bounding Box +pub struct Bbox { + pub min_x: f64, + pub min_y: f64, + pub max_x: f64, + pub max_y: f64, +} + +impl Default for Bbox { + fn default() -> Self { + Bbox { + min_x: f64::INFINITY, + min_y: f64::INFINITY, + max_x: f64::NEG_INFINITY, + max_y: f64::NEG_INFINITY, + } + } +} + +impl Bbox { + pub fn new(min_x: f64, min_y: f64, max_x: f64, max_y: f64) -> Bbox { + Bbox { + min_x, + min_y, + max_x, + max_y, + } + } + + pub fn reset(&mut self) { + self.min_x = f64::INFINITY; + self.min_y = f64::INFINITY; + self.max_x = f64::NEG_INFINITY; + self.max_y = f64::NEG_INFINITY; + } + + pub fn width(&self) -> f64 { + self.max_x - self.min_x + } + + pub fn height(&self) -> f64 { + self.max_y - self.min_y + } + + pub fn sum(mut a: Bbox, b: &Bbox) -> Bbox { + a.expand(b); + a + } + + pub fn expand(&mut self, r: &Bbox) { + if r.min_x < self.min_x { + self.min_x = r.min_x; + } + if r.min_y < self.min_y { + self.min_y = r.min_y; + } + if r.max_x > self.max_x { + self.max_x = r.max_x; + } + if r.max_y > self.max_y { + self.max_y = r.max_y; + } + } + + pub fn expand_xy(&mut self, x: f64, y: f64) { + if x < self.min_x { + self.min_x = x; + } + if y < self.min_y { + self.min_y = y; + } + if x > self.max_x { + self.max_x = x; + } + if y > self.max_y { + self.max_y = y; + } + } + + pub fn intersects(&self, r: &Bbox) -> bool { + if self.max_x < r.min_x { + return false; + } + if self.max_y < r.min_y { + return false; + } + if self.min_x > r.max_x { + return false; + } + if self.min_y > r.max_y { + return false; + } + true + } +} + +impl GeomProcessor for Bbox { + fn xy(&mut self, x: f64, y: f64, _idx: usize) -> Result<()> { + self.expand_xy(x, y); + Ok(()) + } + fn coordinate( + &mut self, + x: f64, + y: f64, + _z: Option, + _m: Option, + _t: Option, + _tm: Option, + _idx: usize, + ) -> Result<()> { + self.expand_xy(x, y); + Ok(()) + } + fn point_begin(&mut self, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn multipoint_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn linestring_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { + if tagged { + self.reset(); + } + Ok(()) + } + fn multilinestring_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn polygon_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { + if tagged { + self.reset(); + } + Ok(()) + } + fn multipolygon_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn geometrycollection_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn circularstring_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn compoundcurve_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn curvepolygon_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn multicurve_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn multisurface_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn triangle_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { + if tagged { + self.reset(); + } + Ok(()) + } + fn polyhedralsurface_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } + fn tin_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { + self.reset(); + Ok(()) + } +} diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs new file mode 100644 index 00000000..a5b07fc5 --- /dev/null +++ b/geozero/src/chaining.rs @@ -0,0 +1,189 @@ +//! Chaining and duplexing processors. + +use crate::error::Result; +use crate::events::GeomEventProcessor; +use crate::events::*; + +// ------- Chain events ------- + +/// Processing geometry events and passing events to a chained visitor +pub trait CĥainedGeomEventProcessor { + /// Geometry processing event with geometry type information + fn chain_event( + &mut self, + event: Event, + geom_type: GeometryType, + collection: bool, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()>; +} + +/// Chaining [GeomEventProcessor] +pub struct ChainedProcessor<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> { + processor1: &'a mut P1, + visitor: GeomVisitor<'a, P2>, +} + +impl<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor<'a, P1, P2> { + pub fn new(processor1: &'a mut P1, processor2: &'a mut P2) -> Self { + ChainedProcessor { + processor1, + visitor: GeomVisitor::new(processor2), + } + } +} + +impl<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor + for ChainedProcessor<'a, P1, P2> +{ + fn event( + &mut self, + event: Event, + geom_type: GeometryType, + collection: bool, + ) -> crate::error::Result<()> { + self.processor1 + .chain_event(event, geom_type, collection, &mut self.visitor) + } +} + +// ------- Duplex --------- + +/// Duplexing [GeomEventProcessor] +pub struct DuplexProcessor<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> { + processor1: &'a mut P1, + processor2: &'a mut P2, +} + +impl<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> DuplexProcessor<'a, P1, P2> { + pub fn new(processor1: &'a mut P1, processor2: &'a mut P2) -> Self { + DuplexProcessor { + processor1, + processor2, + } + } +} + +impl<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor + for DuplexProcessor<'a, P1, P2> +{ + fn event( + &mut self, + event: Event, + geom_type: GeometryType, + collection: bool, + ) -> crate::error::Result<()> { + self.processor1 + .event(event.clone(), geom_type, collection)?; + self.processor2.event(event, geom_type, collection)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::error::Result; + use crate::events::test::{GeomEventBuffer, NullIsland}; + use crate::events::Event::*; + use crate::events::GeomEventSink; + + pub struct PromoteToMulti; + impl CĥainedGeomEventProcessor for PromoteToMulti { + fn chain_event( + &mut self, + event: Event, + geom_type: GeometryType, + _collection: bool, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()> { + match event { + PointBegin(idx) if geom_type == GeometryType::Point => { + visitor.multipoint_begin(1, idx)?; + visitor.point_begin(0)?; + } + PointEnd(idx) if geom_type == GeometryType::Point => { + visitor.point_end(0)?; + visitor.multipoint_end(idx)?; + } + _ => visitor.emit(event)?, + } + Ok(()) + } + } + + #[test] + fn chained_processor() -> Result<()> { + let mut processor1 = PromoteToMulti; + let mut processor2 = GeomEventBuffer::new(); + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + let mut visitor = GeomVisitor::new(&mut processor); + + let mut geom = NullIsland; + geom.process_geom(&mut visitor)?; + + assert_eq!( + processor2.buffer, + [ + MultiPointBegin(1, 0), + PointBegin(0), + Xy(0.0, 0.0, 0), + PointEnd(0), + MultiPointEnd(0) + ] + ); + + Ok(()) + } + + #[test] + fn duplex_processor() -> Result<()> { + let mut processor1 = GeomEventSink; + let mut processor2 = GeomEventBuffer::new(); + let mut processor = DuplexProcessor::new(&mut processor1, &mut processor2); + let mut visitor = GeomVisitor::new(&mut processor); + + let mut geom = NullIsland; + geom.process_geom(&mut visitor)?; + + assert_eq!( + processor2.buffer, + [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] + ); + + Ok(()) + } + + #[test] + fn chain_and_duplex() -> Result<()> { + // geom ------+----> PromotToMulti (1a) ----> GeomEventBuffer (2a) + // | + // +----> GeomEventBuffer (1b) + let mut processor1a = PromoteToMulti; + let mut processor2a = GeomEventBuffer::new(); + let mut processor_a = ChainedProcessor::new(&mut processor1a, &mut processor2a); + let mut processor1b = GeomEventBuffer::new(); + let mut processor = DuplexProcessor::new(&mut processor_a, &mut processor1b); + let mut visitor = GeomVisitor::new(&mut processor); + + let mut geom = NullIsland; + geom.process_geom(&mut visitor)?; + + assert_eq!( + processor2a.buffer, + [ + MultiPointBegin(1, 0), + PointBegin(0), + Xy(0.0, 0.0, 0), + PointEnd(0), + MultiPointEnd(0) + ] + ); + assert_eq!( + processor1b.buffer, + [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] + ); + + Ok(()) + } +} diff --git a/geozero/src/events.rs b/geozero/src/events.rs new file mode 100644 index 00000000..38fbaac3 --- /dev/null +++ b/geozero/src/events.rs @@ -0,0 +1,679 @@ +//! Traits for reading and creating geomeries. +//! +//! Main traits: +//! * [GeometryReader]: Reading geometries by passing events to a visitor object +//! * [GeomEventProcessor]: Processing geometry events, e.g. for producing an output geometry +//! +//! Main structs: +//! * [GeomVisitor]: Geometry visitor emitting events to a [GeomEventProcessor] +//! +//! ```md +//! Geometry ---------------> GeomVisitor +//! GeometryReader -------------------> Geometry +//! GeomEventProcessor +//! ``` +// +// GeomProcessor API: +// ```md +// Geometry ----------------> -------------------> Geometry +// GeozeroGeometry GeomProcessor +// ``` + +use crate::error::{GeozeroError, Result}; +use crate::GeomProcessor; + +/// Geometry processing events +/// +/// State machine: +/// ```md +/// +-----------------+ +/// | | +/// | Initial <-------------+ +/// | | | +/// +--------^--------+ +--------v---------+ +/// | | | +/// +-+-+-+-+-+ |GeometryCollection| +/// | | | | | | | | +/// v v v v v v +--------^---------+ +/// +-----------------+ | +/// | | +-+-+-+-+-+ +/// | MultiPolygon | | | | | | | +/// | | v v v v v v +/// +--------^--------+ +-----------------+ +-----------------+ +/// | | | | | +/// | | MultiLineString | | MultiPoint | +/// +--------v--------+ | | | | +/// | | +--------^--------+ +--------^--------+ +/// | Polygon | | | +/// | | | | +/// +--------^--------+ +--------v--------+ +--------v--------+ +/// | | | | | +/// +----------->| LineString | | Point | +/// | | | | +/// +--------+--------+ +-----------------+ +--------+--------+ +/// | | | | +/// +------------> Coordinate <------------+ +/// | | +/// +-----------------+ +/// ``` +#[derive(Clone, PartialEq, Debug)] +pub enum Event { + /// Coordinate with x,y dimensions (x, y, idx) + Xy(f64, f64, usize), + /// Coordinate with all requested dimensions (x, y, z, m, t, tm, idx) + Coordinate( + f64, + f64, + Option, + Option, + Option, + Option, + usize, + ), + /// Empty coordinates, like WKT's `POINT EMPTY` (idx) + EmptyPoint(usize), + /// Begin of Point (idx) + PointBegin(usize), + /// End of Point (idx) + PointEnd(usize), + /// Begin of MultiPoint (size, idx) + MultiPointBegin(usize, usize), + /// End of MultiPoint (idx) + MultiPointEnd(usize), + /// Begin of LineString (size, idx) + /// + /// Can be also a Polygon ring or part of a MultiLineString + LineStringBegin(usize, usize), + /// End of LineString (idx) + LineStringEnd(usize), + /// Begin of MultiLineString (size, idx) + MultiLineStringBegin(usize, usize), + /// End of MultiLineString (idx) + MultiLineStringEnd(usize), + /// Begin of Polygon (size, idx) + PolygonBegin(usize, usize), + /// End of Polygon (idx) + PolygonEnd(usize), + /// Begin of MultiPolygon (size, idx) + MultiPolygonBegin(usize, usize), + /// End of MultiPolygon (idx) + MultiPolygonEnd(usize), + /// Begin of GeometryCollection (size, idx) + GeometryCollectionBegin(usize, usize), + /// End of GeometryCollection (idx) + GeometryCollectionEnd(usize), + /// Begin of CircularString (size, idx) + /// + /// The CircularString is the basic curve type, similar to a LineString in the linear world. A single segment required three points, the start and end points (first and third) and any other point on the arc. The exception to this is for a closed circle, where the start and end points are the same. In this case the second point MUST be the center of the arc, ie the opposite side of the circle. To chain arcs together, the last point of the previous arc becomes the first point of the next arc, just like in LineString. This means that a valid circular string must have an odd number of points greated than 1. + CircularStringBegin(usize, usize), + /// End of CircularString (idx) + CircularStringEnd(usize), + /// Begin of CompoundCurve (size, idx) + /// + /// A compound curve is a single, continuous curve that has both curved (circular) segments and linear segments. That means that in addition to having well-formed components, the end point of every component (except the last) must be coincident with the start point of the following component. + CompoundCurveBegin(usize, usize), + /// End of CompoundCurve (idx) + CompoundCurveEnd(usize), + /// Begin of CurvePolygon (size, idx) + /// + /// A CurvePolygon is just like a polygon, with an outer ring and zero or more inner rings. The difference is that a ring can take the form of a circular string, linear string or compound string. + CurvePolygonBegin(usize, usize), + /// End of CurvePolygon (idx) + CurvePolygonEnd(usize), + /// Begin of MultiCurve (size, idx) + /// + /// The MultiCurve is a collection of curves, which can include linear strings, circular strings or compound strings. + MultiCurveBegin(usize, usize), + /// End of MultiCurve (idx) + MultiCurveEnd(usize), + /// Begin of MultiSurface (size, idx) + /// + /// The MultiSurface is a collection of surfaces, which can be (linear) polygons or curve polygons. + MultiSurfaceBegin(usize, usize), + /// End of MultiSurface (idx) + MultiSurfaceEnd(usize), + /// Begin of Triangle (size, idx) + /// + /// An untagged Triangle is part of a Tin + TriangleBegin(usize, usize), + /// End of Triangle (idx) + TriangleEnd(usize), + /// Begin of PolyhedralSurface (size, idx) + PolyhedralSurfaceBegin(usize, usize), + /// End of PolyhedralSurface (idx) + PolyhedralSurfaceEnd(usize), + /// Begin of Tin (size, idx) + TinBegin(usize, usize), + /// End of Tin (idx) + TinEnd(usize), +} + +/// Main Geometry type +/// +/// This is the first state after `Initial` or `GeometryCollection` +/// according to the state diagram of [Event] +// WKB Types according to OGC 06-103r4 () +#[derive(PartialEq, Copy, Clone, Debug)] +pub enum GeometryType { + Unknown, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + //GeometryCollection, + CircularString, + CompoundCurve, + CurvePolygon, + MultiCurve, + MultiSurface, + Curve, + Surface, + PolyhedralSurface, + Tin, + Triangle, +} + +/// Geometry visitor emitting events to a processor +pub struct GeomVisitor<'a, P: GeomEventProcessor> { + // pub dims: CoordDimensions, + /// Main geometry type + geom_type: GeometryType, + /// Geometry is part of collection + collection: bool, + processor: &'a mut P, +} + +/// Processing geometry events, e.g. for producing an output geometry +pub trait GeomEventProcessor { + /// Geometry processing event with geometry type information + fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()>; +} + +/// Geometry processor without any actions +pub struct GeomEventSink; + +impl GeomEventProcessor for GeomEventSink { + fn event(&mut self, _event: Event, _geom_type: GeometryType, _collection: bool) -> Result<()> { + Ok(()) + } +} + +/// Reading geometries by passing events to a visitor object +pub trait GeometryReader { + /// Process geometry. + fn process_geom( + &mut self, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()>; +} + +impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { + pub fn new(processor: &'a mut P) -> Self { + GeomVisitor { + geom_type: GeometryType::Unknown, + collection: false, + processor, + } + } + pub fn emit(&mut self, event: Event) -> Result<()> { + self.processor.event(event, self.geom_type, self.collection) + } + fn set_type(&mut self, inner_type: GeometryType) -> Result<()> { + match self.geom_type { + GeometryType::Unknown => { + self.geom_type = inner_type; + } + _ if self.collection => { + // new type within collection + self.geom_type = inner_type; + } + _ => { + // type already defined (check if self.geom_type = match inner_type ?) + } + } + Ok(()) + } + fn check_type(&self, geom_type: GeometryType) -> Result<()> { + if self.geom_type == geom_type { + Ok(()) + } else { + self.type_seq_err() + } + } + fn type_seq_err(&self) -> Result<()> { + // TODO: unexpected event in self.geom_type + Err(GeozeroError::GeometryFormat) + } + + /// Process coordinate with x,y dimensions + pub fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { + self.emit(Event::Xy(x, y, idx))?; + Ok(()) + } + + /// Process coordinate with all requested dimensions + pub fn coordinate( + &mut self, + x: f64, + y: f64, + z: Option, + m: Option, + t: Option, + tm: Option, + idx: usize, + ) -> Result<()> { + self.emit(Event::Coordinate(x, y, z, m, t, tm, idx))?; + Ok(()) + } + /// Begin of Point processing + pub fn point_begin(&mut self, idx: usize) -> Result<()> { + self.set_type(GeometryType::Point)?; + self.emit(Event::PointBegin(idx))?; + Ok(()) + } + + /// End of Point processing + pub fn point_end(&mut self, idx: usize) -> Result<()> { + // self.check_type(GeometryType::Point)?; || MultiPoint, etc. + self.emit(Event::PointEnd(idx))?; + Ok(()) + } + + pub fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::MultiPoint)?; + self.emit(Event::MultiPointBegin(size, idx))?; + Ok(()) + } + + /// End of MultiPoint processing + pub fn multipoint_end(&mut self, idx: usize) -> Result<()> { + self.check_type(GeometryType::MultiPoint)?; + self.emit(Event::MultiPointEnd(idx))?; + Ok(()) + } + + /// Begin of LineString processing + pub fn linestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::LineString)?; + self.emit(Event::LineStringBegin(size, idx))?; + Ok(()) + } + + /// End of LineString processing + pub fn linestring_end(&mut self, idx: usize) -> Result<()> { + // self.check_type(GeometryType::LineString)?; || polygon, etc. + self.emit(Event::LineStringEnd(idx))?; + Ok(()) + } + + /// Begin of Polygon processing + pub fn polygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::Polygon)?; + self.emit(Event::PolygonBegin(size, idx))?; + Ok(()) + } + + /// End of Polygon processing + pub fn polygon_end(&mut self, idx: usize) -> Result<()> { + self.check_type(GeometryType::Polygon)?; + self.emit(Event::PolygonEnd(idx))?; + Ok(()) + } + + /// Begin of GeometryCollection processing + pub fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.collection = true; + self.geom_type = GeometryType::Unknown; + self.emit(Event::GeometryCollectionBegin(size, idx))?; + Ok(()) + } + + /// End of GeometryCollection processing + pub fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { + if !self.collection { + return self.type_seq_err(); + } + self.geom_type = GeometryType::Unknown; + self.emit(Event::GeometryCollectionEnd(idx))?; + self.collection = false; + Ok(()) + } +} + +#[allow(unused)] +impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { + fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { + self.xy(x, y, idx) + } + fn coordinate( + &mut self, + x: f64, + y: f64, + z: Option, + m: Option, + t: Option, + tm: Option, + idx: usize, + ) -> Result<()> { + self.coordinate(x, y, z, m, t, tm, idx) + } + fn empty_point(&mut self, idx: usize) -> Result<()> { + self.point_begin(idx)?; + self.point_end(idx) + } + fn point_begin(&mut self, idx: usize) -> Result<()> { + self.point_begin(idx) + } + fn point_end(&mut self, idx: usize) -> Result<()> { + self.point_end(idx) + } + fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multipoint_begin(size, idx) + } + fn multipoint_end(&mut self, idx: usize) -> Result<()> { + self.multipoint_end(idx) + } + fn linestring_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { + self.linestring_begin(size, idx) + } + fn linestring_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { + self.linestring_end(idx) + } + fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn multilinestring_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn polygon_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { + self.polygon_begin(size, idx) + } + fn polygon_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { + self.polygon_end(idx) + } + fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn multipolygon_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.geometrycollection_begin(size, idx) + } + fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { + self.geometrycollection_end(idx) + } + fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn circularstring_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn multicurve_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn multisurface_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()> { + todo!() + } + fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { + todo!() + } + fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { + todo!() + } + fn tin_end(&mut self, idx: usize) -> Result<()> { + todo!() + } +} + +#[cfg(test)] +pub(crate) mod test { + use super::*; + use crate::events::Event::*; + + // -- Event emitter (geometry input) -- + + pub struct NullIsland; + + impl GeometryReader for NullIsland { + fn process_geom( + &mut self, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()> { + visitor.point_begin(0)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.point_end(0)?; + Ok(()) + } + } + + // -- Event processor (geometry output) -- + + pub struct GeomEventBuffer { + pub buffer: Vec, + } + + impl GeomEventBuffer { + pub fn new() -> Self { + GeomEventBuffer { buffer: Vec::new() } + } + } + + impl GeomEventProcessor for GeomEventBuffer { + fn event( + &mut self, + event: Event, + _geom_type: GeometryType, + _collection: bool, + ) -> Result<()> { + self.buffer.push(event); + Ok(()) + } + } + + #[test] + fn processing() -> Result<()> { + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); + + let mut geom = NullIsland; + geom.process_geom(&mut visitor)?; + + assert_eq!( + processor.buffer, + [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0)] + ); + + Ok(()) + } + + struct Point2D { + pub x: f64, + pub y: f64, + } + + impl GeomEventProcessor for Point2D { + fn event( + &mut self, + event: Event, + _geom_type: GeometryType, + _collection: bool, + ) -> Result<()> { + match event { + PointBegin(_) | PointEnd(_) => {} // OK + Xy(x, y, _idx) => (self.x, self.y) = (x, y), + _ => return Err(GeozeroError::GeometryFormat), + } + Ok(()) + } + } + + #[test] + fn process_point() -> Result<()> { + let mut geom_out = Point2D { + x: f64::NAN, + y: f64::NAN, + }; + let mut visitor = GeomVisitor::new(&mut geom_out); + + let mut geom_in = NullIsland; + geom_in.process_geom(&mut visitor)?; + + assert_eq!((geom_out.x, geom_out.y), (0.0, 0.0)); + + Ok(()) + } + + #[test] + fn polygon() -> Result<()> { + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); + visitor.polygon_begin(2, 0)?; + visitor.linestring_begin(2, 0)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.xy(1.0, 1.0, 1)?; + visitor.linestring_end(0)?; + visitor.linestring_begin(2, 1)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.xy(1.0, 1.0, 1)?; + visitor.linestring_end(1)?; + visitor.polygon_end(0)?; + + dbg!(&processor.buffer); + assert_eq!( + processor.buffer, + [ + PolygonBegin(2, 0), + LineStringBegin(2, 0), + Xy(0.0, 0.0, 0), + Xy(1.0, 1.0, 1), + LineStringEnd(0), + LineStringBegin(2, 1), + Xy(0.0, 0.0, 0), + Xy(1.0, 1.0, 1), + LineStringEnd(1), + PolygonEnd(0) + ] + ); + + Ok(()) + } + + #[test] + fn collection() -> Result<()> { + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); + visitor.geometrycollection_begin(2, 0)?; + visitor.point_begin(0)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.point_end(0)?; + visitor.linestring_begin(2, 1)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.xy(1.0, 1.0, 1)?; + visitor.linestring_end(1)?; + visitor.geometrycollection_end(0)?; + + assert_eq!( + processor.buffer, + [ + GeometryCollectionBegin(2, 0), + PointBegin(0), + Xy(0.0, 0.0, 0), + PointEnd(0), + LineStringBegin(2, 1), + Xy(0.0, 0.0, 0), + Xy(1.0, 1.0, 1), + LineStringEnd(1), + GeometryCollectionEnd(0) + ] + ); + + Ok(()) + } + + #[test] + fn invalid_transitions() -> Result<()> { + let mut processor = GeomEventSink {}; + let mut visitor = GeomVisitor::new(&mut processor); + visitor.point_begin(0)?; + visitor.xy(0.0, 0.0, 0)?; + let result = visitor.polygon_end(0); + assert!(result.is_err()); + + Ok(()) + } + + #[test] + #[cfg(feature = "with-geojson")] + fn geozero_geometry_api() -> Result<()> { + use crate::api::GeozeroGeometry; + use crate::geojson::GeoJson; + + let geojson = GeoJson( + r#"{"type": "Feature", "properties": {"fid": 0, "name": "Albania"}, "geometry": {"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}"#, + ); + let mut processor = GeomEventBuffer::new(); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + assert_eq!( + processor.buffer, + [ + PolygonBegin(1, 0), + LineStringBegin(22, 0), + Xy(20.590247, 41.855404, 0), + Xy(20.463175, 41.515089, 1), + Xy(20.605182, 41.086226, 2), + Xy(21.02004, 40.842727, 3), + Xy(20.99999, 40.580004, 4), + Xy(20.674997, 40.435, 5), + Xy(20.615, 40.110007, 6), + Xy(20.150016, 39.624998, 7), + Xy(19.98, 39.694993, 8), + Xy(19.960002, 39.915006, 9), + Xy(19.406082, 40.250773, 10), + Xy(19.319059, 40.72723, 11), + Xy(19.40355, 41.409566, 12), + Xy(19.540027, 41.719986, 13), + Xy(19.371769, 41.877548, 14), + Xy(19.304486, 42.195745, 15), + Xy(19.738051, 42.688247, 16), + Xy(19.801613, 42.500093, 17), + Xy(20.0707, 42.58863, 18), + Xy(20.283755, 42.32026, 19), + Xy(20.52295, 42.21787, 20), + Xy(20.590247, 41.855404, 21), + LineStringEnd(0), + PolygonEnd(0) + ] + ); + Ok(()) + } +} diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 5b933df1..9a32c933 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -1,7 +1,7 @@ use crate::error::{GeozeroError, Result}; /// Dimensions requested for processing -#[derive(Default, Clone, Copy)] +#[derive(Default, Clone, Copy, Debug)] pub struct CoordDimensions { /// height pub z: bool, diff --git a/geozero/src/lib.rs b/geozero/src/lib.rs index 4a8c35f9..d566ef3b 100644 --- a/geozero/src/lib.rs +++ b/geozero/src/lib.rs @@ -29,7 +29,10 @@ //! | WKT | [wkt::WktStr], [wkt::WktString] | XYZM | [wkt::WktReader], [wkt::WktStr], [wkt::WktString] | [ToWkt] | [WktWriter](wkt::WktWriter) | mod api; +pub mod bbox; +pub mod chaining; pub mod error; +pub mod events; mod feature_processor; mod geometry_processor; mod multiplex; From c8886d86defba205e448e9967514c224d08672e7 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 16 May 2022 22:00:31 +0200 Subject: [PATCH 02/22] Replace diacritics --- geozero/src/chaining.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index a5b07fc5..1d1aa8ba 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -7,7 +7,7 @@ use crate::events::*; // ------- Chain events ------- /// Processing geometry events and passing events to a chained visitor -pub trait CĥainedGeomEventProcessor { +pub trait ChainedGeomEventProcessor { /// Geometry processing event with geometry type information fn chain_event( &mut self, @@ -19,12 +19,12 @@ pub trait CĥainedGeomEventProcessor { } /// Chaining [GeomEventProcessor] -pub struct ChainedProcessor<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> { +pub struct ChainedProcessor<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> { processor1: &'a mut P1, visitor: GeomVisitor<'a, P2>, } -impl<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor<'a, P1, P2> { +impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor<'a, P1, P2> { pub fn new(processor1: &'a mut P1, processor2: &'a mut P2) -> Self { ChainedProcessor { processor1, @@ -33,7 +33,7 @@ impl<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcesso } } -impl<'a, P1: CĥainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor +impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor for ChainedProcessor<'a, P1, P2> { fn event( @@ -89,7 +89,7 @@ mod test { use crate::events::GeomEventSink; pub struct PromoteToMulti; - impl CĥainedGeomEventProcessor for PromoteToMulti { + impl ChainedGeomEventProcessor for PromoteToMulti { fn chain_event( &mut self, event: Event, From 7b04a30efd7ac039421b492a7c86542e8dbca1c5 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 16 May 2022 22:29:58 +0200 Subject: [PATCH 03/22] Add state transition validation --- geozero/src/events.rs | 246 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 224 insertions(+), 22 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 38fbaac3..bdeeb906 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -50,11 +50,9 @@ use crate::GeomProcessor; /// | | | | | /// +----------->| LineString | | Point | /// | | | | -/// +--------+--------+ +-----------------+ +--------+--------+ -/// | | | | +/// +--------+--------+ +--------+--------+ +/// | | /// +------------> Coordinate <------------+ -/// | | -/// +-----------------+ /// ``` #[derive(Clone, PartialEq, Debug)] pub enum Event { @@ -175,6 +173,28 @@ pub enum GeometryType { Triangle, } +#[derive(PartialEq, Clone, Debug)] +enum Vstate { + Initial, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + GeometryCollection, + CircularString, + CompoundCurve, + CurvePolygon, + MultiCurve, + MultiSurface, + Curve, + Surface, + PolyhedralSurface, + Tin, + Triangle, +} + /// Geometry visitor emitting events to a processor pub struct GeomVisitor<'a, P: GeomEventProcessor> { // pub dims: CoordDimensions, @@ -182,6 +202,7 @@ pub struct GeomVisitor<'a, P: GeomEventProcessor> { geom_type: GeometryType, /// Geometry is part of collection collection: bool, + state: Vstate, processor: &'a mut P, } @@ -214,19 +235,207 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { GeomVisitor { geom_type: GeometryType::Unknown, collection: false, + state: Vstate::Initial, processor, } } pub fn emit(&mut self, event: Event) -> Result<()> { self.processor.event(event, self.geom_type, self.collection) } + fn enter_state(&mut self, state: Vstate) -> Result<()> { + match (&self.state, &&state) { + (Vstate::Initial, Vstate::GeometryCollection) + | (Vstate::Initial, Vstate::Point) + | (Vstate::Initial, Vstate::LineString) + | (Vstate::Initial, Vstate::Polygon) + | (Vstate::Initial, Vstate::MultiPoint) + | (Vstate::Initial, Vstate::MultiLineString) + | (Vstate::Initial, Vstate::MultiPolygon) + | (Vstate::Initial, Vstate::CircularString) + | (Vstate::Initial, Vstate::CompoundCurve) + | (Vstate::Initial, Vstate::CurvePolygon) + | (Vstate::Initial, Vstate::MultiCurve) + | (Vstate::Initial, Vstate::MultiSurface) + | (Vstate::Initial, Vstate::Curve) + | (Vstate::Initial, Vstate::Surface) + | (Vstate::Initial, Vstate::PolyhedralSurface) + | (Vstate::Initial, Vstate::Tin) + | (Vstate::Initial, Vstate::Triangle) + | (Vstate::Polygon, Vstate::LineString) + | (Vstate::MultiPoint, Vstate::Point) + | (Vstate::MultiPolygon, Vstate::Polygon) + | (Vstate::GeometryCollection, Vstate::Point) + | (Vstate::GeometryCollection, Vstate::LineString) + | (Vstate::GeometryCollection, Vstate::Polygon) + | (Vstate::GeometryCollection, Vstate::MultiPoint) + | (Vstate::GeometryCollection, Vstate::MultiLineString) + | (Vstate::GeometryCollection, Vstate::MultiPolygon) + | (Vstate::GeometryCollection, Vstate::CircularString) + | (Vstate::GeometryCollection, Vstate::CompoundCurve) + | (Vstate::GeometryCollection, Vstate::CurvePolygon) + | (Vstate::GeometryCollection, Vstate::MultiCurve) + | (Vstate::GeometryCollection, Vstate::MultiSurface) + | (Vstate::GeometryCollection, Vstate::Curve) + | (Vstate::GeometryCollection, Vstate::Surface) + | (Vstate::GeometryCollection, Vstate::PolyhedralSurface) + | (Vstate::GeometryCollection, Vstate::Tin) + | (Vstate::GeometryCollection, Vstate::Triangle) + | (Vstate::CompoundCurve, Vstate::CircularString) + | (Vstate::CompoundCurve, Vstate::LineString) + | (Vstate::CurvePolygon, Vstate::CircularString) + | (Vstate::CurvePolygon, Vstate::LineString) + | (Vstate::CurvePolygon, Vstate::CompoundCurve) + | (Vstate::MultiCurve, Vstate::CircularString) + | (Vstate::MultiCurve, Vstate::LineString) + | (Vstate::MultiCurve, Vstate::CompoundCurve) + | (Vstate::MultiSurface, Vstate::CurvePolygon) + | (Vstate::MultiSurface, Vstate::Polygon) + | (Vstate::Triangle, Vstate::LineString) + | (Vstate::PolyhedralSurface, Vstate::Polygon) + | (Vstate::Tin, Vstate::Polygon) => { + // println!("Enter state {:?}=>{:?}", self.state, state); + self.state = state; + Ok(()) + } + _ => Err(GeozeroError::Geometry(format!( + "Invalid state transition from {:?} to {:?}", + self.state, state + ))), + } + } + fn exit_state(&mut self, state: Vstate) -> Result<()> { + let next_state = match (&self.state, &self.geom_type, self.collection, &state) { + // --- Back to Vstate::Initial --- + (Vstate::Point, GeometryType::Point, false, Vstate::Point) + | (Vstate::LineString, GeometryType::LineString, false, Vstate::LineString) + | (Vstate::Polygon, GeometryType::Polygon, false, Vstate::Polygon) + | (Vstate::MultiPoint, GeometryType::MultiPoint, false, Vstate::MultiPoint) + | ( + Vstate::MultiLineString, + GeometryType::MultiLineString, + false, + Vstate::MultiLineString, + ) + | (Vstate::MultiPolygon, GeometryType::MultiPolygon, false, Vstate::MultiPolygon) + | ( + Vstate::CircularString, + GeometryType::CircularString, + false, + Vstate::CircularString, + ) + | (Vstate::CompoundCurve, GeometryType::CompoundCurve, false, Vstate::CompoundCurve) + | (Vstate::CurvePolygon, GeometryType::CurvePolygon, false, Vstate::CurvePolygon) + | (Vstate::MultiCurve, GeometryType::MultiCurve, false, Vstate::MultiCurve) + | (Vstate::MultiSurface, GeometryType::MultiSurface, false, Vstate::MultiSurface) + | (Vstate::Curve, GeometryType::Curve, false, Vstate::Curve) + | (Vstate::Surface, GeometryType::Surface, false, Vstate::Surface) + | ( + Vstate::PolyhedralSurface, + GeometryType::PolyhedralSurface, + false, + Vstate::PolyhedralSurface, + ) + | (Vstate::Tin, GeometryType::Tin, false, Vstate::Tin) + | (Vstate::Triangle, GeometryType::Triangle, false, Vstate::Triangle) + | (Vstate::GeometryCollection, _, true, Vstate::GeometryCollection) => Vstate::Initial, + // --- Back to Vstate::GeometryCollection --- + (Vstate::Point, GeometryType::Point, true, Vstate::Point) + | (Vstate::LineString, GeometryType::LineString, true, Vstate::LineString) + | (Vstate::Polygon, GeometryType::Polygon, true, Vstate::Polygon) + | (Vstate::MultiPoint, GeometryType::MultiPoint, true, Vstate::MultiPoint) + | ( + Vstate::MultiLineString, + GeometryType::MultiLineString, + true, + Vstate::MultiLineString, + ) + | (Vstate::MultiPolygon, GeometryType::MultiPolygon, true, Vstate::MultiPolygon) + | ( + Vstate::CircularString, + GeometryType::CircularString, + true, + Vstate::CircularString, + ) + | (Vstate::CompoundCurve, GeometryType::CompoundCurve, true, Vstate::CompoundCurve) + | (Vstate::CurvePolygon, GeometryType::CurvePolygon, true, Vstate::CurvePolygon) + | (Vstate::MultiCurve, GeometryType::MultiCurve, true, Vstate::MultiCurve) + | (Vstate::MultiSurface, GeometryType::MultiSurface, true, Vstate::MultiSurface) + | (Vstate::Curve, GeometryType::Curve, true, Vstate::Curve) + | (Vstate::Surface, GeometryType::Surface, true, Vstate::Surface) + | ( + Vstate::PolyhedralSurface, + GeometryType::PolyhedralSurface, + true, + Vstate::PolyhedralSurface, + ) + | (Vstate::Tin, GeometryType::Tin, true, Vstate::Tin) + | (Vstate::Triangle, GeometryType::Triangle, true, Vstate::Triangle) => { + Vstate::GeometryCollection + } + // --- Other cases --- + (Vstate::LineString, GeometryType::Polygon, _, Vstate::LineString) => Vstate::Polygon, + (Vstate::Point, GeometryType::MultiPoint, _, Vstate::Point) => Vstate::MultiPoint, + (Vstate::Polygon, GeometryType::MultiPolygon, _, Vstate::Polygon) => { + Vstate::MultiPolygon + } + (Vstate::CircularString, GeometryType::CompoundCurve, _, Vstate::CircularString) => { + Vstate::CompoundCurve + } + (Vstate::LineString, GeometryType::CompoundCurve, _, Vstate::LineString) => { + Vstate::CompoundCurve + } + (Vstate::CircularString, GeometryType::CurvePolygon, _, Vstate::CircularString) => { + Vstate::CurvePolygon + } + (Vstate::LineString, GeometryType::CurvePolygon, _, Vstate::LineString) => { + Vstate::CurvePolygon + } + (Vstate::CompoundCurve, GeometryType::CurvePolygon, _, Vstate::CompoundCurve) => { + Vstate::CurvePolygon + } + (Vstate::CircularString, GeometryType::MultiCurve, _, Vstate::CircularString) => { + Vstate::MultiCurve + } + (Vstate::LineString, GeometryType::MultiCurve, _, Vstate::LineString) => { + Vstate::MultiCurve + } + (Vstate::CompoundCurve, GeometryType::MultiCurve, _, Vstate::CompoundCurve) => { + Vstate::MultiCurve + } + (Vstate::CurvePolygon, GeometryType::MultiSurface, _, Vstate::CurvePolygon) => { + Vstate::MultiSurface + } + (Vstate::Polygon, GeometryType::MultiSurface, _, Vstate::Polygon) => { + Vstate::MultiSurface + } + (Vstate::LineString, GeometryType::Triangle, _, Vstate::LineString) => Vstate::Triangle, + (Vstate::Polygon, GeometryType::PolyhedralSurface, _, Vstate::Polygon) => { + Vstate::PolyhedralSurface + } + (Vstate::Polygon, GeometryType::Tin, _, Vstate::Polygon) => Vstate::Tin, + _ => { + return Err(GeozeroError::Geometry(format!( + "Invalid state transition from {:?} to {:?}", + self.state, state + ))) + } + }; + // println!( + // "Exit state {:?} (GeometryType::{:?})=>{:?}", + // &self.state, &self.geom_type, next_state + // ); + self.state = next_state; + Ok(()) + } fn set_type(&mut self, inner_type: GeometryType) -> Result<()> { match self.geom_type { GeometryType::Unknown => { + // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); self.geom_type = inner_type; } _ if self.collection => { // new type within collection + // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); self.geom_type = inner_type; } _ => { @@ -235,17 +444,6 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } Ok(()) } - fn check_type(&self, geom_type: GeometryType) -> Result<()> { - if self.geom_type == geom_type { - Ok(()) - } else { - self.type_seq_err() - } - } - fn type_seq_err(&self) -> Result<()> { - // TODO: unexpected event in self.geom_type - Err(GeozeroError::GeometryFormat) - } /// Process coordinate with x,y dimensions pub fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { @@ -270,26 +468,29 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Begin of Point processing pub fn point_begin(&mut self, idx: usize) -> Result<()> { self.set_type(GeometryType::Point)?; + self.enter_state(Vstate::Point)?; self.emit(Event::PointBegin(idx))?; Ok(()) } /// End of Point processing pub fn point_end(&mut self, idx: usize) -> Result<()> { - // self.check_type(GeometryType::Point)?; || MultiPoint, etc. + self.exit_state(Vstate::Point)?; self.emit(Event::PointEnd(idx))?; Ok(()) } + /// Begin of MultiPoint processing pub fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiPoint)?; + self.enter_state(Vstate::MultiPoint)?; self.emit(Event::MultiPointBegin(size, idx))?; Ok(()) } /// End of MultiPoint processing pub fn multipoint_end(&mut self, idx: usize) -> Result<()> { - self.check_type(GeometryType::MultiPoint)?; + self.exit_state(Vstate::MultiPoint)?; self.emit(Event::MultiPointEnd(idx))?; Ok(()) } @@ -297,13 +498,14 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Begin of LineString processing pub fn linestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::LineString)?; + self.enter_state(Vstate::LineString)?; self.emit(Event::LineStringBegin(size, idx))?; Ok(()) } /// End of LineString processing pub fn linestring_end(&mut self, idx: usize) -> Result<()> { - // self.check_type(GeometryType::LineString)?; || polygon, etc. + self.exit_state(Vstate::LineString)?; self.emit(Event::LineStringEnd(idx))?; Ok(()) } @@ -311,13 +513,14 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Begin of Polygon processing pub fn polygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::Polygon)?; + self.enter_state(Vstate::Polygon)?; self.emit(Event::PolygonBegin(size, idx))?; Ok(()) } /// End of Polygon processing pub fn polygon_end(&mut self, idx: usize) -> Result<()> { - self.check_type(GeometryType::Polygon)?; + self.exit_state(Vstate::Polygon)?; self.emit(Event::PolygonEnd(idx))?; Ok(()) } @@ -326,15 +529,14 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { pub fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.collection = true; self.geom_type = GeometryType::Unknown; + self.enter_state(Vstate::GeometryCollection)?; self.emit(Event::GeometryCollectionBegin(size, idx))?; Ok(()) } /// End of GeometryCollection processing pub fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { - if !self.collection { - return self.type_seq_err(); - } + self.exit_state(Vstate::GeometryCollection)?; self.geom_type = GeometryType::Unknown; self.emit(Event::GeometryCollectionEnd(idx))?; self.collection = false; From fad87d701c53539295010727ddfa9a953656c3d8 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 16 May 2022 23:38:45 +0200 Subject: [PATCH 04/22] Implement remaining geometry types --- geozero/src/events.rs | 240 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 220 insertions(+), 20 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index bdeeb906..b6fbb1ab 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -188,7 +188,9 @@ enum Vstate { CurvePolygon, MultiCurve, MultiSurface, + #[allow(dead_code)] Curve, + #[allow(dead_code)] Surface, PolyhedralSurface, Tin, @@ -465,6 +467,15 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { self.emit(Event::Coordinate(x, y, z, m, t, tm, idx))?; Ok(()) } + /// Process empty coordinates, like WKT's `POINT EMPTY` + pub fn empty_point(&mut self, idx: usize) -> Result<()> { + self.set_type(GeometryType::Point)?; + self.enter_state(Vstate::Point)?; + self.emit(Event::EmptyPoint(idx))?; + self.exit_state(Vstate::Point)?; + Ok(()) + } + /// Begin of Point processing pub fn point_begin(&mut self, idx: usize) -> Result<()> { self.set_type(GeometryType::Point)?; @@ -496,6 +507,10 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } /// Begin of LineString processing + /// + /// Can also be a Polygon ring or part of a MultiLineString + /// + /// Next: size * xy/coordinate pub fn linestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::LineString)?; self.enter_state(Vstate::LineString)?; @@ -510,7 +525,28 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { Ok(()) } + /// Begin of MultiLineString processing + /// + /// Next: size * LineString + pub fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::MultiLineString)?; + self.enter_state(Vstate::MultiLineString)?; + self.emit(Event::MultiLineStringBegin(size, idx))?; + Ok(()) + } + + /// End of MultiLineString processing + pub fn multilinestring_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::MultiLineString)?; + self.emit(Event::MultiLineStringEnd(idx))?; + Ok(()) + } + /// Begin of Polygon processing + /// + /// Can also be part of a MultiPolygon + /// + /// Next: size * LineString = rings pub fn polygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::Polygon)?; self.enter_state(Vstate::Polygon)?; @@ -525,6 +561,23 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { Ok(()) } + /// Begin of MultiPolygon processing + /// + /// Next: size * Polygon + pub fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::MultiPolygon)?; + self.enter_state(Vstate::MultiPolygon)?; + self.emit(Event::MultiPolygonBegin(size, idx))?; + Ok(()) + } + + /// End of MultiPolygon processing + pub fn multipolygon_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::MultiPolygon)?; + self.emit(Event::MultiPolygonEnd(idx))?; + Ok(()) + } + /// Begin of GeometryCollection processing pub fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.collection = true; @@ -542,6 +595,153 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { self.collection = false; Ok(()) } + + /// Begin of CircularString processing + /// + /// The CircularString is the basic curve type, similar to a LineString in the linear world. A single segment required three points, the start and end points (first and third) and any other point on the arc. The exception to this is for a closed circle, where the start and end points are the same. In this case the second point MUST be the center of the arc, ie the opposite side of the circle. To chain arcs together, the last point of the previous arc becomes the first point of the next arc, just like in LineString. This means that a valid circular string must have an odd number of points greated than 1. + /// + /// Next: size * xy/coordinate + pub fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::CircularString)?; + self.enter_state(Vstate::CircularString)?; + self.emit(Event::CircularStringBegin(size, idx))?; + Ok(()) + } + + /// End of CircularString processing + pub fn circularstring_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::CircularString)?; + self.emit(Event::CircularStringEnd(idx))?; + Ok(()) + } + + /// Begin of CompoundCurve processing + /// + /// A compound curve is a single, continuous curve that has both curved (circular) segments and linear segments. That means that in addition to having well-formed components, the end point of every component (except the last) must be coincident with the start point of the following component. + /// + /// Next: size * (CircularString | LineString) + pub fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::CompoundCurve)?; + self.enter_state(Vstate::CompoundCurve)?; + self.emit(Event::CompoundCurveBegin(size, idx))?; + Ok(()) + } + + /// End of CompoundCurve processing + pub fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::CompoundCurve)?; + self.emit(Event::CompoundCurveEnd(idx))?; + Ok(()) + } + + /// Begin of CurvePolygon processing + /// + /// A CurvePolygon is just like a polygon, with an outer ring and zero or more inner rings. The difference is that a ring can take the form of a circular string, linear string or compound string. + /// + /// Next: size * (CircularString | LineString | CompoundCurve) + pub fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::CurvePolygon)?; + self.enter_state(Vstate::CurvePolygon)?; + self.emit(Event::CurvePolygonBegin(size, idx))?; + Ok(()) + } + + /// End of CurvePolygon processing + pub fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::CurvePolygon)?; + self.emit(Event::CurvePolygonEnd(idx))?; + Ok(()) + } + + /// Begin of MultiCurve processing + /// + /// The MultiCurve is a collection of curves, which can include linear strings, circular strings or compound strings. + /// + /// Next: size * (CircularString | LineString | CompoundCurve) + pub fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::MultiCurve)?; + self.enter_state(Vstate::MultiCurve)?; + self.emit(Event::MultiCurveBegin(size, idx))?; + Ok(()) + } + + /// End of MultiCurve processing + pub fn multicurve_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::MultiCurve)?; + self.emit(Event::MultiCurveEnd(idx))?; + Ok(()) + } + + /// Begin of MultiSurface processing + /// + /// The MultiSurface is a collection of surfaces, which can be (linear) polygons or curve polygons. + /// + /// Next: size * (CurvePolygon | Polygon) + pub fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::MultiSurface)?; + self.enter_state(Vstate::MultiSurface)?; + self.emit(Event::MultiSurfaceBegin(size, idx))?; + Ok(()) + } + + /// End of MultiSurface processing + pub fn multisurface_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::MultiSurface)?; + self.emit(Event::MultiSurfaceEnd(idx))?; + Ok(()) + } + /// Begin of Triangle processing + /// + /// Can also be part of a Tin + /// + /// Next: size * LineString = rings + pub fn triangle_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::Triangle)?; + self.enter_state(Vstate::Triangle)?; + self.emit(Event::TriangleBegin(size, idx))?; + Ok(()) + } + + /// End of Triangle processing + pub fn triangle_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::Triangle)?; + self.emit(Event::TriangleEnd(idx))?; + Ok(()) + } + + /// Begin of PolyhedralSurface processing + /// + /// Next: size * Polygon + pub fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::PolyhedralSurface)?; + self.enter_state(Vstate::PolyhedralSurface)?; + self.emit(Event::PolyhedralSurfaceBegin(size, idx))?; + Ok(()) + } + + /// End of PolyhedralSurface processing + pub fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::PolyhedralSurface)?; + self.emit(Event::PolyhedralSurfaceEnd(idx))?; + Ok(()) + } + + /// Begin of Tin processing + /// + /// Next: size * Polygon + pub fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.set_type(GeometryType::Tin)?; + self.enter_state(Vstate::Tin)?; + self.emit(Event::TinBegin(size, idx))?; + Ok(()) + } + + /// End of Tin processing + pub fn tin_end(&mut self, idx: usize) -> Result<()> { + self.exit_state(Vstate::Tin)?; + self.emit(Event::TinEnd(idx))?; + Ok(()) + } } #[allow(unused)] @@ -584,10 +784,10 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { self.linestring_end(idx) } fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.multilinestring_begin(size, idx) } fn multilinestring_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.multilinestring_end(idx) } fn polygon_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { self.polygon_begin(size, idx) @@ -596,10 +796,10 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { self.polygon_end(idx) } fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.multipolygon_begin(size, idx) } fn multipolygon_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.multipolygon_end(idx) } fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.geometrycollection_begin(size, idx) @@ -608,52 +808,52 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { self.geometrycollection_end(idx) } fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.circularstring_begin(size, idx) } fn circularstring_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.circularstring_end(idx) } fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.compoundcurve_begin(size, idx) } fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.compoundcurve_end(idx) } fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.curvepolygon_begin(size, idx) } fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.curvepolygon_end(idx) } fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.multicurve_begin(size, idx) } fn multicurve_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.multicurve_end(idx) } fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.multisurface_begin(size, idx) } fn multisurface_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.multisurface_end(idx) } fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { - todo!() + self.triangle_begin(size, idx) } fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()> { - todo!() + self.triangle_end(idx) } fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.polyhedralsurface_begin(size, idx) } fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.polyhedralsurface_end(idx) } fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { - todo!() + self.tin_begin(size, idx) } fn tin_end(&mut self, idx: usize) -> Result<()> { - todo!() + self.tin_end(idx) } } From 480df7c1bffb10b8381733d2a82eaf8a88d136ad Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 16 May 2022 23:47:43 +0200 Subject: [PATCH 05/22] Make state check optional --- geozero/src/events.rs | 139 +++++++++++++++++++++++++++++++----------- 1 file changed, 105 insertions(+), 34 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index b6fbb1ab..78732ee3 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -173,7 +173,7 @@ pub enum GeometryType { Triangle, } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Debug)] enum Vstate { Initial, Point, @@ -200,6 +200,7 @@ enum Vstate { /// Geometry visitor emitting events to a processor pub struct GeomVisitor<'a, P: GeomEventProcessor> { // pub dims: CoordDimensions, + pub check_states: bool, /// Main geometry type geom_type: GeometryType, /// Geometry is part of collection @@ -235,6 +236,7 @@ pub trait GeometryReader { impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { pub fn new(processor: &'a mut P) -> Self { GeomVisitor { + check_states: true, // Should maybe set from env var? geom_type: GeometryType::Unknown, collection: false, state: Vstate::Initial, @@ -245,7 +247,7 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { self.processor.event(event, self.geom_type, self.collection) } fn enter_state(&mut self, state: Vstate) -> Result<()> { - match (&self.state, &&state) { + match (&self.state, &state) { (Vstate::Initial, Vstate::GeometryCollection) | (Vstate::Initial, Vstate::Point) | (Vstate::Initial, Vstate::LineString) @@ -470,23 +472,31 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Process empty coordinates, like WKT's `POINT EMPTY` pub fn empty_point(&mut self, idx: usize) -> Result<()> { self.set_type(GeometryType::Point)?; - self.enter_state(Vstate::Point)?; + if self.check_states { + self.enter_state(Vstate::Point)?; + } self.emit(Event::EmptyPoint(idx))?; - self.exit_state(Vstate::Point)?; + if self.check_states { + self.exit_state(Vstate::Point)?; + } Ok(()) } /// Begin of Point processing pub fn point_begin(&mut self, idx: usize) -> Result<()> { self.set_type(GeometryType::Point)?; - self.enter_state(Vstate::Point)?; + if self.check_states { + self.enter_state(Vstate::Point)?; + } self.emit(Event::PointBegin(idx))?; Ok(()) } /// End of Point processing pub fn point_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::Point)?; + if self.check_states { + self.exit_state(Vstate::Point)?; + } self.emit(Event::PointEnd(idx))?; Ok(()) } @@ -494,14 +504,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Begin of MultiPoint processing pub fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiPoint)?; - self.enter_state(Vstate::MultiPoint)?; + if self.check_states { + self.enter_state(Vstate::MultiPoint)?; + } self.emit(Event::MultiPointBegin(size, idx))?; Ok(()) } /// End of MultiPoint processing pub fn multipoint_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::MultiPoint)?; + if self.check_states { + self.exit_state(Vstate::MultiPoint)?; + } self.emit(Event::MultiPointEnd(idx))?; Ok(()) } @@ -513,14 +527,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * xy/coordinate pub fn linestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::LineString)?; - self.enter_state(Vstate::LineString)?; + if self.check_states { + self.enter_state(Vstate::LineString)?; + } self.emit(Event::LineStringBegin(size, idx))?; Ok(()) } /// End of LineString processing pub fn linestring_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::LineString)?; + if self.check_states { + self.exit_state(Vstate::LineString)?; + } self.emit(Event::LineStringEnd(idx))?; Ok(()) } @@ -530,14 +548,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * LineString pub fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiLineString)?; - self.enter_state(Vstate::MultiLineString)?; + if self.check_states { + self.enter_state(Vstate::MultiLineString)?; + } self.emit(Event::MultiLineStringBegin(size, idx))?; Ok(()) } /// End of MultiLineString processing pub fn multilinestring_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::MultiLineString)?; + if self.check_states { + self.exit_state(Vstate::MultiLineString)?; + } self.emit(Event::MultiLineStringEnd(idx))?; Ok(()) } @@ -549,14 +571,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * LineString = rings pub fn polygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::Polygon)?; - self.enter_state(Vstate::Polygon)?; + if self.check_states { + self.enter_state(Vstate::Polygon)?; + } self.emit(Event::PolygonBegin(size, idx))?; Ok(()) } /// End of Polygon processing pub fn polygon_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::Polygon)?; + if self.check_states { + self.exit_state(Vstate::Polygon)?; + } self.emit(Event::PolygonEnd(idx))?; Ok(()) } @@ -566,14 +592,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * Polygon pub fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiPolygon)?; - self.enter_state(Vstate::MultiPolygon)?; + if self.check_states { + self.enter_state(Vstate::MultiPolygon)?; + } self.emit(Event::MultiPolygonBegin(size, idx))?; Ok(()) } /// End of MultiPolygon processing pub fn multipolygon_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::MultiPolygon)?; + if self.check_states { + self.exit_state(Vstate::MultiPolygon)?; + } self.emit(Event::MultiPolygonEnd(idx))?; Ok(()) } @@ -582,14 +612,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { pub fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.collection = true; self.geom_type = GeometryType::Unknown; - self.enter_state(Vstate::GeometryCollection)?; + if self.check_states { + self.enter_state(Vstate::GeometryCollection)?; + } self.emit(Event::GeometryCollectionBegin(size, idx))?; Ok(()) } /// End of GeometryCollection processing pub fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::GeometryCollection)?; + if self.check_states { + self.exit_state(Vstate::GeometryCollection)?; + } self.geom_type = GeometryType::Unknown; self.emit(Event::GeometryCollectionEnd(idx))?; self.collection = false; @@ -603,14 +637,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * xy/coordinate pub fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::CircularString)?; - self.enter_state(Vstate::CircularString)?; + if self.check_states { + self.enter_state(Vstate::CircularString)?; + } self.emit(Event::CircularStringBegin(size, idx))?; Ok(()) } /// End of CircularString processing pub fn circularstring_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::CircularString)?; + if self.check_states { + self.exit_state(Vstate::CircularString)?; + } self.emit(Event::CircularStringEnd(idx))?; Ok(()) } @@ -622,14 +660,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * (CircularString | LineString) pub fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::CompoundCurve)?; - self.enter_state(Vstate::CompoundCurve)?; + if self.check_states { + self.enter_state(Vstate::CompoundCurve)?; + } self.emit(Event::CompoundCurveBegin(size, idx))?; Ok(()) } /// End of CompoundCurve processing pub fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::CompoundCurve)?; + if self.check_states { + self.exit_state(Vstate::CompoundCurve)?; + } self.emit(Event::CompoundCurveEnd(idx))?; Ok(()) } @@ -641,14 +683,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * (CircularString | LineString | CompoundCurve) pub fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::CurvePolygon)?; - self.enter_state(Vstate::CurvePolygon)?; + if self.check_states { + self.enter_state(Vstate::CurvePolygon)?; + } self.emit(Event::CurvePolygonBegin(size, idx))?; Ok(()) } /// End of CurvePolygon processing pub fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::CurvePolygon)?; + if self.check_states { + self.exit_state(Vstate::CurvePolygon)?; + } self.emit(Event::CurvePolygonEnd(idx))?; Ok(()) } @@ -660,14 +706,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * (CircularString | LineString | CompoundCurve) pub fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiCurve)?; - self.enter_state(Vstate::MultiCurve)?; + if self.check_states { + self.enter_state(Vstate::MultiCurve)?; + } self.emit(Event::MultiCurveBegin(size, idx))?; Ok(()) } /// End of MultiCurve processing pub fn multicurve_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::MultiCurve)?; + if self.check_states { + self.exit_state(Vstate::MultiCurve)?; + } self.emit(Event::MultiCurveEnd(idx))?; Ok(()) } @@ -679,14 +729,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * (CurvePolygon | Polygon) pub fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiSurface)?; - self.enter_state(Vstate::MultiSurface)?; + if self.check_states { + self.enter_state(Vstate::MultiSurface)?; + } self.emit(Event::MultiSurfaceBegin(size, idx))?; Ok(()) } /// End of MultiSurface processing pub fn multisurface_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::MultiSurface)?; + if self.check_states { + self.exit_state(Vstate::MultiSurface)?; + } self.emit(Event::MultiSurfaceEnd(idx))?; Ok(()) } @@ -697,14 +751,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * LineString = rings pub fn triangle_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::Triangle)?; - self.enter_state(Vstate::Triangle)?; + if self.check_states { + self.enter_state(Vstate::Triangle)?; + } self.emit(Event::TriangleBegin(size, idx))?; Ok(()) } /// End of Triangle processing pub fn triangle_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::Triangle)?; + if self.check_states { + self.exit_state(Vstate::Triangle)?; + } self.emit(Event::TriangleEnd(idx))?; Ok(()) } @@ -714,14 +772,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * Polygon pub fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::PolyhedralSurface)?; - self.enter_state(Vstate::PolyhedralSurface)?; + if self.check_states { + self.enter_state(Vstate::PolyhedralSurface)?; + } self.emit(Event::PolyhedralSurfaceBegin(size, idx))?; Ok(()) } /// End of PolyhedralSurface processing pub fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::PolyhedralSurface)?; + if self.check_states { + self.exit_state(Vstate::PolyhedralSurface)?; + } self.emit(Event::PolyhedralSurfaceEnd(idx))?; Ok(()) } @@ -731,14 +793,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// Next: size * Polygon pub fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::Tin)?; - self.enter_state(Vstate::Tin)?; + if self.check_states { + self.enter_state(Vstate::Tin)?; + } self.emit(Event::TinBegin(size, idx))?; Ok(()) } /// End of Tin processing pub fn tin_end(&mut self, idx: usize) -> Result<()> { - self.exit_state(Vstate::Tin)?; + if self.check_states { + self.exit_state(Vstate::Tin)?; + } self.emit(Event::TinEnd(idx))?; Ok(()) } @@ -1031,6 +1097,11 @@ pub(crate) mod test { let result = visitor.polygon_end(0); assert!(result.is_err()); + visitor.check_states = false; + visitor.point_begin(0)?; + visitor.xy(0.0, 0.0, 0)?; + visitor.polygon_end(0)?; + Ok(()) } From 1212335ba7e74c3e580332e183b8f151efa6ffe4 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 16 May 2022 23:57:52 +0200 Subject: [PATCH 06/22] Fix empty_point in GeomProcessor impl --- geozero/src/events.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 78732ee3..8cb7d822 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -810,7 +810,6 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } } -#[allow(unused)] impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { self.xy(x, y, idx) @@ -828,8 +827,7 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { self.coordinate(x, y, z, m, t, tm, idx) } fn empty_point(&mut self, idx: usize) -> Result<()> { - self.point_begin(idx)?; - self.point_end(idx) + self.empty_point(idx) } fn point_begin(&mut self, idx: usize) -> Result<()> { self.point_begin(idx) @@ -903,10 +901,10 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { fn multisurface_end(&mut self, idx: usize) -> Result<()> { self.multisurface_end(idx) } - fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { + fn triangle_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { self.triangle_begin(size, idx) } - fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()> { + fn triangle_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { self.triangle_end(idx) } fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { From 05c852feac9dab76ca050fe2f6b77f014396da0d Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Tue, 17 May 2022 00:20:50 +0200 Subject: [PATCH 07/22] impl GeomEventProcessor for GeoWriter --- geozero/src/geo_types/geo_types_writer.rs | 133 ++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index ea39fd6a..9792a7c9 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -1,4 +1,5 @@ use crate::error::{GeozeroError, Result}; +use crate::events::{self, Event, GeomEventProcessor}; use crate::{FeatureProcessor, GeomProcessor, PropertyProcessor}; use geo_types::*; use std::mem; @@ -50,6 +51,138 @@ impl GeoWriter { } } +impl GeomEventProcessor for GeoWriter { + fn event( + &mut self, + event: Event, + geom_type: events::GeometryType, + _collection: bool, + ) -> Result<()> { + match event { + Event::Xy(x, y, _idx) => { + let coords = self + .coords + .as_mut() + .ok_or(GeozeroError::Geometry("Not ready for coords".to_string()))?; + coords.push(coord!(x: x, y: y)); + } + + Event::PointBegin(_idx) => { + debug_assert!(self.coords.is_none()); + self.coords = Some(Vec::with_capacity(1)); + } + + Event::PointEnd(_idx) => { + let coords = self + .coords + .take() + .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; + debug_assert!(coords.len() == 1); + self.finish_geometry(Point(coords[0]).into())?; + } + + Event::MultiPointBegin(size, _idx) => { + debug_assert!(self.coords.is_none()); + self.coords = Some(Vec::with_capacity(size)); + } + + Event::MultiPointEnd(_idx) => { + let coords = self.coords.take().ok_or(GeozeroError::Geometry( + "No coords for MultiPoint".to_string(), + ))?; + let points: Vec> = coords.into_iter().map(From::from).collect(); + self.finish_geometry(MultiPoint(points).into())?; + } + + Event::LineStringBegin(size, _idx) => { + debug_assert!(self.coords.is_none()); + self.coords = Some(Vec::with_capacity(size)); + } + + Event::LineStringEnd(_idx) => { + let coords = self.coords.take().ok_or(GeozeroError::Geometry( + "No coords for LineString".to_string(), + ))?; + let line_string = LineString(coords); + if geom_type == events::GeometryType::LineString { + self.finish_geometry(line_string.into())?; + } else { + let line_strings = self.line_strings.as_mut().ok_or(GeozeroError::Geometry( + "Missing container for LineString".to_string(), + ))?; + line_strings.push(line_string); + } + } + + Event::MultiLineStringBegin(size, _idx) => { + debug_assert!(self.line_strings.is_none()); + self.line_strings = Some(Vec::with_capacity(size)); + } + + Event::MultiLineStringEnd(_idx) => { + let line_strings = self.line_strings.take().ok_or(GeozeroError::Geometry( + "No LineStrings for MultiLineString".to_string(), + ))?; + self.finish_geometry(MultiLineString(line_strings).into())?; + } + + Event::PolygonBegin(size, _idx) => { + debug_assert!(self.line_strings.is_none()); + self.line_strings = Some(Vec::with_capacity(size)); + } + + Event::PolygonEnd(_idx) => { + let mut line_strings = self.line_strings.take().ok_or(GeozeroError::Geometry( + "Missing LineStrings for Polygon".to_string(), + ))?; + + let polygon = if line_strings.len() == 0 { + Polygon::new(LineString(vec![]), vec![]) + } else { + let exterior = line_strings.remove(0); + Polygon::new(exterior, mem::take(&mut line_strings)) + }; + + if geom_type == events::GeometryType::Polygon { + self.finish_geometry(polygon.into())?; + } else { + let polygons = self.polygons.as_mut().ok_or(GeozeroError::Geometry( + "Missing container for Polygon".to_string(), + ))?; + polygons.push(polygon); + } + } + + Event::MultiPolygonBegin(size, _idx) => { + debug_assert!(self.polygons.is_none()); + self.polygons = Some(Vec::with_capacity(size)); + } + + Event::MultiPolygonEnd(_idx) => { + let polygons = self.polygons.take().ok_or(GeozeroError::Geometry( + "Missing polygons for MultiPolygon".to_string(), + ))?; + self.finish_geometry(MultiPolygon(polygons).into())?; + } + + Event::GeometryCollectionBegin(size, _idx) => { + self.collections.push(Vec::with_capacity(size)); + } + + Event::GeometryCollectionEnd(_idx) => { + let geometries = self.collections.pop().ok_or(GeozeroError::Geometry( + "Unexpected geometry type".to_string(), + ))?; + + self.finish_geometry(Geometry::GeometryCollection(GeometryCollection(geometries)))?; + } + + _ => return Err(GeozeroError::GeometryFormat), // ?? With GeomProcessor we ignore all other states + } + Ok(()) + } +} + impl GeomProcessor for GeoWriter { fn xy(&mut self, x: f64, y: f64, _idx: usize) -> Result<()> { let coords = self From 21c9767a7158849b80e681435f39b781cd3c3fc3 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Wed, 18 May 2022 00:06:55 +0200 Subject: [PATCH 08/22] Implement geo-types writer with event API --- geozero/src/chaining.rs | 2 +- geozero/src/events.rs | 312 +++++---------------- geozero/src/geo_types/geo_types_writer.rs | 151 +---------- geozero/src/geo_types/mod.rs | 6 +- geozero/src/geometry_processor.rs | 316 ++++++++++++++++++++++ 5 files changed, 402 insertions(+), 385 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 1d1aa8ba..8a844abd 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -156,7 +156,7 @@ mod test { #[test] fn chain_and_duplex() -> Result<()> { - // geom ------+----> PromotToMulti (1a) ----> GeomEventBuffer (2a) + // geom ------+----> PromoteToMulti (1a) ----> GeomEventBuffer (2a) // | // +----> GeomEventBuffer (1b) let mut processor1a = PromoteToMulti; diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 8cb7d822..af25b6d0 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -20,7 +20,6 @@ // ``` use crate::error::{GeozeroError, Result}; -use crate::GeomProcessor; /// Geometry processing events /// @@ -205,7 +204,7 @@ pub struct GeomVisitor<'a, P: GeomEventProcessor> { geom_type: GeometryType, /// Geometry is part of collection collection: bool, - state: Vstate, + state_stack: Vec, processor: &'a mut P, } @@ -239,15 +238,23 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { check_states: true, // Should maybe set from env var? geom_type: GeometryType::Unknown, collection: false, - state: Vstate::Initial, + state_stack: Vec::new(), processor, } } pub fn emit(&mut self, event: Event) -> Result<()> { self.processor.event(event, self.geom_type, self.collection) } + fn state(&self) -> &Vstate { + let len = self.state_stack.len(); + if len > 0 { + &self.state_stack[len - 1] + } else { + &Vstate::Initial + } + } fn enter_state(&mut self, state: Vstate) -> Result<()> { - match (&self.state, &state) { + match (self.state(), &state) { (Vstate::Initial, Vstate::GeometryCollection) | (Vstate::Initial, Vstate::Point) | (Vstate::Initial, Vstate::LineString) @@ -267,6 +274,7 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { | (Vstate::Initial, Vstate::Triangle) | (Vstate::Polygon, Vstate::LineString) | (Vstate::MultiPoint, Vstate::Point) + | (Vstate::MultiLineString, Vstate::LineString) | (Vstate::MultiPolygon, Vstate::Polygon) | (Vstate::GeometryCollection, Vstate::Point) | (Vstate::GeometryCollection, Vstate::LineString) @@ -274,6 +282,7 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { | (Vstate::GeometryCollection, Vstate::MultiPoint) | (Vstate::GeometryCollection, Vstate::MultiLineString) | (Vstate::GeometryCollection, Vstate::MultiPolygon) + | (Vstate::GeometryCollection, Vstate::GeometryCollection) | (Vstate::GeometryCollection, Vstate::CircularString) | (Vstate::GeometryCollection, Vstate::CompoundCurve) | (Vstate::GeometryCollection, Vstate::CurvePolygon) @@ -297,138 +306,36 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { | (Vstate::Triangle, Vstate::LineString) | (Vstate::PolyhedralSurface, Vstate::Polygon) | (Vstate::Tin, Vstate::Polygon) => { - // println!("Enter state {:?}=>{:?}", self.state, state); - self.state = state; + // println!("Enter state {:?}=>{:?}", self.state(), state); + self.state_stack.push(state); Ok(()) } _ => Err(GeozeroError::Geometry(format!( "Invalid state transition from {:?} to {:?}", - self.state, state + self.state(), + state ))), } } fn exit_state(&mut self, state: Vstate) -> Result<()> { - let next_state = match (&self.state, &self.geom_type, self.collection, &state) { - // --- Back to Vstate::Initial --- - (Vstate::Point, GeometryType::Point, false, Vstate::Point) - | (Vstate::LineString, GeometryType::LineString, false, Vstate::LineString) - | (Vstate::Polygon, GeometryType::Polygon, false, Vstate::Polygon) - | (Vstate::MultiPoint, GeometryType::MultiPoint, false, Vstate::MultiPoint) - | ( - Vstate::MultiLineString, - GeometryType::MultiLineString, - false, - Vstate::MultiLineString, - ) - | (Vstate::MultiPolygon, GeometryType::MultiPolygon, false, Vstate::MultiPolygon) - | ( - Vstate::CircularString, - GeometryType::CircularString, - false, - Vstate::CircularString, - ) - | (Vstate::CompoundCurve, GeometryType::CompoundCurve, false, Vstate::CompoundCurve) - | (Vstate::CurvePolygon, GeometryType::CurvePolygon, false, Vstate::CurvePolygon) - | (Vstate::MultiCurve, GeometryType::MultiCurve, false, Vstate::MultiCurve) - | (Vstate::MultiSurface, GeometryType::MultiSurface, false, Vstate::MultiSurface) - | (Vstate::Curve, GeometryType::Curve, false, Vstate::Curve) - | (Vstate::Surface, GeometryType::Surface, false, Vstate::Surface) - | ( - Vstate::PolyhedralSurface, - GeometryType::PolyhedralSurface, - false, - Vstate::PolyhedralSurface, - ) - | (Vstate::Tin, GeometryType::Tin, false, Vstate::Tin) - | (Vstate::Triangle, GeometryType::Triangle, false, Vstate::Triangle) - | (Vstate::GeometryCollection, _, true, Vstate::GeometryCollection) => Vstate::Initial, - // --- Back to Vstate::GeometryCollection --- - (Vstate::Point, GeometryType::Point, true, Vstate::Point) - | (Vstate::LineString, GeometryType::LineString, true, Vstate::LineString) - | (Vstate::Polygon, GeometryType::Polygon, true, Vstate::Polygon) - | (Vstate::MultiPoint, GeometryType::MultiPoint, true, Vstate::MultiPoint) - | ( - Vstate::MultiLineString, - GeometryType::MultiLineString, - true, - Vstate::MultiLineString, - ) - | (Vstate::MultiPolygon, GeometryType::MultiPolygon, true, Vstate::MultiPolygon) - | ( - Vstate::CircularString, - GeometryType::CircularString, - true, - Vstate::CircularString, - ) - | (Vstate::CompoundCurve, GeometryType::CompoundCurve, true, Vstate::CompoundCurve) - | (Vstate::CurvePolygon, GeometryType::CurvePolygon, true, Vstate::CurvePolygon) - | (Vstate::MultiCurve, GeometryType::MultiCurve, true, Vstate::MultiCurve) - | (Vstate::MultiSurface, GeometryType::MultiSurface, true, Vstate::MultiSurface) - | (Vstate::Curve, GeometryType::Curve, true, Vstate::Curve) - | (Vstate::Surface, GeometryType::Surface, true, Vstate::Surface) - | ( - Vstate::PolyhedralSurface, - GeometryType::PolyhedralSurface, - true, - Vstate::PolyhedralSurface, - ) - | (Vstate::Tin, GeometryType::Tin, true, Vstate::Tin) - | (Vstate::Triangle, GeometryType::Triangle, true, Vstate::Triangle) => { - Vstate::GeometryCollection - } - // --- Other cases --- - (Vstate::LineString, GeometryType::Polygon, _, Vstate::LineString) => Vstate::Polygon, - (Vstate::Point, GeometryType::MultiPoint, _, Vstate::Point) => Vstate::MultiPoint, - (Vstate::Polygon, GeometryType::MultiPolygon, _, Vstate::Polygon) => { - Vstate::MultiPolygon - } - (Vstate::CircularString, GeometryType::CompoundCurve, _, Vstate::CircularString) => { - Vstate::CompoundCurve - } - (Vstate::LineString, GeometryType::CompoundCurve, _, Vstate::LineString) => { - Vstate::CompoundCurve - } - (Vstate::CircularString, GeometryType::CurvePolygon, _, Vstate::CircularString) => { - Vstate::CurvePolygon - } - (Vstate::LineString, GeometryType::CurvePolygon, _, Vstate::LineString) => { - Vstate::CurvePolygon - } - (Vstate::CompoundCurve, GeometryType::CurvePolygon, _, Vstate::CompoundCurve) => { - Vstate::CurvePolygon - } - (Vstate::CircularString, GeometryType::MultiCurve, _, Vstate::CircularString) => { - Vstate::MultiCurve - } - (Vstate::LineString, GeometryType::MultiCurve, _, Vstate::LineString) => { - Vstate::MultiCurve - } - (Vstate::CompoundCurve, GeometryType::MultiCurve, _, Vstate::CompoundCurve) => { - Vstate::MultiCurve - } - (Vstate::CurvePolygon, GeometryType::MultiSurface, _, Vstate::CurvePolygon) => { - Vstate::MultiSurface - } - (Vstate::Polygon, GeometryType::MultiSurface, _, Vstate::Polygon) => { - Vstate::MultiSurface - } - (Vstate::LineString, GeometryType::Triangle, _, Vstate::LineString) => Vstate::Triangle, - (Vstate::Polygon, GeometryType::PolyhedralSurface, _, Vstate::Polygon) => { - Vstate::PolyhedralSurface - } - (Vstate::Polygon, GeometryType::Tin, _, Vstate::Polygon) => Vstate::Tin, - _ => { - return Err(GeozeroError::Geometry(format!( - "Invalid state transition from {:?} to {:?}", - self.state, state - ))) - } + let ok = if let Some(prev_state) = self.state_stack.pop() { + state == prev_state + } else { + false }; - // println!( - // "Exit state {:?} (GeometryType::{:?})=>{:?}", - // &self.state, &self.geom_type, next_state - // ); - self.state = next_state; + if ok { + // println!( + // "Exit state {:?} (GeometryType::{:?})=>{:?}", + // &self.state_stack, + // &self.geom_type, + // self.state() + // ); + } else { + return Err(GeozeroError::Geometry(format!( + "Invalid state transition from {:?} to {:?}", + self.state_stack, state + ))); + } Ok(()) } fn set_type(&mut self, inner_type: GeometryType) -> Result<()> { @@ -438,9 +345,36 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { self.geom_type = inner_type; } _ if self.collection => { - // new type within collection - // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); - self.geom_type = inner_type; + match (self.geom_type, inner_type) { + (GeometryType::Polygon, GeometryType::LineString) + | (GeometryType::MultiPoint, GeometryType::Point) + | (GeometryType::MultiLineString, GeometryType::LineString) + | (GeometryType::MultiPolygon, GeometryType::Polygon) + | (GeometryType::MultiPolygon, GeometryType::LineString) + | (GeometryType::CompoundCurve, GeometryType::CircularString) + | (GeometryType::CompoundCurve, GeometryType::LineString) + | (GeometryType::CurvePolygon, GeometryType::CircularString) + | (GeometryType::CurvePolygon, GeometryType::LineString) + | (GeometryType::CurvePolygon, GeometryType::CompoundCurve) + | (GeometryType::MultiCurve, GeometryType::CircularString) + | (GeometryType::MultiCurve, GeometryType::LineString) + | (GeometryType::MultiCurve, GeometryType::CompoundCurve) + | (GeometryType::MultiSurface, GeometryType::CurvePolygon) + | (GeometryType::MultiSurface, GeometryType::CircularString) + | (GeometryType::MultiSurface, GeometryType::LineString) + | (GeometryType::MultiSurface, GeometryType::CompoundCurve) + | (GeometryType::MultiSurface, GeometryType::Polygon) + | (GeometryType::Triangle, GeometryType::LineString) + | (GeometryType::PolyhedralSurface, GeometryType::Polygon) + | (GeometryType::PolyhedralSurface, GeometryType::LineString) + | (GeometryType::Tin, GeometryType::Polygon) + | (GeometryType::Tin, GeometryType::LineString) => { /* skip nested */ } + _ => { + // new type within collection + // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); + self.geom_type = inner_type; + } + } } _ => { // type already defined (check if self.geom_type = match inner_type ?) @@ -448,11 +382,9 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } Ok(()) } - /// Process coordinate with x,y dimensions pub fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { - self.emit(Event::Xy(x, y, idx))?; - Ok(()) + self.emit(Event::Xy(x, y, idx)) } /// Process coordinate with all requested dimensions @@ -466,8 +398,7 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { tm: Option, idx: usize, ) -> Result<()> { - self.emit(Event::Coordinate(x, y, z, m, t, tm, idx))?; - Ok(()) + self.emit(Event::Coordinate(x, y, z, m, t, tm, idx)) } /// Process empty coordinates, like WKT's `POINT EMPTY` pub fn empty_point(&mut self, idx: usize) -> Result<()> { @@ -810,117 +741,6 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } } -impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { - fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { - self.xy(x, y, idx) - } - fn coordinate( - &mut self, - x: f64, - y: f64, - z: Option, - m: Option, - t: Option, - tm: Option, - idx: usize, - ) -> Result<()> { - self.coordinate(x, y, z, m, t, tm, idx) - } - fn empty_point(&mut self, idx: usize) -> Result<()> { - self.empty_point(idx) - } - fn point_begin(&mut self, idx: usize) -> Result<()> { - self.point_begin(idx) - } - fn point_end(&mut self, idx: usize) -> Result<()> { - self.point_end(idx) - } - fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.multipoint_begin(size, idx) - } - fn multipoint_end(&mut self, idx: usize) -> Result<()> { - self.multipoint_end(idx) - } - fn linestring_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { - self.linestring_begin(size, idx) - } - fn linestring_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { - self.linestring_end(idx) - } - fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.multilinestring_begin(size, idx) - } - fn multilinestring_end(&mut self, idx: usize) -> Result<()> { - self.multilinestring_end(idx) - } - fn polygon_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { - self.polygon_begin(size, idx) - } - fn polygon_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { - self.polygon_end(idx) - } - fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.multipolygon_begin(size, idx) - } - fn multipolygon_end(&mut self, idx: usize) -> Result<()> { - self.multipolygon_end(idx) - } - fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.geometrycollection_begin(size, idx) - } - fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { - self.geometrycollection_end(idx) - } - fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.circularstring_begin(size, idx) - } - fn circularstring_end(&mut self, idx: usize) -> Result<()> { - self.circularstring_end(idx) - } - fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.compoundcurve_begin(size, idx) - } - fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { - self.compoundcurve_end(idx) - } - fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.curvepolygon_begin(size, idx) - } - fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { - self.curvepolygon_end(idx) - } - fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.multicurve_begin(size, idx) - } - fn multicurve_end(&mut self, idx: usize) -> Result<()> { - self.multicurve_end(idx) - } - fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.multisurface_begin(size, idx) - } - fn multisurface_end(&mut self, idx: usize) -> Result<()> { - self.multisurface_end(idx) - } - fn triangle_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { - self.triangle_begin(size, idx) - } - fn triangle_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { - self.triangle_end(idx) - } - fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.polyhedralsurface_begin(size, idx) - } - fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { - self.polyhedralsurface_end(idx) - } - fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.tin_begin(size, idx) - } - fn tin_end(&mut self, idx: usize) -> Result<()> { - self.tin_end(idx) - } -} - #[cfg(test)] pub(crate) mod test { use super::*; diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index 9792a7c9..9562a298 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -1,6 +1,6 @@ use crate::error::{GeozeroError, Result}; use crate::events::{self, Event, GeomEventProcessor}; -use crate::{FeatureProcessor, GeomProcessor, PropertyProcessor}; +use crate::{FeatureProcessor, PropertyProcessor}; use geo_types::*; use std::mem; @@ -67,6 +67,8 @@ impl GeomEventProcessor for GeoWriter { coords.push(coord!(x: x, y: y)); } + Event::EmptyPoint(_idx) => {} + Event::PointBegin(_idx) => { debug_assert!(self.coords.is_none()); self.coords = Some(Vec::with_capacity(1)); @@ -183,144 +185,15 @@ impl GeomEventProcessor for GeoWriter { } } -impl GeomProcessor for GeoWriter { - fn xy(&mut self, x: f64, y: f64, _idx: usize) -> Result<()> { - let coords = self - .coords - .as_mut() - .ok_or(GeozeroError::Geometry("Not ready for coords".to_string()))?; - coords.push(coord!(x: x, y: y)); - Ok(()) - } - - fn point_begin(&mut self, _idx: usize) -> Result<()> { - debug_assert!(self.coords.is_none()); - self.coords = Some(Vec::with_capacity(1)); - Ok(()) - } - - fn point_end(&mut self, _idx: usize) -> Result<()> { - let coords = self - .coords - .take() - .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; - debug_assert!(coords.len() == 1); - self.finish_geometry(Point(coords[0]).into()) - } - - fn multipoint_begin(&mut self, size: usize, _idx: usize) -> Result<()> { - debug_assert!(self.coords.is_none()); - self.coords = Some(Vec::with_capacity(size)); - Ok(()) - } - - fn multipoint_end(&mut self, _idx: usize) -> Result<()> { - let coords = self.coords.take().ok_or(GeozeroError::Geometry( - "No coords for MultiPoint".to_string(), - ))?; - let points: Vec> = coords.into_iter().map(From::from).collect(); - self.finish_geometry(MultiPoint(points).into()) - } - - fn linestring_begin(&mut self, _tagged: bool, size: usize, _idx: usize) -> Result<()> { - debug_assert!(self.coords.is_none()); - self.coords = Some(Vec::with_capacity(size)); - Ok(()) - } +impl PropertyProcessor for events::GeomVisitor<'_, GeoWriter> {} - fn linestring_end(&mut self, tagged: bool, _idx: usize) -> Result<()> { - let coords = self.coords.take().ok_or(GeozeroError::Geometry( - "No coords for LineString".to_string(), - ))?; - let line_string = LineString(coords); - if tagged { - self.finish_geometry(line_string.into())?; - } else { - let line_strings = self.line_strings.as_mut().ok_or(GeozeroError::Geometry( - "Missing container for LineString".to_string(), - ))?; - line_strings.push(line_string); - } - Ok(()) - } - - fn multilinestring_begin(&mut self, size: usize, _idx: usize) -> Result<()> { - debug_assert!(self.line_strings.is_none()); - self.line_strings = Some(Vec::with_capacity(size)); - Ok(()) - } - - fn multilinestring_end(&mut self, _idx: usize) -> Result<()> { - let line_strings = self.line_strings.take().ok_or(GeozeroError::Geometry( - "No LineStrings for MultiLineString".to_string(), - ))?; - self.finish_geometry(MultiLineString(line_strings).into()) - } - - fn polygon_begin(&mut self, _tagged: bool, size: usize, _idx: usize) -> Result<()> { - debug_assert!(self.line_strings.is_none()); - self.line_strings = Some(Vec::with_capacity(size)); - Ok(()) - } - - fn polygon_end(&mut self, tagged: bool, _idx: usize) -> Result<()> { - let mut line_strings = self.line_strings.take().ok_or(GeozeroError::Geometry( - "Missing LineStrings for Polygon".to_string(), - ))?; - - let polygon = if line_strings.len() == 0 { - Polygon::new(LineString(vec![]), vec![]) - } else { - let exterior = line_strings.remove(0); - Polygon::new(exterior, mem::take(&mut line_strings)) - }; - - if tagged { - self.finish_geometry(polygon.into())?; - } else { - let polygons = self.polygons.as_mut().ok_or(GeozeroError::Geometry( - "Missing container for Polygon".to_string(), - ))?; - polygons.push(polygon); - } - Ok(()) - } - - fn multipolygon_begin(&mut self, size: usize, _idx: usize) -> Result<()> { - debug_assert!(self.polygons.is_none()); - self.polygons = Some(Vec::with_capacity(size)); - Ok(()) - } - - fn multipolygon_end(&mut self, _idx: usize) -> Result<()> { - let polygons = self.polygons.take().ok_or(GeozeroError::Geometry( - "Missing polygons for MultiPolygon".to_string(), - ))?; - self.finish_geometry(MultiPolygon(polygons).into()) - } - - fn geometrycollection_begin(&mut self, size: usize, _idx: usize) -> Result<()> { - self.collections.push(Vec::with_capacity(size)); - Ok(()) - } - - fn geometrycollection_end(&mut self, _idx: usize) -> Result<()> { - let geometries = self.collections.pop().ok_or(GeozeroError::Geometry( - "Unexpected geometry type".to_string(), - ))?; - - self.finish_geometry(Geometry::GeometryCollection(GeometryCollection(geometries))) - } -} - -impl PropertyProcessor for GeoWriter {} - -impl FeatureProcessor for GeoWriter {} +impl FeatureProcessor for events::GeomVisitor<'_, GeoWriter> {} #[cfg(test)] #[cfg(feature = "with-geojson")] mod test { use super::*; + use crate::events::GeomVisitor; use crate::geojson::{read_geojson, GeoJson}; use crate::ToGeo; use geo::algorithm::coords_iter::CoordsIter; @@ -329,7 +202,7 @@ mod test { fn line_string() -> Result<()> { let geojson = r#"{"type": "LineString", "coordinates": [[1875038.447610231,-3269648.6879248763],[1874359.641504197,-3270196.812984864],[1874141.0428635243,-3270953.7840121365],[1874440.1778162003,-3271619.4315206874],[1876396.0598222911,-3274138.747656357],[1876442.0805243007,-3275052.60551469],[1874739.312657555,-3275457.333765534]]}"#; let mut geo = GeoWriter::new(); - assert!(read_geojson(geojson.as_bytes(), &mut geo).is_ok()); + assert!(read_geojson(geojson.as_bytes(), &mut GeomVisitor::new(&mut geo)).is_ok()); let geom = geo.take_geometry().unwrap(); match geom { Geometry::LineString(line) => { @@ -408,8 +281,14 @@ mod test { #[test] fn complex() { use crate::wkt::WktStr; - let wkt = WktStr("GEOMETRYCOLLECTION (LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516), POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)))"); - + let wkt = WktStr("GEOMETRYCOLLECTION ( + LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), + LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), + LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), + LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), + LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516), + POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)) + )"); assert!(wkt.to_geo().is_ok()); } diff --git a/geozero/src/geo_types/mod.rs b/geozero/src/geo_types/mod.rs index 9ea1bd9b..2eaeee61 100644 --- a/geozero/src/geo_types/mod.rs +++ b/geozero/src/geo_types/mod.rs @@ -8,6 +8,7 @@ pub use geo_types_writer::*; pub(crate) mod conversion { use super::geo_types_writer::*; use crate::error::{GeozeroError, Result}; + use crate::events::GeomVisitor; use crate::GeozeroGeometry; /// Convert to geo-types Geometry. @@ -19,7 +20,7 @@ pub(crate) mod conversion { impl ToGeo for T { fn to_geo(&self) -> Result> { let mut geo = GeoWriter::new(); - self.process_geom(&mut geo)?; + self.process_geom(&mut GeomVisitor::new(&mut geo))?; geo.take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } @@ -30,13 +31,14 @@ pub(crate) mod conversion { mod wkb { use super::geo_types_writer::*; use crate::error::{GeozeroError, Result}; + use crate::events::GeomVisitor; use crate::wkb::{FromWkb, WkbDialect}; use std::io::Read; impl FromWkb for geo_types::Geometry { fn from_wkb(rdr: &mut R, dialect: WkbDialect) -> Result { let mut geo = GeoWriter::new(); - crate::wkb::process_wkb_type_geom(rdr, &mut geo, dialect)?; + crate::wkb::process_wkb_type_geom(rdr, &mut GeomVisitor::new(&mut geo), dialect)?; geo.take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 9a32c933..1e209f3e 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -1,4 +1,5 @@ use crate::error::{GeozeroError, Result}; +use crate::events::{GeomEventProcessor, GeomVisitor}; /// Dimensions requested for processing #[derive(Default, Clone, Copy, Debug)] @@ -303,6 +304,321 @@ pub trait GeomProcessor { } } +impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { + fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { + self.xy(x, y, idx) + } + fn coordinate( + &mut self, + x: f64, + y: f64, + z: Option, + m: Option, + t: Option, + tm: Option, + idx: usize, + ) -> Result<()> { + self.coordinate(x, y, z, m, t, tm, idx) + } + fn empty_point(&mut self, idx: usize) -> Result<()> { + self.empty_point(idx) + } + fn point_begin(&mut self, idx: usize) -> Result<()> { + self.point_begin(idx) + } + fn point_end(&mut self, idx: usize) -> Result<()> { + self.point_end(idx) + } + fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multipoint_begin(size, idx) + } + fn multipoint_end(&mut self, idx: usize) -> Result<()> { + self.multipoint_end(idx) + } + fn linestring_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { + self.linestring_begin(size, idx) + } + fn linestring_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { + self.linestring_end(idx) + } + fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multilinestring_begin(size, idx) + } + fn multilinestring_end(&mut self, idx: usize) -> Result<()> { + self.multilinestring_end(idx) + } + fn polygon_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { + self.polygon_begin(size, idx) + } + fn polygon_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { + self.polygon_end(idx) + } + fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multipolygon_begin(size, idx) + } + fn multipolygon_end(&mut self, idx: usize) -> Result<()> { + self.multipolygon_end(idx) + } + fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.geometrycollection_begin(size, idx) + } + fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { + self.geometrycollection_end(idx) + } + fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.circularstring_begin(size, idx) + } + fn circularstring_end(&mut self, idx: usize) -> Result<()> { + self.circularstring_end(idx) + } + fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.compoundcurve_begin(size, idx) + } + fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { + self.compoundcurve_end(idx) + } + fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.curvepolygon_begin(size, idx) + } + fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { + self.curvepolygon_end(idx) + } + fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multicurve_begin(size, idx) + } + fn multicurve_end(&mut self, idx: usize) -> Result<()> { + self.multicurve_end(idx) + } + fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.multisurface_begin(size, idx) + } + fn multisurface_end(&mut self, idx: usize) -> Result<()> { + self.multisurface_end(idx) + } + fn triangle_begin(&mut self, _tagged: bool, size: usize, idx: usize) -> Result<()> { + self.triangle_begin(size, idx) + } + fn triangle_end(&mut self, _tagged: bool, idx: usize) -> Result<()> { + self.triangle_end(idx) + } + fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.polyhedralsurface_begin(size, idx) + } + fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { + self.polyhedralsurface_end(idx) + } + fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.tin_begin(size, idx) + } + fn tin_end(&mut self, idx: usize) -> Result<()> { + self.tin_end(idx) + } +} + +/* +impl GeomProcessor for dyn GeomEventProcessor { + fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { + self.event(Event::Xy(x, y, idx), events::GeometryType::Unknown, false) + } + fn coordinate( + &mut self, + x: f64, + y: f64, + z: Option, + m: Option, + t: Option, + tm: Option, + idx: usize, + ) -> Result<()> { + self.event( + Event::Coordinate(x, y, z, m, t, tm, idx), + events::GeometryType::Unknown, + false, + ) + } + fn point_begin(&mut self, idx: usize) -> Result<()> { + self.event(Event::PointBegin(idx), events::GeometryType::Unknown, false) + } + fn point_end(&mut self, idx: usize) -> Result<()> { + self.event(Event::PointEnd(idx), events::GeometryType::Unknown, false) + } + fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::MultiPointBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn multipoint_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::MultiPointEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn linestring_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { + self.event( + Event::LineStringBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn linestring_end(&mut self, tagged: bool, idx: usize) -> Result<()> { + self.event( + Event::LineStringEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::MultiLineStringBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn multilinestring_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::MultiLineStringEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn polygon_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { + self.event( + Event::PolygonBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn polygon_end(&mut self, tagged: bool, idx: usize) -> Result<()> { + self.event(Event::PolygonEnd(idx), events::GeometryType::Unknown, false) + } + fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::MultiPolygonBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn multipolygon_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::MultiPolygonEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::CircularStringBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn circularstring_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::CircularStringEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::CompoundCurveBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::CompoundCurveEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::CurvePolygonBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::CurvePolygonEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::MultiCurveBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn multicurve_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::MultiCurveEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::MultiSurfaceBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn multisurface_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::MultiSurfaceEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { + self.event( + Event::TriangleBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()> { + self.event( + Event::TriangleEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::PolyhedralSurfaceBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { + self.event( + Event::PolyhedralSurfaceEnd(idx), + events::GeometryType::Unknown, + false, + ) + } + fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { + self.event( + Event::TinBegin(size, idx), + events::GeometryType::Unknown, + false, + ) + } + fn tin_end(&mut self, idx: usize) -> Result<()> { + self.event(Event::TinEnd(idx), events::GeometryType::Unknown, false) + } +} +*/ + #[test] fn error_message() { use crate::error::GeozeroError; From 5edc3517e80efb4e7071cbe8f2e3ba5ba6279c0d Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 00:03:38 +0200 Subject: [PATCH 09/22] Reset geom type within collections --- geozero/src/events.rs | 99 ++++++++++------------- geozero/src/geo_types/geo_types_writer.rs | 4 +- 2 files changed, 43 insertions(+), 60 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index af25b6d0..61eef2ec 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -318,12 +318,12 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } } fn exit_state(&mut self, state: Vstate) -> Result<()> { - let ok = if let Some(prev_state) = self.state_stack.pop() { + let valid = if let Some(prev_state) = self.state_stack.pop() { state == prev_state } else { false }; - if ok { + if valid { // println!( // "Exit state {:?} (GeometryType::{:?})=>{:?}", // &self.state_stack, @@ -339,49 +339,18 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { Ok(()) } fn set_type(&mut self, inner_type: GeometryType) -> Result<()> { - match self.geom_type { - GeometryType::Unknown => { - // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); - self.geom_type = inner_type; - } - _ if self.collection => { - match (self.geom_type, inner_type) { - (GeometryType::Polygon, GeometryType::LineString) - | (GeometryType::MultiPoint, GeometryType::Point) - | (GeometryType::MultiLineString, GeometryType::LineString) - | (GeometryType::MultiPolygon, GeometryType::Polygon) - | (GeometryType::MultiPolygon, GeometryType::LineString) - | (GeometryType::CompoundCurve, GeometryType::CircularString) - | (GeometryType::CompoundCurve, GeometryType::LineString) - | (GeometryType::CurvePolygon, GeometryType::CircularString) - | (GeometryType::CurvePolygon, GeometryType::LineString) - | (GeometryType::CurvePolygon, GeometryType::CompoundCurve) - | (GeometryType::MultiCurve, GeometryType::CircularString) - | (GeometryType::MultiCurve, GeometryType::LineString) - | (GeometryType::MultiCurve, GeometryType::CompoundCurve) - | (GeometryType::MultiSurface, GeometryType::CurvePolygon) - | (GeometryType::MultiSurface, GeometryType::CircularString) - | (GeometryType::MultiSurface, GeometryType::LineString) - | (GeometryType::MultiSurface, GeometryType::CompoundCurve) - | (GeometryType::MultiSurface, GeometryType::Polygon) - | (GeometryType::Triangle, GeometryType::LineString) - | (GeometryType::PolyhedralSurface, GeometryType::Polygon) - | (GeometryType::PolyhedralSurface, GeometryType::LineString) - | (GeometryType::Tin, GeometryType::Polygon) - | (GeometryType::Tin, GeometryType::LineString) => { /* skip nested */ } - _ => { - // new type within collection - // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); - self.geom_type = inner_type; - } - } - } - _ => { - // type already defined (check if self.geom_type = match inner_type ?) - } + if self.geom_type == GeometryType::Unknown { + // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); + self.geom_type = inner_type; } Ok(()) } + fn reset_type(&mut self, inner_type: GeometryType) { + // Reset geometry type within collections + if self.collection && self.geom_type == inner_type { + self.geom_type = GeometryType::Unknown; + } + } /// Process coordinate with x,y dimensions pub fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { self.emit(Event::Xy(x, y, idx)) @@ -425,10 +394,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of Point processing pub fn point_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::PointEnd(idx))?; + self.reset_type(GeometryType::Point); if self.check_states { self.exit_state(Vstate::Point)?; } - self.emit(Event::PointEnd(idx))?; Ok(()) } @@ -444,10 +414,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of MultiPoint processing pub fn multipoint_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::MultiPointEnd(idx))?; + self.reset_type(GeometryType::MultiPoint); if self.check_states { self.exit_state(Vstate::MultiPoint)?; } - self.emit(Event::MultiPointEnd(idx))?; Ok(()) } @@ -467,10 +438,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of LineString processing pub fn linestring_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::LineStringEnd(idx))?; + self.reset_type(GeometryType::LineString); if self.check_states { self.exit_state(Vstate::LineString)?; } - self.emit(Event::LineStringEnd(idx))?; Ok(()) } @@ -488,10 +460,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of MultiLineString processing pub fn multilinestring_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::MultiLineStringEnd(idx))?; + self.reset_type(GeometryType::MultiLineString); if self.check_states { self.exit_state(Vstate::MultiLineString)?; } - self.emit(Event::MultiLineStringEnd(idx))?; Ok(()) } @@ -511,10 +484,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of Polygon processing pub fn polygon_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::PolygonEnd(idx))?; + self.reset_type(GeometryType::Polygon); if self.check_states { self.exit_state(Vstate::Polygon)?; } - self.emit(Event::PolygonEnd(idx))?; Ok(()) } @@ -532,10 +506,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of MultiPolygon processing pub fn multipolygon_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::MultiPolygonEnd(idx))?; + self.reset_type(GeometryType::MultiPolygon); if self.check_states { self.exit_state(Vstate::MultiPolygon)?; } - self.emit(Event::MultiPolygonEnd(idx))?; Ok(()) } @@ -552,11 +527,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of GeometryCollection processing pub fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::GeometryCollectionEnd(idx))?; + self.geom_type = GeometryType::Unknown; if self.check_states { self.exit_state(Vstate::GeometryCollection)?; } - self.geom_type = GeometryType::Unknown; - self.emit(Event::GeometryCollectionEnd(idx))?; self.collection = false; Ok(()) } @@ -577,10 +552,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of CircularString processing pub fn circularstring_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::CircularStringEnd(idx))?; + self.reset_type(GeometryType::CircularString); if self.check_states { self.exit_state(Vstate::CircularString)?; } - self.emit(Event::CircularStringEnd(idx))?; Ok(()) } @@ -600,10 +576,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of CompoundCurve processing pub fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::CompoundCurveEnd(idx))?; + self.reset_type(GeometryType::CompoundCurve); if self.check_states { self.exit_state(Vstate::CompoundCurve)?; } - self.emit(Event::CompoundCurveEnd(idx))?; Ok(()) } @@ -623,10 +600,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of CurvePolygon processing pub fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::CurvePolygonEnd(idx))?; + self.reset_type(GeometryType::CurvePolygon); if self.check_states { self.exit_state(Vstate::CurvePolygon)?; } - self.emit(Event::CurvePolygonEnd(idx))?; Ok(()) } @@ -646,10 +624,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of MultiCurve processing pub fn multicurve_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::MultiCurveEnd(idx))?; + self.reset_type(GeometryType::MultiCurve); if self.check_states { self.exit_state(Vstate::MultiCurve)?; } - self.emit(Event::MultiCurveEnd(idx))?; Ok(()) } @@ -669,10 +648,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of MultiSurface processing pub fn multisurface_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::MultiSurfaceEnd(idx))?; + self.reset_type(GeometryType::MultiSurface); if self.check_states { self.exit_state(Vstate::MultiSurface)?; } - self.emit(Event::MultiSurfaceEnd(idx))?; Ok(()) } /// Begin of Triangle processing @@ -691,10 +671,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of Triangle processing pub fn triangle_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::TriangleEnd(idx))?; + self.reset_type(GeometryType::Triangle); if self.check_states { self.exit_state(Vstate::Triangle)?; } - self.emit(Event::TriangleEnd(idx))?; Ok(()) } @@ -712,10 +693,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of PolyhedralSurface processing pub fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::PolyhedralSurfaceEnd(idx))?; + self.reset_type(GeometryType::PolyhedralSurface); if self.check_states { self.exit_state(Vstate::PolyhedralSurface)?; } - self.emit(Event::PolyhedralSurfaceEnd(idx))?; Ok(()) } @@ -733,10 +715,11 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { /// End of Tin processing pub fn tin_end(&mut self, idx: usize) -> Result<()> { + self.emit(Event::TinEnd(idx))?; + self.reset_type(GeometryType::Tin); if self.check_states { self.exit_state(Vstate::Tin)?; } - self.emit(Event::TinEnd(idx))?; Ok(()) } } diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index 9562a298..7002ab2a 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -285,9 +285,9 @@ mod test { LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), + POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)), LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), - LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516), - POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)) + LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516) )"); assert!(wkt.to_geo().is_ok()); } From f4de1126fc10dbaa6de9b794c0197c681584d0fe Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 00:55:53 +0200 Subject: [PATCH 10/22] Add a feature_collection test for geo-types --- geozero/src/geo_types/geo_types_writer.rs | 48 +++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index 7002ab2a..c33ef695 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -195,16 +195,17 @@ mod test { use super::*; use crate::events::GeomVisitor; use crate::geojson::{read_geojson, GeoJson}; - use crate::ToGeo; + use crate::{ToGeo, ToJson}; use geo::algorithm::coords_iter::CoordsIter; #[test] fn line_string() -> Result<()> { - let geojson = r#"{"type": "LineString", "coordinates": [[1875038.447610231,-3269648.6879248763],[1874359.641504197,-3270196.812984864],[1874141.0428635243,-3270953.7840121365],[1874440.1778162003,-3271619.4315206874],[1876396.0598222911,-3274138.747656357],[1876442.0805243007,-3275052.60551469],[1874739.312657555,-3275457.333765534]]}"#; - let mut geo = GeoWriter::new(); - assert!(read_geojson(geojson.as_bytes(), &mut GeomVisitor::new(&mut geo)).is_ok()); - let geom = geo.take_geometry().unwrap(); - match geom { + let geojson = GeoJson( + r#"{"type": "LineString", "coordinates": [[1875038.447610231,-3269648.6879248763],[1874359.641504197,-3270196.812984864],[1874141.0428635243,-3270953.7840121365],[1874440.1778162003,-3271619.4315206874],[1876396.0598222911,-3274138.747656357],[1876442.0805243007,-3275052.60551469],[1874739.312657555,-3275457.333765534]]}"#, + ); + let geo = geojson.to_geo().unwrap(); + println!("{:?}", geo); + match geo { Geometry::LineString(line) => { assert_eq!(line.coords_count(), 7); assert_eq!( @@ -251,6 +252,16 @@ mod test { ])); assert_eq!(expected, actual); + + let wkt = WktStr("GEOMETRYCOLLECTION ( + LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), + LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), + LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), + POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)), + LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), + LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516) + )"); + assert!(wkt.to_geo().is_ok()); } #[test] @@ -279,17 +290,20 @@ mod test { } #[test] - fn complex() { - use crate::wkt::WktStr; - let wkt = WktStr("GEOMETRYCOLLECTION ( - LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), - LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), - LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), - POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235)), - LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), - LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516) - )"); - assert!(wkt.to_geo().is_ok()); + fn feature_collection() -> Result<()> { + let geojson = r#"{"type": "FeatureCollection","name": "countries","features": [ + {"type": "Feature", "properties": {"id": "ALB", "name": "Albania"}, "geometry": {"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}, + {"type": "Feature", "properties": {"id": "TLS", "name": "East Timor"}, "geometry": {"type": "MultiPolygon", "coordinates": [[[[124.968682, -8.89279], [125.086246, -8.656887], [125.947072, -8.432095], [126.644704, -8.398247], [126.957243, -8.273345], [127.335928, -8.397317], [126.967992, -8.668256], [125.925885, -9.106007], [125.08852, -9.393173], [125.07002, -9.089987], [124.968682, -8.89279]]]]}} + ]}"#; + let mut geo = GeoWriter::new(); + assert!(read_geojson(geojson.as_bytes(), &mut GeomVisitor::new(&mut geo)).is_ok()); + let geom = geo.take_geometry().unwrap(); + dbg!(&geom); + println!("{}", geom.to_json()?); + // TODO: we get a broken GeometryCollection + let expected = r#"{"type": "GeometryCollection", "geometries": [{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]},{"type": "Polygon", "coordinates": [[[124.968682,-8.89279],[125.086246,-8.656887],[125.947072,-8.432095],[126.644704,-8.398247],[126.957243,-8.273345],[127.335928,-8.397317],[126.967992,-8.668256],[125.925885,-9.106007],[125.08852,-9.393173],[125.07002,-9.089987],[124.968682,-8.89279]]]},{"type": "MultiPolygon", "coordinates": []}]}"#; + assert_eq!(expected, geom.to_json()?); + Ok(()) } #[test] From 4c69bbff9385f57ec7f4834a8f40f3718b66a1d7 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 10:38:26 +0200 Subject: [PATCH 11/22] Impl GeomEventProcessor for Bbox --- geozero/src/bbox.rs | 185 ------------------------------- geozero/src/chaining.rs | 2 +- geozero/src/events.rs | 12 +- geozero/src/lib.rs | 2 +- geozero/src/processor/bbox.rs | 199 ++++++++++++++++++++++++++++++++++ geozero/src/processor/mod.rs | 5 + geozero/src/processor/sink.rs | 11 ++ 7 files changed, 219 insertions(+), 197 deletions(-) delete mode 100644 geozero/src/bbox.rs create mode 100644 geozero/src/processor/bbox.rs create mode 100644 geozero/src/processor/mod.rs create mode 100644 geozero/src/processor/sink.rs diff --git a/geozero/src/bbox.rs b/geozero/src/bbox.rs deleted file mode 100644 index 5c62b0f8..00000000 --- a/geozero/src/bbox.rs +++ /dev/null @@ -1,185 +0,0 @@ -use crate::error::Result; -use crate::GeomProcessor; - -#[derive(Clone, PartialEq, Debug)] -/// Bounding Box -pub struct Bbox { - pub min_x: f64, - pub min_y: f64, - pub max_x: f64, - pub max_y: f64, -} - -impl Default for Bbox { - fn default() -> Self { - Bbox { - min_x: f64::INFINITY, - min_y: f64::INFINITY, - max_x: f64::NEG_INFINITY, - max_y: f64::NEG_INFINITY, - } - } -} - -impl Bbox { - pub fn new(min_x: f64, min_y: f64, max_x: f64, max_y: f64) -> Bbox { - Bbox { - min_x, - min_y, - max_x, - max_y, - } - } - - pub fn reset(&mut self) { - self.min_x = f64::INFINITY; - self.min_y = f64::INFINITY; - self.max_x = f64::NEG_INFINITY; - self.max_y = f64::NEG_INFINITY; - } - - pub fn width(&self) -> f64 { - self.max_x - self.min_x - } - - pub fn height(&self) -> f64 { - self.max_y - self.min_y - } - - pub fn sum(mut a: Bbox, b: &Bbox) -> Bbox { - a.expand(b); - a - } - - pub fn expand(&mut self, r: &Bbox) { - if r.min_x < self.min_x { - self.min_x = r.min_x; - } - if r.min_y < self.min_y { - self.min_y = r.min_y; - } - if r.max_x > self.max_x { - self.max_x = r.max_x; - } - if r.max_y > self.max_y { - self.max_y = r.max_y; - } - } - - pub fn expand_xy(&mut self, x: f64, y: f64) { - if x < self.min_x { - self.min_x = x; - } - if y < self.min_y { - self.min_y = y; - } - if x > self.max_x { - self.max_x = x; - } - if y > self.max_y { - self.max_y = y; - } - } - - pub fn intersects(&self, r: &Bbox) -> bool { - if self.max_x < r.min_x { - return false; - } - if self.max_y < r.min_y { - return false; - } - if self.min_x > r.max_x { - return false; - } - if self.min_y > r.max_y { - return false; - } - true - } -} - -impl GeomProcessor for Bbox { - fn xy(&mut self, x: f64, y: f64, _idx: usize) -> Result<()> { - self.expand_xy(x, y); - Ok(()) - } - fn coordinate( - &mut self, - x: f64, - y: f64, - _z: Option, - _m: Option, - _t: Option, - _tm: Option, - _idx: usize, - ) -> Result<()> { - self.expand_xy(x, y); - Ok(()) - } - fn point_begin(&mut self, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn multipoint_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn linestring_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { - if tagged { - self.reset(); - } - Ok(()) - } - fn multilinestring_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn polygon_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { - if tagged { - self.reset(); - } - Ok(()) - } - fn multipolygon_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn geometrycollection_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn circularstring_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn compoundcurve_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn curvepolygon_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn multicurve_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn multisurface_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn triangle_begin(&mut self, tagged: bool, _size: usize, _idx: usize) -> Result<()> { - if tagged { - self.reset(); - } - Ok(()) - } - fn polyhedralsurface_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } - fn tin_begin(&mut self, _size: usize, _idx: usize) -> Result<()> { - self.reset(); - Ok(()) - } -} diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 8a844abd..8f099e83 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -86,7 +86,7 @@ mod test { use crate::error::Result; use crate::events::test::{GeomEventBuffer, NullIsland}; use crate::events::Event::*; - use crate::events::GeomEventSink; + use crate::processor::GeomEventSink; pub struct PromoteToMulti; impl ChainedGeomEventProcessor for PromoteToMulti { diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 61eef2ec..5c45b281 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -214,15 +214,6 @@ pub trait GeomEventProcessor { fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()>; } -/// Geometry processor without any actions -pub struct GeomEventSink; - -impl GeomEventProcessor for GeomEventSink { - fn event(&mut self, _event: Event, _geom_type: GeometryType, _collection: bool) -> Result<()> { - Ok(()) - } -} - /// Reading geometries by passing events to a visitor object pub trait GeometryReader { /// Process geometry. @@ -728,6 +719,7 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { pub(crate) mod test { use super::*; use crate::events::Event::*; + use crate::processor::GeomEventSink; // -- Event emitter (geometry input) -- @@ -913,7 +905,7 @@ pub(crate) mod test { use crate::geojson::GeoJson; let geojson = GeoJson( - r#"{"type": "Feature", "properties": {"fid": 0, "name": "Albania"}, "geometry": {"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}"#, + r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); let mut processor = GeomEventBuffer::new(); geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; diff --git a/geozero/src/lib.rs b/geozero/src/lib.rs index d566ef3b..eebcc389 100644 --- a/geozero/src/lib.rs +++ b/geozero/src/lib.rs @@ -29,13 +29,13 @@ //! | WKT | [wkt::WktStr], [wkt::WktString] | XYZM | [wkt::WktReader], [wkt::WktStr], [wkt::WktString] | [ToWkt] | [WktWriter](wkt::WktWriter) | mod api; -pub mod bbox; pub mod chaining; pub mod error; pub mod events; mod feature_processor; mod geometry_processor; mod multiplex; +pub mod processor; mod property_processor; pub use api::*; diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs new file mode 100644 index 00000000..93869029 --- /dev/null +++ b/geozero/src/processor/bbox.rs @@ -0,0 +1,199 @@ +use crate::error::Result; +use crate::events::{Event, GeomEventProcessor, GeometryType}; + +#[derive(Clone, PartialEq, Debug)] +/// Bounding Box +pub struct Bbox { + pub min_x: f64, + pub min_y: f64, + pub max_x: f64, + pub max_y: f64, +} + +impl Default for Bbox { + fn default() -> Self { + Bbox { + min_x: f64::INFINITY, + min_y: f64::INFINITY, + max_x: f64::NEG_INFINITY, + max_y: f64::NEG_INFINITY, + } + } +} + +impl Bbox { + pub fn new(min_x: f64, min_y: f64, max_x: f64, max_y: f64) -> Bbox { + Bbox { + min_x, + min_y, + max_x, + max_y, + } + } + + pub fn reset(&mut self) { + self.min_x = f64::INFINITY; + self.min_y = f64::INFINITY; + self.max_x = f64::NEG_INFINITY; + self.max_y = f64::NEG_INFINITY; + } + + pub fn width(&self) -> f64 { + self.max_x - self.min_x + } + + pub fn height(&self) -> f64 { + self.max_y - self.min_y + } + + pub fn sum(mut a: Bbox, b: &Bbox) -> Bbox { + a.expand(b); + a + } + + pub fn expand(&mut self, r: &Bbox) { + if r.min_x < self.min_x { + self.min_x = r.min_x; + } + if r.min_y < self.min_y { + self.min_y = r.min_y; + } + if r.max_x > self.max_x { + self.max_x = r.max_x; + } + if r.max_y > self.max_y { + self.max_y = r.max_y; + } + } + + pub fn expand_xy(&mut self, x: f64, y: f64) { + if x < self.min_x { + self.min_x = x; + } + if y < self.min_y { + self.min_y = y; + } + if x > self.max_x { + self.max_x = x; + } + if y > self.max_y { + self.max_y = y; + } + } + + pub fn intersects(&self, r: &Bbox) -> bool { + if self.max_x < r.min_x { + return false; + } + if self.max_y < r.min_y { + return false; + } + if self.min_x > r.max_x { + return false; + } + if self.min_y > r.max_y { + return false; + } + true + } +} + +impl GeomEventProcessor for Bbox { + fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()> { + match event { + Event::Xy(x, y, _idx) => { + self.expand_xy(x, y); + } + Event::Coordinate(x, y, _z, _m, _t, _tm, _idx) => { + self.expand_xy(x, y); + } + Event::PointBegin(_idifx) if !collection => { + self.reset(); + } + Event::MultiPointBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::LineStringBegin(_size, _idx) if !collection => { + if geom_type == GeometryType::LineString { + self.reset(); + } + } + Event::MultiLineStringBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::PolygonBegin(_size, _idx) if !collection => { + if geom_type == GeometryType::Polygon { + self.reset(); + } + } + Event::MultiPolygonBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::GeometryCollectionBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::CircularStringBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::CompoundCurveBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::CurvePolygonBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::MultiCurveBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::MultiSurfaceBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::TriangleBegin(_size, _idx) if !collection => { + if geom_type == GeometryType::Triangle { + self.reset(); + } + } + Event::PolyhedralSurfaceBegin(_size, _idx) if !collection => { + self.reset(); + } + Event::TinBegin(_sizeif, _idx) if !collection => { + self.reset(); + } + _ => {} + } + Ok(()) + } +} + +#[cfg(test)] +#[cfg(feature = "with-geojson")] +mod test { + use super::*; + use crate::api::GeozeroGeometry; + use crate::events::GeomVisitor; + use crate::geojson::GeoJson; + + #[test] + fn polygon() -> Result<()> { + let geojson = GeoJson( + r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, + ); + let mut processor = Bbox::default(); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + assert_eq!( + processor, + Bbox::new(19.304486, 39.624998, 21.02004, 42.688247) + ); + Ok(()) + } + + #[test] + fn geomcollection() -> Result<()> { + let geojson = GeoJson( + r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, + ); + let mut processor = Bbox::default(); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + assert_eq!(processor, Bbox::new(100.1, 0.1, 102.1, 1.1)); + Ok(()) + } +} diff --git a/geozero/src/processor/mod.rs b/geozero/src/processor/mod.rs new file mode 100644 index 00000000..3221605e --- /dev/null +++ b/geozero/src/processor/mod.rs @@ -0,0 +1,5 @@ +mod bbox; +mod sink; + +pub use bbox::*; +pub use sink::*; diff --git a/geozero/src/processor/sink.rs b/geozero/src/processor/sink.rs new file mode 100644 index 00000000..4bae1f2e --- /dev/null +++ b/geozero/src/processor/sink.rs @@ -0,0 +1,11 @@ +use crate::error::Result; +use crate::events::{Event, GeomEventProcessor, GeometryType}; + +/// Geometry processor without any actions +pub struct GeomEventSink; + +impl GeomEventProcessor for GeomEventSink { + fn event(&mut self, _event: Event, _geom_type: GeometryType, _collection: bool) -> Result<()> { + Ok(()) + } +} From a504c6afe8acab441a47830b743c04ca7c702332 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 11:17:46 +0200 Subject: [PATCH 12/22] Add chained processor PromoteToMulti --- geozero/src/events.rs | 2 +- geozero/src/geo_types/geo_types_writer.rs | 27 ++++--- geozero/src/processor/bbox.rs | 35 ++++----- geozero/src/processor/mod.rs | 2 + geozero/src/processor/promote_to_multi.rs | 88 +++++++++++++++++++++++ 5 files changed, 127 insertions(+), 27 deletions(-) create mode 100644 geozero/src/processor/promote_to_multi.rs diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 5c45b281..c8a52de9 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -883,7 +883,7 @@ pub(crate) mod test { #[test] fn invalid_transitions() -> Result<()> { - let mut processor = GeomEventSink {}; + let mut processor = GeomEventSink; let mut visitor = GeomVisitor::new(&mut processor); visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index c33ef695..3128b77a 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -70,17 +70,21 @@ impl GeomEventProcessor for GeoWriter { Event::EmptyPoint(_idx) => {} Event::PointBegin(_idx) => { - debug_assert!(self.coords.is_none()); - self.coords = Some(Vec::with_capacity(1)); + if geom_type == events::GeometryType::Point { + debug_assert!(self.coords.is_none()); + self.coords = Some(Vec::with_capacity(1)); + } } Event::PointEnd(_idx) => { - let coords = self - .coords - .take() - .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; - debug_assert!(coords.len() == 1); - self.finish_geometry(Point(coords[0]).into())?; + if geom_type == events::GeometryType::Point { + let coords = self + .coords + .take() + .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; + debug_assert!(coords.len() == 1); + self.finish_geometry(Point(coords[0]).into())?; + } } Event::MultiPointBegin(size, _idx) => { @@ -179,7 +183,12 @@ impl GeomEventProcessor for GeoWriter { self.finish_geometry(Geometry::GeometryCollection(GeometryCollection(geometries)))?; } - _ => return Err(GeozeroError::GeometryFormat), // ?? With GeomProcessor we ignore all other states + _ => { + return Err(GeozeroError::Geometry(format!( + "Unexpected geometry event {:?}", + event + ))) + } // ?? With GeomProcessor we ignore all other states } Ok(()) } diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index 93869029..a0fb731f 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -1,4 +1,5 @@ use crate::error::Result; +use crate::events::Event::*; use crate::events::{Event, GeomEventProcessor, GeometryType}; #[derive(Clone, PartialEq, Debug)] @@ -101,61 +102,61 @@ impl Bbox { impl GeomEventProcessor for Bbox { fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()> { match event { - Event::Xy(x, y, _idx) => { + Xy(x, y, _idx) => { self.expand_xy(x, y); } - Event::Coordinate(x, y, _z, _m, _t, _tm, _idx) => { + Coordinate(x, y, _z, _m, _t, _tm, _idx) => { self.expand_xy(x, y); } - Event::PointBegin(_idifx) if !collection => { + PointBegin(_idifx) if !collection => { self.reset(); } - Event::MultiPointBegin(_size, _idx) if !collection => { + MultiPointBegin(_size, _idx) if !collection => { self.reset(); } - Event::LineStringBegin(_size, _idx) if !collection => { + LineStringBegin(_size, _idx) if !collection => { if geom_type == GeometryType::LineString { self.reset(); } } - Event::MultiLineStringBegin(_size, _idx) if !collection => { + MultiLineStringBegin(_size, _idx) if !collection => { self.reset(); } - Event::PolygonBegin(_size, _idx) if !collection => { + PolygonBegin(_size, _idx) if !collection => { if geom_type == GeometryType::Polygon { self.reset(); } } - Event::MultiPolygonBegin(_size, _idx) if !collection => { + MultiPolygonBegin(_size, _idx) if !collection => { self.reset(); } - Event::GeometryCollectionBegin(_size, _idx) if !collection => { + GeometryCollectionBegin(_size, _idx) if !collection => { self.reset(); } - Event::CircularStringBegin(_size, _idx) if !collection => { + CircularStringBegin(_size, _idx) if !collection => { self.reset(); } - Event::CompoundCurveBegin(_size, _idx) if !collection => { + CompoundCurveBegin(_size, _idx) if !collection => { self.reset(); } - Event::CurvePolygonBegin(_size, _idx) if !collection => { + CurvePolygonBegin(_size, _idx) if !collection => { self.reset(); } - Event::MultiCurveBegin(_size, _idx) if !collection => { + MultiCurveBegin(_size, _idx) if !collection => { self.reset(); } - Event::MultiSurfaceBegin(_size, _idx) if !collection => { + MultiSurfaceBegin(_size, _idx) if !collection => { self.reset(); } - Event::TriangleBegin(_size, _idx) if !collection => { + TriangleBegin(_size, _idx) if !collection => { if geom_type == GeometryType::Triangle { self.reset(); } } - Event::PolyhedralSurfaceBegin(_size, _idx) if !collection => { + PolyhedralSurfaceBegin(_size, _idx) if !collection => { self.reset(); } - Event::TinBegin(_sizeif, _idx) if !collection => { + TinBegin(_sizeif, _idx) if !collection => { self.reset(); } _ => {} diff --git a/geozero/src/processor/mod.rs b/geozero/src/processor/mod.rs index 3221605e..45e99766 100644 --- a/geozero/src/processor/mod.rs +++ b/geozero/src/processor/mod.rs @@ -1,5 +1,7 @@ mod bbox; +mod promote_to_multi; mod sink; pub use bbox::*; +pub use promote_to_multi::*; pub use sink::*; diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs new file mode 100644 index 00000000..c1fe8466 --- /dev/null +++ b/geozero/src/processor/promote_to_multi.rs @@ -0,0 +1,88 @@ +use crate::chaining::ChainedGeomEventProcessor; +use crate::error::Result; +use crate::events::Event::*; +use crate::events::{Event, GeomEventProcessor, GeomVisitor, GeometryType}; + +/// Convert single geometry types to multi geometry types +pub struct PromoteToMulti; + +impl ChainedGeomEventProcessor for PromoteToMulti { + fn chain_event( + &mut self, + event: Event, + geom_type: GeometryType, + _collection: bool, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()> { + match event { + PointBegin(idx) if geom_type == GeometryType::Point => { + visitor.multipoint_begin(1, idx)?; + visitor.point_begin(0)?; + } + PointEnd(idx) if geom_type == GeometryType::Point => { + visitor.point_end(0)?; + visitor.multipoint_end(idx)?; + } + LineStringBegin(size, idx) if geom_type == GeometryType::LineString => { + visitor.multilinestring_begin(1, idx)?; + visitor.linestring_begin(size, 0)?; + } + LineStringEnd(idx) if geom_type == GeometryType::LineString => { + visitor.linestring_end(0)?; + visitor.multilinestring_end(idx)?; + } + PolygonBegin(size, idx) if geom_type == GeometryType::Polygon => { + visitor.multipolygon_begin(1, idx)?; + visitor.polygon_begin(size, 0)?; + } + PolygonEnd(idx) if geom_type == GeometryType::Polygon => { + visitor.polygon_end(0)?; + visitor.multipolygon_end(idx)?; + } + _ => visitor.emit(event)?, + } + Ok(()) + } +} + +#[cfg(test)] +#[cfg(feature = "with-geojson")] +mod test { + use super::*; + use crate::api::GeozeroGeometry; + use crate::chaining::ChainedProcessor; + use crate::events::GeomVisitor; + use crate::geo_types::GeoWriter; + use crate::geojson::conversion::ToJson; + use crate::geojson::GeoJson; + + #[test] + fn polygon() -> Result<()> { + let geojson = GeoJson( + r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, + ); + let mut processor1 = PromoteToMulti; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + let geom = processor2.take_geometry().unwrap(); + let expected = r#"{"type": "MultiPolygon", "coordinates": [[[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]]}"#; + assert_eq!(expected, geom.to_json()?); + Ok(()) + } + + #[test] + fn geomcollection() -> Result<()> { + let geojson = GeoJson( + r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, + ); + let mut processor1 = PromoteToMulti; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + let geom = processor2.take_geometry().unwrap(); + let expected = r#"{"type": "GeometryCollection", "geometries": [{"type": "MultiPoint", "coordinates": [[100.1,0.1]]},{"type": "MultiLineString", "coordinates": [[[101.1,0.1],[102.1,1.1]]]}]}"#; + assert_eq!(expected, geom.to_json()?); + Ok(()) + } +} From 7ed778e9e6dd2ccdb6d686194f856a3269633e1d Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 19:03:36 +0200 Subject: [PATCH 13/22] Add lat/lon->Mercator reprojection --- geozero/src/chaining.rs | 2 +- geozero/src/events.rs | 49 ++++++++++++++++- geozero/src/processor/mod.rs | 2 + geozero/src/processor/promote_to_multi.rs | 4 +- geozero/src/processor/reprojection.rs | 64 +++++++++++++++++++++++ 5 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 geozero/src/processor/reprojection.rs diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 8f099e83..0a73ab8f 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -106,7 +106,7 @@ mod test { visitor.point_end(0)?; visitor.multipoint_end(idx)?; } - _ => visitor.emit(event)?, + _ => visitor.emit_event(event)?, } Ok(()) } diff --git a/geozero/src/events.rs b/geozero/src/events.rs index c8a52de9..d72eef20 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -233,9 +233,56 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { processor, } } - pub fn emit(&mut self, event: Event) -> Result<()> { + fn emit(&mut self, event: Event) -> Result<()> { self.processor.event(event, self.geom_type, self.collection) } + /// Pass event to chained visitor with original state + pub fn chain_event( + &mut self, + event: Event, + geom_type: GeometryType, + collection: bool, + ) -> Result<()> { + self.processor.event(event, geom_type, collection) + } + /// Pass event to visitor with state recalculation + pub fn emit_event(&mut self, event: Event) -> Result<()> { + match event { + Event::Xy(x, y, idx) => self.xy(x, y, idx), + Event::Coordinate(x, y, z, m, t, tm, idx) => self.coordinate(x, y, z, m, t, tm, idx), + Event::EmptyPoint(idx) => self.empty_point(idx), + Event::PointBegin(idx) => self.point_begin(idx), + Event::PointEnd(idx) => self.point_end(idx), + Event::MultiPointBegin(size, idx) => self.multipoint_begin(size, idx), + Event::MultiPointEnd(idx) => self.multipoint_end(idx), + Event::LineStringBegin(size, idx) => self.linestring_begin(size, idx), + Event::LineStringEnd(idx) => self.linestring_end(idx), + Event::MultiLineStringBegin(size, idx) => self.multilinestring_begin(size, idx), + Event::MultiLineStringEnd(idx) => self.multilinestring_end(idx), + Event::PolygonBegin(size, idx) => self.polygon_begin(size, idx), + Event::PolygonEnd(idx) => self.polygon_end(idx), + Event::MultiPolygonBegin(size, idx) => self.multipolygon_begin(size, idx), + Event::MultiPolygonEnd(idx) => self.multipolygon_end(idx), + Event::GeometryCollectionBegin(size, idx) => self.geometrycollection_begin(size, idx), + Event::GeometryCollectionEnd(idx) => self.geometrycollection_end(idx), + Event::CircularStringBegin(size, idx) => self.circularstring_begin(size, idx), + Event::CircularStringEnd(idx) => self.circularstring_end(idx), + Event::CompoundCurveBegin(size, idx) => self.compoundcurve_begin(size, idx), + Event::CompoundCurveEnd(idx) => self.compoundcurve_end(idx), + Event::CurvePolygonBegin(size, idx) => self.curvepolygon_begin(size, idx), + Event::CurvePolygonEnd(idx) => self.curvepolygon_end(idx), + Event::MultiCurveBegin(size, idx) => self.multicurve_begin(size, idx), + Event::MultiCurveEnd(idx) => self.multicurve_end(idx), + Event::MultiSurfaceBegin(size, idx) => self.multisurface_begin(size, idx), + Event::MultiSurfaceEnd(idx) => self.multisurface_end(idx), + Event::TriangleBegin(size, idx) => self.triangle_begin(size, idx), + Event::TriangleEnd(idx) => self.triangle_end(idx), + Event::PolyhedralSurfaceBegin(size, idx) => self.polyhedralsurface_begin(size, idx), + Event::PolyhedralSurfaceEnd(idx) => self.polyhedralsurface_end(idx), + Event::TinBegin(size, idx) => self.tin_begin(size, idx), + Event::TinEnd(idx) => self.tin_end(idx), + } + } fn state(&self) -> &Vstate { let len = self.state_stack.len(); if len > 0 { diff --git a/geozero/src/processor/mod.rs b/geozero/src/processor/mod.rs index 45e99766..0666cd6b 100644 --- a/geozero/src/processor/mod.rs +++ b/geozero/src/processor/mod.rs @@ -1,7 +1,9 @@ mod bbox; mod promote_to_multi; +mod reprojection; mod sink; pub use bbox::*; pub use promote_to_multi::*; +pub use reprojection::*; pub use sink::*; diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs index c1fe8466..d6cec58b 100644 --- a/geozero/src/processor/promote_to_multi.rs +++ b/geozero/src/processor/promote_to_multi.rs @@ -39,14 +39,14 @@ impl ChainedGeomEventProcessor for PromoteToMulti { visitor.polygon_end(0)?; visitor.multipolygon_end(idx)?; } - _ => visitor.emit(event)?, + _ => visitor.emit_event(event)?, } Ok(()) } } #[cfg(test)] -#[cfg(feature = "with-geojson")] +#[cfg(all(feature = "with-geojson", feature = "with-geo"))] mod test { use super::*; use crate::api::GeozeroGeometry; diff --git a/geozero/src/processor/reprojection.rs b/geozero/src/processor/reprojection.rs new file mode 100644 index 00000000..ea006780 --- /dev/null +++ b/geozero/src/processor/reprojection.rs @@ -0,0 +1,64 @@ +use crate::chaining::ChainedGeomEventProcessor; +use crate::error::Result; +use crate::events::Event::*; +use crate::events::{Event, GeomEventProcessor, GeomVisitor, GeometryType}; +use std::f64::consts; + +/// Convert lon/lat to Spherical Mercator in meters +pub struct LonLatToMercator; + +fn lonlat_to_merc(lon: f64, lat: f64) -> (f64, f64) { + let x = 6378137.0 * lon.to_radians(); + let y = 6378137.0 * ((consts::PI * 0.25) + (0.5 * lat.to_radians())).tan().ln(); + (x, y) +} + +impl ChainedGeomEventProcessor for LonLatToMercator { + fn chain_event( + &mut self, + event: Event, + geom_type: GeometryType, + collection: bool, + visitor: &mut GeomVisitor<'_, P>, + ) -> Result<()> { + match event { + Xy(x, y, idx) => { + let (x, y) = lonlat_to_merc(x, y); + visitor.chain_event(Xy(x, y, idx), geom_type, collection)?; + } + Coordinate(x, y, z, m, t, tm, idx) => { + let (x, y) = lonlat_to_merc(x, y); + visitor.chain_event(Coordinate(x, y, z, m, t, tm, idx), geom_type, collection)?; + } + _ => visitor.chain_event(event, geom_type, collection)?, + } + Ok(()) + } +} + +#[cfg(test)] +#[cfg(all(feature = "with-geojson", feature = "with-geo"))] +mod test { + use super::*; + use crate::api::GeozeroGeometry; + use crate::chaining::ChainedProcessor; + use crate::events::GeomVisitor; + use crate::geo_types::GeoWriter; + use crate::geojson::conversion::ToJson; + use crate::geojson::GeoJson; + + #[test] + fn polygon() -> Result<()> { + let geojson = GeoJson( + r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, + ); + let mut processor1 = LonLatToMercator; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + let geom = processor2.take_geometry().unwrap(); + let expected = r#"{"type": "Polygon", "coordinates": [[[2292095.811347729,5139344.213425913],[2277950.2210136456,5088616.6330585545],[2293758.3679427262,5025068.310371113],[2339940.1492542424,4989171.535691388],[2337708.193463837,4950588.339806374],[2301530.138192459,4929358.117761691],[2294851.3027033345,4881941.097754033],[2243089.5205963156,4811596.717986056],[2224163.426049606,4821717.98297803],[2221937.2588727223,4853598.859120461],[2160275.1665325123,4902451.127115252],[2150587.810485209,4972191.022999316],[2159993.3055818235,5072941.548683907],[2175185.8557268167,5119126.5562673],[2156455.4608449223,5142654.340537157],[2148965.551545879,5190346.344385106],[2197229.7865716643,5264639.607013478],[2204305.476045466,5236187.825747299],[2234260.1038645557,5249565.284016839],[2257977.2779755164,5209074.219280535],[2284604.3435758143,5193671.390117393],[2292095.811347729,5139344.213425913]]]}"#; + assert_eq!(expected, geom.to_json()?); + Ok(()) + } +} From 7c3e1d450f53b1caffadb5cb04cbbd2bc2490d89 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 20:03:13 +0200 Subject: [PATCH 14/22] Shorten bbox event match expression --- geozero/src/geometry_processor.rs | 204 ------------------------------ geozero/src/processor/bbox.rs | 56 +++----- 2 files changed, 20 insertions(+), 240 deletions(-) diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 1e209f3e..1e1bc9fd 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -415,210 +415,6 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { } } -/* -impl GeomProcessor for dyn GeomEventProcessor { - fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { - self.event(Event::Xy(x, y, idx), events::GeometryType::Unknown, false) - } - fn coordinate( - &mut self, - x: f64, - y: f64, - z: Option, - m: Option, - t: Option, - tm: Option, - idx: usize, - ) -> Result<()> { - self.event( - Event::Coordinate(x, y, z, m, t, tm, idx), - events::GeometryType::Unknown, - false, - ) - } - fn point_begin(&mut self, idx: usize) -> Result<()> { - self.event(Event::PointBegin(idx), events::GeometryType::Unknown, false) - } - fn point_end(&mut self, idx: usize) -> Result<()> { - self.event(Event::PointEnd(idx), events::GeometryType::Unknown, false) - } - fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::MultiPointBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn multipoint_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::MultiPointEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn linestring_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { - self.event( - Event::LineStringBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn linestring_end(&mut self, tagged: bool, idx: usize) -> Result<()> { - self.event( - Event::LineStringEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::MultiLineStringBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn multilinestring_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::MultiLineStringEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn polygon_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { - self.event( - Event::PolygonBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn polygon_end(&mut self, tagged: bool, idx: usize) -> Result<()> { - self.event(Event::PolygonEnd(idx), events::GeometryType::Unknown, false) - } - fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::MultiPolygonBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn multipolygon_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::MultiPolygonEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::CircularStringBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn circularstring_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::CircularStringEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::CompoundCurveBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::CompoundCurveEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::CurvePolygonBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::CurvePolygonEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::MultiCurveBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn multicurve_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::MultiCurveEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::MultiSurfaceBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn multisurface_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::MultiSurfaceEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()> { - self.event( - Event::TriangleBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()> { - self.event( - Event::TriangleEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::PolyhedralSurfaceBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { - self.event( - Event::PolyhedralSurfaceEnd(idx), - events::GeometryType::Unknown, - false, - ) - } - fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()> { - self.event( - Event::TinBegin(size, idx), - events::GeometryType::Unknown, - false, - ) - } - fn tin_end(&mut self, idx: usize) -> Result<()> { - self.event(Event::TinEnd(idx), events::GeometryType::Unknown, false) - } -} -*/ - #[test] fn error_message() { use crate::error::GeozeroError; diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index a0fb731f..a4a41853 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -108,57 +108,41 @@ impl GeomEventProcessor for Bbox { Coordinate(x, y, _z, _m, _t, _tm, _idx) => { self.expand_xy(x, y); } - PointBegin(_idifx) if !collection => { + MultiPointBegin(_, _) + | MultiLineStringBegin(_, _) + | MultiPolygonBegin(_, _) + | GeometryCollectionBegin(_, _) + | CircularStringBegin(_, _) + | CompoundCurveBegin(_, _) + | CurvePolygonBegin(_, _) + | MultiCurveBegin(_, _) + | MultiSurfaceBegin(_, _) + | PolyhedralSurfaceBegin(_, _) + | TinBegin(_, _) + if !collection => + { self.reset(); } - MultiPointBegin(_size, _idx) if !collection => { - self.reset(); + PointBegin(_) if !collection => { + if geom_type == GeometryType::Point { + self.reset(); + } } - LineStringBegin(_size, _idx) if !collection => { + LineStringBegin(_, _) if !collection => { if geom_type == GeometryType::LineString { self.reset(); } } - MultiLineStringBegin(_size, _idx) if !collection => { - self.reset(); - } - PolygonBegin(_size, _idx) if !collection => { + PolygonBegin(_, _) if !collection => { if geom_type == GeometryType::Polygon { self.reset(); } } - MultiPolygonBegin(_size, _idx) if !collection => { - self.reset(); - } - GeometryCollectionBegin(_size, _idx) if !collection => { - self.reset(); - } - CircularStringBegin(_size, _idx) if !collection => { - self.reset(); - } - CompoundCurveBegin(_size, _idx) if !collection => { - self.reset(); - } - CurvePolygonBegin(_size, _idx) if !collection => { - self.reset(); - } - MultiCurveBegin(_size, _idx) if !collection => { - self.reset(); - } - MultiSurfaceBegin(_size, _idx) if !collection => { - self.reset(); - } - TriangleBegin(_size, _idx) if !collection => { + TriangleBegin(_, _) if !collection => { if geom_type == GeometryType::Triangle { self.reset(); } } - PolyhedralSurfaceBegin(_size, _idx) if !collection => { - self.reset(); - } - TinBegin(_sizeif, _idx) if !collection => { - self.reset(); - } _ => {} } Ok(()) From 2b28b569748f436a22a5d4b082a3d4ad0b8b4382 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 22 May 2022 20:34:19 +0200 Subject: [PATCH 15/22] Same MultiPoint state transition as in old API --- geozero/src/chaining.rs | 22 +++----------- geozero/src/events.rs | 37 ++++++++++++----------- geozero/src/geo_types/geo_types_writer.rs | 20 +++++------- geozero/src/processor/bbox.rs | 4 +-- geozero/src/processor/promote_to_multi.rs | 6 ++-- 5 files changed, 35 insertions(+), 54 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 0a73ab8f..745151f8 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -98,12 +98,10 @@ mod test { visitor: &mut GeomVisitor<'_, P>, ) -> Result<()> { match event { - PointBegin(idx) if geom_type == GeometryType::Point => { + PointBegin(idx) => { visitor.multipoint_begin(1, idx)?; - visitor.point_begin(0)?; } - PointEnd(idx) if geom_type == GeometryType::Point => { - visitor.point_end(0)?; + PointEnd(idx) => { visitor.multipoint_end(idx)?; } _ => visitor.emit_event(event)?, @@ -124,13 +122,7 @@ mod test { assert_eq!( processor2.buffer, - [ - MultiPointBegin(1, 0), - PointBegin(0), - Xy(0.0, 0.0, 0), - PointEnd(0), - MultiPointEnd(0) - ] + [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); Ok(()) @@ -171,13 +163,7 @@ mod test { assert_eq!( processor2a.buffer, - [ - MultiPointBegin(1, 0), - PointBegin(0), - Xy(0.0, 0.0, 0), - PointEnd(0), - MultiPointEnd(0) - ] + [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); assert_eq!( processor1b.buffer, diff --git a/geozero/src/events.rs b/geozero/src/events.rs index d72eef20..22f4bd99 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -31,27 +31,29 @@ use crate::error::{GeozeroError, Result}; /// | | | /// +--------^--------+ +--------v---------+ /// | | | -/// +-+-+-+-+-+ |GeometryCollection| +/// +-+-+---+-+ |GeometryCollection| /// | | | | | | | | /// v v v v v v +--------^---------+ /// +-----------------+ | -/// | | +-+-+-+-+-+ +/// | | +-+-+---+-+ /// | MultiPolygon | | | | | | | /// | | v v v v v v -/// +--------^--------+ +-----------------+ +-----------------+ -/// | | | | | -/// | | MultiLineString | | MultiPoint | -/// +--------v--------+ | | | | -/// | | +--------^--------+ +--------^--------+ -/// | Polygon | | | -/// | | | | -/// +--------^--------+ +--------v--------+ +--------v--------+ -/// | | | | | -/// +----------->| LineString | | Point | -/// | | | | -/// +--------+--------+ +--------+--------+ -/// | | -/// +------------> Coordinate <------------+ +/// +--------^--------+ +-----------------+ +/// | | | +/// | | MultiLineString | +/// +--------v--------+ | | +/// | | +--------^--------+ +/// | Polygon | | +/// | | | +/// +--------^--------+ +--------v--------+ +-------------+ +--------------+ +/// | | | | | | | +/// +----------->+ LineString | | Point | | MultiPoint | +/// | | | | | | +/// +--------+--------+ +-----------------+ +------+------+ +-------+------+ +/// | | | | | +/// +------------> Coordinate <----------+------------------+ +/// | | +/// +-----------------+ /// ``` #[derive(Clone, PartialEq, Debug)] pub enum Event { @@ -311,7 +313,6 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { | (Vstate::Initial, Vstate::Tin) | (Vstate::Initial, Vstate::Triangle) | (Vstate::Polygon, Vstate::LineString) - | (Vstate::MultiPoint, Vstate::Point) | (Vstate::MultiLineString, Vstate::LineString) | (Vstate::MultiPolygon, Vstate::Polygon) | (Vstate::GeometryCollection, Vstate::Point) @@ -441,6 +442,8 @@ impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { } /// Begin of MultiPoint processing + /// + /// Next: size * xy/coordinate pub fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()> { self.set_type(GeometryType::MultiPoint)?; if self.check_states { diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index 3128b77a..d125820e 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -70,21 +70,17 @@ impl GeomEventProcessor for GeoWriter { Event::EmptyPoint(_idx) => {} Event::PointBegin(_idx) => { - if geom_type == events::GeometryType::Point { - debug_assert!(self.coords.is_none()); - self.coords = Some(Vec::with_capacity(1)); - } + debug_assert!(self.coords.is_none()); + self.coords = Some(Vec::with_capacity(1)); } Event::PointEnd(_idx) => { - if geom_type == events::GeometryType::Point { - let coords = self - .coords - .take() - .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; - debug_assert!(coords.len() == 1); - self.finish_geometry(Point(coords[0]).into())?; - } + let coords = self + .coords + .take() + .ok_or(GeozeroError::Geometry("No coords for Point".to_string()))?; + debug_assert!(coords.len() == 1); + self.finish_geometry(Point(coords[0]).into())?; } Event::MultiPointBegin(size, _idx) => { diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index a4a41853..73d00be7 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -124,9 +124,7 @@ impl GeomEventProcessor for Bbox { self.reset(); } PointBegin(_) if !collection => { - if geom_type == GeometryType::Point { - self.reset(); - } + self.reset(); } LineStringBegin(_, _) if !collection => { if geom_type == GeometryType::LineString { diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs index d6cec58b..0447b06f 100644 --- a/geozero/src/processor/promote_to_multi.rs +++ b/geozero/src/processor/promote_to_multi.rs @@ -15,12 +15,10 @@ impl ChainedGeomEventProcessor for PromoteToMulti { visitor: &mut GeomVisitor<'_, P>, ) -> Result<()> { match event { - PointBegin(idx) if geom_type == GeometryType::Point => { + PointBegin(idx) => { visitor.multipoint_begin(1, idx)?; - visitor.point_begin(0)?; } - PointEnd(idx) if geom_type == GeometryType::Point => { - visitor.point_end(0)?; + PointEnd(idx) => { visitor.multipoint_end(idx)?; } LineStringBegin(size, idx) if geom_type == GeometryType::LineString => { From bd3f1ddb7842401a8c70b29a0be1ce41b13e5147 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 23 May 2022 23:42:48 +0200 Subject: [PATCH 16/22] Make processors owned by visitor --- geozero/src/chaining.rs | 61 ++++++++++------------- geozero/src/events.rs | 51 +++++++++---------- geozero/src/geo_types/geo_types_writer.rs | 11 ++-- geozero/src/geo_types/mod.rs | 9 ++-- geozero/src/geometry_processor.rs | 3 +- geozero/src/processor/bbox.rs | 12 ++--- geozero/src/processor/promote_to_multi.rs | 24 +++++---- geozero/src/processor/reprojection.rs | 13 ++--- 8 files changed, 90 insertions(+), 94 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 745151f8..0c5d672a 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -14,18 +14,18 @@ pub trait ChainedGeomEventProcessor { event: Event, geom_type: GeometryType, collection: bool, - visitor: &mut GeomVisitor<'_, P>, + visitor: &mut GeomVisitor

, ) -> Result<()>; } /// Chaining [GeomEventProcessor] -pub struct ChainedProcessor<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> { - processor1: &'a mut P1, - visitor: GeomVisitor<'a, P2>, +pub struct ChainedProcessor { + pub processor1: P1, + pub visitor: GeomVisitor, } -impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor<'a, P1, P2> { - pub fn new(processor1: &'a mut P1, processor2: &'a mut P2) -> Self { +impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor { + pub fn new(processor1: P1, processor2: P2) -> Self { ChainedProcessor { processor1, visitor: GeomVisitor::new(processor2), @@ -34,7 +34,7 @@ impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor } impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor - for ChainedProcessor<'a, P1, P2> + for ChainedProcessor { fn event( &mut self, @@ -50,13 +50,13 @@ impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcess // ------- Duplex --------- /// Duplexing [GeomEventProcessor] -pub struct DuplexProcessor<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> { - processor1: &'a mut P1, - processor2: &'a mut P2, +pub struct DuplexProcessor { + pub processor1: P1, + pub processor2: P2, } -impl<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> DuplexProcessor<'a, P1, P2> { - pub fn new(processor1: &'a mut P1, processor2: &'a mut P2) -> Self { +impl DuplexProcessor { + pub fn new(processor1: P1, processor2: P2) -> Self { DuplexProcessor { processor1, processor2, @@ -64,8 +64,8 @@ impl<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> DuplexProcessor<'a, P1, } } -impl<'a, P1: GeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor - for DuplexProcessor<'a, P1, P2> +impl GeomEventProcessor + for DuplexProcessor { fn event( &mut self, @@ -93,9 +93,9 @@ mod test { fn chain_event( &mut self, event: Event, - geom_type: GeometryType, + _geom_type: GeometryType, _collection: bool, - visitor: &mut GeomVisitor<'_, P>, + visitor: &mut GeomVisitor

, ) -> Result<()> { match event { PointBegin(idx) => { @@ -112,16 +112,14 @@ mod test { #[test] fn chained_processor() -> Result<()> { - let mut processor1 = PromoteToMulti; - let mut processor2 = GeomEventBuffer::new(); - let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); - let mut visitor = GeomVisitor::new(&mut processor); + let processor = ChainedProcessor::new(PromoteToMulti, GeomEventBuffer::new()); + let mut visitor = GeomVisitor::new(processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - processor2.buffer, + visitor.processor.visitor.processor.buffer, [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); @@ -130,16 +128,14 @@ mod test { #[test] fn duplex_processor() -> Result<()> { - let mut processor1 = GeomEventSink; - let mut processor2 = GeomEventBuffer::new(); - let mut processor = DuplexProcessor::new(&mut processor1, &mut processor2); - let mut visitor = GeomVisitor::new(&mut processor); + let processor = DuplexProcessor::new(GeomEventSink, GeomEventBuffer::new()); + let mut visitor = GeomVisitor::new(processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - processor2.buffer, + visitor.processor.processor2.buffer, [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] ); @@ -151,22 +147,19 @@ mod test { // geom ------+----> PromoteToMulti (1a) ----> GeomEventBuffer (2a) // | // +----> GeomEventBuffer (1b) - let mut processor1a = PromoteToMulti; - let mut processor2a = GeomEventBuffer::new(); - let mut processor_a = ChainedProcessor::new(&mut processor1a, &mut processor2a); - let mut processor1b = GeomEventBuffer::new(); - let mut processor = DuplexProcessor::new(&mut processor_a, &mut processor1b); - let mut visitor = GeomVisitor::new(&mut processor); + let processor_a = ChainedProcessor::new(PromoteToMulti, GeomEventBuffer::new()); + let processor = DuplexProcessor::new(processor_a, GeomEventBuffer::new()); + let mut visitor = GeomVisitor::new(processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - processor2a.buffer, + visitor.processor.processor1.visitor.processor.buffer, // 2a [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); assert_eq!( - processor1b.buffer, + visitor.processor.processor2.buffer, // 1b [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] ); diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 22f4bd99..b929f726 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -199,7 +199,7 @@ enum Vstate { } /// Geometry visitor emitting events to a processor -pub struct GeomVisitor<'a, P: GeomEventProcessor> { +pub struct GeomVisitor { // pub dims: CoordDimensions, pub check_states: bool, /// Main geometry type @@ -207,7 +207,8 @@ pub struct GeomVisitor<'a, P: GeomEventProcessor> { /// Geometry is part of collection collection: bool, state_stack: Vec, - processor: &'a mut P, + /// Event processor + pub processor: P, } /// Processing geometry events, e.g. for producing an output geometry @@ -219,14 +220,11 @@ pub trait GeomEventProcessor { /// Reading geometries by passing events to a visitor object pub trait GeometryReader { /// Process geometry. - fn process_geom( - &mut self, - visitor: &mut GeomVisitor<'_, P>, - ) -> Result<()>; + fn process_geom(&mut self, visitor: &mut GeomVisitor

) -> Result<()>; } -impl<'a, P: GeomEventProcessor> GeomVisitor<'a, P> { - pub fn new(processor: &'a mut P) -> Self { +impl GeomVisitor

{ + pub fn new(processor: P) -> Self { GeomVisitor { check_states: true, // Should maybe set from env var? geom_type: GeometryType::Unknown, @@ -778,7 +776,7 @@ pub(crate) mod test { impl GeometryReader for NullIsland { fn process_geom( &mut self, - visitor: &mut GeomVisitor<'_, P>, + visitor: &mut GeomVisitor

, ) -> Result<()> { visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; @@ -813,14 +811,12 @@ pub(crate) mod test { #[test] fn processing() -> Result<()> { - let mut processor = GeomEventBuffer::new(); - let mut visitor = GeomVisitor::new(&mut processor); - + let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - processor.buffer, + visitor.processor.buffer, [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0)] ); @@ -850,24 +846,24 @@ pub(crate) mod test { #[test] fn process_point() -> Result<()> { - let mut geom_out = Point2D { + let geom_out = Point2D { x: f64::NAN, y: f64::NAN, }; - let mut visitor = GeomVisitor::new(&mut geom_out); + let mut visitor = GeomVisitor::new(geom_out); let mut geom_in = NullIsland; geom_in.process_geom(&mut visitor)?; - assert_eq!((geom_out.x, geom_out.y), (0.0, 0.0)); + let geom = visitor.processor; + assert_eq!((geom.x, geom.y), (0.0, 0.0)); Ok(()) } #[test] fn polygon() -> Result<()> { - let mut processor = GeomEventBuffer::new(); - let mut visitor = GeomVisitor::new(&mut processor); + let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); visitor.polygon_begin(2, 0)?; visitor.linestring_begin(2, 0)?; visitor.xy(0.0, 0.0, 0)?; @@ -879,9 +875,9 @@ pub(crate) mod test { visitor.linestring_end(1)?; visitor.polygon_end(0)?; - dbg!(&processor.buffer); + dbg!(&visitor.processor.buffer); assert_eq!( - processor.buffer, + visitor.processor.buffer, [ PolygonBegin(2, 0), LineStringBegin(2, 0), @@ -901,8 +897,7 @@ pub(crate) mod test { #[test] fn collection() -> Result<()> { - let mut processor = GeomEventBuffer::new(); - let mut visitor = GeomVisitor::new(&mut processor); + let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); visitor.geometrycollection_begin(2, 0)?; visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; @@ -914,7 +909,7 @@ pub(crate) mod test { visitor.geometrycollection_end(0)?; assert_eq!( - processor.buffer, + visitor.processor.buffer, [ GeometryCollectionBegin(2, 0), PointBegin(0), @@ -933,8 +928,8 @@ pub(crate) mod test { #[test] fn invalid_transitions() -> Result<()> { - let mut processor = GeomEventSink; - let mut visitor = GeomVisitor::new(&mut processor); + let processor = GeomEventSink; + let mut visitor = GeomVisitor::new(processor); visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; let result = visitor.polygon_end(0); @@ -957,10 +952,10 @@ pub(crate) mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut processor = GeomEventBuffer::new(); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); + geojson.process_geom(&mut visitor)?; assert_eq!( - processor.buffer, + visitor.processor.buffer, [ PolygonBegin(1, 0), LineStringBegin(22, 0), diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index d125820e..ef61e341 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -190,9 +190,9 @@ impl GeomEventProcessor for GeoWriter { } } -impl PropertyProcessor for events::GeomVisitor<'_, GeoWriter> {} +impl PropertyProcessor for events::GeomVisitor {} -impl FeatureProcessor for events::GeomVisitor<'_, GeoWriter> {} +impl FeatureProcessor for events::GeomVisitor {} #[cfg(test)] #[cfg(feature = "with-geojson")] @@ -300,9 +300,10 @@ mod test { {"type": "Feature", "properties": {"id": "ALB", "name": "Albania"}, "geometry": {"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}, {"type": "Feature", "properties": {"id": "TLS", "name": "East Timor"}, "geometry": {"type": "MultiPolygon", "coordinates": [[[[124.968682, -8.89279], [125.086246, -8.656887], [125.947072, -8.432095], [126.644704, -8.398247], [126.957243, -8.273345], [127.335928, -8.397317], [126.967992, -8.668256], [125.925885, -9.106007], [125.08852, -9.393173], [125.07002, -9.089987], [124.968682, -8.89279]]]]}} ]}"#; - let mut geo = GeoWriter::new(); - assert!(read_geojson(geojson.as_bytes(), &mut GeomVisitor::new(&mut geo)).is_ok()); - let geom = geo.take_geometry().unwrap(); + let geo = GeoWriter::new(); + let mut visitor = GeomVisitor::new(geo); + assert!(read_geojson(geojson.as_bytes(), &mut visitor).is_ok()); + let geom = visitor.processor.take_geometry().unwrap(); dbg!(&geom); println!("{}", geom.to_json()?); // TODO: we get a broken GeometryCollection diff --git a/geozero/src/geo_types/mod.rs b/geozero/src/geo_types/mod.rs index 2eaeee61..b7af3bb8 100644 --- a/geozero/src/geo_types/mod.rs +++ b/geozero/src/geo_types/mod.rs @@ -19,9 +19,12 @@ pub(crate) mod conversion { impl ToGeo for T { fn to_geo(&self) -> Result> { - let mut geo = GeoWriter::new(); - self.process_geom(&mut GeomVisitor::new(&mut geo))?; - geo.take_geometry() + let geo = GeoWriter::new(); + let mut visitor = GeomVisitor::new(geo); + self.process_geom(&mut visitor)?; + visitor + .processor + .take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } } diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 1e1bc9fd..d6da9ca3 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -304,7 +304,7 @@ pub trait GeomProcessor { } } -impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { +impl GeomProcessor for GeomVisitor

{ fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { self.xy(x, y, idx) } @@ -415,6 +415,7 @@ impl<'a, P: GeomEventProcessor> GeomProcessor for GeomVisitor<'a, P> { } } + #[test] fn error_message() { use crate::error::GeozeroError; diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index 73d00be7..59d57b6c 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -160,10 +160,10 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut processor = Bbox::default(); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; + let mut visitor = GeomVisitor::new(Bbox::default()); + geojson.process_geom(&mut visitor)?; assert_eq!( - processor, + visitor.processor, Bbox::new(19.304486, 39.624998, 21.02004, 42.688247) ); Ok(()) @@ -174,9 +174,9 @@ mod test { let geojson = GeoJson( r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, ); - let mut processor = Bbox::default(); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; - assert_eq!(processor, Bbox::new(100.1, 0.1, 102.1, 1.1)); + let mut visitor = GeomVisitor::new(Bbox::default()); + geojson.process_geom(&mut visitor)?; + assert_eq!(visitor.processor, Bbox::new(100.1, 0.1, 102.1, 1.1)); Ok(()) } } diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs index 0447b06f..d72a7f43 100644 --- a/geozero/src/processor/promote_to_multi.rs +++ b/geozero/src/processor/promote_to_multi.rs @@ -12,7 +12,7 @@ impl ChainedGeomEventProcessor for PromoteToMulti { event: Event, geom_type: GeometryType, _collection: bool, - visitor: &mut GeomVisitor<'_, P>, + visitor: &mut GeomVisitor

, ) -> Result<()> { match event { PointBegin(idx) => { @@ -59,11 +59,12 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut processor1 = PromoteToMulti; - let mut processor2 = GeoWriter::new(); // TODO: Json writer - let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; - let geom = processor2.take_geometry().unwrap(); + let processor1 = PromoteToMulti; + let processor2 = GeoWriter::new(); // TODO: Json writer + let processor = ChainedProcessor::new(processor1, processor2); + let mut visitor = GeomVisitor::new(processor); + geojson.process_geom(&mut visitor)?; + let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); // processor2 let expected = r#"{"type": "MultiPolygon", "coordinates": [[[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) @@ -74,11 +75,12 @@ mod test { let geojson = GeoJson( r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, ); - let mut processor1 = PromoteToMulti; - let mut processor2 = GeoWriter::new(); // TODO: Json writer - let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; - let geom = processor2.take_geometry().unwrap(); + let processor1 = PromoteToMulti; + let processor2 = GeoWriter::new(); // TODO: Json writer + let processor = ChainedProcessor::new(processor1, processor2); + let mut visitor = GeomVisitor::new(processor); + geojson.process_geom(&mut visitor)?; + let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); // processor2 let expected = r#"{"type": "GeometryCollection", "geometries": [{"type": "MultiPoint", "coordinates": [[100.1,0.1]]},{"type": "MultiLineString", "coordinates": [[[101.1,0.1],[102.1,1.1]]]}]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) diff --git a/geozero/src/processor/reprojection.rs b/geozero/src/processor/reprojection.rs index ea006780..a9410bf8 100644 --- a/geozero/src/processor/reprojection.rs +++ b/geozero/src/processor/reprojection.rs @@ -19,7 +19,7 @@ impl ChainedGeomEventProcessor for LonLatToMercator { event: Event, geom_type: GeometryType, collection: bool, - visitor: &mut GeomVisitor<'_, P>, + visitor: &mut GeomVisitor

, ) -> Result<()> { match event { Xy(x, y, idx) => { @@ -52,11 +52,12 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut processor1 = LonLatToMercator; - let mut processor2 = GeoWriter::new(); // TODO: Json writer - let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); - geojson.process_geom(&mut GeomVisitor::new(&mut processor))?; - let geom = processor2.take_geometry().unwrap(); + let processor1 = LonLatToMercator; + let processor2 = GeoWriter::new(); // TODO: Json writer + let processor = ChainedProcessor::new(processor1, processor2); + let mut visitor = GeomVisitor::new(processor); + geojson.process_geom(&mut visitor)?; + let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); let expected = r#"{"type": "Polygon", "coordinates": [[[2292095.811347729,5139344.213425913],[2277950.2210136456,5088616.6330585545],[2293758.3679427262,5025068.310371113],[2339940.1492542424,4989171.535691388],[2337708.193463837,4950588.339806374],[2301530.138192459,4929358.117761691],[2294851.3027033345,4881941.097754033],[2243089.5205963156,4811596.717986056],[2224163.426049606,4821717.98297803],[2221937.2588727223,4853598.859120461],[2160275.1665325123,4902451.127115252],[2150587.810485209,4972191.022999316],[2159993.3055818235,5072941.548683907],[2175185.8557268167,5119126.5562673],[2156455.4608449223,5142654.340537157],[2148965.551545879,5190346.344385106],[2197229.7865716643,5264639.607013478],[2204305.476045466,5236187.825747299],[2234260.1038645557,5249565.284016839],[2257977.2779755164,5209074.219280535],[2284604.3435758143,5193671.390117393],[2292095.811347729,5139344.213425913]]]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) From 089f0a5839bf78083236743f5a35d08fdfd6a7a7 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Tue, 24 May 2022 01:00:40 +0200 Subject: [PATCH 17/22] Pass events by reference --- geozero/src/chaining.rs | 13 ++-- geozero/src/events.rs | 84 +++++++++++------------ geozero/src/geo_types/geo_types_writer.rs | 4 +- geozero/src/geometry_processor.rs | 1 - geozero/src/processor/bbox.rs | 4 +- geozero/src/processor/promote_to_multi.rs | 4 +- geozero/src/processor/reprojection.rs | 8 +-- geozero/src/processor/sink.rs | 2 +- 8 files changed, 59 insertions(+), 61 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 0c5d672a..282ac5ed 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -11,7 +11,7 @@ pub trait ChainedGeomEventProcessor { /// Geometry processing event with geometry type information fn chain_event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, collection: bool, visitor: &mut GeomVisitor

, @@ -38,7 +38,7 @@ impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcess { fn event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, collection: bool, ) -> crate::error::Result<()> { @@ -69,12 +69,11 @@ impl GeomEventProcessor { fn event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, collection: bool, ) -> crate::error::Result<()> { - self.processor1 - .event(event.clone(), geom_type, collection)?; + self.processor1.event(event, geom_type, collection)?; self.processor2.event(event, geom_type, collection)?; Ok(()) } @@ -92,12 +91,12 @@ mod test { impl ChainedGeomEventProcessor for PromoteToMulti { fn chain_event( &mut self, - event: Event, + event: &Event, _geom_type: GeometryType, _collection: bool, visitor: &mut GeomVisitor

, ) -> Result<()> { - match event { + match *event { PointBegin(idx) => { visitor.multipoint_begin(1, idx)?; } diff --git a/geozero/src/events.rs b/geozero/src/events.rs index b929f726..da34b803 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -214,7 +214,7 @@ pub struct GeomVisitor { /// Processing geometry events, e.g. for producing an output geometry pub trait GeomEventProcessor { /// Geometry processing event with geometry type information - fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()>; + fn event(&mut self, event: &Event, geom_type: GeometryType, collection: bool) -> Result<()>; } /// Reading geometries by passing events to a visitor object @@ -233,21 +233,21 @@ impl GeomVisitor

{ processor, } } - fn emit(&mut self, event: Event) -> Result<()> { + fn emit(&mut self, event: &Event) -> Result<()> { self.processor.event(event, self.geom_type, self.collection) } /// Pass event to chained visitor with original state pub fn chain_event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, collection: bool, ) -> Result<()> { self.processor.event(event, geom_type, collection) } /// Pass event to visitor with state recalculation - pub fn emit_event(&mut self, event: Event) -> Result<()> { - match event { + pub fn emit_event(&mut self, event: &Event) -> Result<()> { + match *event { Event::Xy(x, y, idx) => self.xy(x, y, idx), Event::Coordinate(x, y, z, m, t, tm, idx) => self.coordinate(x, y, z, m, t, tm, idx), Event::EmptyPoint(idx) => self.empty_point(idx), @@ -390,7 +390,7 @@ impl GeomVisitor

{ } /// Process coordinate with x,y dimensions pub fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { - self.emit(Event::Xy(x, y, idx)) + self.emit(&Event::Xy(x, y, idx)) } /// Process coordinate with all requested dimensions @@ -404,7 +404,7 @@ impl GeomVisitor

{ tm: Option, idx: usize, ) -> Result<()> { - self.emit(Event::Coordinate(x, y, z, m, t, tm, idx)) + self.emit(&Event::Coordinate(x, y, z, m, t, tm, idx)) } /// Process empty coordinates, like WKT's `POINT EMPTY` pub fn empty_point(&mut self, idx: usize) -> Result<()> { @@ -412,7 +412,7 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::Point)?; } - self.emit(Event::EmptyPoint(idx))?; + self.emit(&Event::EmptyPoint(idx))?; if self.check_states { self.exit_state(Vstate::Point)?; } @@ -425,13 +425,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::Point)?; } - self.emit(Event::PointBegin(idx))?; + self.emit(&Event::PointBegin(idx))?; Ok(()) } /// End of Point processing pub fn point_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::PointEnd(idx))?; + self.emit(&Event::PointEnd(idx))?; self.reset_type(GeometryType::Point); if self.check_states { self.exit_state(Vstate::Point)?; @@ -447,13 +447,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::MultiPoint)?; } - self.emit(Event::MultiPointBegin(size, idx))?; + self.emit(&Event::MultiPointBegin(size, idx))?; Ok(()) } /// End of MultiPoint processing pub fn multipoint_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::MultiPointEnd(idx))?; + self.emit(&Event::MultiPointEnd(idx))?; self.reset_type(GeometryType::MultiPoint); if self.check_states { self.exit_state(Vstate::MultiPoint)?; @@ -471,13 +471,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::LineString)?; } - self.emit(Event::LineStringBegin(size, idx))?; + self.emit(&Event::LineStringBegin(size, idx))?; Ok(()) } /// End of LineString processing pub fn linestring_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::LineStringEnd(idx))?; + self.emit(&Event::LineStringEnd(idx))?; self.reset_type(GeometryType::LineString); if self.check_states { self.exit_state(Vstate::LineString)?; @@ -493,13 +493,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::MultiLineString)?; } - self.emit(Event::MultiLineStringBegin(size, idx))?; + self.emit(&Event::MultiLineStringBegin(size, idx))?; Ok(()) } /// End of MultiLineString processing pub fn multilinestring_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::MultiLineStringEnd(idx))?; + self.emit(&Event::MultiLineStringEnd(idx))?; self.reset_type(GeometryType::MultiLineString); if self.check_states { self.exit_state(Vstate::MultiLineString)?; @@ -517,13 +517,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::Polygon)?; } - self.emit(Event::PolygonBegin(size, idx))?; + self.emit(&Event::PolygonBegin(size, idx))?; Ok(()) } /// End of Polygon processing pub fn polygon_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::PolygonEnd(idx))?; + self.emit(&Event::PolygonEnd(idx))?; self.reset_type(GeometryType::Polygon); if self.check_states { self.exit_state(Vstate::Polygon)?; @@ -539,13 +539,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::MultiPolygon)?; } - self.emit(Event::MultiPolygonBegin(size, idx))?; + self.emit(&Event::MultiPolygonBegin(size, idx))?; Ok(()) } /// End of MultiPolygon processing pub fn multipolygon_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::MultiPolygonEnd(idx))?; + self.emit(&Event::MultiPolygonEnd(idx))?; self.reset_type(GeometryType::MultiPolygon); if self.check_states { self.exit_state(Vstate::MultiPolygon)?; @@ -560,13 +560,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::GeometryCollection)?; } - self.emit(Event::GeometryCollectionBegin(size, idx))?; + self.emit(&Event::GeometryCollectionBegin(size, idx))?; Ok(()) } /// End of GeometryCollection processing pub fn geometrycollection_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::GeometryCollectionEnd(idx))?; + self.emit(&Event::GeometryCollectionEnd(idx))?; self.geom_type = GeometryType::Unknown; if self.check_states { self.exit_state(Vstate::GeometryCollection)?; @@ -585,13 +585,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::CircularString)?; } - self.emit(Event::CircularStringBegin(size, idx))?; + self.emit(&Event::CircularStringBegin(size, idx))?; Ok(()) } /// End of CircularString processing pub fn circularstring_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::CircularStringEnd(idx))?; + self.emit(&Event::CircularStringEnd(idx))?; self.reset_type(GeometryType::CircularString); if self.check_states { self.exit_state(Vstate::CircularString)?; @@ -609,13 +609,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::CompoundCurve)?; } - self.emit(Event::CompoundCurveBegin(size, idx))?; + self.emit(&Event::CompoundCurveBegin(size, idx))?; Ok(()) } /// End of CompoundCurve processing pub fn compoundcurve_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::CompoundCurveEnd(idx))?; + self.emit(&Event::CompoundCurveEnd(idx))?; self.reset_type(GeometryType::CompoundCurve); if self.check_states { self.exit_state(Vstate::CompoundCurve)?; @@ -633,13 +633,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::CurvePolygon)?; } - self.emit(Event::CurvePolygonBegin(size, idx))?; + self.emit(&Event::CurvePolygonBegin(size, idx))?; Ok(()) } /// End of CurvePolygon processing pub fn curvepolygon_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::CurvePolygonEnd(idx))?; + self.emit(&Event::CurvePolygonEnd(idx))?; self.reset_type(GeometryType::CurvePolygon); if self.check_states { self.exit_state(Vstate::CurvePolygon)?; @@ -657,13 +657,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::MultiCurve)?; } - self.emit(Event::MultiCurveBegin(size, idx))?; + self.emit(&Event::MultiCurveBegin(size, idx))?; Ok(()) } /// End of MultiCurve processing pub fn multicurve_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::MultiCurveEnd(idx))?; + self.emit(&Event::MultiCurveEnd(idx))?; self.reset_type(GeometryType::MultiCurve); if self.check_states { self.exit_state(Vstate::MultiCurve)?; @@ -681,13 +681,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::MultiSurface)?; } - self.emit(Event::MultiSurfaceBegin(size, idx))?; + self.emit(&Event::MultiSurfaceBegin(size, idx))?; Ok(()) } /// End of MultiSurface processing pub fn multisurface_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::MultiSurfaceEnd(idx))?; + self.emit(&Event::MultiSurfaceEnd(idx))?; self.reset_type(GeometryType::MultiSurface); if self.check_states { self.exit_state(Vstate::MultiSurface)?; @@ -704,13 +704,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::Triangle)?; } - self.emit(Event::TriangleBegin(size, idx))?; + self.emit(&Event::TriangleBegin(size, idx))?; Ok(()) } /// End of Triangle processing pub fn triangle_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::TriangleEnd(idx))?; + self.emit(&Event::TriangleEnd(idx))?; self.reset_type(GeometryType::Triangle); if self.check_states { self.exit_state(Vstate::Triangle)?; @@ -726,13 +726,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::PolyhedralSurface)?; } - self.emit(Event::PolyhedralSurfaceBegin(size, idx))?; + self.emit(&Event::PolyhedralSurfaceBegin(size, idx))?; Ok(()) } /// End of PolyhedralSurface processing pub fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::PolyhedralSurfaceEnd(idx))?; + self.emit(&Event::PolyhedralSurfaceEnd(idx))?; self.reset_type(GeometryType::PolyhedralSurface); if self.check_states { self.exit_state(Vstate::PolyhedralSurface)?; @@ -748,13 +748,13 @@ impl GeomVisitor

{ if self.check_states { self.enter_state(Vstate::Tin)?; } - self.emit(Event::TinBegin(size, idx))?; + self.emit(&Event::TinBegin(size, idx))?; Ok(()) } /// End of Tin processing pub fn tin_end(&mut self, idx: usize) -> Result<()> { - self.emit(Event::TinEnd(idx))?; + self.emit(&Event::TinEnd(idx))?; self.reset_type(GeometryType::Tin); if self.check_states { self.exit_state(Vstate::Tin)?; @@ -800,11 +800,11 @@ pub(crate) mod test { impl GeomEventProcessor for GeomEventBuffer { fn event( &mut self, - event: Event, + event: &Event, _geom_type: GeometryType, _collection: bool, ) -> Result<()> { - self.buffer.push(event); + self.buffer.push(event.clone()); Ok(()) } } @@ -831,11 +831,11 @@ pub(crate) mod test { impl GeomEventProcessor for Point2D { fn event( &mut self, - event: Event, + event: &Event, _geom_type: GeometryType, _collection: bool, ) -> Result<()> { - match event { + match *event { PointBegin(_) | PointEnd(_) => {} // OK Xy(x, y, _idx) => (self.x, self.y) = (x, y), _ => return Err(GeozeroError::GeometryFormat), diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index ef61e341..a39e8083 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -54,11 +54,11 @@ impl GeoWriter { impl GeomEventProcessor for GeoWriter { fn event( &mut self, - event: Event, + event: &Event, geom_type: events::GeometryType, _collection: bool, ) -> Result<()> { - match event { + match *event { Event::Xy(x, y, _idx) => { let coords = self .coords diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index d6da9ca3..5a6c28f6 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -415,7 +415,6 @@ impl GeomProcessor for GeomVisitor

{ } } - #[test] fn error_message() { use crate::error::GeozeroError; diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index 59d57b6c..1e440d26 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -100,8 +100,8 @@ impl Bbox { } impl GeomEventProcessor for Bbox { - fn event(&mut self, event: Event, geom_type: GeometryType, collection: bool) -> Result<()> { - match event { + fn event(&mut self, event: &Event, geom_type: GeometryType, collection: bool) -> Result<()> { + match *event { Xy(x, y, _idx) => { self.expand_xy(x, y); } diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs index d72a7f43..539dd58b 100644 --- a/geozero/src/processor/promote_to_multi.rs +++ b/geozero/src/processor/promote_to_multi.rs @@ -9,12 +9,12 @@ pub struct PromoteToMulti; impl ChainedGeomEventProcessor for PromoteToMulti { fn chain_event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, _collection: bool, visitor: &mut GeomVisitor

, ) -> Result<()> { - match event { + match *event { PointBegin(idx) => { visitor.multipoint_begin(1, idx)?; } diff --git a/geozero/src/processor/reprojection.rs b/geozero/src/processor/reprojection.rs index a9410bf8..1c0ad3cd 100644 --- a/geozero/src/processor/reprojection.rs +++ b/geozero/src/processor/reprojection.rs @@ -16,19 +16,19 @@ fn lonlat_to_merc(lon: f64, lat: f64) -> (f64, f64) { impl ChainedGeomEventProcessor for LonLatToMercator { fn chain_event( &mut self, - event: Event, + event: &Event, geom_type: GeometryType, collection: bool, visitor: &mut GeomVisitor

, ) -> Result<()> { - match event { + match *event { Xy(x, y, idx) => { let (x, y) = lonlat_to_merc(x, y); - visitor.chain_event(Xy(x, y, idx), geom_type, collection)?; + visitor.chain_event(&Xy(x, y, idx), geom_type, collection)?; } Coordinate(x, y, z, m, t, tm, idx) => { let (x, y) = lonlat_to_merc(x, y); - visitor.chain_event(Coordinate(x, y, z, m, t, tm, idx), geom_type, collection)?; + visitor.chain_event(&Coordinate(x, y, z, m, t, tm, idx), geom_type, collection)?; } _ => visitor.chain_event(event, geom_type, collection)?, } diff --git a/geozero/src/processor/sink.rs b/geozero/src/processor/sink.rs index 4bae1f2e..55300cc2 100644 --- a/geozero/src/processor/sink.rs +++ b/geozero/src/processor/sink.rs @@ -5,7 +5,7 @@ use crate::events::{Event, GeomEventProcessor, GeometryType}; pub struct GeomEventSink; impl GeomEventProcessor for GeomEventSink { - fn event(&mut self, _event: Event, _geom_type: GeometryType, _collection: bool) -> Result<()> { + fn event(&mut self, _event: &Event, _geom_type: GeometryType, _collection: bool) -> Result<()> { Ok(()) } } From 8c3b62b215333bfb2f0177f520ee3f0661b1fd47 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Tue, 24 May 2022 01:08:09 +0200 Subject: [PATCH 18/22] Fix from_wkb for geo_types::Geometry --- geozero/src/geo_types/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/geozero/src/geo_types/mod.rs b/geozero/src/geo_types/mod.rs index b7af3bb8..b8aa3a43 100644 --- a/geozero/src/geo_types/mod.rs +++ b/geozero/src/geo_types/mod.rs @@ -19,8 +19,7 @@ pub(crate) mod conversion { impl ToGeo for T { fn to_geo(&self) -> Result> { - let geo = GeoWriter::new(); - let mut visitor = GeomVisitor::new(geo); + let mut visitor = GeomVisitor::new(GeoWriter::new()); self.process_geom(&mut visitor)?; visitor .processor @@ -40,9 +39,11 @@ mod wkb { impl FromWkb for geo_types::Geometry { fn from_wkb(rdr: &mut R, dialect: WkbDialect) -> Result { - let mut geo = GeoWriter::new(); - crate::wkb::process_wkb_type_geom(rdr, &mut GeomVisitor::new(&mut geo), dialect)?; - geo.take_geometry() + let mut visitor = GeomVisitor::new(GeoWriter::new()); + crate::wkb::process_wkb_type_geom(rdr, &mut visitor, dialect)?; + visitor + .processor + .take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } } From 8731087e53a4c76070902ab12f517f5bb37439ce Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Wed, 25 May 2022 21:33:15 +0200 Subject: [PATCH 19/22] Replace EmptyPoint with generic Empty event --- geozero/src/events.rs | 19 ++++++------------- geozero/src/geo_types/geo_types_writer.rs | 11 ++++++++++- geozero/src/geometry_processor.rs | 5 ++++- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index da34b803..e4e701e4 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -69,8 +69,8 @@ pub enum Event { Option, usize, ), - /// Empty coordinates, like WKT's `POINT EMPTY` (idx) - EmptyPoint(usize), + /// Empty geometry + Empty, /// Begin of Point (idx) PointBegin(usize), /// End of Point (idx) @@ -250,7 +250,7 @@ impl GeomVisitor

{ match *event { Event::Xy(x, y, idx) => self.xy(x, y, idx), Event::Coordinate(x, y, z, m, t, tm, idx) => self.coordinate(x, y, z, m, t, tm, idx), - Event::EmptyPoint(idx) => self.empty_point(idx), + Event::Empty => self.empty(), Event::PointBegin(idx) => self.point_begin(idx), Event::PointEnd(idx) => self.point_end(idx), Event::MultiPointBegin(size, idx) => self.multipoint_begin(size, idx), @@ -406,16 +406,9 @@ impl GeomVisitor

{ ) -> Result<()> { self.emit(&Event::Coordinate(x, y, z, m, t, tm, idx)) } - /// Process empty coordinates, like WKT's `POINT EMPTY` - pub fn empty_point(&mut self, idx: usize) -> Result<()> { - self.set_type(GeometryType::Point)?; - if self.check_states { - self.enter_state(Vstate::Point)?; - } - self.emit(&Event::EmptyPoint(idx))?; - if self.check_states { - self.exit_state(Vstate::Point)?; - } + /// Process empty coordinates, like an empty point + pub fn empty(&mut self) -> Result<()> { + self.emit(&Event::Empty)?; Ok(()) } diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index a39e8083..2fa22bd8 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -15,12 +15,15 @@ pub struct GeoWriter { line_strings: Option>>, // In-progress point or line_string coords: Option>>, + // Empty geometry flag + empty: bool, } impl GeoWriter { pub fn new() -> GeoWriter { GeoWriter { geoms: Vec::new(), + empty: false, coords: None, line_strings: None, polygons: None, @@ -60,6 +63,7 @@ impl GeomEventProcessor for GeoWriter { ) -> Result<()> { match *event { Event::Xy(x, y, _idx) => { + self.empty = false; let coords = self .coords .as_mut() @@ -67,7 +71,9 @@ impl GeomEventProcessor for GeoWriter { coords.push(coord!(x: x, y: y)); } - Event::EmptyPoint(_idx) => {} + Event::Empty => { + self.empty = true; + } Event::PointBegin(_idx) => { debug_assert!(self.coords.is_none()); @@ -75,6 +81,9 @@ impl GeomEventProcessor for GeoWriter { } Event::PointEnd(_idx) => { + if self.empty { + return Ok(()); + } let coords = self .coords .take() diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 5a6c28f6..612ab2d6 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -321,7 +321,10 @@ impl GeomProcessor for GeomVisitor

{ self.coordinate(x, y, z, m, t, tm, idx) } fn empty_point(&mut self, idx: usize) -> Result<()> { - self.empty_point(idx) + self.point_begin(idx)?; + self.empty()?; + self.point_end(idx)?; + Ok(()) } fn point_begin(&mut self, idx: usize) -> Result<()> { self.point_begin(idx) From d35922ca66233024198460a388a710ec2329479c Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Mon, 30 May 2022 23:21:51 +0200 Subject: [PATCH 20/22] Some performance optimizations --- geozero/src/events.rs | 108 +++++++++++++++++++++++++++++++++- geozero/src/processor/bbox.rs | 3 + 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/geozero/src/events.rs b/geozero/src/events.rs index e4e701e4..79eed646 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -55,6 +55,106 @@ use crate::error::{GeozeroError, Result}; /// | | /// +-----------------+ /// ``` +/* Type size: +print-type-size type: `geozero::events::Event`: 96 bytes, alignment: 8 bytes +print-type-size discriminant: 8 bytes +print-type-size variant `Coordinate`: 88 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size field `.2`: 16 bytes +print-type-size field `.3`: 16 bytes +print-type-size field `.4`: 16 bytes +print-type-size field `.5`: 16 bytes +print-type-size field `.6`: 8 bytes +print-type-size variant `Xy`: 24 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size field `.2`: 8 bytes +print-type-size variant `XySlice`: 24 bytes +print-type-size field `.0`: 16 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `MultiPointBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `LineStringBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `MultiLineStringBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `PolygonBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `MultiPolygonBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `GeometryCollectionBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `CircularStringBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `CompoundCurveBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `CurvePolygonBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `MultiCurveBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `MultiSurfaceBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `TriangleBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `PolyhedralSurfaceBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `TinBegin`: 16 bytes +print-type-size field `.0`: 8 bytes +print-type-size field `.1`: 8 bytes +print-type-size variant `PointBegin`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `PointEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `MultiPointEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `LineStringEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `MultiLineStringEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `PolygonEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `MultiPolygonEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `GeometryCollectionEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `CircularStringEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `CompoundCurveEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `CurvePolygonEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `MultiCurveEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `MultiSurfaceEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `TriangleEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `PolyhedralSurfaceEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `TinEnd`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `Empty`: 0 bytes + +With Coordinate(Box<(..)>): +print-type-size type: `events::Event`: 32 bytes, alignment: 8 bytes +print-type-size discriminant: 8 bytes +print-type-size variant `Coordinate`: 8 bytes +print-type-size field `.0`: 8 bytes +*/ #[derive(Clone, PartialEq, Debug)] pub enum Event { /// Coordinate with x,y dimensions (x, y, idx) @@ -236,7 +336,8 @@ impl GeomVisitor

{ fn emit(&mut self, event: &Event) -> Result<()> { self.processor.event(event, self.geom_type, self.collection) } - /// Pass event to chained visitor with original state + /// Pass event to chained processor with original state + #[inline(always)] pub fn chain_event( &mut self, event: &Event, @@ -246,10 +347,11 @@ impl GeomVisitor

{ self.processor.event(event, geom_type, collection) } /// Pass event to visitor with state recalculation + #[inline] pub fn emit_event(&mut self, event: &Event) -> Result<()> { match *event { - Event::Xy(x, y, idx) => self.xy(x, y, idx), - Event::Coordinate(x, y, z, m, t, tm, idx) => self.coordinate(x, y, z, m, t, tm, idx), + Event::Xy(_x, _y, _idx) => self.emit(event), + Event::Coordinate(_x, _y, _z, _m, _t, _tm, _idx) => self.emit(event), Event::Empty => self.empty(), Event::PointBegin(idx) => self.point_begin(idx), Event::PointEnd(idx) => self.point_end(idx), diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index 1e440d26..df19ce6f 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -32,6 +32,7 @@ impl Bbox { } } + #[inline] pub fn reset(&mut self) { self.min_x = f64::INFINITY; self.min_y = f64::INFINITY; @@ -52,6 +53,7 @@ impl Bbox { a } + #[inline] pub fn expand(&mut self, r: &Bbox) { if r.min_x < self.min_x { self.min_x = r.min_x; @@ -67,6 +69,7 @@ impl Bbox { } } + #[inline] pub fn expand_xy(&mut self, x: f64, y: f64) { if x < self.min_x { self.min_x = x; From feac153aa6bb93edb34ebbd88e257b974d675c74 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sat, 4 Jun 2022 22:05:22 +0200 Subject: [PATCH 21/22] Replace generic parameters of processors with refs --- geozero/src/chaining.rs | 71 ++++++++------- geozero/src/events.rs | 102 +++++++++++++++++----- geozero/src/geo_types/geo_types_writer.rs | 10 +-- geozero/src/geo_types/mod.rs | 12 +-- geozero/src/geometry_processor.rs | 4 +- geozero/src/processor/bbox.rs | 10 ++- geozero/src/processor/promote_to_multi.rs | 26 +++--- geozero/src/processor/reprojection.rs | 16 ++-- 8 files changed, 158 insertions(+), 93 deletions(-) diff --git a/geozero/src/chaining.rs b/geozero/src/chaining.rs index 282ac5ed..dc7a0bed 100644 --- a/geozero/src/chaining.rs +++ b/geozero/src/chaining.rs @@ -9,23 +9,26 @@ use crate::events::*; /// Processing geometry events and passing events to a chained visitor pub trait ChainedGeomEventProcessor { /// Geometry processing event with geometry type information - fn chain_event( + fn chain_event( &mut self, event: &Event, geom_type: GeometryType, collection: bool, - visitor: &mut GeomVisitor

, + visitor: &mut GeomVisitor, ) -> Result<()>; } /// Chaining [GeomEventProcessor] -pub struct ChainedProcessor { - pub processor1: P1, - pub visitor: GeomVisitor, +pub struct ChainedProcessor<'a> { + processor1: &'a mut dyn ChainedGeomEventProcessor, + visitor: GeomVisitor<'a>, } -impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor { - pub fn new(processor1: P1, processor2: P2) -> Self { +impl<'a> ChainedProcessor<'a> { + pub fn new( + processor1: &'a mut dyn ChainedGeomEventProcessor, + processor2: &'a mut dyn GeomEventProcessor, + ) -> Self { ChainedProcessor { processor1, visitor: GeomVisitor::new(processor2), @@ -33,9 +36,7 @@ impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> ChainedProcessor } } -impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcessor - for ChainedProcessor -{ +impl<'a> GeomEventProcessor for ChainedProcessor<'a> { fn event( &mut self, event: &Event, @@ -50,13 +51,16 @@ impl<'a, P1: ChainedGeomEventProcessor, P2: GeomEventProcessor> GeomEventProcess // ------- Duplex --------- /// Duplexing [GeomEventProcessor] -pub struct DuplexProcessor { - pub processor1: P1, - pub processor2: P2, +pub struct DuplexProcessor<'a> { + processor1: &'a mut dyn GeomEventProcessor, + processor2: &'a mut dyn GeomEventProcessor, } -impl DuplexProcessor { - pub fn new(processor1: P1, processor2: P2) -> Self { +impl<'a> DuplexProcessor<'a> { + pub fn new( + processor1: &'a mut dyn GeomEventProcessor, + processor2: &'a mut dyn GeomEventProcessor, + ) -> Self { DuplexProcessor { processor1, processor2, @@ -64,9 +68,7 @@ impl DuplexProcessor { } } -impl GeomEventProcessor - for DuplexProcessor -{ +impl GeomEventProcessor for DuplexProcessor<'_> { fn event( &mut self, event: &Event, @@ -89,12 +91,12 @@ mod test { pub struct PromoteToMulti; impl ChainedGeomEventProcessor for PromoteToMulti { - fn chain_event( + fn chain_event( &mut self, event: &Event, _geom_type: GeometryType, _collection: bool, - visitor: &mut GeomVisitor

, + visitor: &mut GeomVisitor, ) -> Result<()> { match *event { PointBegin(idx) => { @@ -111,14 +113,16 @@ mod test { #[test] fn chained_processor() -> Result<()> { - let processor = ChainedProcessor::new(PromoteToMulti, GeomEventBuffer::new()); - let mut visitor = GeomVisitor::new(processor); + let mut buffer_processor = GeomEventBuffer::new(); + let mut multi = PromoteToMulti; + let mut processor = ChainedProcessor::new(&mut multi, &mut buffer_processor); + let mut visitor = GeomVisitor::new(&mut processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - visitor.processor.visitor.processor.buffer, + buffer_processor.buffer, [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); @@ -127,14 +131,16 @@ mod test { #[test] fn duplex_processor() -> Result<()> { - let processor = DuplexProcessor::new(GeomEventSink, GeomEventBuffer::new()); - let mut visitor = GeomVisitor::new(processor); + let mut buffer_processor = GeomEventBuffer::new(); + let mut sink = GeomEventSink; + let mut processor = DuplexProcessor::new(&mut sink, &mut buffer_processor); + let mut visitor = GeomVisitor::new(&mut processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - visitor.processor.processor2.buffer, + buffer_processor.buffer, [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] ); @@ -146,19 +152,22 @@ mod test { // geom ------+----> PromoteToMulti (1a) ----> GeomEventBuffer (2a) // | // +----> GeomEventBuffer (1b) - let processor_a = ChainedProcessor::new(PromoteToMulti, GeomEventBuffer::new()); - let processor = DuplexProcessor::new(processor_a, GeomEventBuffer::new()); - let mut visitor = GeomVisitor::new(processor); + let mut processor1a = PromoteToMulti; + let mut processor2a = GeomEventBuffer::new(); + let mut processor1b = GeomEventBuffer::new(); + let mut processor_a = ChainedProcessor::new(&mut processor1a, &mut processor2a); + let mut processor = DuplexProcessor::new(&mut processor_a, &mut processor1b); + let mut visitor = GeomVisitor::new(&mut processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - visitor.processor.processor1.visitor.processor.buffer, // 2a + processor2a.buffer, [MultiPointBegin(1, 0), Xy(0.0, 0.0, 0), MultiPointEnd(0)] ); assert_eq!( - visitor.processor.processor2.buffer, // 1b + processor1b.buffer, [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0),] ); diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 79eed646..3f04c837 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -299,7 +299,7 @@ enum Vstate { } /// Geometry visitor emitting events to a processor -pub struct GeomVisitor { +pub struct GeomVisitor<'a> { // pub dims: CoordDimensions, pub check_states: bool, /// Main geometry type @@ -308,7 +308,7 @@ pub struct GeomVisitor { collection: bool, state_stack: Vec, /// Event processor - pub processor: P, + pub processor: &'a mut dyn GeomEventProcessor, } /// Processing geometry events, e.g. for producing an output geometry @@ -320,11 +320,11 @@ pub trait GeomEventProcessor { /// Reading geometries by passing events to a visitor object pub trait GeometryReader { /// Process geometry. - fn process_geom(&mut self, visitor: &mut GeomVisitor

) -> Result<()>; + fn process_geom(&mut self, visitor: &mut GeomVisitor) -> Result<()>; } -impl GeomVisitor

{ - pub fn new(processor: P) -> Self { +impl<'a> GeomVisitor<'a> { + pub fn new(processor: &'a mut dyn GeomEventProcessor) -> Self { GeomVisitor { check_states: true, // Should maybe set from env var? geom_type: GeometryType::Unknown, @@ -869,10 +869,7 @@ pub(crate) mod test { pub struct NullIsland; impl GeometryReader for NullIsland { - fn process_geom( - &mut self, - visitor: &mut GeomVisitor

, - ) -> Result<()> { + fn process_geom(&mut self, visitor: &mut GeomVisitor) -> Result<()> { visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; visitor.point_end(0)?; @@ -906,18 +903,73 @@ pub(crate) mod test { #[test] fn processing() -> Result<()> { - let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); let mut geom = NullIsland; geom.process_geom(&mut visitor)?; assert_eq!( - visitor.processor.buffer, + processor.buffer, [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0)] ); Ok(()) } + #[test] + fn runtime_definition() -> Result<()> { + let do_buffer = true; + let mut processor = GeomEventBuffer::new(); + let mut sink = GeomEventSink; + let mut visitor = if do_buffer { + GeomVisitor::new(&mut processor) + } else { + GeomVisitor::new(&mut sink) + }; + let mut geom = NullIsland; + geom.process_geom(&mut visitor)?; + + if do_buffer { + assert_eq!( + processor.buffer, + [PointBegin(0), Xy(0.0, 0.0, 0), PointEnd(0)] + ); + } + Ok(()) + } + + #[test] + fn owned_visitor() -> Result<()> { + struct App { + processor: GeomEventBuffer, + } + struct AppVisitor<'a> { + visitor: GeomVisitor<'a>, + } + impl App { + fn new() -> Self { + App { + processor: GeomEventBuffer::new(), + } + } + fn visitor(&mut self) -> AppVisitor { + AppVisitor { + visitor: GeomVisitor::new(&mut self.processor), + } + } + fn buf_size(&mut self) -> usize { + self.processor.buffer.len() + } + } + let mut app = App::new(); + let mut app_visitor = app.visitor(); + let mut geom = NullIsland; + geom.process_geom(&mut app_visitor.visitor)?; + let size = app.buf_size(); + assert_eq!(size, 3); + Ok(()) + } + struct Point2D { pub x: f64, pub y: f64, @@ -941,24 +993,24 @@ pub(crate) mod test { #[test] fn process_point() -> Result<()> { - let geom_out = Point2D { + let mut geom_out = Point2D { x: f64::NAN, y: f64::NAN, }; - let mut visitor = GeomVisitor::new(geom_out); + let mut visitor = GeomVisitor::new(&mut geom_out); let mut geom_in = NullIsland; geom_in.process_geom(&mut visitor)?; - let geom = visitor.processor; - assert_eq!((geom.x, geom.y), (0.0, 0.0)); + assert_eq!((geom_out.x, geom_out.y), (0.0, 0.0)); Ok(()) } #[test] fn polygon() -> Result<()> { - let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); visitor.polygon_begin(2, 0)?; visitor.linestring_begin(2, 0)?; visitor.xy(0.0, 0.0, 0)?; @@ -970,9 +1022,9 @@ pub(crate) mod test { visitor.linestring_end(1)?; visitor.polygon_end(0)?; - dbg!(&visitor.processor.buffer); + dbg!(&processor.buffer); assert_eq!( - visitor.processor.buffer, + processor.buffer, [ PolygonBegin(2, 0), LineStringBegin(2, 0), @@ -992,7 +1044,8 @@ pub(crate) mod test { #[test] fn collection() -> Result<()> { - let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); visitor.geometrycollection_begin(2, 0)?; visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; @@ -1004,7 +1057,7 @@ pub(crate) mod test { visitor.geometrycollection_end(0)?; assert_eq!( - visitor.processor.buffer, + processor.buffer, [ GeometryCollectionBegin(2, 0), PointBegin(0), @@ -1023,8 +1076,8 @@ pub(crate) mod test { #[test] fn invalid_transitions() -> Result<()> { - let processor = GeomEventSink; - let mut visitor = GeomVisitor::new(processor); + let mut processor = GeomEventSink; + let mut visitor = GeomVisitor::new(&mut processor); visitor.point_begin(0)?; visitor.xy(0.0, 0.0, 0)?; let result = visitor.polygon_end(0); @@ -1047,10 +1100,11 @@ pub(crate) mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut visitor = GeomVisitor::new(GeomEventBuffer::new()); + let mut processor = GeomEventBuffer::new(); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; assert_eq!( - visitor.processor.buffer, + processor.buffer, [ PolygonBegin(1, 0), LineStringBegin(22, 0), diff --git a/geozero/src/geo_types/geo_types_writer.rs b/geozero/src/geo_types/geo_types_writer.rs index 2fa22bd8..04c9ca72 100644 --- a/geozero/src/geo_types/geo_types_writer.rs +++ b/geozero/src/geo_types/geo_types_writer.rs @@ -199,9 +199,9 @@ impl GeomEventProcessor for GeoWriter { } } -impl PropertyProcessor for events::GeomVisitor {} +impl PropertyProcessor for events::GeomVisitor<'_> {} -impl FeatureProcessor for events::GeomVisitor {} +impl FeatureProcessor for events::GeomVisitor<'_> {} #[cfg(test)] #[cfg(feature = "with-geojson")] @@ -309,10 +309,10 @@ mod test { {"type": "Feature", "properties": {"id": "ALB", "name": "Albania"}, "geometry": {"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}, {"type": "Feature", "properties": {"id": "TLS", "name": "East Timor"}, "geometry": {"type": "MultiPolygon", "coordinates": [[[[124.968682, -8.89279], [125.086246, -8.656887], [125.947072, -8.432095], [126.644704, -8.398247], [126.957243, -8.273345], [127.335928, -8.397317], [126.967992, -8.668256], [125.925885, -9.106007], [125.08852, -9.393173], [125.07002, -9.089987], [124.968682, -8.89279]]]]}} ]}"#; - let geo = GeoWriter::new(); - let mut visitor = GeomVisitor::new(geo); + let mut geo = GeoWriter::new(); + let mut visitor = GeomVisitor::new(&mut geo); assert!(read_geojson(geojson.as_bytes(), &mut visitor).is_ok()); - let geom = visitor.processor.take_geometry().unwrap(); + let geom = geo.take_geometry().unwrap(); dbg!(&geom); println!("{}", geom.to_json()?); // TODO: we get a broken GeometryCollection diff --git a/geozero/src/geo_types/mod.rs b/geozero/src/geo_types/mod.rs index b8aa3a43..d3efae9c 100644 --- a/geozero/src/geo_types/mod.rs +++ b/geozero/src/geo_types/mod.rs @@ -19,10 +19,10 @@ pub(crate) mod conversion { impl ToGeo for T { fn to_geo(&self) -> Result> { - let mut visitor = GeomVisitor::new(GeoWriter::new()); + let mut writer = GeoWriter::new(); + let mut visitor = GeomVisitor::new(&mut writer); self.process_geom(&mut visitor)?; - visitor - .processor + writer .take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } @@ -39,10 +39,10 @@ mod wkb { impl FromWkb for geo_types::Geometry { fn from_wkb(rdr: &mut R, dialect: WkbDialect) -> Result { - let mut visitor = GeomVisitor::new(GeoWriter::new()); + let mut writer = GeoWriter::new(); + let mut visitor = GeomVisitor::new(&mut writer); crate::wkb::process_wkb_type_geom(rdr, &mut visitor, dialect)?; - visitor - .processor + writer .take_geometry() .ok_or(GeozeroError::Geometry("Missing Geometry".to_string())) } diff --git a/geozero/src/geometry_processor.rs b/geozero/src/geometry_processor.rs index 612ab2d6..baa4a84d 100644 --- a/geozero/src/geometry_processor.rs +++ b/geozero/src/geometry_processor.rs @@ -1,5 +1,5 @@ use crate::error::{GeozeroError, Result}; -use crate::events::{GeomEventProcessor, GeomVisitor}; +use crate::events::GeomVisitor; /// Dimensions requested for processing #[derive(Default, Clone, Copy, Debug)] @@ -304,7 +304,7 @@ pub trait GeomProcessor { } } -impl GeomProcessor for GeomVisitor

{ +impl GeomProcessor for GeomVisitor<'_> { fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> { self.xy(x, y, idx) } diff --git a/geozero/src/processor/bbox.rs b/geozero/src/processor/bbox.rs index df19ce6f..0978fd98 100644 --- a/geozero/src/processor/bbox.rs +++ b/geozero/src/processor/bbox.rs @@ -163,10 +163,11 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let mut visitor = GeomVisitor::new(Bbox::default()); + let mut processor = Bbox::default(); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; assert_eq!( - visitor.processor, + processor, Bbox::new(19.304486, 39.624998, 21.02004, 42.688247) ); Ok(()) @@ -177,9 +178,10 @@ mod test { let geojson = GeoJson( r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, ); - let mut visitor = GeomVisitor::new(Bbox::default()); + let mut processor = Bbox::default(); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; - assert_eq!(visitor.processor, Bbox::new(100.1, 0.1, 102.1, 1.1)); + assert_eq!(processor, Bbox::new(100.1, 0.1, 102.1, 1.1)); Ok(()) } } diff --git a/geozero/src/processor/promote_to_multi.rs b/geozero/src/processor/promote_to_multi.rs index 539dd58b..295a39f0 100644 --- a/geozero/src/processor/promote_to_multi.rs +++ b/geozero/src/processor/promote_to_multi.rs @@ -1,18 +1,18 @@ use crate::chaining::ChainedGeomEventProcessor; use crate::error::Result; use crate::events::Event::*; -use crate::events::{Event, GeomEventProcessor, GeomVisitor, GeometryType}; +use crate::events::{Event, GeomVisitor, GeometryType}; /// Convert single geometry types to multi geometry types pub struct PromoteToMulti; impl ChainedGeomEventProcessor for PromoteToMulti { - fn chain_event( + fn chain_event( &mut self, event: &Event, geom_type: GeometryType, _collection: bool, - visitor: &mut GeomVisitor

, + visitor: &mut GeomVisitor, ) -> Result<()> { match *event { PointBegin(idx) => { @@ -59,12 +59,12 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let processor1 = PromoteToMulti; - let processor2 = GeoWriter::new(); // TODO: Json writer - let processor = ChainedProcessor::new(processor1, processor2); - let mut visitor = GeomVisitor::new(processor); + let mut processor1 = PromoteToMulti; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; - let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); // processor2 + let geom = processor2.take_geometry().unwrap(); let expected = r#"{"type": "MultiPolygon", "coordinates": [[[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) @@ -75,12 +75,12 @@ mod test { let geojson = GeoJson( r#"{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [100.1,0.1]},{"type": "LineString", "coordinates": [[101.1,0.1],[102.1,1.1]]}]}"#, ); - let processor1 = PromoteToMulti; - let processor2 = GeoWriter::new(); // TODO: Json writer - let processor = ChainedProcessor::new(processor1, processor2); - let mut visitor = GeomVisitor::new(processor); + let mut processor1 = PromoteToMulti; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; - let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); // processor2 + let geom = processor2.take_geometry().unwrap(); let expected = r#"{"type": "GeometryCollection", "geometries": [{"type": "MultiPoint", "coordinates": [[100.1,0.1]]},{"type": "MultiLineString", "coordinates": [[[101.1,0.1],[102.1,1.1]]]}]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) diff --git a/geozero/src/processor/reprojection.rs b/geozero/src/processor/reprojection.rs index 1c0ad3cd..387d0e18 100644 --- a/geozero/src/processor/reprojection.rs +++ b/geozero/src/processor/reprojection.rs @@ -1,7 +1,7 @@ use crate::chaining::ChainedGeomEventProcessor; use crate::error::Result; use crate::events::Event::*; -use crate::events::{Event, GeomEventProcessor, GeomVisitor, GeometryType}; +use crate::events::{Event, GeomVisitor, GeometryType}; use std::f64::consts; /// Convert lon/lat to Spherical Mercator in meters @@ -14,12 +14,12 @@ fn lonlat_to_merc(lon: f64, lat: f64) -> (f64, f64) { } impl ChainedGeomEventProcessor for LonLatToMercator { - fn chain_event( + fn chain_event( &mut self, event: &Event, geom_type: GeometryType, collection: bool, - visitor: &mut GeomVisitor

, + visitor: &mut GeomVisitor, ) -> Result<()> { match *event { Xy(x, y, idx) => { @@ -52,12 +52,12 @@ mod test { let geojson = GeoJson( r#"{"type": "Polygon", "coordinates": [[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}"#, ); - let processor1 = LonLatToMercator; - let processor2 = GeoWriter::new(); // TODO: Json writer - let processor = ChainedProcessor::new(processor1, processor2); - let mut visitor = GeomVisitor::new(processor); + let mut processor1 = LonLatToMercator; + let mut processor2 = GeoWriter::new(); // TODO: Json writer + let mut processor = ChainedProcessor::new(&mut processor1, &mut processor2); + let mut visitor = GeomVisitor::new(&mut processor); geojson.process_geom(&mut visitor)?; - let geom = visitor.processor.visitor.processor.take_geometry().unwrap(); + let geom = processor2.take_geometry().unwrap(); let expected = r#"{"type": "Polygon", "coordinates": [[[2292095.811347729,5139344.213425913],[2277950.2210136456,5088616.6330585545],[2293758.3679427262,5025068.310371113],[2339940.1492542424,4989171.535691388],[2337708.193463837,4950588.339806374],[2301530.138192459,4929358.117761691],[2294851.3027033345,4881941.097754033],[2243089.5205963156,4811596.717986056],[2224163.426049606,4821717.98297803],[2221937.2588727223,4853598.859120461],[2160275.1665325123,4902451.127115252],[2150587.810485209,4972191.022999316],[2159993.3055818235,5072941.548683907],[2175185.8557268167,5119126.5562673],[2156455.4608449223,5142654.340537157],[2148965.551545879,5190346.344385106],[2197229.7865716643,5264639.607013478],[2204305.476045466,5236187.825747299],[2234260.1038645557,5249565.284016839],[2257977.2779755164,5209074.219280535],[2284604.3435758143,5193671.390117393],[2292095.811347729,5139344.213425913]]]}"#; assert_eq!(expected, geom.to_json()?); Ok(()) From d1b7fe63aa2941123b1d53b8020133d4f4983165 Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Sun, 24 Jul 2022 19:50:04 +0200 Subject: [PATCH 22/22] Introduce event emitting geometry iterator --- geozero/src/events.rs | 2 +- geozero/src/iterator.rs | 225 ++++++++++++++++++++++++++++++++++++++++ geozero/src/lib.rs | 1 + 3 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 geozero/src/iterator.rs diff --git a/geozero/src/events.rs b/geozero/src/events.rs index 3f04c837..e8b13f6f 100644 --- a/geozero/src/events.rs +++ b/geozero/src/events.rs @@ -275,7 +275,7 @@ pub enum GeometryType { } #[derive(PartialEq, Debug)] -enum Vstate { +pub(crate) enum Vstate { Initial, Point, LineString, diff --git a/geozero/src/iterator.rs b/geozero/src/iterator.rs new file mode 100644 index 00000000..a3baceaa --- /dev/null +++ b/geozero/src/iterator.rs @@ -0,0 +1,225 @@ +//! Event emitting geometry iterator. +// Inspiration: https://docs.rs/lyon_path/latest/lyon_path/enum.Event.html# + +use crate::error::{GeozeroError, Result}; +use crate::events::{GeometryType, Vstate}; +use crate::CoordDimensions; + +pub struct EventIter { + visitor: T, + state: IterState, +} + +struct IterState { + /// Main geometry type + pub geom_type: GeometryType, + /// Geometry is part of collection + pub collection: bool, + // Iterator settings + iter_dims: CoordDimensions, + check_states: bool, + state_stack: Vec, + // Convert single to multi geometries, if declared as multi type or Unknown + promote_to_multi: bool, +} + +impl IterState { + fn state(&self) -> &Vstate { + let len = self.state_stack.len(); + if len > 0 { + &self.state_stack[len - 1] + } else { + &Vstate::Initial + } + } + fn enter_state(&mut self, state: Vstate) -> Result<()> { + match (self.state(), &state) { + (Vstate::Initial, Vstate::GeometryCollection) + | (Vstate::Initial, Vstate::Point) + | (Vstate::Initial, Vstate::LineString) + | (Vstate::Initial, Vstate::Polygon) + | (Vstate::Initial, Vstate::MultiPoint) + | (Vstate::Initial, Vstate::MultiLineString) + | (Vstate::Initial, Vstate::MultiPolygon) + | (Vstate::Initial, Vstate::CircularString) + | (Vstate::Initial, Vstate::CompoundCurve) + | (Vstate::Initial, Vstate::CurvePolygon) + | (Vstate::Initial, Vstate::MultiCurve) + | (Vstate::Initial, Vstate::MultiSurface) + | (Vstate::Initial, Vstate::Curve) + | (Vstate::Initial, Vstate::Surface) + | (Vstate::Initial, Vstate::PolyhedralSurface) + | (Vstate::Initial, Vstate::Tin) + | (Vstate::Initial, Vstate::Triangle) + | (Vstate::Polygon, Vstate::LineString) + | (Vstate::MultiLineString, Vstate::LineString) + | (Vstate::MultiPolygon, Vstate::Polygon) + | (Vstate::GeometryCollection, Vstate::Point) + | (Vstate::GeometryCollection, Vstate::LineString) + | (Vstate::GeometryCollection, Vstate::Polygon) + | (Vstate::GeometryCollection, Vstate::MultiPoint) + | (Vstate::GeometryCollection, Vstate::MultiLineString) + | (Vstate::GeometryCollection, Vstate::MultiPolygon) + | (Vstate::GeometryCollection, Vstate::GeometryCollection) + | (Vstate::GeometryCollection, Vstate::CircularString) + | (Vstate::GeometryCollection, Vstate::CompoundCurve) + | (Vstate::GeometryCollection, Vstate::CurvePolygon) + | (Vstate::GeometryCollection, Vstate::MultiCurve) + | (Vstate::GeometryCollection, Vstate::MultiSurface) + | (Vstate::GeometryCollection, Vstate::Curve) + | (Vstate::GeometryCollection, Vstate::Surface) + | (Vstate::GeometryCollection, Vstate::PolyhedralSurface) + | (Vstate::GeometryCollection, Vstate::Tin) + | (Vstate::GeometryCollection, Vstate::Triangle) + | (Vstate::CompoundCurve, Vstate::CircularString) + | (Vstate::CompoundCurve, Vstate::LineString) + | (Vstate::CurvePolygon, Vstate::CircularString) + | (Vstate::CurvePolygon, Vstate::LineString) + | (Vstate::CurvePolygon, Vstate::CompoundCurve) + | (Vstate::MultiCurve, Vstate::CircularString) + | (Vstate::MultiCurve, Vstate::LineString) + | (Vstate::MultiCurve, Vstate::CompoundCurve) + | (Vstate::MultiSurface, Vstate::CurvePolygon) + | (Vstate::MultiSurface, Vstate::Polygon) + | (Vstate::Triangle, Vstate::LineString) + | (Vstate::PolyhedralSurface, Vstate::Polygon) + | (Vstate::Tin, Vstate::Polygon) => { + // println!("Enter state {:?}=>{:?}", self.state(), state); + self.state_stack.push(state); + Ok(()) + } + _ => Err(GeozeroError::Geometry(format!( + "Invalid state transition from {:?} to {:?}", + self.state(), + state + ))), + } + } + fn exit_state(&mut self, state: Vstate) -> Result<()> { + let valid = if let Some(prev_state) = self.state_stack.pop() { + state == prev_state + } else { + false + }; + if valid { + // println!( + // "Exit state {:?} (GeometryType::{:?})=>{:?}", + // &self.state_stack, + // &self.geom_type, + // self.state() + // ); + } else { + return Err(GeozeroError::Geometry(format!( + "Invalid state transition from {:?} to {:?}", + self.state_stack, state + ))); + } + Ok(()) + } + fn set_type(&mut self, inner_type: GeometryType) -> Result<()> { + if self.geom_type == GeometryType::Unknown { + // println!("Set GeometryType {:?} => {:?}", &self.geom_type, inner_type); + self.geom_type = inner_type; + } + Ok(()) + } + fn reset_type(&mut self, inner_type: GeometryType) { + // Reset geometry type within collections + if self.collection && self.geom_type == inner_type { + self.geom_type = GeometryType::Unknown; + } + } +} + +impl EventIter { + // Default iterator (XY) + pub fn new(visitor: T) -> EventIter { + Self::new_with_config(visitor, CoordDimensions::xy(), true, false) + } + pub fn new_with_config( + visitor: T, + dims: CoordDimensions, + check_states: bool, + promote_to_multi: bool, + ) -> EventIter { + EventIter:: { + visitor, + state: IterState { + geom_type: GeometryType::Unknown, + collection: false, + iter_dims: dims, + check_states, + state_stack: Vec::new(), + promote_to_multi, + }, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::events::Event; + use std::io::{BufWriter, Write}; + + pub struct NullIsland { + events: Vec, + } + + impl NullIsland { + pub fn new() -> Self { + Self { + events: vec![ + Event::PointBegin(1), + Event::Xy(0.0, 0.0, 0), + Event::PointEnd(1), + ], + } + } + } + + pub struct NullIslandVisitor<'a> { + events: std::slice::Iter<'a, Event>, + } + + impl<'a> NullIslandVisitor<'a> { + pub fn new(geom: &'a NullIsland) -> Self { + NullIslandVisitor { + events: geom.events.iter(), + } + } + } + + // Implement reader for NullIsland type + impl<'a> Iterator for EventIter> { + type Item = Result<&'a Event>; + fn next(&mut self) -> Option { + // We have access to self.visitor and self.state + if self.state.geom_type == GeometryType::Unknown { + self.state.set_type(GeometryType::Point).unwrap(); //TODO: propagate errors + } + // we should also call enter_state/exit_state to ensure + // valid state transitions. + self.visitor.events.next().map(|ev| Ok(ev)) + } + } + + #[test] + fn null_island_to_wkt() -> std::io::Result<()> { + let mut out = BufWriter::new(Vec::new()); + let geom = NullIsland::new(); + let visitor = NullIslandVisitor::new(&geom); + for (i, event) in EventIter::new(visitor).enumerate() { + let event = event.unwrap(); + assert_eq!(*event, geom.events[i]); + let _ = match event { + Event::PointBegin(_) => out.write(b"POINT(")?, + Event::Xy(x, y, _) => out.write(&format!("{x} {y}").as_bytes())?, + Event::PointEnd(_) => out.write(b")")?, + _ => 0, + }; + } + assert_eq!(std::str::from_utf8(&out.into_inner()?), Ok("POINT(0 0)")); + Ok(()) + } +} diff --git a/geozero/src/lib.rs b/geozero/src/lib.rs index eebcc389..fdd44d27 100644 --- a/geozero/src/lib.rs +++ b/geozero/src/lib.rs @@ -34,6 +34,7 @@ pub mod error; pub mod events; mod feature_processor; mod geometry_processor; +pub mod iterator; mod multiplex; pub mod processor; mod property_processor;