From d5516c77364cba71d980ecfb3f8cee41a6570e63 Mon Sep 17 00:00:00 2001 From: Taku Fukada Date: Sun, 7 Jan 2024 15:37:39 +0900 Subject: [PATCH] refactor geojson geom gen --- nusamai-citygml/src/geometry.rs | 6 +- nusamai-geojson/src/conversion.rs | 142 ++++++++++++++++++++++-------- 2 files changed, 108 insertions(+), 40 deletions(-) diff --git a/nusamai-citygml/src/geometry.rs b/nusamai-citygml/src/geometry.rs index 8f6689922..866e77a50 100644 --- a/nusamai-citygml/src/geometry.rs +++ b/nusamai-citygml/src/geometry.rs @@ -1,4 +1,4 @@ -use nusamai_geometry::{MultiLineString, MultiPoint, MultiPolygon}; +use nusamai_geometry::{MultiLineString, MultiLineString, MultiPolygon}; #[derive(Debug, Clone, Copy)] pub enum GeometryParseType { @@ -51,7 +51,7 @@ pub struct GeometryStore { pub vertices: Vec<[f64; 3]>, pub multipolygon: MultiPolygon<'static, 1, u32>, pub multilinestring: MultiLineString<'static, 1, u32>, - pub multipoint: MultiPoint<'static, 1, u32>, + pub multipoint: MultiLineString<'static, 1, u32>, } /// Store for collecting vertices and polygons from GML. @@ -60,7 +60,7 @@ pub struct GeometryCollector { pub vertices: indexmap::IndexSet<[u64; 3]>, pub multipolygon: MultiPolygon<'static, 1, u32>, pub multilinestring: MultiLineString<'static, 1, u32>, - pub multipoint: MultiPoint<'static, 1, u32>, + pub multipoint: MultiLineString<'static, 1, u32>, } impl GeometryCollector { diff --git a/nusamai-geojson/src/conversion.rs b/nusamai-geojson/src/conversion.rs index 5a6d591e1..137495968 100644 --- a/nusamai-geojson/src/conversion.rs +++ b/nusamai-geojson/src/conversion.rs @@ -1,71 +1,91 @@ -use nusamai_geometry::{MultiLineString, MultiPoint, MultiPolygon, Polygon}; +use nusamai_geometry::{CoordNum, MultiLineString, MultiPoint, MultiPolygon}; -/// Create a GeoJSON geometry from `nusamai_geometry::MultiPolygon` +/// Create a GeoJSON MultiPolygon from `nusamai_geometry::MultiPolygon`. pub fn multipolygon_to_geometry(mpoly: &MultiPolygon<3>) -> geojson::Geometry { - let rings_list = mpoly - .iter() - .map(|poly| { - poly.rings() - .map(|c| c.iter_closed().map(|v| v.to_vec()).collect()) - .collect::>() - }) - .collect(); - geojson::Value::MultiPolygon(rings_list).into() + multipolygon_to_geometry_with_mapping(mpoly, |c| c.to_vec()) } -/// Create a GeoJSON geometry from vertices and MultiPolygon indices. +/// Create a GeoJSON MultiPolygon from vertices and indices. pub fn indexed_multipolygon_to_geometry( vertices: &[[f64; 3]], - mpoly: &MultiPolygon<1, u32>, + mpoly_idx: &MultiPolygon<1, u32>, ) -> geojson::Geometry { - let rings_list: Vec = mpoly + multipolygon_to_geometry_with_mapping(mpoly_idx, |idx| vertices[idx[0] as usize].to_vec()) +} + +/// Create a GeoJSON MultiPolygon from `nusamai_geometry::MultiPolygon` with a mapping function. +pub fn multipolygon_to_geometry_with_mapping( + mpoly: &MultiPolygon, + mapping: impl Fn(&[T]) -> Vec, +) -> geojson::Geometry { + let coords: Vec = mpoly .iter() - .map(|poly| indexed_polygon_to_rings(vertices, &poly)) + .map(|poly| { + poly.rings() + .map(|ls| { + ls.iter_closed() + .map(&mapping) // Get the actual coord values + .collect() + }) + .collect::>() + }) .collect(); - geojson::Value::MultiPolygon(rings_list).into() + geojson::Value::MultiPolygon(coords).into() } -fn indexed_polygon_to_rings( - vertices: &[[f64; 3]], - poly_idx: &Polygon<1, u32>, -) -> geojson::PolygonType { - poly_idx - .rings() - .map(|ls| { - ls.iter_closed() - .map(|idx| vertices[idx[0] as usize].to_vec()) // Get the actual coord values - .collect() - }) - .collect() +/// Create a GeoJSON MultiLineString from `nusamai_geometry::MultiLineString`. +pub fn multilinestring_to_geometry(mls: &MultiLineString<3>) -> geojson::Geometry { + multilinestring_to_geometry_with_mapping(mls, |c| c.to_vec()) } -/// Create a GeoJSON geometry from vertices and MultiLineString indices. +/// Create a GeoJSON MultiLineString from vertices and indices. pub fn indexed_multilinestring_to_geometry( vertices: &[[f64; 3]], mls_idx: &MultiLineString<1, u32>, ) -> geojson::Geometry { - let mls_coords = mls_idx + multilinestring_to_geometry_with_mapping(mls_idx, |idx| vertices[idx[0] as usize].to_vec()) +} + +/// Create a GeoJSON MultiLineString from `nusamai_geometry::MultiPolygon` with a mapping function. +pub fn multilinestring_to_geometry_with_mapping( + mls: &MultiLineString, + mapping: impl Fn(&[T]) -> Vec, +) -> geojson::Geometry { + let coords = mls .iter() .map(|ls_idx| { ls_idx .iter() - .map(|idx| vertices[idx[0] as usize].to_vec()) // Get the actual coord values + .map(&mapping) // Get the actual coord values .collect() }) .collect(); - geojson::Value::MultiLineString(mls_coords).into() + geojson::Value::MultiLineString(coords).into() +} + +/// Create a GeoJSON MultiPoint from `nusamai_geometry::MultiPoint`. +pub fn multipoint_to_geometry(mpoint: &MultiPoint<3>) -> geojson::Geometry { + multipoint_to_geometry_with_mapping(mpoint, |c| c.to_vec()) } -/// Create a GeoJSON geometry from vertices and MultiPoint indices. +/// Create a GeoJSON MultiPoint from vertices and indices. pub fn indexed_multipoint_to_geometry( vertices: &[[f64; 3]], - mpoint: &MultiPoint<1, u32>, + mpoint_idx: &MultiPoint<1, u32>, +) -> geojson::Geometry { + multipoint_to_geometry_with_mapping(mpoint_idx, |idx| vertices[idx[0] as usize].to_vec()) +} + +/// Create a GeoJSON MultiPoint from `nusamai_geometry::MultiPoint` with a mapping function. +pub fn multipoint_to_geometry_with_mapping( + mpoint: &MultiPoint, + mapping: impl Fn(&[T]) -> Vec, ) -> geojson::Geometry { - let mpoint_coords = mpoint + let coords = mpoint .iter() - .map(|p| vertices[p[0] as usize].to_vec()) // Get the actual coord values + .map(&mapping) // Get the actual coord values .collect(); - geojson::Value::MultiPoint(mpoint_coords).into() + geojson::Value::MultiPoint(coords).into() } #[cfg(test)] @@ -266,6 +286,33 @@ mod tests { }; } + #[test] + fn test_multilinestring() { + let mut mls = MultiLineString::<3>::new(); + mls.add_linestring([[11., 12., 13.], [21., 22., 23.], [31., 32., 33.]]); + mls.add_linestring([[111., 112., 113.], [121., 122., 123.], [131., 132., 133.]]); + + let geom = multilinestring_to_geometry(&mls); + let geojson::Value::MultiLineString(mls) = geom.value else { + panic!("The result is not a GeoJSON MultiPolygon"); + }; + assert_eq!( + mls, + vec![ + vec![ + vec![11., 12., 13.], + vec![21., 22., 23.], + vec![31., 32., 33.], + ], + vec![ + vec![111., 112., 113.], + vec![121., 122., 123.], + vec![131., 132., 133.], + ], + ] + ); + } + #[test] fn test_indexed_multilinestring() { let vertices = vec![ @@ -318,6 +365,27 @@ mod tests { } } + #[test] + fn test_multipoint() { + let mut mpoint = MultiPoint::<3>::new(); + mpoint.push(&[11., 12., 13.]); + mpoint.push(&[21., 22., 23.]); + mpoint.push(&[31., 32., 33.]); + + let geom = multipoint_to_geometry(&mpoint); + let geojson::Value::MultiPoint(mpoint) = geom.value else { + panic!("The result is not a GeoJSON MultiPolygon"); + }; + assert_eq!( + mpoint, + vec![ + vec![11., 12., 13.], + vec![21., 22., 23.], + vec![31., 32., 33.], + ] + ); + } + #[test] fn test_indexed_multipoint() { let vertices = vec![[0., 0., 111.], [1., 2., 222.], [3., 4., 333.]];