Skip to content

Commit

Permalink
Merge branch 'main' into kyle/traits-to-geo
Browse files Browse the repository at this point in the history
  • Loading branch information
kylebarron authored Nov 7, 2024
2 parents b553005 + 2537a07 commit da03b8b
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 4 deletions.
5 changes: 5 additions & 0 deletions geo-types/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changes

## Unreleased
* Add rstar compatibility for MultiPolygon
* Add multi-threading support to Multi* geometries.
* Feature-gated ('multithreading'), disabled by default, enabled by default when geo-types is used by geo

## 0.7.13

* POSSIBLY BREAKING: Minimum supported version of Rust (MSRV) is now 1.70
Expand Down
2 changes: 2 additions & 0 deletions geo-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition = "2021"
[features]
default = ["std"]
std = ["approx?/std", "num-traits/std", "serde?/std"]
multithreading = ["rayon"]
# Prefer `use-rstar` feature rather than enabling rstar directly.
# rstar integration relies on the optional approx crate, but implicit features cannot yet enable other features.
# See: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#namespaced-features
Expand All @@ -25,6 +26,7 @@ use-rstar_0_11 = ["rstar_0_11", "approx"]
use-rstar_0_12 = ["rstar_0_12", "approx"]

[dependencies]
rayon = { version = "1.10.0", optional = true }
approx = { version = ">= 0.4.0, < 0.6.0", optional = true, default-features = false }
arbitrary = { version = "1.2.0", optional = true }
num-traits = { version = "0.2", default-features = false, features = ["libm"] }
Expand Down
4 changes: 2 additions & 2 deletions geo-types/src/geometry/line_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use alloc::vec::Vec;
use core::iter::FromIterator;
use core::ops::{Index, IndexMut};

/// An ordered collection of two or more [`Coord`]s, representing a
/// path between locations.
/// An ordered collection of [`Coord`]s, representing a path between locations.
/// To be valid, a `LineString` must be empty, or have two or more coords.
///
/// # Semantics
///
Expand Down
47 changes: 47 additions & 0 deletions geo-types/src/geometry/multi_line_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use alloc::vec::Vec;
#[cfg(any(feature = "approx", test))]
use approx::{AbsDiffEq, RelativeEq};
use core::iter::FromIterator;
#[cfg(feature = "multithreading")]
use rayon::prelude::*;

/// A collection of
/// [`LineString`s](line_string/struct.LineString.html). Can
Expand Down Expand Up @@ -118,6 +120,36 @@ impl<T: CoordNum> MultiLineString<T> {
}
}

