Skip to content

Commit 1b9557f

Browse files
Merge #1011
1011: Initial geo-traits implementation r=frewsxcv a=kylebarron - [x] I agree to follow the project's [code of conduct](https://github.com/georust/geo/blob/main/CODE_OF_CONDUCT.md). - [ ] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users. --- As discussed on the discord, in #838, and originally in #67, this is an initial bare-bones implementation of geometry access traits for discussion. As `@frewsxcv` suggested, for now this is a separate crate in the workspace to let us iterate on some ideas. ### Future work #### Minimize cloning in the geo-types implementation I got lost in lifetime errors so to get things to compile I added cloning to the geo-types implementations. I.e. for `MultiPoint` each point is cloned when accessed. Co-authored-by: Kyle Barron <[email protected]>
2 parents 138e4b3 + 10cdce0 commit 1b9557f

12 files changed

+598
-1
lines changed

Diff for: Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["geo", "geo-types", "geo-postgis", "geo-test-fixtures", "jts-test-runner", "geo-bool-ops-benches"]
2+
members = ["geo", "geo-types", "geo-traits", "geo-postgis", "geo-test-fixtures", "jts-test-runner", "geo-bool-ops-benches"]
33

44
[patch.crates-io]
55

Diff for: geo-traits/Cargo.toml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "geo-traits"
3+
version = "0.1.0"
4+
license = "MIT OR Apache-2.0"
5+
repository = "https://github.com/georust/geo"
6+
documentation = "https://docs.rs/geo-traits/"
7+
readme = "../README.md"
8+
keywords = ["gis", "geo", "geography", "geospatial"]
9+
description = "Geospatial traits"
10+
rust-version = "1.65"
11+
edition = "2021"
12+
13+
[features]
14+
15+
[dependencies]
16+
geo-types = "0.7.9"
17+
18+
[dev-dependencies]
19+
approx = ">= 0.4.0, < 0.6.0"

Diff for: geo-traits/src/coord.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use geo_types::{Coord, CoordNum, Point};
2+
3+
pub trait CoordTrait: Send + Sync {
4+
type T: CoordNum + Send + Sync;
5+
6+
/// x component of this coord
7+
fn x(&self) -> Self::T;
8+
9+
/// y component of this coord
10+
fn y(&self) -> Self::T;
11+
12+
/// Returns a tuple that contains the x/horizontal & y/vertical component of the coord.
13+
fn x_y(&self) -> (Self::T, Self::T) {
14+
(self.x(), self.y())
15+
}
16+
}
17+
18+
impl<T: CoordNum + Send + Sync> CoordTrait for Point<T> {
19+
type T = T;
20+
21+
fn x(&self) -> T {
22+
self.0.x
23+
}
24+
25+
fn y(&self) -> T {
26+
self.0.y
27+
}
28+
}
29+
30+
impl<T: CoordNum + Send + Sync> CoordTrait for &Point<T> {
31+
type T = T;
32+
33+
fn x(&self) -> T {
34+
self.0.x
35+
}
36+
37+
fn y(&self) -> T {
38+
self.0.y
39+
}
40+
}
41+
42+
impl<T: CoordNum + Send + Sync> CoordTrait for Coord<T> {
43+
type T = T;
44+
45+
fn x(&self) -> T {
46+
self.x
47+
}
48+
49+
fn y(&self) -> T {
50+
self.y
51+
}
52+
}
53+
54+
impl<T: CoordNum + Send + Sync> CoordTrait for &Coord<T> {
55+
type T = T;
56+
57+
fn x(&self) -> T {
58+
self.x
59+
}
60+
61+
fn y(&self) -> T {
62+
self.y
63+
}
64+
}

