1use super::info::{Method, OperationType, Turn};
24use crate::predicate::segment_intersection::SegmentIntersection;
25use geometry_trait::Point;
26
27#[must_use]
39pub fn method_of<P>(outcome: &SegmentIntersection<P>) -> Method {
40 match outcome {
41 SegmentIntersection::Single(_) => Method::Crosses,
42 SegmentIntersection::Collinear { .. } => Method::Collinear,
43 SegmentIntersection::Disjoint | SegmentIntersection::OutOfRange => Method::Disjoint,
44 }
45}
46
47#[must_use]
55pub fn refine_touch<P>(point: &P, a0: &P, a1: &P, b0: &P, b1: &P) -> Method
56where
57 P: Point,
58 P::Scalar: PartialEq,
59{
60 let at_endpoint = eq(point, a0) || eq(point, a1) || eq(point, b0) || eq(point, b1);
61 if at_endpoint {
62 Method::Touch
63 } else {
64 Method::Crosses
65 }
66}
67
68#[must_use]
73pub const fn operations_for_crossing() -> [OperationType; 2] {
74 [OperationType::Union, OperationType::Intersection]
75}
76
77pub fn set_from_outcome<P>(
82 turn: &mut Turn<P>,
83 outcome: &SegmentIntersection<P>,
84 a0: &P,
85 a1: &P,
86 b0: &P,
87 b1: &P,
88) where
89 P: Point,
90 P::Scalar: PartialEq,
91{
92 let base = method_of(outcome);
93 turn.method = match base {
94 Method::Crosses => refine_touch(&turn.point, a0, a1, b0, b1),
95 other => other,
96 };
97 match turn.method {
98 Method::Crosses => {
99 let ops = operations_for_crossing();
100 turn.operations[0].operation = ops[0];
101 turn.operations[1].operation = ops[1];
102 turn.touch_only = false;
103 }
104 Method::Touch => {
105 turn.operations[0].operation = OperationType::Union;
108 turn.operations[1].operation = OperationType::Union;
109 turn.touch_only = true;
110 }
111 Method::Collinear => {
112 turn.operations[0].operation = OperationType::Continue;
113 turn.operations[1].operation = OperationType::Continue;
114 turn.touch_only = false;
115 }
116 _ => {}
117 }
118}
119
120fn eq<P: Point>(a: &P, b: &P) -> bool
121where
122 P::Scalar: PartialEq,
123{
124 a.get::<0>() == b.get::<0>() && a.get::<1>() == b.get::<1>()
125}
126
127#[cfg(test)]
128mod tests {
129 use super::{method_of, operations_for_crossing, refine_touch, set_from_outcome};
134 use crate::predicate::segment_intersection::SegmentIntersection;
135 use crate::turn::info::{Method, Operation, OperationType, RingKind, SegmentId, Turn};
136 use geometry_cs::Cartesian;
137 use geometry_model::Point2D;
138
139 type P = Point2D<f64, Cartesian>;
140
141 fn sid(src: usize) -> SegmentId {
142 SegmentId {
143 source_index: src,
144 ring: RingKind::Exterior,
145 segment_index: 0,
146 }
147 }
148
149 fn turn_at(x: f64, y: f64) -> Turn<P> {
150 Turn {
151 point: P::new(x, y),
152 method: Method::None,
153 operations: [Operation::new(sid(0)), Operation::new(sid(1))],
154 touch_only: false,
155 }
156 }
157
158 #[test]
159 fn method_from_outcome() {
160 assert_eq!(
161 method_of(&SegmentIntersection::Single(P::new(0.0, 0.0))),
162 Method::Crosses
163 );
164 assert_eq!(
165 method_of(&SegmentIntersection::Collinear {
166 from: P::new(0.0, 0.0),
167 to: P::new(1.0, 0.0)
168 }),
169 Method::Collinear
170 );
171 assert_eq!(
172 method_of::<P>(&SegmentIntersection::Disjoint),
173 Method::Disjoint
174 );
175 }
176
177 #[test]
178 fn crossing_at_interior_is_cross() {
179 let m = refine_touch(
181 &P::new(1.0, 1.0),
182 &P::new(0.0, 0.0),
183 &P::new(2.0, 2.0),
184 &P::new(0.0, 2.0),
185 &P::new(2.0, 0.0),
186 );
187 assert_eq!(m, Method::Crosses);
188 }
189
190 #[test]
191 fn crossing_at_endpoint_is_touch() {
192 let m = refine_touch(
194 &P::new(2.0, 0.0),
195 &P::new(0.0, 0.0),
196 &P::new(4.0, 0.0),
197 &P::new(2.0, 0.0),
198 &P::new(2.0, 3.0),
199 );
200 assert_eq!(m, Method::Touch);
201 }
202
203 #[test]
204 fn crossing_sets_opposite_operations() {
205 let mut t = turn_at(1.0, 1.0);
206 set_from_outcome(
207 &mut t,
208 &SegmentIntersection::Single(P::new(1.0, 1.0)),
209 &P::new(0.0, 0.0),
210 &P::new(2.0, 2.0),
211 &P::new(0.0, 2.0),
212 &P::new(2.0, 0.0),
213 );
214 assert_eq!(t.method, Method::Crosses);
215 let ops = operations_for_crossing();
216 assert_eq!(t.operations[0].operation, ops[0]);
217 assert_eq!(t.operations[1].operation, ops[1]);
218 assert_eq!(t.operations[0].operation, OperationType::Union);
219 assert_eq!(t.operations[1].operation, OperationType::Intersection);
220 }
221
222 #[test]
223 fn collinear_sets_continue() {
224 let mut t = turn_at(2.0, 0.0);
225 set_from_outcome(
226 &mut t,
227 &SegmentIntersection::Collinear {
228 from: P::new(2.0, 0.0),
229 to: P::new(4.0, 0.0),
230 },
231 &P::new(0.0, 0.0),
232 &P::new(4.0, 0.0),
233 &P::new(2.0, 0.0),
234 &P::new(6.0, 0.0),
235 );
236 assert_eq!(t.method, Method::Collinear);
237 assert_eq!(t.operations[0].operation, OperationType::Continue);
238 }
239}