geo/algorithm/relate/
mod.rs

1pub(crate) use edge_end_builder::EdgeEndBuilder;
2pub use geomgraph::intersection_matrix::IntersectionMatrix;
3
4use crate::geometry::*;
5use crate::{GeoFloat, GeometryCow};
6
7mod edge_end_builder;
8mod geomgraph;
9mod relate_operation;
10
11/// Topologically relate two geometries based on [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM) semantics.
12///
13/// See [`IntersectionMatrix`] for details.
14///
15/// # Examples
16///
17/// ```
18/// use geo::{coord, Line, Rect, line_string};
19/// use crate::geo::relate::Relate;
20///
21/// let line = Line::new(coord! { x: 2.0, y: 2.0}, coord! { x: 4.0, y: 4.0 });
22/// let rect = Rect::new(coord! { x: 2.0, y: 2.0}, coord! { x: 4.0, y: 4.0 });
23/// let intersection_matrix = rect.relate(&line);
24///
25/// assert!(intersection_matrix.is_intersects());
26/// assert!(!intersection_matrix.is_disjoint());
27/// assert!(intersection_matrix.is_contains());
28/// assert!(!intersection_matrix.is_within());
29///
30/// let line = Line::new(coord! { x: 1.0, y: 1.0}, coord! { x: 5.0, y: 5.0 });
31/// let rect = Rect::new(coord! { x: 2.0, y: 2.0}, coord! { x: 4.0, y: 4.0 });
32/// let intersection_matrix = rect.relate(&line);
33/// assert!(intersection_matrix.is_intersects());
34/// assert!(!intersection_matrix.is_disjoint());
35/// assert!(!intersection_matrix.is_contains());
36/// assert!(!intersection_matrix.is_within());
37///
38/// let rect_boundary = line_string![
39///     (x: 2.0, y: 2.0),
40///     (x: 4.0, y: 2.0),
41///     (x: 4.0, y: 4.0),
42///     (x: 2.0, y: 4.0),
43///     (x: 2.0, y: 2.0)
44/// ];
45/// let intersection_matrix = rect.relate(&rect_boundary);
46/// assert!(intersection_matrix.is_intersects());
47/// assert!(!intersection_matrix.is_disjoint());
48/// // According to DE-9IM, polygons don't contain their own boundary
49/// assert!(!intersection_matrix.is_contains());
50/// assert!(!intersection_matrix.is_within());
51/// ```
52///
53/// Note: `Relate` must not be called on geometries containing `NaN` coordinates.
54pub trait Relate<F, T> {
55    fn relate(&self, other: &T) -> IntersectionMatrix;
56}
57
58impl<F: GeoFloat> Relate<F, GeometryCow<'_, F>> for GeometryCow<'_, F> {
59    fn relate(&self, other: &GeometryCow<F>) -> IntersectionMatrix {
60        let mut relate_computer = relate_operation::RelateOperation::new(self, other);
61        relate_computer.compute_intersection_matrix()
62    }
63}
64
65macro_rules! relate_impl {
66    ($k:ty, $t:ty) => {
67        relate_impl![($k, $t),];
68    };
69    ($(($k:ty, $t:ty),)*) => {
70        $(
71            impl<F: GeoFloat> Relate<F, $t> for $k {
72                fn relate(&self, other: &$t) -> IntersectionMatrix {
73                    GeometryCow::from(self).relate(&GeometryCow::from(other))
74                }
75            }
76        )*
77    };
78}
79
80/// Call the given macro with every pair of inputs
81///
82/// # Examples
83///
84/// ```ignore
85/// cartesian_pairs!(foo, [Bar, Baz, Qux]);
86/// ```
87/// Is akin to calling:
88/// ```ignore
89/// foo![(Bar, Bar), (Bar, Baz), (Bar, Qux), (Baz, Bar), (Baz, Baz), (Baz, Qux), (Qux, Bar), (Qux, Baz), (Qux, Qux)];
90/// ```
91macro_rules! cartesian_pairs {
92    ($macro_name:ident, [$($a:ty),*]) => {
93        cartesian_pairs_helper! { [] [$($a,)*] [$($a,)*] [$($a,)*] $macro_name}
94    };
95}
96
97macro_rules! cartesian_pairs_helper {
98    // popped all a's - we're done. Use the accumulated output as the input to relate macro.
99    ([$($out_pairs:tt)*] [] [$($b:ty,)*] $init_b:tt $macro_name:ident) => {
100        $macro_name!{$($out_pairs)*}
101    };
102    // finished one loop of b, pop next a and reset b
103    ($out_pairs:tt [$a_car:ty, $($a_cdr:ty,)*] [] $init_b:tt $macro_name:ident) => {
104        cartesian_pairs_helper!{$out_pairs [$($a_cdr,)*] $init_b $init_b $macro_name}
105    };
106    // pop b through all of b with head of a
107    ([$($out_pairs:tt)*] [$a_car:ty, $($a_cdr:ty,)*] [$b_car:ty, $($b_cdr:ty,)*] $init_b:tt $macro_name:ident) => {
108        cartesian_pairs_helper!{[$($out_pairs)* ($a_car, $b_car),] [$a_car, $($a_cdr,)*] [$($b_cdr,)*] $init_b $macro_name}
109    };
110}
111
112// Implement Relate for every combination of Geometry. Alternatively we could do something like
113// `impl Relate<Into<GeometryCow>> for Into<GeometryCow> { }`
114// but I don't know that we want to make GeometryCow public (yet?).
115cartesian_pairs!(relate_impl, [Point<F>, Line<F>, LineString<F>, Polygon<F>, MultiPoint<F>, MultiLineString<F>, MultiPolygon<F>, Rect<F>, Triangle<F>, GeometryCollection<F>]);
116relate_impl!(Geometry<F>, Geometry<F>);