From f70269e41f69b5e9ecbea084382429e7afd20ee4 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Mon, 11 May 2020 12:10:43 -0700 Subject: [PATCH 1/2] Switch to internal bounding box type. --- lib/Cargo.toml | 2 +- lib/src/boolean/fill_queue.rs | 9 ++++---- lib/src/boolean/mod.rs | 28 +++++++++++++++++++++++-- lib/src/boolean/segment_intersection.rs | 17 ++++++++------- lib/src/boolean/subdivide_segments.rs | 6 +++--- tests/Cargo.toml | 4 ++-- tests/src/fill_queue_test.rs | 11 +++++----- tests/src/possible_intersection_test.rs | 5 +++-- 8 files changed, 55 insertions(+), 27 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 698bc12..a6fa206 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -10,7 +10,7 @@ readme = "../README.md" keywords = ["gis", "geo", "geography", "geospatial"] [dependencies] -geo-types = { version = "0.4", default-features = false } +geo-types = { version = "0.5.0", default-features = false } num-traits = "0.2" robust = "0.1" float_next_after = "0.1" diff --git a/lib/src/boolean/fill_queue.rs b/lib/src/boolean/fill_queue.rs index b05e40f..7856901 100644 --- a/lib/src/boolean/fill_queue.rs +++ b/lib/src/boolean/fill_queue.rs @@ -1,16 +1,17 @@ use super::helper::Float; -use geo_types::{LineString, Polygon, Rect}; +use geo_types::{LineString, Polygon}; use std::collections::BinaryHeap; use std::rc::{Rc, Weak}; use super::sweep_event::SweepEvent; use super::Operation; +use super::BoundingBox; pub fn fill_queue( subject: &[Polygon], clipping: &[Polygon], - sbbox: &mut Rect, - cbbox: &mut Rect, + sbbox: &mut BoundingBox, + cbbox: &mut BoundingBox, operation: Operation, ) -> BinaryHeap>> where @@ -53,7 +54,7 @@ fn process_polygon( is_subject: bool, contour_id: u32, event_queue: &mut BinaryHeap>>, - bbox: &mut Rect, + bbox: &mut BoundingBox, is_exterior_ring: bool, ) where F: Float, diff --git a/lib/src/boolean/mod.rs b/lib/src/boolean/mod.rs index dd8dc0e..67d6ea3 100644 --- a/lib/src/boolean/mod.rs +++ b/lib/src/boolean/mod.rs @@ -1,4 +1,4 @@ -use geo_types::{Coordinate, LineString, MultiPolygon, Polygon, Rect}; +use geo_types::{Coordinate, CoordinateType, LineString, MultiPolygon, Polygon}; pub mod compare_segments; pub mod compute_fields; @@ -89,7 +89,7 @@ fn boolean_operation(subject: &[Polygon], clipping: &[Polygon], operati where F: Float, { - let mut sbbox = Rect { + let mut sbbox = BoundingBox { min: Coordinate { x: F::infinity(), y: F::infinity(), @@ -139,3 +139,27 @@ where Operation::Union | Operation::Xor => MultiPolygon(subject.iter().chain(clipping).cloned().collect()), } } + +/// A bounded 2D quadrilateral whose area is defined by minimum and maximum `Coordinates`. +/// +/// A simple implementation copied from geo_types 0.4.0, because this version is a better +/// fit for the needs of this crate than the newer ones. +#[derive(PartialEq, Clone, Copy, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct BoundingBox + where + T: CoordinateType, +{ + pub min: Coordinate, + pub max: Coordinate, +} + +impl BoundingBox { + pub fn width(self) -> T { + self.max.x - self.min.x + } + + pub fn height(self) -> T { + self.max.y - self.min.y + } +} diff --git a/lib/src/boolean/segment_intersection.rs b/lib/src/boolean/segment_intersection.rs index af54c78..0921baf 100644 --- a/lib/src/boolean/segment_intersection.rs +++ b/lib/src/boolean/segment_intersection.rs @@ -1,5 +1,6 @@ use super::helper::Float; -use geo_types::{Coordinate, Rect}; +use super::BoundingBox; +use geo_types::{Coordinate}; #[derive(Debug, Clone, Copy, PartialEq)] pub enum LineIntersection @@ -17,7 +18,7 @@ fn get_intersection_bounding_box( a2: Coordinate, b1: Coordinate, b2: Coordinate, -) -> Option> +) -> Option> where F: Float, { @@ -30,7 +31,7 @@ where let interval_end_x = a_end_x.min(b_end_x); let interval_end_y = a_end_y.min(b_end_y); if interval_start_x <= interval_end_x && interval_start_y <= interval_end_y { - Some(Rect { + Some(BoundingBox { min: Coordinate { x: interval_start_x, y: interval_start_y, @@ -46,7 +47,7 @@ where } #[inline] -fn constrain_to_bounding_box(p: Coordinate, bb: Rect) -> Coordinate +fn constrain_to_bounding_box(p: Coordinate, bb: BoundingBox) -> Coordinate where F: Float, { @@ -198,22 +199,22 @@ mod test { use super::super::helper::test::xy; use super::*; - fn rect(min: Coordinate, max: Coordinate) -> Rect { - Rect { min, max } + fn rect(min: Coordinate, max: Coordinate) -> BoundingBox { + BoundingBox { min, max } } #[test] fn test_get_intersection_bounding_box() { assert_eq!( get_intersection_bounding_box(xy(0, 0), xy(2, 2), xy(1, 1), xy(3, 3)), - Some(Rect { + Some(BoundingBox { min: xy(1, 1), max: xy(2, 2) }), ); assert_eq!( get_intersection_bounding_box(xy(-1, 0), xy(1, 0), xy(0, -1), xy(0, 1)), - Some(Rect { + Some(BoundingBox { min: xy(0, 0), max: xy(0, 0) }), diff --git a/lib/src/boolean/subdivide_segments.rs b/lib/src/boolean/subdivide_segments.rs index 57620ce..95e5107 100644 --- a/lib/src/boolean/subdivide_segments.rs +++ b/lib/src/boolean/subdivide_segments.rs @@ -4,8 +4,8 @@ use super::helper::Float; use super::possible_intersection::possible_intersection; use super::sweep_event::SweepEvent; use super::Operation; +use super::BoundingBox; use crate::splay::SplaySet; -use geo_types::Rect; use std::collections::BinaryHeap; use std::rc::Rc; @@ -14,8 +14,8 @@ use super::sweep_event::JsonDebug; pub fn subdivide( event_queue: &mut BinaryHeap>>, - sbbox: &Rect, - cbbox: &Rect, + sbbox: &BoundingBox, + cbbox: &BoundingBox, operation: Operation, ) -> Vec>> where diff --git a/tests/Cargo.toml b/tests/Cargo.toml index b90c1c0..04194be 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -6,11 +6,11 @@ edition = "2018" [dependencies] geo-booleanop = { path = "../lib", features = [] } # add "debug-booleanop" for debugging -geo = "0.12" +geo = "0.13" # Note: It is crucial to enable arbitrary_precision on serde_json, otherwise # JSON parsing isn't exact. -geojson = { version = "0.16", features = ["geo-types"] } +geojson = { version = "0.18", features = ["geo-types"] } serde_json = { version = "1.0.44", features = ["arbitrary_precision"] } clap = "2.3.3" diff --git a/tests/src/fill_queue_test.rs b/tests/src/fill_queue_test.rs index 8c39a5c..2d28b7c 100644 --- a/tests/src/fill_queue_test.rs +++ b/tests/src/fill_queue_test.rs @@ -1,7 +1,8 @@ use super::helper::fixture_shapes; -use geo::{Coordinate, Rect}; +use geo::Coordinate; use geo_booleanop::boolean::fill_queue::fill_queue; use geo_booleanop::boolean::Operation; +use geo_booleanop::boolean::BoundingBox; use num_traits::Float; use super::helper::xy; @@ -9,7 +10,7 @@ use super::helper::xy; #[test] fn test_two_polygons() { let (s, c) = fixture_shapes("two_shapes.geojson"); - let mut sbbox = Rect { + let mut sbbox = BoundingBox { min: Coordinate { x: f64::infinity(), y: f64::infinity(), @@ -59,7 +60,7 @@ fn test_two_polygons() { #[test] fn test_fill_event_queue() { let (s, c) = fixture_shapes("two_triangles.geojson"); - let mut sbbox = Rect { + let mut sbbox = BoundingBox { min: xy(f64::infinity(), f64::infinity()), max: xy(f64::neg_infinity(), f64::neg_infinity()), }; @@ -68,14 +69,14 @@ fn test_fill_event_queue() { assert_eq!( sbbox, - Rect { + BoundingBox { min: xy(20.0, -113.5), max: xy(226.5, 74.0) }, ); assert_eq!( cbbox, - Rect { + BoundingBox { min: xy(54.5, -198.0), max: xy(239.5, 33.5) }, diff --git a/tests/src/possible_intersection_test.rs b/tests/src/possible_intersection_test.rs index 3a1c3ee..10e7a63 100644 --- a/tests/src/possible_intersection_test.rs +++ b/tests/src/possible_intersection_test.rs @@ -1,11 +1,12 @@ use super::helper::fixture_shapes; -use geo::{Coordinate, Rect}; +use geo::Coordinate; use geo_booleanop::boolean::compare_segments::compare_segments; use geo_booleanop::boolean::fill_queue::fill_queue; use geo_booleanop::boolean::possible_intersection::possible_intersection; use geo_booleanop::boolean::subdivide_segments::subdivide; use geo_booleanop::boolean::sweep_event::SweepEvent; use geo_booleanop::boolean::Operation; +use geo_booleanop::boolean::BoundingBox; use geo_booleanop::splay::SplaySet; use num_traits::Float; use std::cmp::Ordering; @@ -74,7 +75,7 @@ fn test_possible_intersection() { #[test] fn test_on_two_polygons() { let (s, c) = fixture_shapes("two_shapes.geojson"); - let mut sbbox = Rect { + let mut sbbox = BoundingBox { min: Coordinate { x: f64::infinity(), y: f64::infinity(), From 225096bf10ae43933d2b5b391530ad26026fa900 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Mon, 11 May 2020 13:28:04 -0700 Subject: [PATCH 2/2] Address review comments. --- lib/Cargo.toml | 2 +- lib/src/boolean/fill_queue.rs | 2 +- lib/src/boolean/helper.rs | 24 +++++++++++++++++++++ lib/src/boolean/mod.rs | 28 ++----------------------- lib/src/boolean/segment_intersection.rs | 2 +- lib/src/boolean/subdivide_segments.rs | 3 +-- tests/Cargo.toml | 2 +- 7 files changed, 31 insertions(+), 32 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index a6fa206..17a7c55 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "geo-booleanop" -version = "0.2.2" +version = "0.3.0" authors = ["Bodo Junglas "] edition = "2018" license = "MIT" diff --git a/lib/src/boolean/fill_queue.rs b/lib/src/boolean/fill_queue.rs index 7856901..9a715d6 100644 --- a/lib/src/boolean/fill_queue.rs +++ b/lib/src/boolean/fill_queue.rs @@ -5,7 +5,7 @@ use std::rc::{Rc, Weak}; use super::sweep_event::SweepEvent; use super::Operation; -use super::BoundingBox; +use super::helper::BoundingBox; pub fn fill_queue( subject: &[Polygon], diff --git a/lib/src/boolean/helper.rs b/lib/src/boolean/helper.rs index 0fdc394..fff42ac 100644 --- a/lib/src/boolean/helper.rs +++ b/lib/src/boolean/helper.rs @@ -1,4 +1,5 @@ use float_next_after::NextAfter as NextAfterFloat; +use geo_types::{Coordinate, CoordinateType}; use num_traits::Float as NumTraitsFloat; use std::cmp::Ordering; use std::fmt::{Debug, Display}; @@ -50,6 +51,29 @@ pub fn less_if_inversed(condition: bool) -> Ordering { } } +/// A bounded 2D quadrilateral whose area is defined by minimum and maximum `Coordinates`. +/// +/// A simple implementation copied from geo_types 0.4.0, because this version is a better +/// fit for the needs of this crate than the newer ones. +#[derive(PartialEq, Clone, Copy, Debug)] +pub struct BoundingBox + where + T: CoordinateType, +{ + pub min: Coordinate, + pub max: Coordinate, +} + +impl BoundingBox { + pub fn width(self) -> T { + self.max.x - self.min.x + } + + pub fn height(self) -> T { + self.max.y - self.min.y + } +} + #[cfg(test)] pub mod test { use super::Float; diff --git a/lib/src/boolean/mod.rs b/lib/src/boolean/mod.rs index 67d6ea3..c8c25c8 100644 --- a/lib/src/boolean/mod.rs +++ b/lib/src/boolean/mod.rs @@ -1,4 +1,4 @@ -use geo_types::{Coordinate, CoordinateType, LineString, MultiPolygon, Polygon}; +use geo_types::{Coordinate, LineString, MultiPolygon, Polygon}; pub mod compare_segments; pub mod compute_fields; @@ -12,7 +12,7 @@ mod signed_area; pub mod subdivide_segments; pub mod sweep_event; -pub use helper::Float; +pub use helper::{BoundingBox, Float}; use self::connect_edges::connect_edges; use self::fill_queue::fill_queue; @@ -139,27 +139,3 @@ where Operation::Union | Operation::Xor => MultiPolygon(subject.iter().chain(clipping).cloned().collect()), } } - -/// A bounded 2D quadrilateral whose area is defined by minimum and maximum `Coordinates`. -/// -/// A simple implementation copied from geo_types 0.4.0, because this version is a better -/// fit for the needs of this crate than the newer ones. -#[derive(PartialEq, Clone, Copy, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct BoundingBox - where - T: CoordinateType, -{ - pub min: Coordinate, - pub max: Coordinate, -} - -impl BoundingBox { - pub fn width(self) -> T { - self.max.x - self.min.x - } - - pub fn height(self) -> T { - self.max.y - self.min.y - } -} diff --git a/lib/src/boolean/segment_intersection.rs b/lib/src/boolean/segment_intersection.rs index 0921baf..dabf0af 100644 --- a/lib/src/boolean/segment_intersection.rs +++ b/lib/src/boolean/segment_intersection.rs @@ -1,5 +1,5 @@ use super::helper::Float; -use super::BoundingBox; +use super::helper::BoundingBox; use geo_types::{Coordinate}; #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/lib/src/boolean/subdivide_segments.rs b/lib/src/boolean/subdivide_segments.rs index 95e5107..28f392f 100644 --- a/lib/src/boolean/subdivide_segments.rs +++ b/lib/src/boolean/subdivide_segments.rs @@ -1,10 +1,9 @@ use super::compare_segments::compare_segments; use super::compute_fields::compute_fields; -use super::helper::Float; +use super::helper::{BoundingBox, Float}; use super::possible_intersection::possible_intersection; use super::sweep_event::SweepEvent; use super::Operation; -use super::BoundingBox; use crate::splay::SplaySet; use std::collections::BinaryHeap; use std::rc::Rc; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 04194be..a8a895b 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "geo-booleanop-tests" -version = "0.2.2" +version = "0.3.0" authors = ["Bodo Junglas "] edition = "2018"