Diff for: geo-traits/src/geometry.rs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use geo_types::{
2+
CoordNum, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon,
3+
Point, Polygon,
4+
};
5+
6+
use super::{
7+
GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait,
8+
MultiPolygonTrait, PointTrait, PolygonTrait,
9+
};
10+
11+
#[allow(clippy::type_complexity)]
12+
pub trait GeometryTrait<'a>: Send + Sync {
13+
type Point: 'a + PointTrait;
14+
type LineString: 'a + LineStringTrait<'a>;
15+
type Polygon: 'a + PolygonTrait<'a>;
16+
type MultiPoint: 'a + MultiPointTrait<'a>;
17+
type MultiLineString: 'a + MultiLineStringTrait<'a>;
18+
type MultiPolygon: 'a + MultiPolygonTrait<'a>;
19+
type GeometryCollection: 'a + GeometryCollectionTrait<'a>;
20+
21+
fn as_type(
22+
&'a self,
23+
) -> GeometryType<
24+
'a,
25+
Self::Point,
26+
Self::LineString,
27+
Self::Polygon,
28+
Self::MultiPoint,
29+
Self::MultiLineString,
30+
Self::MultiPolygon,
31+
Self::GeometryCollection,
32+
>;
33+
}
34+
35+
#[derive(Debug)]
36+
pub enum GeometryType<'a, P, L, Y, MP, ML, MY, GC>
37+
where
38+
P: 'a + PointTrait,
39+
L: 'a + LineStringTrait<'a>,
40+
Y: 'a + PolygonTrait<'a>,
41+
MP: 'a + MultiPointTrait<'a>,
42+
ML: 'a + MultiLineStringTrait<'a>,
43+
MY: 'a + MultiPolygonTrait<'a>,
44+
GC: 'a + GeometryCollectionTrait<'a>,
45+
{
46+
Point(&'a P),
47+
LineString(&'a L),
48+
Polygon(&'a Y),
49+
MultiPoint(&'a MP),
50+
MultiLineString(&'a ML),
51+
MultiPolygon(&'a MY),
52+
GeometryCollection(&'a GC),
53+
}
54+
55+
impl<'a, T: CoordNum + Send + Sync + 'a> GeometryTrait<'a> for Geometry<T> {
56+
type Point = Point<T>;
57+
type LineString = LineString<T>;
58+
type Polygon = Polygon<T>;
59+
type MultiPoint = MultiPoint<T>;
60+
type MultiLineString = MultiLineString<T>;
61+
type MultiPolygon = MultiPolygon<T>;
62+
type GeometryCollection = GeometryCollection<T>;
63+
64+
fn as_type(
65+
&'a self,
66+
) -> GeometryType<
67+
'a,
68+
Point<T>,
69+
LineString<T>,
70+
Polygon<T>,
71+
MultiPoint<T>,
72+
MultiLineString<T>,
73+
MultiPolygon<T>,
74+
GeometryCollection<T>,
75+
> {
76+
match self {
77+
Geometry::Point(p) => GeometryType::Point(p),
78+
Geometry::LineString(p) => GeometryType::LineString(p),
79+
Geometry::Polygon(p) => GeometryType::Polygon(p),
80+
Geometry::MultiPoint(p) => GeometryType::MultiPoint(p),
81+
Geometry::MultiLineString(p) => GeometryType::MultiLineString(p),
82+
Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p),
83+
Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p),
84+
_ => todo!(),
85+
}
86+
}
87+
}

Diff for: geo-traits/src/geometry_collection.rs

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use super::GeometryTrait;
2+
use geo_types::{CoordNum, Geometry, GeometryCollection};
3+
use std::iter::Cloned;
4+
use std::slice::Iter;
5+
6+
pub trait GeometryCollectionTrait<'a>: Send + Sync {
7+
type ItemType: 'a + GeometryTrait<'a>;
8+
type Iter: ExactSizeIterator<Item = Self::ItemType>;
9+
10+
/// An iterator over the geometries in this GeometryCollection
11+
fn geometries(&'a self) -> Self::Iter;
12+
13+
/// The number of geometries in this GeometryCollection
14+
fn num_geometries(&'a self) -> usize;
15+
16+
/// Access to a specified geometry in this GeometryCollection
17+
/// Will return None if the provided index is out of bounds
18+
fn geometry(&'a self, i: usize) -> Option<Self::ItemType>;
19+
}
20+
21+
impl<'a, T: CoordNum + Send + Sync + 'a> GeometryCollectionTrait<'a> for GeometryCollection<T> {
22+
type ItemType = Geometry<T>;
23+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
24+
25+
fn geometries(&'a self) -> Self::Iter {
26+
self.0.iter().cloned()
27+
}
28+
29+
fn num_geometries(&'a self) -> usize {
30+
self.0.len()
31+
}
32+
33+
fn geometry(&'a self, i: usize) -> Option<Self::ItemType> {
34+
self.0.get(i).cloned()
35+
}
36+
}
37+
38+
impl<'a, T: CoordNum + Send + Sync + 'a> GeometryCollectionTrait<'a> for &GeometryCollection<T> {
39+
type ItemType = Geometry<T>;
40+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
41+
42+
fn geometries(&'a self) -> Self::Iter {
43+
self.0.iter().cloned()
44+
}
45+
46+
fn num_geometries(&'a self) -> usize {
47+
self.0.len()
48+
}
49+
50+
fn geometry(&'a self, i: usize) -> Option<Self::ItemType> {
51+
self.0.get(i).cloned()
52+
}
53+
}

Diff for: geo-traits/src/lib.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
pub use coord::CoordTrait;
2+
pub use geometry::{GeometryTrait, GeometryType};
3+
pub use geometry_collection::GeometryCollectionTrait;
4+
pub use line_string::LineStringTrait;
5+
pub use multi_line_string::MultiLineStringTrait;
6+
pub use multi_point::MultiPointTrait;
7+
pub use multi_polygon::MultiPolygonTrait;
8+
pub use point::PointTrait;
9+
pub use polygon::PolygonTrait;
10+
11+
mod coord;
12+
mod geometry;
13+
mod geometry_collection;
14+
mod line_string;
15+
mod multi_line_string;
16+
mod multi_point;
17+
mod multi_polygon;
18+
mod point;
19+
mod polygon;

Diff for: geo-traits/src/line_string.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use geo_types::{Coord, CoordNum, LineString};
2+
3+
use super::CoordTrait;
4+
use std::iter::Cloned;
5+
use std::slice::Iter;
6+
7+
pub trait LineStringTrait<'a>: Send + Sync {
8+
type ItemType: 'a + CoordTrait;
9+
type Iter: ExactSizeIterator<Item = Self::ItemType>;
10+
11+
/// An iterator over the coords in this LineString
12+
fn coords(&'a self) -> Self::Iter;
13+
14+
/// The number of coords in this LineString
15+
fn num_coords(&'a self) -> usize;
16+
17+
/// Access to a specified point in this LineString
18+
/// Will return None if the provided index is out of bounds
19+
fn coord(&'a self, i: usize) -> Option<Self::ItemType>;
20+
}
21+
22+
impl<'a, T: CoordNum + Send + Sync + 'a> LineStringTrait<'a> for LineString<T> {
23+
type ItemType = Coord<T>;
24+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
25+
26+
fn coords(&'a self) -> Self::Iter {
27+
self.0.iter().cloned()
28+
}
29+
30+
fn num_coords(&self) -> usize {
31+
self.0.len()
32+
}
33+
34+
fn coord(&'a self, i: usize) -> Option<Self::ItemType> {
35+
self.0.get(i).cloned()
36+
}
37+
}
38+
39+
impl<'a, T: CoordNum + Send + Sync + 'a> LineStringTrait<'a> for &LineString<T> {
40+
type ItemType = Coord<T>;
41+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
42+
43+
fn coords(&'a self) -> Self::Iter {
44+
self.0.iter().cloned()
45+
}
46+
47+
fn num_coords(&self) -> usize {
48+
self.0.len()
49+
}
50+
51+
fn coord(&'a self, i: usize) -> Option<Self::ItemType> {
52+
self.0.get(i).cloned()
53+
}
54+
}

Diff for: geo-traits/src/multi_line_string.rs

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use super::line_string::LineStringTrait;
2+
use geo_types::{CoordNum, LineString, MultiLineString};
3+
use std::iter::Cloned;
4+
use std::slice::Iter;
5+
6+
pub trait MultiLineStringTrait<'a>: Send + Sync {
7+
type ItemType: 'a + LineStringTrait<'a>;
8+
type Iter: ExactSizeIterator<Item = Self::ItemType>;
9+
10+
/// An iterator over the LineStrings in this MultiLineString
11+
fn lines(&'a self) -> Self::Iter;
12+
13+
/// The number of lines in this MultiLineString
14+
fn num_lines(&'a self) -> usize;
15+
16+
/// Access to a specified line in this MultiLineString
17+
/// Will return None if the provided index is out of bounds
18+
fn line(&'a self, i: usize) -> Option<Self::ItemType>;
19+
}
20+
21+
impl<'a, T: CoordNum + Send + Sync + 'a> MultiLineStringTrait<'a> for MultiLineString<T> {
22+
type ItemType = LineString<T>;
23+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
24+
25+
fn lines(&'a self) -> Self::Iter {
26+
self.0.iter().cloned()
27+
}
28+
29+
fn num_lines(&'a self) -> usize {
30+
self.0.len()
31+
}
32+
33+
fn line(&'a self, i: usize) -> Option<Self::ItemType> {
34+
self.0.get(i).cloned()
35+
}
36+
}
37+
38+
impl<'a, T: CoordNum + Send + Sync + 'a> MultiLineStringTrait<'a> for &MultiLineString<T> {
39+
type ItemType = LineString<T>;
40+
type Iter = Cloned<Iter<'a, Self::ItemType>>;
41+
42+
fn lines(&'a self) -> Self::Iter {
43+
self.0.iter().cloned()
44+
}
45+
46+
fn num_lines(&'a self) -> usize {
47+
self.0.len()
48+
}
49+
50+
fn line(&'a self, i: usize) -> Option<Self::ItemType> {
51+
self.0.get(i).cloned()
52+
}
53+
}

0 commit comments

Comments
 (0)