Skip to content

Commit

Permalink
Merge pull request #1157 from kylebarron/kyle/geo-traits-crate
Browse files Browse the repository at this point in the history
Add geo-traits crate
  • Loading branch information
frewsxcv authored Oct 26, 2024
2 parents a513ac3 + 711dfac commit b1a0142
Show file tree
Hide file tree
Showing 18 changed files with 1,706 additions and 3 deletions.
27 changes: 26 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,32 @@ jobs:
# we don't want to test `proj-network` because it only enables the `proj` feature
- run: cargo test --features "use-proj use-serde"

geo_traits:
name: geo-traits
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
defaults:
run:
working-directory: geo-traits
strategy:
matrix:
container_image:
# We aim to support rust-stable plus (at least) the prior 3 releases,
# giving us about 6 months of coverage.
#
# Minimum supported rust version (MSRV)
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.75"
# Two most recent releases - we omit older ones for expedient CI
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.78"
- "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.79"
container:
image: ${{ matrix.container_image }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
- run: cargo check --all-targets
- run: cargo test

geo_postgis:
name: geo-postgis
runs-on: ubuntu-latest
Expand Down Expand Up @@ -184,4 +210,3 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
resolver = "2"
members = [
"geo",
"geo-types",
"geo-bool-ops-benches",
"geo-postgis",
"geo-test-fixtures",
"geo-traits",
"geo-types",
"jts-test-runner",
"geo-bool-ops-benches",
]

[patch.crates-io]
Expand Down
16 changes: 16 additions & 0 deletions geo-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "geo-traits"
version = "0.1.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/georust/geo"
documentation = "https://docs.rs/geo-traits/"
readme = "../README.md"
keywords = ["gis", "geo", "geography", "geospatial"]
description = "Geospatial traits"
rust-version = "1.65"
edition = "2021"

[dependencies]
geo-types = "0.7"

[dev-dependencies]
141 changes: 141 additions & 0 deletions geo-traits/src/coord.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::marker::PhantomData;

use geo_types::{Coord, CoordNum};

use crate::Dimensions;

/// A trait for accessing data from a generic Coord.
///
/// Refer to [geo_types::Coord] for information about semantics and validity.
pub trait CoordTrait {
/// The coordinate type of this geometry
type T: CoordNum;

/// Dimensions of the coordinate tuple
fn dim(&self) -> Dimensions;

/// Access the n'th (0-based) element of the CoordinateTuple.
/// Returns `None` if `n >= DIMENSION`.
/// See also [`nth_unchecked()`](Self::nth_unchecked).
fn nth(&self, n: usize) -> Option<Self::T> {
if n < self.dim().size() {
Some(self.nth_unchecked(n))
} else {
None
}
}

/// x component of this coord.
fn x(&self) -> Self::T;

/// y component of this coord.
fn y(&self) -> Self::T;

/// Returns a tuple that contains the x/horizontal & y/vertical component of the coord.
fn x_y(&self) -> (Self::T, Self::T) {
(self.x(), self.y())
}

/// Access the n'th (0-based) element of the CoordinateTuple.
/// May panic if n >= DIMENSION.
/// See also [`nth()`](Self::nth).
fn nth_unchecked(&self, n: usize) -> Self::T;
}

impl<T: CoordNum> CoordTrait for Coord<T> {
type T = T;

fn nth_unchecked(&self, n: usize) -> Self::T {
match n {
0 => self.x(),
1 => self.y(),
_ => panic!("Coord only supports 2 dimensions"),
}
}

fn dim(&self) -> Dimensions {
Dimensions::Xy
}

fn x(&self) -> Self::T {
self.x
}

fn y(&self) -> Self::T {
self.y
}
}

impl<T: CoordNum> CoordTrait for &Coord<T> {
type T = T;

fn nth_unchecked(&self, n: usize) -> Self::T {
match n {
0 => self.x(),
1 => self.y(),
_ => panic!("Coord only supports 2 dimensions"),
}
}

fn dim(&self) -> Dimensions {
Dimensions::Xy
}

fn x(&self) -> Self::T {
self.x
}

fn y(&self) -> Self::T {
self.y
}
}

impl<T: CoordNum> CoordTrait for (T, T) {
type T = T;

fn nth_unchecked(&self, n: usize) -> Self::T {
match n {
0 => self.x(),
1 => self.y(),
_ => panic!("(T, T) only supports 2 dimensions"),
}
}

fn dim(&self) -> Dimensions {
Dimensions::Xy
}

fn x(&self) -> Self::T {
self.0
}

fn y(&self) -> Self::T {
self.1
}
}

/// An empty struct that implements [CoordTrait].
///
/// This can be used as the `CoordType` of the `GeometryTrait` by implementations that don't have a
/// Coord concept
pub struct UnimplementedCoord<T: CoordNum>(PhantomData<T>);

impl<T: CoordNum> CoordTrait for UnimplementedCoord<T> {
type T = T;

fn dim(&self) -> Dimensions {
unimplemented!()
}

fn nth_unchecked(&self, _n: usize) -> Self::T {
unimplemented!()
}

fn x(&self) -> Self::T {
unimplemented!()
}

fn y(&self) -> Self::T {
unimplemented!()
}
}
33 changes: 33 additions & 0 deletions geo-traits/src/dimension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// The logical dimension of the geometry.
///
///
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Dimensions {
/// A two-dimensional geometry with X and Y values
Xy,

/// A three-dimensional geometry with X, Y, and Z values
Xyz,

/// A three-dimensional geometry with X, Y, and M values
Xym,

/// A four-dimensional geometry with X, Y, Z, and M values
Xyzm,

/// A geometry with unknown logical type. The contained `usize` value represents the number of
/// physical dimensions.
Unknown(usize),
}

impl Dimensions {
/// The physical number of dimensions in this geometry.
pub fn size(&self) -> usize {
match self {
Self::Xy => 2,
Self::Xyz | Self::Xym => 3,
Self::Xyzm => 4,
Self::Unknown(val) => *val,
}
}
}
Loading

0 comments on commit b1a0142

Please sign in to comment.