#[cfg(feature = "multithreading")]
impl<T: CoordNum + Send> IntoParallelIterator for MultiLineString<T> {
type Item = LineString<T>;
type Iter = rayon::vec::IntoIter<LineString<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.into_par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiLineString<T> {
type Item = &'a LineString<T>;
type Iter = rayon::slice::Iter<'a, LineString<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiLineString<T> {
type Item = &'a mut LineString<T>;
type Iter = rayon::slice::IterMut<'a, LineString<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter_mut()
}
}

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for MultiLineString<T>
where
Expand Down Expand Up @@ -199,6 +231,21 @@ mod test {
use super::*;
use crate::{line_string, wkt};

#[cfg(feature = "multithreading")]
#[test]
fn test_multithreading_linestring() {
let multi: MultiLineString<i32> = wkt! {
MULTILINESTRING((0 0,2 0,1 2,0 0), (10 10,12 10,11 12,10 10))
};
let mut multimut: MultiLineString<i32> = wkt! {
MULTILINESTRING((0 0,2 0,1 2,0 0), (10 10,12 10,11 12,10 10))
};
multi.par_iter().for_each(|_p| ());
multimut.par_iter_mut().for_each(|_p| ());
let _ = &multi.into_par_iter().for_each(|_p| ());
let _ = &mut multimut.par_iter_mut().for_each(|_p| ());
}

#[test]
fn test_iter() {
let multi: MultiLineString<i32> = wkt! {
Expand Down
32 changes: 32 additions & 0 deletions geo-types/src/geometry/multi_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use approx::{AbsDiffEq, RelativeEq};
use alloc::vec;
use alloc::vec::Vec;
use core::iter::FromIterator;
#[cfg(feature = "multithreading")]
use rayon::prelude::*;

/// A collection of [`Point`s](struct.Point.html). Can
/// be created from a `Vec` of `Point`s, or from an
Expand Down Expand Up @@ -85,6 +87,36 @@ impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPoint<T> {
}
}

#[cfg(feature = "multithreading")]
impl<T: CoordNum + Send> IntoParallelIterator for MultiPoint<T> {
type Item = Point<T>;
type Iter = rayon::vec::IntoIter<Point<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.into_par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPoint<T> {
type Item = &'a Point<T>;
type Iter = rayon::slice::Iter<'a, Point<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPoint<T> {
type Item = &'a mut Point<T>;
type Iter = rayon::slice::IterMut<'a, Point<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter_mut()
}
}

impl<T: CoordNum> MultiPoint<T> {
pub fn new(value: Vec<Point<T>>) -> Self {
Self(value)
Expand Down
83 changes: 83 additions & 0 deletions geo-types/src/geometry/multi_polygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use alloc::vec;
use alloc::vec::Vec;
#[cfg(any(feature = "approx", test))]
use approx::{AbsDiffEq, RelativeEq};

use core::iter::FromIterator;
#[cfg(feature = "multithreading")]
use rayon::prelude::*;

/// A collection of [`Polygon`s](struct.Polygon.html). Can
/// be created from a `Vec` of `Polygon`s, or from an
Expand Down Expand Up @@ -75,6 +78,36 @@ impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPolygon<T> {
}
}

#[cfg(feature = "multithreading")]
impl<T: CoordNum + Send> IntoParallelIterator for MultiPolygon<T> {
type Item = Polygon<T>;
type Iter = rayon::vec::IntoIter<Polygon<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.into_par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPolygon<T> {
type Item = &'a Polygon<T>;
type Iter = rayon::slice::Iter<'a, Polygon<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter()
}
}

#[cfg(feature = "multithreading")]
impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPolygon<T> {
type Item = &'a mut Polygon<T>;
type Iter = rayon::slice::IterMut<'a, Polygon<T>>;

fn into_par_iter(self) -> Self::Iter {
self.0.par_iter_mut()
}
}

impl<T: CoordNum> MultiPolygon<T> {
/// Instantiate Self from the raw content value
pub fn new(value: Vec<Polygon<T>>) -> Self {
Expand Down Expand Up @@ -170,6 +203,40 @@ where
}
}

#[cfg(any(
feature = "rstar_0_8",
feature = "rstar_0_9",
feature = "rstar_0_10",
feature = "rstar_0_11",
feature = "rstar_0_12"
))]
macro_rules! impl_rstar_multi_polygon {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for MultiPolygon<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<$crate::Point<T>>;
fn envelope(&self) -> Self::Envelope {
use ::$rstar::Envelope;
self.iter()
.map(|p| p.envelope())
.fold(::$rstar::AABB::new_empty(), |a, b| a.merged(&b))
}
}
};
}
#[cfg(feature = "rstar_0_8")]
impl_rstar_multi_polygon!(rstar_0_8);
#[cfg(feature = "rstar_0_9")]
impl_rstar_multi_polygon!(rstar_0_9);
#[cfg(feature = "rstar_0_10")]
impl_rstar_multi_polygon!(rstar_0_10);
#[cfg(feature = "rstar_0_11")]
impl_rstar_multi_polygon!(rstar_0_11);
#[cfg(feature = "rstar_0_12")]
impl_rstar_multi_polygon!(rstar_0_12);

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -216,6 +283,22 @@ mod test {
}
}

#[cfg(feature = "multithreading")]
#[test]
fn test_par_iter() {
let multi = MultiPolygon::new(vec![
polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
]);
let mut multimut = MultiPolygon::new(vec![
polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
]);
multi.par_iter().for_each(|_p| ());
let _ = &multimut.par_iter_mut().for_each(|_p| ());
let _ = &multi.into_par_iter().for_each(|_p| ());
let _ = &mut multimut.par_iter_mut().for_each(|_p| ());
}
#[test]
fn test_iter_mut() {
let mut multi = MultiPolygon::new(vec![
Expand Down
2 changes: 2 additions & 0 deletions geo-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
//! The following optional [Cargo features] are available:
//!
//! - `std`: Enables use of the full `std` library. Enabled by default.
//! - `multithreading`: Enables multi-threaded iteration over `Multi*` geometries. **Disabled**
//! by default but **enabled** by `geo`'s default features.
//! - `approx`: Allows geometry types to be checked for approximate equality with [approx]
//! - `arbitrary`: Allows geometry types to be created from unstructured input with [arbitrary]
//! - `serde`: Allows geometry types to be serialized and deserialized with [Serde]
Expand Down
2 changes: 1 addition & 1 deletion geo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ default = ["earcutr", "spade", "multithreading"]
use-proj = ["proj"]
proj-network = ["use-proj", "proj/network"]
use-serde = ["serde", "geo-types/serde"]
multithreading = ["i_overlay/allow_multithreading"]
multithreading = ["i_overlay/allow_multithreading", "geo-types/multithreading"]

[dependencies]
earcutr = { version = "0.4.2", optional = true }
Expand Down
3 changes: 2 additions & 1 deletion geo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@
//! - Allows geometry types to be serialized and deserialized with [Serde].
//! - ☐ Disabled by default.
//! - `multithreading`:
//! - Enables multithreading support for the `i_overlay` crate.
//! - Enables multithreading support for the `i_overlay` crate (via Rayon), and activates the `multithreading` flag
//! in `geo-types`, enabling multi-threaded iteration over `Multi*` geometries.
//! - ☑ Enabled by default.
//!
//! # Ecosystem
Expand Down

0 comments on commit da03b8b

Please sign in to comment.