1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! `equals(&a, &b)` — see
//! `boost/geometry/algorithms/equals.hpp`.
//!
//! Cartesian-only in v1. The per-pair strategy is selected by the
//! tag-keyed [`geometry_strategy::EqualsPairStrategy`] picker on
//! `(A::Kind, B::Kind)`, so any concept-adapted foreign type resolves
//! through the same path as the equivalent `geometry-model` value.
use geometry_strategy::{EqualsPairStrategy, EqualsStrategy};
use geometry_trait::Geometry;
/// `true` iff `a` and `b` describe the same point set.
///
/// Mirrors `boost::geometry::equals(a, b)` from
/// `boost/geometry/algorithms/equals.hpp`. Polygon equality is
/// up-to-rotation and traversal direction; vertex-order normalisation
/// happens inside the strategy kernel.
#[inline]
#[must_use]
pub fn equals<A, B>(a: &A, b: &B) -> bool
where
A: Geometry,
B: Geometry,
A::Kind: EqualsPairStrategy<B::Kind>,
<A::Kind as EqualsPairStrategy<B::Kind>>::S: EqualsStrategy<A, B>,
{
<<A::Kind as EqualsPairStrategy<B::Kind>>::S as Default>::default().equals(a, b)
}
#[cfg(test)]
mod tests {
use super::equals;
use geometry_cs::Cartesian;
use geometry_model::{Point2D, Polygon, polygon};
type P = Point2D<f64, Cartesian>;
fn pt(x: f64, y: f64) -> P {
Point2D::new(x, y)
}
#[test]
fn equals_same_point() {
assert!(equals(&pt(1.0, 2.0), &pt(1.0, 2.0)));
assert!(!equals(&pt(1.0, 2.0), &pt(1.0, 2.1)));
}
#[test]
fn equals_polygon_rotated_and_reversed() {
let a: Polygon<P> = polygon![[(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 4.0), (0.0, 0.0)]];
let b: Polygon<P> = polygon![[(4.0, 4.0), (0.0, 4.0), (0.0, 0.0), (4.0, 0.0), (4.0, 4.0)]];
assert!(equals(&a, &b));
}
/// Point equality compares all three ordinates in 3D — the `2 =>`
/// arm. Points equal in x,y but differing in z are not equal.
#[test]
fn equals_point_in_three_dimensions() {
use geometry_model::Point3D;
type P3 = Point3D<f64, Cartesian>;
let a = P3::new(1.0, 2.0, 3.0);
assert!(equals(&a, &P3::new(1.0, 2.0, 3.0)));
assert!(!equals(&a, &P3::new(1.0, 2.0, 9.0)));
}
/// Two polygons with matching holes (given in a different order) are
/// equal — the interior-ring permutation match with a `break`.
#[test]
fn equals_polygon_with_holes_matched_by_permutation() {
let a: Polygon<P> = polygon![
[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
],
[(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 1.0)],
[(5.0, 5.0), (6.0, 5.0), (6.0, 6.0), (5.0, 5.0)]
];
// Same polygon, holes listed in the opposite order.
let b: Polygon<P> = polygon![
[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
],
[(5.0, 5.0), (6.0, 5.0), (6.0, 6.0), (5.0, 5.0)],
[(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 1.0)]
];
assert!(equals(&a, &b));
}
/// Polygons whose exteriors match but whose hole *counts* differ are
/// not equal (the count-mismatch short-circuit).
#[test]
fn polygon_not_equals_on_different_hole_count() {
let a: Polygon<P> = polygon![
[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
],
[(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 1.0)]
];
let b: Polygon<P> = polygon![[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
]];
assert!(!equals(&a, &b));
}
/// Polygons with the same hole count but a hole that has no match are
/// not equal (the `if !found { return false }` arm).
#[test]
fn polygon_not_equals_when_a_hole_has_no_match() {
let a: Polygon<P> = polygon![
[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
],
[(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 1.0)]
];
let b: Polygon<P> = polygon![
[
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0)
],
[(7.0, 7.0), (8.0, 7.0), (8.0, 8.0), (7.0, 7.0)]
];
assert!(!equals(&a, &b));
}
/// Polygons whose exterior rings differ in vertex count are not equal
/// (the `av.len() != bv.len()` short-circuit in `rings_equal`).
#[test]
fn polygon_not_equals_on_different_vertex_count() {
let a: Polygon<P> = polygon![[(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 0.0)]]; // triangle
let b: Polygon<P> = polygon![[(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 4.0), (0.0, 0.0)]]; // square
assert!(!equals(&a, &b));
}
}