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}