From 06a248ea187829d99f038ff33998df2fe501be01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Wed, 19 Jan 2022 17:09:12 +0100 Subject: [PATCH 1/6] update gdal --- datatypes/Cargo.toml | 2 +- operators/Cargo.toml | 4 ++-- services/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/datatypes/Cargo.toml b/datatypes/Cargo.toml index 18e0d8aed..72ce47b2e 100644 --- a/datatypes/Cargo.toml +++ b/datatypes/Cargo.toml @@ -17,7 +17,7 @@ pro = ["postgres"] arrow = { version = "6.0", features = ["simd"] } chrono = "0.4" float-cmp = "0.9" -gdal = "0.11" +gdal = "0.12" geo = "0.18" geojson = "0.22" image = "0.23" diff --git a/operators/Cargo.toml b/operators/Cargo.toml index d818a2487..16c3a99f2 100644 --- a/operators/Cargo.toml +++ b/operators/Cargo.toml @@ -20,8 +20,8 @@ crossbeam = "0.8" csv = "1.1" float-cmp = "0.9" futures = "0.3" -gdal = "0.11" -gdal-sys = "0.5" +gdal = "0.12" +gdal-sys = "0.6" geo = "0.18" geoengine-datatypes = { path = "../datatypes" } itertools = "0.10" diff --git a/services/Cargo.toml b/services/Cargo.toml index 2d7f65eb5..75db2b147 100644 --- a/services/Cargo.toml +++ b/services/Cargo.toml @@ -34,7 +34,7 @@ config = "0.11" flexi_logger = "0.22" futures = "0.3" futures-util = "0.3" -gdal = "0.11" +gdal = "0.12" geo = "0.18" geoengine-datatypes = { path = "../datatypes" } geoengine-operators = { path = "../operators" } From 3cc9686c9859fe8aeacc7f9a44279ab9d9577d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Wed, 19 Jan 2022 17:09:33 +0100 Subject: [PATCH 2/6] impl approx_eq for coords and other geoms --- .../multi_line_string_collection.rs | 45 ++++++++------ .../src/collections/multi_point_collection.rs | 37 +++++------ .../collections/multi_polygon_collection.rs | 61 +++++++++++-------- datatypes/src/operations/reproject.rs | 14 ++++- datatypes/src/primitives/bounding_box.rs | 17 ++++++ datatypes/src/primitives/coordinate.rs | 13 ++++ datatypes/src/primitives/line.rs | 11 ++++ datatypes/src/primitives/multi_line_string.rs | 13 ++++ datatypes/src/primitives/multi_point.rs | 13 ++++ datatypes/src/primitives/multi_polygon.rs | 22 +++++++ 10 files changed, 177 insertions(+), 69 deletions(-) diff --git a/datatypes/src/collections/multi_line_string_collection.rs b/datatypes/src/collections/multi_line_string_collection.rs index 1c5763a62..f190e38cb 100644 --- a/datatypes/src/collections/multi_line_string_collection.rs +++ b/datatypes/src/collections/multi_line_string_collection.rs @@ -277,6 +277,8 @@ impl ReplaceRawArrayCoords for MultiLineStringCollection { #[cfg(test)] mod tests { + use float_cmp::approx_eq; + use super::*; use crate::collections::{BuilderProvider, FeatureCollectionModifications}; @@ -562,27 +564,32 @@ mod tests { ) .unwrap(); - let expected_collection = MultiLineStringCollection::from_slices( - &[ - MultiLineString::new(vec![vec![MARBURG_EPSG_900_913, HAMBURG_EPSG_900_913]]) - .unwrap(), - MultiLineString::new(vec![ - vec![ - COLOGNE_EPSG_900_913, - MARBURG_EPSG_900_913, - HAMBURG_EPSG_900_913, - ], - vec![HAMBURG_EPSG_900_913, COLOGNE_EPSG_900_913], - ]) - .unwrap(), - ], - &[TimeInterval::default(), TimeInterval::default()], - &[("A", FeatureData::Int(vec![1, 2]))], - ) - .unwrap(); + let expected = [ + MultiLineString::new(vec![vec![MARBURG_EPSG_900_913, HAMBURG_EPSG_900_913]]).unwrap(), + MultiLineString::new(vec![ + vec![ + COLOGNE_EPSG_900_913, + MARBURG_EPSG_900_913, + HAMBURG_EPSG_900_913, + ], + vec![HAMBURG_EPSG_900_913, COLOGNE_EPSG_900_913], + ]) + .unwrap(), + ]; let proj_collection = collection.reproject(&projector).unwrap(); - assert_eq!(proj_collection, expected_collection); + proj_collection + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiLineString, + a.into(), + e.clone(), + epsilon = 0.00001 + )); + }); } } diff --git a/datatypes/src/collections/multi_point_collection.rs b/datatypes/src/collections/multi_point_collection.rs index ed33c20b5..1abf79c67 100755 --- a/datatypes/src/collections/multi_point_collection.rs +++ b/datatypes/src/collections/multi_point_collection.rs @@ -1173,31 +1173,26 @@ mod tests { ) .unwrap(); - let pc_expected = MultiPointCollection::from_data( - MultiPoint::many(vec![ - vec![MARBURG_EPSG_900_913, COLOGNE_EPSG_900_913], - vec![HAMBURG_EPSG_900_913], - ]) - .unwrap(), - vec![ - TimeInterval::new_unchecked(0, 1), - TimeInterval::new_unchecked(1, 2), - ], - { - let mut map = HashMap::new(); - map.insert("numbers".into(), FeatureData::Float(vec![0., 1.])); - map.insert( - "number_nulls".into(), - FeatureData::NullableFloat(vec![Some(0.), None]), - ); - map - }, - ) + let expected = MultiPoint::many(vec![ + vec![MARBURG_EPSG_900_913, COLOGNE_EPSG_900_913], + vec![HAMBURG_EPSG_900_913], + ]) .unwrap(); let proj_pc = pc.reproject(&projector).unwrap(); - assert_eq!(proj_pc, pc_expected); + proj_pc + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiPoint, + a.into(), + e.clone(), + epsilon = 0.000_001 + )); + }); } #[test] diff --git a/datatypes/src/collections/multi_polygon_collection.rs b/datatypes/src/collections/multi_polygon_collection.rs index 1673b1538..0cd52c5f8 100644 --- a/datatypes/src/collections/multi_polygon_collection.rs +++ b/datatypes/src/collections/multi_polygon_collection.rs @@ -403,6 +403,7 @@ impl From>> for MultiPolygonCollection { #[cfg(test)] mod tests { + use float_cmp::approx_eq; use geo::polygon; use super::*; @@ -823,7 +824,7 @@ mod tests { } #[test] - fn reproject_multi_lines_epsg4326_epsg900913_collection() { + fn reproject_multi_polygons_epsg4326_epsg900913_collection() { use crate::operations::reproject::Reproject; use crate::operations::reproject::{CoordinateProjection, CoordinateProjector}; use crate::primitives::FeatureData; @@ -868,39 +869,45 @@ mod tests { ) .unwrap(); - let expected_collection = MultiPolygonCollection::from_slices( - &[ - MultiPolygon::new(vec![ - vec![vec![ - HAMBURG_EPSG_900_913, - MARBURG_EPSG_900_913, - COLOGNE_EPSG_900_913, - HAMBURG_EPSG_900_913, - ]], - vec![vec![ - COLOGNE_EPSG_900_913, - HAMBURG_EPSG_900_913, - MARBURG_EPSG_900_913, - COLOGNE_EPSG_900_913, - ]], - ]) - .unwrap(), - MultiPolygon::new(vec![vec![vec![ + let expected = [ + MultiPolygon::new(vec![ + vec![vec![ + HAMBURG_EPSG_900_913, MARBURG_EPSG_900_913, COLOGNE_EPSG_900_913, HAMBURG_EPSG_900_913, + ]], + vec![vec![ + COLOGNE_EPSG_900_913, + HAMBURG_EPSG_900_913, MARBURG_EPSG_900_913, - ]]]) - .unwrap(), - ], - &[TimeInterval::default(), TimeInterval::default()], - &[("A", FeatureData::Int(vec![1, 2]))], - ) - .unwrap(); + COLOGNE_EPSG_900_913, + ]], + ]) + .unwrap(), + MultiPolygon::new(vec![vec![vec![ + MARBURG_EPSG_900_913, + COLOGNE_EPSG_900_913, + HAMBURG_EPSG_900_913, + MARBURG_EPSG_900_913, + ]]]) + .unwrap(), + ]; let proj_collection = collection.reproject(&projector).unwrap(); - assert_eq!(proj_collection, expected_collection); + proj_collection + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiPolygon, + a.into(), + e.clone(), + epsilon = 0.00001 + )); + }); } #[test] diff --git a/datatypes/src/operations/reproject.rs b/datatypes/src/operations/reproject.rs index ed0cdc006..654f29d63 100644 --- a/datatypes/src/operations/reproject.rs +++ b/datatypes/src/operations/reproject.rs @@ -657,7 +657,12 @@ mod tests { (20_037_508.342_789_244, 20_048_966.104_014_594).into(), ); - assert_eq!(projected, expected); + assert!(approx_eq!( + BoundingBox2D, + projected, + expected, + epsilon = 0.000_001 + )); } #[test] @@ -678,7 +683,12 @@ mod tests { (20_037_508.342_789_244, 20_048_966.104_014_594).into(), ); - assert_eq!(projected, expected); + assert!(approx_eq!( + BoundingBox2D, + projected, + expected, + epsilon = 0.000_001 + )); } #[test] diff --git a/datatypes/src/primitives/bounding_box.rs b/datatypes/src/primitives/bounding_box.rs index 4d9723271..dafc4b819 100644 --- a/datatypes/src/primitives/bounding_box.rs +++ b/datatypes/src/primitives/bounding_box.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use super::{AxisAlignedRectangle, Coordinate2D, SpatialBounded}; use crate::error; use crate::util::Result; +use float_cmp::ApproxEq; #[cfg(feature = "postgres")] use postgres_types::{FromSql, ToSql}; use serde::{Deserialize, Serialize}; @@ -549,6 +550,22 @@ impl TryFrom for gdal::vector::Geometry { } } +impl ApproxEq for BoundingBox2D { + type Margin = float_cmp::F64Margin; + + fn approx_eq(self, other: Self, margin: M) -> bool + where + M: Into, + { + let m = margin.into(); + self.upper_right_coordinate + .approx_eq(other.upper_right_coordinate, m) + && self + .lower_left_coordinate + .approx_eq(other.lower_left_coordinate, m) + } +} + #[cfg(test)] mod tests { diff --git a/datatypes/src/primitives/coordinate.rs b/datatypes/src/primitives/coordinate.rs index fc1f081a9..20d4b6552 100644 --- a/datatypes/src/primitives/coordinate.rs +++ b/datatypes/src/primitives/coordinate.rs @@ -2,6 +2,7 @@ use crate::util::arrow::ArrowTyped; use arrow::array::{ArrayBuilder, BooleanArray, Float64Builder}; use arrow::datatypes::{DataType, Field}; use arrow::error::ArrowError; +use float_cmp::ApproxEq; use ocl::OclPrm; #[cfg(feature = "postgres")] use postgres_types::{FromSql, ToSql}; @@ -304,6 +305,18 @@ impl Div for Coordinate2D { } } +impl ApproxEq for Coordinate2D { + type Margin = float_cmp::F64Margin; + + fn approx_eq(self, other: Self, margin: M) -> bool + where + M: Into, + { + let m = margin.into(); + self.x.approx_eq(other.x, m) && self.y.approx_eq(other.y, m) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/datatypes/src/primitives/line.rs b/datatypes/src/primitives/line.rs index 735677f6c..d43c94f32 100644 --- a/datatypes/src/primitives/line.rs +++ b/datatypes/src/primitives/line.rs @@ -1,3 +1,5 @@ +use float_cmp::{ApproxEq, F64Margin}; + use super::{BoundingBox2D, Coordinate2D, SpatialBounded}; #[derive(Debug, Clone, Copy, PartialEq)] @@ -48,6 +50,15 @@ impl SpatialBounded for Line { } } +impl ApproxEq for Line { + type Margin = F64Margin; + + fn approx_eq>(self, other: Self, margin: M) -> bool { + let m = margin.into(); + self.start.approx_eq(other.start, m) && self.end.approx_eq(other.end, m) + } +} + #[cfg(test)] mod tests { use float_cmp::approx_eq; diff --git a/datatypes/src/primitives/multi_line_string.rs b/datatypes/src/primitives/multi_line_string.rs index 0e96c45ec..3769aaef0 100644 --- a/datatypes/src/primitives/multi_line_string.rs +++ b/datatypes/src/primitives/multi_line_string.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use arrow::array::{ArrayBuilder, BooleanArray}; use arrow::error::ArrowError; +use float_cmp::{ApproxEq, F64Margin}; use geo::algorithm::intersects::Intersects; use serde::{Deserialize, Serialize}; use snafu::ensure; @@ -100,6 +101,18 @@ impl AsRef<[Vec]> for MultiLineString { } } +impl ApproxEq for MultiLineString { + type Margin = F64Margin; + + fn approx_eq>(self, other: Self, margin: M) -> bool { + let m = margin.into(); + self.lines() + .iter() + .zip(other.lines().iter()) + .all(|(line_a, line_b)| line_a.approx_eq(line_b, m)) + } +} + impl ArrowTyped for MultiLineString { type ArrowArray = arrow::array::ListArray; type ArrowBuilder = arrow::array::ListBuilder< diff --git a/datatypes/src/primitives/multi_point.rs b/datatypes/src/primitives/multi_point.rs index 1363c9cbe..7010baf52 100644 --- a/datatypes/src/primitives/multi_point.rs +++ b/datatypes/src/primitives/multi_point.rs @@ -2,6 +2,7 @@ use std::convert::{TryFrom, TryInto}; use arrow::array::{ArrayBuilder, BooleanArray}; use arrow::error::ArrowError; +use float_cmp::{ApproxEq, F64Margin}; use serde::{Deserialize, Serialize}; use snafu::ensure; @@ -285,6 +286,18 @@ where } } +impl ApproxEq for MultiPoint { + type Margin = F64Margin; + + fn approx_eq>(self, other: Self, margin: M) -> bool { + let m = margin.into(); + self.coordinates + .iter() + .zip(other.coordinates.iter()) + .all(|(&a, &b)| a.approx_eq(b, m)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/datatypes/src/primitives/multi_polygon.rs b/datatypes/src/primitives/multi_polygon.rs index c5f1db91f..c1e357881 100644 --- a/datatypes/src/primitives/multi_polygon.rs +++ b/datatypes/src/primitives/multi_polygon.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use arrow::array::{ArrayBuilder, BooleanArray}; use arrow::error::ArrowError; +use float_cmp::{ApproxEq, F64Margin}; use geo::intersects::Intersects; use serde::{Deserialize, Serialize}; use snafu::ensure; @@ -401,6 +402,27 @@ impl<'g> From<&MultiPolygonRef<'g>> for MultiPolygon { } } +impl ApproxEq for MultiPolygon { + type Margin = F64Margin; + + fn approx_eq>(self, other: Self, margin: M) -> bool { + let m = margin.into(); + self.polygons() + .iter() + .zip(other.polygons()) + .all(|(polygon_a, polygon_b)| { + polygon_a.iter().zip(polygon_b).all(|(ring_a, ring_b)| { + ring_a + .iter() + .zip(ring_b) + .all(|(&coordinate_a, &coordinate_b)| { + coordinate_a.approx_eq(coordinate_b, m) + }) + }) + }) + } +} + #[cfg(test)] mod tests { use super::*; From 2b6f5a37aa84e6c9ad42d58b15a4a05ed63b4e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Wed, 19 Jan 2022 18:44:37 +0100 Subject: [PATCH 3/6] more approx_eq --- operators/src/processing/reprojection.rs | 112 ++++++++++++-------- services/Cargo.toml | 2 +- services/src/handlers/spatial_references.rs | 37 ++++--- 3 files changed, 95 insertions(+), 56 deletions(-) diff --git a/operators/src/processing/reprojection.rs b/operators/src/processing/reprojection.rs index e71320f30..4b45b6e27 100644 --- a/operators/src/processing/reprojection.rs +++ b/operators/src/processing/reprojection.rs @@ -486,7 +486,9 @@ mod tests { test_data, util::gdal::{add_ndvi_dataset, gdal_open_dataset}, }; + use float_cmp::approx_eq; use futures::StreamExt; + use geoengine_datatypes::collections::IntoGeometryIterator; use geoengine_datatypes::{ collections::{ GeometryCollection, MultiLineStringCollection, MultiPointCollection, @@ -525,16 +527,12 @@ mod tests { Default::default(), )?; - let projected_points = MultiPointCollection::from_data( - MultiPoint::many(vec![ - MARBURG_EPSG_900_913, - COLOGNE_EPSG_900_913, - HAMBURG_EPSG_900_913, - ]) - .unwrap(), - vec![TimeInterval::new_unchecked(0, 1); 3], - Default::default(), - )?; + let expected = MultiPoint::many(vec![ + MARBURG_EPSG_900_913, + COLOGNE_EPSG_900_913, + HAMBURG_EPSG_900_913, + ]) + .unwrap(); let point_source = MockFeatureCollectionSource::single(points.clone()).boxed(); @@ -576,7 +574,18 @@ mod tests { assert_eq!(result.len(), 1); - assert_eq!(result[0], projected_points); + result[0] + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiPoint, + a.into(), + e.clone(), + epsilon = 0.00001 + )); + }); Ok(()) } @@ -594,16 +603,12 @@ mod tests { Default::default(), )?; - let projected_lines = MultiLineStringCollection::from_data( - vec![MultiLineString::new(vec![vec![ - MARBURG_EPSG_900_913, - COLOGNE_EPSG_900_913, - HAMBURG_EPSG_900_913, - ]]) - .unwrap()], - vec![TimeInterval::new_unchecked(0, 1); 1], - Default::default(), - )?; + let expected = [MultiLineString::new(vec![vec![ + MARBURG_EPSG_900_913, + COLOGNE_EPSG_900_913, + HAMBURG_EPSG_900_913, + ]]) + .unwrap()]; let lines_source = MockFeatureCollectionSource::single(lines.clone()).boxed(); @@ -645,7 +650,18 @@ mod tests { assert_eq!(result.len(), 1); - assert_eq!(result[0], projected_lines); + result[0] + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiLineString, + a.into(), + e.clone(), + epsilon = 0.00001 + )); + }); Ok(()) } @@ -664,17 +680,13 @@ mod tests { Default::default(), )?; - let projected_polygons = MultiPolygonCollection::from_data( - vec![MultiPolygon::new(vec![vec![vec![ - MARBURG_EPSG_900_913, - COLOGNE_EPSG_900_913, - HAMBURG_EPSG_900_913, - MARBURG_EPSG_900_913, - ]]]) - .unwrap()], - vec![TimeInterval::new_unchecked(0, 1); 1], - Default::default(), - )?; + let expected = [MultiPolygon::new(vec![vec![vec![ + MARBURG_EPSG_900_913, + COLOGNE_EPSG_900_913, + HAMBURG_EPSG_900_913, + MARBURG_EPSG_900_913, + ]]]) + .unwrap()]; let polygon_source = MockFeatureCollectionSource::single(polygons.clone()).boxed(); @@ -716,7 +728,18 @@ mod tests { assert_eq!(result.len(), 1); - assert_eq!(result[0], projected_polygons); + result[0] + .geometries() + .into_iter() + .zip(expected.iter()) + .for_each(|(a, e)| { + assert!(approx_eq!( + MultiPolygon, + a.into(), + e.clone(), + epsilon = 0.00001 + )); + }); Ok(()) } @@ -917,16 +940,19 @@ mod tests { (20_037_508.342_789_244, 20_048_966.104_014_594).into(), ); - assert_eq!( + let reprojected = reproject_query( + query, + SpatialReference::new(SpatialReferenceAuthority::Epsg, 3857), + SpatialReference::epsg_4326(), + ) + .unwrap(); + + assert!(approx_eq!( + BoundingBox2D, expected, - reproject_query( - query, - SpatialReference::new(SpatialReferenceAuthority::Epsg, 3857), - SpatialReference::epsg_4326(), - ) - .unwrap() - .spatial_bounds - ); + reprojected.spatial_bounds, + epsilon = 0.000_001 + )); } #[tokio::test] diff --git a/services/Cargo.toml b/services/Cargo.toml index 75db2b147..b4db4a7cb 100644 --- a/services/Cargo.toml +++ b/services/Cargo.toml @@ -32,6 +32,7 @@ bytes = "1.0" chrono = { version = "0.4", features = ["serde"] } config = "0.11" flexi_logger = "0.22" +float-cmp = "0.9" futures = "0.3" futures-util = "0.3" gdal = "0.12" @@ -67,7 +68,6 @@ typetag = "0.1" url = { version = "2.2", features = ["serde"] } uuid = { version = "0.8", features = ["serde", "v4", "v5"] } zip = "0.5" - [dev-dependencies] httptest = "0.15.2" rand = "0.8.4" diff --git a/services/src/handlers/spatial_references.rs b/services/src/handlers/spatial_references.rs index 11c6ea709..a4a7c2bff 100755 --- a/services/src/handlers/spatial_references.rs +++ b/services/src/handlers/spatial_references.rs @@ -1,3 +1,5 @@ +use crate::handlers::Context; +use crate::{error, error::Error, error::Result}; use actix_web::{web, FromRequest, Responder}; use geoengine_datatypes::{ primitives::BoundingBox2D, @@ -8,9 +10,6 @@ use serde::{Deserialize, Serialize}; use snafu::ResultExt; use std::str::FromStr; -use crate::handlers::Context; -use crate::{error, error::Error, error::Result}; - pub(crate) fn init_spatial_reference_routes(cfg: &mut web::ServiceConfig) where C: Context, @@ -231,6 +230,7 @@ mod tests { use actix_web; use actix_web::http::header; use actix_web_httpauth::headers::authorization::Bearer; + use float_cmp::approx_eq; use geoengine_datatypes::spatial_reference::SpatialReference; use geoengine_datatypes::spatial_reference::SpatialReferenceAuthority; use geoengine_datatypes::util::test::TestDefault; @@ -268,16 +268,29 @@ mod tests { #[test] fn spec_webmercator() { let spec = spatial_reference_specification("EPSG:3857").unwrap(); - assert_eq!(SpatialReferenceSpecification { - name: "WGS 84 / Pseudo-Mercator".to_owned(), - spatial_reference: SpatialReference::new(SpatialReferenceAuthority::Epsg, 3857), - proj_string: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs".into(), - extent: BoundingBox2D::new_unchecked((-20_037_508.342_789_244, -20_048_966.104_014_6).into(), (20_037_508.342_789_244, 20_048_966.104_014_594).into()), - axis_labels: Some(("Easting".to_owned(), "Northing".to_owned())), - axis_order: Some(AxisOrder::EastNorth), - }, - spec + assert_eq!(spec.name, "WGS 84 / Pseudo-Mercator"); + assert_eq!( + spec.spatial_reference, + SpatialReference::new(SpatialReferenceAuthority::Epsg, 3857) + ); + assert_eq!( + spec.proj_string, + "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs", + ); + assert!(approx_eq!( + BoundingBox2D, + spec.extent, + BoundingBox2D::new_unchecked( + (-20_037_508.342_789_244, -20_048_966.104_014_6).into(), + (20_037_508.342_789_244, 20_048_966.104_014_594).into() + ), + epsilon = 0.000_001 + )); + assert_eq!( + spec.axis_labels, + Some(("Easting".to_owned(), "Northing".to_owned())) ); + assert_eq!(spec.axis_order, Some(AxisOrder::EastNorth)); } #[test] From 598074c88b0ea9f6b6459117a051a6ff01c2a387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Thu, 20 Jan 2022 09:42:58 +0100 Subject: [PATCH 4/6] add length checks for Multi* --- datatypes/src/primitives/multi_line_string.rs | 70 +++++- datatypes/src/primitives/multi_point.rs | 51 +++- datatypes/src/primitives/multi_polygon.rs | 227 +++++++++++++++++- 3 files changed, 329 insertions(+), 19 deletions(-) diff --git a/datatypes/src/primitives/multi_line_string.rs b/datatypes/src/primitives/multi_line_string.rs index 3769aaef0..4d8f7e546 100644 --- a/datatypes/src/primitives/multi_line_string.rs +++ b/datatypes/src/primitives/multi_line_string.rs @@ -106,10 +106,12 @@ impl ApproxEq for MultiLineString { fn approx_eq>(self, other: Self, margin: M) -> bool { let m = margin.into(); - self.lines() - .iter() - .zip(other.lines().iter()) - .all(|(line_a, line_b)| line_a.approx_eq(line_b, m)) + self.lines().len() == other.lines().len() + && self + .lines() + .iter() + .zip(other.lines().iter()) + .all(|(line_a, line_b)| line_a.len() == line_b.len() && line_a.approx_eq(line_b, m)) } } @@ -319,6 +321,8 @@ impl<'g> From<&MultiLineStringRef<'g>> for MultiLineString { #[cfg(test)] mod tests { + use float_cmp::approx_eq; + use super::*; #[test] @@ -349,4 +353,62 @@ mod tests { aggregate(&multi_line_string_ref) ); } + + #[test] + fn approx_equal() { + let a = MultiLineString::new(vec![ + vec![(0.1, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into()], + vec![(0.6, 0.6).into(), (0.9, 0.9).into()], + ]) + .unwrap(); + + let b = MultiLineString::new(vec![ + vec![(0.099_999_999, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into()], + vec![(0.6, 0.6).into(), (0.9, 0.9).into()], + ]) + .unwrap(); + + assert!(approx_eq!(MultiLineString, a, b, epsilon = 0.000_001)); + } + + #[test] + fn not_approx_equal_outer_len() { + let a = MultiLineString::new(vec![ + vec![(0.1, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into()], + vec![(0.6, 0.6).into(), (0.9, 0.9).into()], + ]) + .unwrap(); + + let b = MultiLineString::new(vec![ + vec![(0.1, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into()], + vec![(0.6, 0.6).into(), (0.9, 0.9).into()], + vec![(0.9, 0.9).into(), (123_456_789.9, 123_456_789.9).into()], + ]) + .unwrap(); + + assert!(!approx_eq!(MultiLineString, a, b, F64Margin::default())); + } + + #[test] + fn not_approx_equal_inner_len() { + let a = MultiLineString::new(vec![ + vec![(0.1, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into(), (0.7, 0.7).into()], + vec![(0.7, 0.7).into(), (0.9, 0.9).into()], + ]) + .unwrap(); + + let b = MultiLineString::new(vec![ + vec![(0.1, 0.1).into(), (0.5, 0.5).into()], + vec![(0.5, 0.5).into(), (0.6, 0.6).into()], + vec![(0.6, 0.6).into(), (0.7, 0.7).into(), (0.9, 0.9).into()], + ]) + .unwrap(); + + assert!(!approx_eq!(MultiLineString, a, b, F64Margin::default())); + } } diff --git a/datatypes/src/primitives/multi_point.rs b/datatypes/src/primitives/multi_point.rs index 7010baf52..a0914c1b6 100644 --- a/datatypes/src/primitives/multi_point.rs +++ b/datatypes/src/primitives/multi_point.rs @@ -291,15 +291,19 @@ impl ApproxEq for MultiPoint { fn approx_eq>(self, other: Self, margin: M) -> bool { let m = margin.into(); - self.coordinates - .iter() - .zip(other.coordinates.iter()) - .all(|(&a, &b)| a.approx_eq(b, m)) + self.coordinates.len() == other.coordinates.len() + && self + .coordinates + .iter() + .zip(other.coordinates.iter()) + .all(|(&a, &b)| a.approx_eq(b, m)) } } #[cfg(test)] mod tests { + use float_cmp::approx_eq; + use super::*; #[test] @@ -349,4 +353,43 @@ mod tests { let mp = MultiPoint { coordinates }; assert_eq!(mp.spatial_bounds(), expected); } + + #[test] + fn approx_equal() { + let a = MultiPoint::new(vec![ + (0.5, 0.5).into(), + (0.5, 0.5).into(), + (0.5, 0.5).into(), + ]) + .unwrap(); + + let b = MultiPoint::new(vec![ + (0.5, 0.499_999_999).into(), + (0.5, 0.5).into(), + (0.5, 0.5).into(), + ]) + .unwrap(); + + assert!(approx_eq!(MultiPoint, a, b, epsilon = 0.000_001)); + } + + #[test] + fn not_approx_equal_len() { + let a = MultiPoint::new(vec![ + (0.5, 0.5).into(), + (0.5, 0.5).into(), + (0.5, 0.5).into(), + ]) + .unwrap(); + + let b = MultiPoint::new(vec![ + (0.5, 0.5).into(), + (0.5, 0.5).into(), + (0.5, 0.5).into(), + (123_456_789.5, 123_456_789.5).into(), + ]) + .unwrap(); + + assert!(!approx_eq!(MultiPoint, a, b, F64Margin::default())); + } } diff --git a/datatypes/src/primitives/multi_polygon.rs b/datatypes/src/primitives/multi_polygon.rs index c1e357881..1324c67af 100644 --- a/datatypes/src/primitives/multi_polygon.rs +++ b/datatypes/src/primitives/multi_polygon.rs @@ -407,24 +407,29 @@ impl ApproxEq for MultiPolygon { fn approx_eq>(self, other: Self, margin: M) -> bool { let m = margin.into(); - self.polygons() - .iter() - .zip(other.polygons()) - .all(|(polygon_a, polygon_b)| { - polygon_a.iter().zip(polygon_b).all(|(ring_a, ring_b)| { - ring_a - .iter() - .zip(ring_b) - .all(|(&coordinate_a, &coordinate_b)| { - coordinate_a.approx_eq(coordinate_b, m) + self.polygons().len() == other.polygons().len() + && self + .polygons() + .iter() + .zip(other.polygons()) + .all(|(polygon_a, polygon_b)| { + polygon_a.len() == polygon_b.len() + && polygon_a.iter().zip(polygon_b).all(|(ring_a, ring_b)| { + ring_a.len() == ring_b.len() + && ring_a.iter().zip(ring_b).all( + |(&coordinate_a, &coordinate_b)| { + coordinate_a.approx_eq(coordinate_b, m) + }, + ) }) }) - }) } } #[cfg(test)] mod tests { + use float_cmp::approx_eq; + use super::*; #[test] @@ -475,4 +480,204 @@ mod tests { assert_eq!(aggregate(&multi_polygon), (1, 2, 8)); assert_eq!(aggregate(&multi_polygon), aggregate(&multi_polygon_ref)); } + + #[test] + fn approx_equal() { + let a = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.1).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.1).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![ + vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ], + vec![ + (1.2, 1.2).into(), + (1.9, 1.2).into(), + (1.9, 1.9).into(), + (1.2, 1.2).into(), + ], + ], + ]) + .unwrap(); + + let b = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.099_999_999).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.099_999_999).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![ + vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ], + vec![ + (1.2, 1.2).into(), + (1.9, 1.2).into(), + (1.9, 1.9).into(), + (1.2, 1.2).into(), + ], + ], + ]) + .unwrap(); + + assert!(approx_eq!(MultiPolygon, a, b, epsilon = 0.000_001)); + } + + #[test] + fn not_approx_equal_ring_len() { + let a = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.1).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.1).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ]], + ]) + .unwrap(); + + let b = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.1).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.1).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![ + vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ], + vec![ + (1.2, 1.2).into(), + (1.9, 1.2).into(), + (1.9, 1.9).into(), + (1.2, 1.2).into(), + ], + ], + ]) + .unwrap(); + + assert!(!approx_eq!(MultiPolygon, a, b, F64Margin::default())); + } + + #[test] + fn not_approx_equal_inner_len() { + let a = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.1).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.1).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![ + vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ], + vec![ + (1.2, 1.2).into(), + (1.9, 1.2).into(), + (1.9, 1.9).into(), + (1.2, 1.2).into(), + ], + ], + ]) + .unwrap(); + + let b = MultiPolygon::new(vec![ + vec![ + vec![ + (0.1, 0.1).into(), + (0.8, 0.1).into(), + (0.8, 0.8).into(), + (0.1, 0.1).into(), + ], + vec![ + (0.2, 0.2).into(), + (0.9, 0.2).into(), + (0.9, 0.9).into(), + (0.2, 0.2).into(), + ], + ], + vec![ + vec![ + (1.1, 1.1).into(), + (1.8, 1.1).into(), + (1.8, 1.8).into(), + (1.1, 1.1).into(), + ], + vec![ + (1.2, 1.2).into(), + (1.7, 1.2).into(), + (1.9, 1.2).into(), + (1.9, 1.9).into(), + (1.2, 1.2).into(), + ], + ], + ]) + .unwrap(); + + assert!(!approx_eq!(MultiPolygon, a, b, F64Margin::default())); + } } From 929f0fdd71d40800b094fa0620875efac7b585f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Thu, 20 Jan 2022 10:15:29 +0100 Subject: [PATCH 5/6] impl ApproxEq for &Multi* --- .../multi_line_string_collection.rs | 6 +++--- .../src/collections/multi_point_collection.rs | 7 +------ .../collections/multi_polygon_collection.rs | 7 +------ datatypes/src/primitives/multi_line_string.rs | 8 ++++---- datatypes/src/primitives/multi_point.rs | 6 +++--- datatypes/src/primitives/multi_polygon.rs | 8 ++++---- operators/src/processing/reprojection.rs | 20 +++++-------------- 7 files changed, 21 insertions(+), 41 deletions(-) diff --git a/datatypes/src/collections/multi_line_string_collection.rs b/datatypes/src/collections/multi_line_string_collection.rs index f190e38cb..275f5269b 100644 --- a/datatypes/src/collections/multi_line_string_collection.rs +++ b/datatypes/src/collections/multi_line_string_collection.rs @@ -585,9 +585,9 @@ mod tests { .zip(expected.iter()) .for_each(|(a, e)| { assert!(approx_eq!( - MultiLineString, - a.into(), - e.clone(), + &MultiLineString, + &a.into(), + e, epsilon = 0.00001 )); }); diff --git a/datatypes/src/collections/multi_point_collection.rs b/datatypes/src/collections/multi_point_collection.rs index 1abf79c67..edd84eabb 100755 --- a/datatypes/src/collections/multi_point_collection.rs +++ b/datatypes/src/collections/multi_point_collection.rs @@ -1186,12 +1186,7 @@ mod tests { .into_iter() .zip(expected.iter()) .for_each(|(a, e)| { - assert!(approx_eq!( - MultiPoint, - a.into(), - e.clone(), - epsilon = 0.000_001 - )); + assert!(approx_eq!(&MultiPoint, &a.into(), e, epsilon = 0.000_001)); }); } diff --git a/datatypes/src/collections/multi_polygon_collection.rs b/datatypes/src/collections/multi_polygon_collection.rs index 0cd52c5f8..f3b44b079 100644 --- a/datatypes/src/collections/multi_polygon_collection.rs +++ b/datatypes/src/collections/multi_polygon_collection.rs @@ -901,12 +901,7 @@ mod tests { .into_iter() .zip(expected.iter()) .for_each(|(a, e)| { - assert!(approx_eq!( - MultiPolygon, - a.into(), - e.clone(), - epsilon = 0.00001 - )); + assert!(approx_eq!(&MultiPolygon, &a.into(), e, epsilon = 0.00001)); }); } diff --git a/datatypes/src/primitives/multi_line_string.rs b/datatypes/src/primitives/multi_line_string.rs index 4d8f7e546..d90952d3f 100644 --- a/datatypes/src/primitives/multi_line_string.rs +++ b/datatypes/src/primitives/multi_line_string.rs @@ -101,7 +101,7 @@ impl AsRef<[Vec]> for MultiLineString { } } -impl ApproxEq for MultiLineString { +impl ApproxEq for &MultiLineString { type Margin = F64Margin; fn approx_eq>(self, other: Self, margin: M) -> bool { @@ -370,7 +370,7 @@ mod tests { ]) .unwrap(); - assert!(approx_eq!(MultiLineString, a, b, epsilon = 0.000_001)); + assert!(approx_eq!(&MultiLineString, &a, &b, epsilon = 0.000_001)); } #[test] @@ -390,7 +390,7 @@ mod tests { ]) .unwrap(); - assert!(!approx_eq!(MultiLineString, a, b, F64Margin::default())); + assert!(!approx_eq!(&MultiLineString, &a, &b, F64Margin::default())); } #[test] @@ -409,6 +409,6 @@ mod tests { ]) .unwrap(); - assert!(!approx_eq!(MultiLineString, a, b, F64Margin::default())); + assert!(!approx_eq!(&MultiLineString, &a, &b, F64Margin::default())); } } diff --git a/datatypes/src/primitives/multi_point.rs b/datatypes/src/primitives/multi_point.rs index a0914c1b6..295bffc49 100644 --- a/datatypes/src/primitives/multi_point.rs +++ b/datatypes/src/primitives/multi_point.rs @@ -286,7 +286,7 @@ where } } -impl ApproxEq for MultiPoint { +impl ApproxEq for &MultiPoint { type Margin = F64Margin; fn approx_eq>(self, other: Self, margin: M) -> bool { @@ -370,7 +370,7 @@ mod tests { ]) .unwrap(); - assert!(approx_eq!(MultiPoint, a, b, epsilon = 0.000_001)); + assert!(approx_eq!(&MultiPoint, &a, &b, epsilon = 0.000_001)); } #[test] @@ -390,6 +390,6 @@ mod tests { ]) .unwrap(); - assert!(!approx_eq!(MultiPoint, a, b, F64Margin::default())); + assert!(!approx_eq!(&MultiPoint, &a, &b, F64Margin::default())); } } diff --git a/datatypes/src/primitives/multi_polygon.rs b/datatypes/src/primitives/multi_polygon.rs index 1324c67af..869c90977 100644 --- a/datatypes/src/primitives/multi_polygon.rs +++ b/datatypes/src/primitives/multi_polygon.rs @@ -402,7 +402,7 @@ impl<'g> From<&MultiPolygonRef<'g>> for MultiPolygon { } } -impl ApproxEq for MultiPolygon { +impl ApproxEq for &MultiPolygon { type Margin = F64Margin; fn approx_eq>(self, other: Self, margin: M) -> bool { @@ -547,7 +547,7 @@ mod tests { ]) .unwrap(); - assert!(approx_eq!(MultiPolygon, a, b, epsilon = 0.000_001)); + assert!(approx_eq!(&MultiPolygon, &a, &b, epsilon = 0.000_001)); } #[test] @@ -608,7 +608,7 @@ mod tests { ]) .unwrap(); - assert!(!approx_eq!(MultiPolygon, a, b, F64Margin::default())); + assert!(!approx_eq!(&MultiPolygon, &a, &b, F64Margin::default())); } #[test] @@ -678,6 +678,6 @@ mod tests { ]) .unwrap(); - assert!(!approx_eq!(MultiPolygon, a, b, F64Margin::default())); + assert!(!approx_eq!(&MultiPolygon, &a, &b, F64Margin::default())); } } diff --git a/operators/src/processing/reprojection.rs b/operators/src/processing/reprojection.rs index 4b45b6e27..b47a3ea20 100644 --- a/operators/src/processing/reprojection.rs +++ b/operators/src/processing/reprojection.rs @@ -579,12 +579,7 @@ mod tests { .into_iter() .zip(expected.iter()) .for_each(|(a, e)| { - assert!(approx_eq!( - MultiPoint, - a.into(), - e.clone(), - epsilon = 0.00001 - )); + assert!(approx_eq!(&MultiPoint, &a.into(), e, epsilon = 0.00001)); }); Ok(()) @@ -656,9 +651,9 @@ mod tests { .zip(expected.iter()) .for_each(|(a, e)| { assert!(approx_eq!( - MultiLineString, - a.into(), - e.clone(), + &MultiLineString, + &a.into(), + e, epsilon = 0.00001 )); }); @@ -733,12 +728,7 @@ mod tests { .into_iter() .zip(expected.iter()) .for_each(|(a, e)| { - assert!(approx_eq!( - MultiPolygon, - a.into(), - e.clone(), - epsilon = 0.00001 - )); + assert!(approx_eq!(&MultiPolygon, &a.into(), e, epsilon = 0.00001)); }); Ok(()) From 84054c135bc03ac075b31a021016cc693301ba7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Thu, 20 Jan 2022 11:07:19 +0100 Subject: [PATCH 6/6] assert that attributes are still there --- .../multi_line_string_collection.rs | 17 +++++++++- .../src/collections/multi_point_collection.rs | 33 ++++++++++++++++--- .../collections/multi_polygon_collection.rs | 17 +++++++++- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/datatypes/src/collections/multi_line_string_collection.rs b/datatypes/src/collections/multi_line_string_collection.rs index 275f5269b..f90e1237f 100644 --- a/datatypes/src/collections/multi_line_string_collection.rs +++ b/datatypes/src/collections/multi_line_string_collection.rs @@ -282,7 +282,7 @@ mod tests { use super::*; use crate::collections::{BuilderProvider, FeatureCollectionModifications}; - use crate::primitives::TimeInterval; + use crate::primitives::{FeatureDataRef, TimeInterval}; #[test] fn single_line() { @@ -579,6 +579,7 @@ mod tests { let proj_collection = collection.reproject(&projector).unwrap(); + // Assert geometrys are approx equal proj_collection .geometries() .into_iter() @@ -591,5 +592,19 @@ mod tests { epsilon = 0.00001 )); }); + + // Assert that feature time intervals did not move around + assert_eq!(proj_collection.time_intervals().len(), 2); + assert_eq!( + proj_collection.time_intervals(), + &[TimeInterval::default(), TimeInterval::default()] + ); + + // Assert that feature data did not magicaly disappear + if let FeatureDataRef::Int(numbers) = proj_collection.data("A").unwrap() { + assert_eq!(numbers.as_ref(), &[1, 2]); + } else { + unreachable!(); + } } } diff --git a/datatypes/src/collections/multi_point_collection.rs b/datatypes/src/collections/multi_point_collection.rs index edd84eabb..070a78579 100755 --- a/datatypes/src/collections/multi_point_collection.rs +++ b/datatypes/src/collections/multi_point_collection.rs @@ -1163,17 +1163,17 @@ mod tests { ], { let mut map = HashMap::new(); - map.insert("numbers".into(), FeatureData::Float(vec![0., 1.])); + map.insert("numbers".into(), FeatureData::Int(vec![0, 1])); map.insert( "number_nulls".into(), - FeatureData::NullableFloat(vec![Some(0.), None]), + FeatureData::NullableInt(vec![Some(0), None]), ); map }, ) .unwrap(); - let expected = MultiPoint::many(vec![ + let expected_points = MultiPoint::many(vec![ vec![MARBURG_EPSG_900_913, COLOGNE_EPSG_900_913], vec![HAMBURG_EPSG_900_913], ]) @@ -1181,13 +1181,38 @@ mod tests { let proj_pc = pc.reproject(&projector).unwrap(); + // Assert geometrys are approx equal proj_pc .geometries() .into_iter() - .zip(expected.iter()) + .zip(expected_points.iter()) .for_each(|(a, e)| { assert!(approx_eq!(&MultiPoint, &a.into(), e, epsilon = 0.000_001)); }); + + // Assert that feature time intervals did not move around + assert_eq!(proj_pc.time_intervals().len(), 2); + assert_eq!( + proj_pc.time_intervals(), + &[ + TimeInterval::new_unchecked(0, 1), + TimeInterval::new_unchecked(1, 2), + ] + ); + + // Assert that feature data did not magicaly disappear + if let FeatureDataRef::Int(numbers) = proj_pc.data("numbers").unwrap() { + assert_eq!(numbers.as_ref(), &[0, 1]); + } else { + unreachable!(); + } + + if let FeatureDataRef::Int(numbers) = proj_pc.data("number_nulls").unwrap() { + assert_eq!(numbers.as_ref()[1], 0); + assert_eq!(numbers.nulls(), vec![false, true]); + } else { + unreachable!(); + } } #[test] diff --git a/datatypes/src/collections/multi_polygon_collection.rs b/datatypes/src/collections/multi_polygon_collection.rs index f3b44b079..0de08887e 100644 --- a/datatypes/src/collections/multi_polygon_collection.rs +++ b/datatypes/src/collections/multi_polygon_collection.rs @@ -409,7 +409,7 @@ mod tests { use super::*; use crate::collections::{BuilderProvider, FeatureCollectionModifications}; - use crate::primitives::TimeInterval; + use crate::primitives::{FeatureDataRef, TimeInterval}; #[test] fn single_polygons() { @@ -896,6 +896,7 @@ mod tests { let proj_collection = collection.reproject(&projector).unwrap(); + // Assert geometrys are approx equal proj_collection .geometries() .into_iter() @@ -903,6 +904,20 @@ mod tests { .for_each(|(a, e)| { assert!(approx_eq!(&MultiPolygon, &a.into(), e, epsilon = 0.00001)); }); + + // Assert that feature time intervals did not move around + assert_eq!(proj_collection.time_intervals().len(), 2); + assert_eq!( + proj_collection.time_intervals(), + &[TimeInterval::default(), TimeInterval::default()] + ); + + // Assert that feature data did not magicaly disappear + if let FeatureDataRef::Int(numbers) = proj_collection.data("A").unwrap() { + assert_eq!(numbers.as_ref(), &[1, 2]); + } else { + unreachable!(); + } } #[test]