This is an automated email from the ASF dual-hosted git repository. prantogg pushed a commit to branch orient-ccw in repository https://gitbox.apache.org/repos/asf/sedona-spatialbench.git
commit 2ea426c408fb793a7c514c0b9e991b07760a8b86 Author: Pranav Toggi <[email protected]> AuthorDate: Sat Nov 8 10:14:14 2025 -0800 add test suite for geometry validation --- spatialbench/tests/geometry_tests.rs | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/spatialbench/tests/geometry_tests.rs b/spatialbench/tests/geometry_tests.rs new file mode 100644 index 0000000..0581be6 --- /dev/null +++ b/spatialbench/tests/geometry_tests.rs @@ -0,0 +1,136 @@ +//! Geometry validation tests for generated spatial data. +//! +//! This test suite validates that all generated geometries meet quality and correctness standards: +//! - **Coordinate validity**: Longitude [-180°, 180°], latitude [-90°, 90°] +//! - **OGC compliance**: Valid topology, counter-clockwise winding for exterior rings +//! - **Precision constraints**: Coordinates limited to 9 decimal places +//! - **Antimeridian handling**: No dateline crossings in generated polygons +//! +//! These tests ensure spatial data quality and compatibility with spatial databases and GIS tools. + +#[cfg(test)] +mod geometry_tests { + use geo::{Validation, Winding}; + use spatialbench::generators::{BuildingGenerator, TripGenerator}; + use spatialbench::spatial::geometry::GEOMETRY_PRECISION; + use spatialbench::spatial::utils::crosses_dateline; + + #[test] + fn test_trip_coordinates_are_valid() { + let generator = TripGenerator::new(0.1, 1, 1); + let trips: Vec<_> = generator.iter().collect(); + + for trip in trips { + // Check pickup coordinates are valid + assert!( + trip.t_pickuploc.x() >= -180.0 && trip.t_pickuploc.x() <= 180.0, + "Pickup longitude out of range: {}", + trip.t_pickuploc.x() + ); + assert!( + trip.t_pickuploc.y() >= -90.0 && trip.t_pickuploc.y() <= 90.0, + "Pickup latitude out of range: {}", + trip.t_pickuploc.y() + ); + + // Check dropoff coordinates are valid + assert!( + trip.t_dropoffloc.x() >= -180.0 && trip.t_dropoffloc.x() <= 180.0, + "Dropoff longitude out of range: {}", + trip.t_dropoffloc.x() + ); + assert!( + trip.t_dropoffloc.y() >= -90.0 && trip.t_dropoffloc.y() <= 90.0, + "Dropoff latitude out of range: {}", + trip.t_dropoffloc.y() + ); + + // Check coordinates have proper precision (9 decimal places) + let pickup_x_precision = + (trip.t_pickuploc.x() * GEOMETRY_PRECISION).round() / GEOMETRY_PRECISION; + assert_eq!(trip.t_pickuploc.x(), pickup_x_precision); + + let dropoff_x_precision = + (trip.t_dropoffloc.x() * GEOMETRY_PRECISION).round() / GEOMETRY_PRECISION; + assert_eq!(trip.t_dropoffloc.x(), dropoff_x_precision); + } + } + + #[test] + fn test_building_polygons_are_valid() { + let generator = BuildingGenerator::new(10.0, 1, 1); + let buildings: Vec<_> = generator.iter().collect(); + + for building in buildings { + let polygon = &building.b_boundary; + + assert!( + polygon.is_valid(), + "Building {} has invalid polygon", + building.b_buildingkey + ); + } + } + + #[test] + fn test_building_polygon_winding() { + // Create a generator with a small scale factor + let generator = BuildingGenerator::new(1.0, 1, 1); + let buildings: Vec<_> = generator.iter().collect(); + + // Check that all building polygons have counter-clockwise winding + for building in buildings.iter() { + let exterior = building.b_boundary.exterior(); + assert!( + exterior.is_ccw(), + "Building {} polygon should have counter-clockwise winding", + building.b_buildingkey + ); + } + } + + #[test] + fn test_coordinate_precision() { + let generator = TripGenerator::new(0.01, 1, 1); + let trips: Vec<_> = generator.iter().collect(); + + for trip in trips { + // Check 8 decimal place precision + let pickup_x_str = format!("{:.9}", trip.t_pickuploc.x()); + let pickup_y_str = format!("{:.9}", trip.t_pickuploc.y()); + let dropoff_x_str = format!("{:.9}", trip.t_dropoffloc.x()); + let dropoff_y_str = format!("{:.9}", trip.t_dropoffloc.y()); + + // Verify no extra precision beyond 8 decimals + let pickup_x_parsed: f64 = pickup_x_str.parse().unwrap(); + let pickup_y_parsed: f64 = pickup_y_str.parse().unwrap(); + let dropoff_x_parsed: f64 = dropoff_x_str.parse().unwrap(); + let dropoff_y_parsed: f64 = dropoff_y_str.parse().unwrap(); + + assert_eq!(trip.t_pickuploc.x(), pickup_x_parsed); + assert_eq!(trip.t_pickuploc.y(), pickup_y_parsed); + assert_eq!(trip.t_dropoffloc.x(), dropoff_x_parsed); + assert_eq!(trip.t_dropoffloc.y(), dropoff_y_parsed); + } + } + + #[test] + fn test_building_dateline_crossing() { + use spatialbench::generators::BuildingGenerator; + + let generator = BuildingGenerator::new(1000.0, 1, 1); + let buildings: Vec<_> = generator.iter().collect(); + + for building in buildings { + let polygon = &building.b_boundary; + + assert_eq!( + crosses_dateline(polygon), + false, + "Building {} polygon crosses dateline: {:?}", + building.b_buildingkey, + building.b_boundary + ); + } + } +}
