Skip to content

Commit b1a0142

Browse files
authored
Merge pull request #1157 from kylebarron/kyle/geo-traits-crate
Add geo-traits crate
2 parents a513ac3 + 711dfac commit b1a0142

18 files changed

+1706
-3
lines changed

.github/workflows/test.yml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,32 @@ jobs:
118118
# we don't want to test `proj-network` because it only enables the `proj` feature
119119
- run: cargo test --features "use-proj use-serde"
120120

121+
geo_traits:
122+
name: geo-traits
123+
runs-on: ubuntu-latest
124+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
125+
defaults:
126+
run:
127+
working-directory: geo-traits
128+
strategy:
129+
matrix:
130+
container_image:
131+
# We aim to support rust-stable plus (at least) the prior 3 releases,
132+
# giving us about 6 months of coverage.
133+
#
134+
# Minimum supported rust version (MSRV)
135+
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.75"
136+
# Two most recent releases - we omit older ones for expedient CI
137+
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.78"
138+
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.79"
139+
container:
140+
image: ${{ matrix.container_image }}
141+
steps:
142+
- name: Checkout repository
143+
uses: actions/checkout@v2
144+
- run: cargo check --all-targets
145+
- run: cargo test
146+
121147
geo_postgis:
122148
name: geo-postgis
123149
runs-on: ubuntu-latest
@@ -184,4 +210,3 @@ jobs:
184210
- name: Checkout repository
185211
uses: actions/checkout@v3
186212
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps
187-

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
resolver = "2"
33
members = [
44
"geo",
5-
"geo-types",
5+
"geo-bool-ops-benches",
66
"geo-postgis",
77
"geo-test-fixtures",
8+
"geo-traits",
9+
"geo-types",
810
"jts-test-runner",
9-
"geo-bool-ops-benches",
1011
]
1112

1213
[patch.crates-io]

geo-traits/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
[dependencies]
14+
geo-types = "0.7"
15+
16+
[dev-dependencies]

geo-traits/src/coord.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use std::marker::PhantomData;
2+
3+
use geo_types::{Coord, CoordNum};
4+
5+
use crate::Dimensions;
6+
7+
/// A trait for accessing data from a generic Coord.
8+
///
9+
/// Refer to [geo_types::Coord] for information about semantics and validity.
10+
pub trait CoordTrait {
11+
/// The coordinate type of this geometry
12+
type T: CoordNum;
13+
14+
/// Dimensions of the coordinate tuple
15+
fn dim(&self) -> Dimensions;
16+
17+
/// Access the n'th (0-based) element of the CoordinateTuple.
18+
/// Returns `None` if `n >= DIMENSION`.
19+
/// See also [`nth_unchecked()`](Self::nth_unchecked).
20+
fn nth(&self, n: usize) -> Option<Self::T> {
21+
if n < self.dim().size() {
22+
Some(self.nth_unchecked(n))
23+
} else {
24+
None
25+
}
26+
}
27+
28+
/// x component of this coord.
29+
fn x(&self) -> Self::T;
30+
31+
/// y component of this coord.
32+
fn y(&self) -> Self::T;
33+
34+
/// Returns a tuple that contains the x/horizontal & y/vertical component of the coord.
35+
fn x_y(&self) -> (Self::T, Self::T) {
36+
(self.x(), self.y())
37+
}
38+
39+
/// Access the n'th (0-based) element of the CoordinateTuple.
40+
/// May panic if n >= DIMENSION.
41+
/// See also [`nth()`](Self::nth).
42+
fn nth_unchecked(&self, n: usize) -> Self::T;
43+
}
44+
45+
impl<T: CoordNum> CoordTrait for Coord<T> {
46+
type T = T;
47+
48+
fn nth_unchecked(&self, n: usize) -> Self::T {
49+
match n {
50+
0 => self.x(),
51+
1 => self.y(),
52+
_ => panic!("Coord only supports 2 dimensions"),
53+
}
54+
}
55+
56+
fn dim(&self) -> Dimensions {
57+
Dimensions::Xy
58+
}
59+
60+
fn x(&self) -> Self::T {
61+
self.x
62+
}
63+
64+
fn y(&self) -> Self::T {
65+
self.y
66+
}
67+
}
68+
69+
impl<T: CoordNum> CoordTrait for &Coord<T> {
70+
type T = T;
71+
72+
fn nth_unchecked(&self, n: usize) -> Self::T {
73+
match n {
74+
0 => self.x(),
75+
1 => self.y(),
76+
_ => panic!("Coord only supports 2 dimensions"),
77+
}
78+
}
79+
80+
fn dim(&self) -> Dimensions {
81+
Dimensions::Xy
82+
}
83+
84+
fn x(&self) -> Self::T {
85+
self.x
86+
}
87+
88+
fn y(&self) -> Self::T {
89+
self.y
90+
}
91+
}
92+
93+
impl<T: CoordNum> CoordTrait for (T, T) {
94+
type T = T;
95+
96+
fn nth_unchecked(&self, n: usize) -> Self::T {
97+
match n {
98+
0 => self.x(),
99+
1 => self.y(),
100+
_ => panic!("(T, T) only supports 2 dimensions"),
101+
}
102+
}
103+
104+
fn dim(&self) -> Dimensions {
105+
Dimensions::Xy
106+
}
107+
108+
fn x(&self) -> Self::T {
109+
self.0
110+
}
111+
112+
fn y(&self) -> Self::T {
113+
self.1
114+
}
115+
}
116+
117+
/// An empty struct that implements [CoordTrait].
118+
///
119+
/// This can be used as the `CoordType` of the `GeometryTrait` by implementations that don't have a
120+
/// Coord concept
121+
pub struct UnimplementedCoord<T: CoordNum>(PhantomData<T>);
122+
123+
impl<T: CoordNum> CoordTrait for UnimplementedCoord<T> {
124+
type T = T;
125+
126+
fn dim(&self) -> Dimensions {
127+
unimplemented!()
128+
}
129+
130+
fn nth_unchecked(&self, _n: usize) -> Self::T {
131+
unimplemented!()
132+
}
133+
134+
fn x(&self) -> Self::T {
135+
unimplemented!()
136+
}
137+
138+
fn y(&self) -> Self::T {
139+
unimplemented!()
140+
}
141+
}

geo-traits/src/dimension.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/// The logical dimension of the geometry.
2+
///
3+
///
4+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5+
pub enum Dimensions {
6+
/// A two-dimensional geometry with X and Y values
7+
Xy,
8+
9+
/// A three-dimensional geometry with X, Y, and Z values
10+
Xyz,
11+
12+
/// A three-dimensional geometry with X, Y, and M values
13+
Xym,
14+
15+
/// A four-dimensional geometry with X, Y, Z, and M values
16+
Xyzm,
17+
18+
/// A geometry with unknown logical type. The contained `usize` value represents the number of
19+
/// physical dimensions.
20+
Unknown(usize),
21+
}
22+
23+
impl Dimensions {
24+
/// The physical number of dimensions in this geometry.
25+
pub fn size(&self) -> usize {
26+
match self {
27+
Self::Xy => 2,
28+
Self::Xyz | Self::Xym => 3,
29+
Self::Xyzm => 4,
30+
Self::Unknown(val) => *val,
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)