Skip to main content

sedona_geo_generic_alg/
lib.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17//! Crate root for generic geometry algorithms ported from `geo`.
18//!
19//! Substantial portions of this crate (algorithm modules, trait patterns, and API surface) are
20//! ported (and contain copied code) from the `geo` crate at commit
21//! `5d667f844716a3d0a17aa60bc0a58528cb5808c3`:
22//! <https://github.com/georust/geo/tree/5d667f844716a3d0a17aa60bc0a58528cb5808c3/geo/src>.
23//! The original upstream project is dual-licensed under Apache-2.0 or MIT; the copied/ported code
24//! here is used under the Apache-2.0 license consistent with this repository.
25//! This top-level file orchestrates module exposure and numeric traits mirroring upstream design.
26pub use crate::algorithm::*;
27use std::cmp::Ordering;
28
29pub use geo_types::{coord, line_string, point, polygon, wkt, CoordFloat, CoordNum};
30
31pub mod geometry;
32pub use geometry::*;
33
34/// This module includes all the functions of geometric calculations
35pub mod algorithm;
36mod utils;
37use crate::kernels::{RobustKernel, SimpleKernel};
38
39#[cfg(test)]
40#[macro_use]
41extern crate approx;
42
43#[cfg(test)]
44#[macro_use]
45extern crate log;
46
47/// A prelude which re-exports the traits for manipulating objects in this
48/// crate. Typically imported with `use geo::prelude::*`.
49pub mod prelude {
50    pub use crate::algorithm::*;
51}
52
53/// A common numeric trait used for geo algorithms
54///
55/// Different numeric types have different tradeoffs. `geo` strives to utilize generics to allow
56/// users to choose their numeric types. If you are writing a function which you'd like to be
57/// generic over all the numeric types supported by geo, you probably want to constrain
58/// your function input to `GeoFloat`. For methods which work for integers, and not just floating
59/// point, see [`GeoNum`].
60pub trait GeoFloat:
61    GeoNum + num_traits::Float + num_traits::Signed + num_traits::Bounded + float_next_after::NextAfter
62{
63}
64impl<T> GeoFloat for T where
65    T: GeoNum
66        + num_traits::Float
67        + num_traits::Signed
68        + num_traits::Bounded
69        + float_next_after::NextAfter
70{
71}
72
73/// A trait for methods which work for both integers **and** floating point
74pub trait GeoNum: CoordNum {
75    type Ker: Kernel<Self>;
76
77    /// Return the ordering between self and other.
78    ///
79    /// For integers, this should behave just like [`Ord`].
80    ///
81    /// For floating point numbers, unlike the standard partial comparison between floating point numbers, this comparison
82    /// always produces an ordering.
83    ///
84    /// See [f64::total_cmp](https://doc.rust-lang.org/src/core/num/f64.rs.html#1432) for details.
85    fn total_cmp(&self, other: &Self) -> Ordering;
86}
87
88macro_rules! impl_geo_num_for_float {
89    ($t: ident) => {
90        impl GeoNum for $t {
91            type Ker = RobustKernel;
92            fn total_cmp(&self, other: &Self) -> Ordering {
93                self.total_cmp(other)
94            }
95        }
96    };
97}
98macro_rules! impl_geo_num_for_int {
99    ($t: ident) => {
100        impl GeoNum for $t {
101            type Ker = SimpleKernel;
102            fn total_cmp(&self, other: &Self) -> Ordering {
103                self.cmp(other)
104            }
105        }
106    };
107}
108
109// This is the list of primitives that we support.
110impl_geo_num_for_float!(f32);
111impl_geo_num_for_float!(f64);
112impl_geo_num_for_int!(i16);
113impl_geo_num_for_int!(i32);
114impl_geo_num_for_int!(i64);
115impl_geo_num_for_int!(i128);
116impl_geo_num_for_int!(isize);
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn total_ord_float() {
124        assert_eq!(GeoNum::total_cmp(&3.0f64, &2.0f64), Ordering::Greater);
125        assert_eq!(GeoNum::total_cmp(&2.0f64, &2.0f64), Ordering::Equal);
126        assert_eq!(GeoNum::total_cmp(&1.0f64, &2.0f64), Ordering::Less);
127        assert_eq!(GeoNum::total_cmp(&1.0f64, &f64::NAN), Ordering::Less);
128        assert_eq!(GeoNum::total_cmp(&f64::NAN, &f64::NAN), Ordering::Equal);
129        assert_eq!(GeoNum::total_cmp(&f64::INFINITY, &f64::NAN), Ordering::Less);
130    }
131
132    #[test]
133    fn total_ord_int() {
134        assert_eq!(GeoNum::total_cmp(&3i32, &2i32), Ordering::Greater);
135        assert_eq!(GeoNum::total_cmp(&2i32, &2i32), Ordering::Equal);
136        assert_eq!(GeoNum::total_cmp(&1i32, &2i32), Ordering::Less);
137    }
138
139    #[test]
140    fn numeric_types() {
141        let _n_i16 = Point::new(1i16, 2i16);
142        let _n_i32 = Point::new(1i32, 2i32);
143        let _n_i64 = Point::new(1i64, 2i64);
144        let _n_i128 = Point::new(1i128, 2i128);
145        let _n_isize = Point::new(1isize, 2isize);
146        let _n_f32 = Point::new(1.0f32, 2.0f32);
147        let _n_f64 = Point::new(1.0f64, 2.0f64);
148    }
149}