1use super::helper::Float;
2use geo_types::Coordinate;
3use std::cell::RefCell;
4use std::cmp::Ordering;
5use std::rc::{Rc, Weak};
6
7use super::helper::less_if;
8use super::signed_area::signed_area;
9
10#[derive(Clone, Copy, PartialEq, Eq, Debug)]
11pub enum EdgeType {
12 Normal,
13 NonContributing,
14 SameTransition,
15 DifferentTransition,
16}
17
18#[derive(Clone, Copy, PartialEq, Eq, Debug)]
19pub enum ResultTransition {
20 None,
21 InOut,
22 OutIn,
23}
24
25#[derive(Clone, Debug)]
26struct MutablePart<F>
27where
28 F: Float,
29{
30 left: bool,
31 other_event: Weak<SweepEvent<F>>,
32 prev_in_result: Weak<SweepEvent<F>>,
33 edge_type: EdgeType,
34 in_out: bool,
35 other_in_out: bool,
36 result_transition: ResultTransition,
37 other_pos: i32,
38 output_contour_id: i32,
39}
40
41#[derive(Clone, Debug)]
42pub struct SweepEvent<F>
43where
44 F: Float,
45{
46 mutable: RefCell<MutablePart<F>>,
47 pub contour_id: u32,
48 pub point: Coordinate<F>,
49 pub is_subject: bool,
50 pub is_exterior_ring: bool,
51}
52
53impl<F> SweepEvent<F>
54where
55 F: Float,
56{
57 pub fn new_rc(
58 contour_id: u32,
59 point: Coordinate<F>,
60 left: bool,
61 other_event: Weak<SweepEvent<F>>,
62 is_subject: bool,
63 is_exterior_ring: bool,
64 ) -> Rc<SweepEvent<F>> {
65 Rc::new(SweepEvent {
66 mutable: RefCell::new(MutablePart {
67 left,
68 other_event,
69 prev_in_result: Weak::new(),
70 edge_type: EdgeType::Normal,
71 in_out: false,
72 other_in_out: false,
73 result_transition: ResultTransition::None,
74 other_pos: 0,
75 output_contour_id: -1,
76 }),
77 contour_id,
78 point,
79 is_subject,
80 is_exterior_ring,
81 })
82 }
83
84 pub fn is_left(&self) -> bool {
85 self.mutable.borrow().left
86 }
87
88 pub fn set_left(&self, left: bool) {
89 self.mutable.borrow_mut().left = left
90 }
91
92 pub fn get_other_event(&self) -> Option<Rc<SweepEvent<F>>> {
93 self.mutable.borrow().other_event.upgrade()
94 }
95
96 pub fn set_other_event(&self, other_event: &Rc<SweepEvent<F>>) {
97 self.mutable.borrow_mut().other_event = Rc::downgrade(other_event);
98 }
99
100 pub fn get_prev_in_result(&self) -> Option<Rc<SweepEvent<F>>> {
101 self.mutable.borrow().prev_in_result.upgrade()
102 }
103
104 pub fn set_prev_in_result(&self, prev_in_result: &Rc<SweepEvent<F>>) {
105 self.mutable.borrow_mut().prev_in_result = Rc::downgrade(prev_in_result);
106 }
107
108 pub fn unset_prev_in_result(&self) {
109 self.mutable.borrow_mut().prev_in_result = Weak::new();
110 }
111
112 pub fn get_edge_type(&self) -> EdgeType {
113 self.mutable.borrow().edge_type
114 }
115
116 pub fn set_edge_type(&self, edge_type: EdgeType) {
117 self.mutable.borrow_mut().edge_type = edge_type
118 }
119
120 pub fn is_in_out(&self) -> bool {
121 self.mutable.borrow().in_out
122 }
123
124 pub fn is_other_in_out(&self) -> bool {
125 self.mutable.borrow().other_in_out
126 }
127
128 pub fn is_in_result(&self) -> bool {
129 self.mutable.borrow().result_transition != ResultTransition::None
130 }
131
132 pub fn set_result_transition(&self, result_transition: ResultTransition) {
133 self.mutable.borrow_mut().result_transition = result_transition
134 }
135
136 pub fn get_result_transition(&self) -> ResultTransition {
137 self.mutable.borrow().result_transition
138 }
139
140 pub fn set_in_out(&self, in_out: bool, other_in_out: bool) {
141 let mut mutable = self.mutable.borrow_mut();
142
143 mutable.in_out = in_out;
144 mutable.other_in_out = other_in_out;
145 }
146
147 pub fn get_other_pos(&self) -> i32 {
148 self.mutable.borrow().other_pos
149 }
150
151 pub fn set_other_pos(&self, other_pos: i32) {
152 self.mutable.borrow_mut().other_pos = other_pos
153 }
154
155 pub fn get_output_contour_id(&self) -> i32 {
156 self.mutable.borrow().output_contour_id
157 }
158
159 pub fn set_output_contour_id(&self, output_contour_id: i32) {
160 self.mutable.borrow_mut().output_contour_id = output_contour_id
161 }
162
163 pub fn is_below(&self, p: Coordinate<F>) -> bool {
164 if let Some(ref other_event) = self.get_other_event() {
165 if self.is_left() {
166 signed_area(self.point, other_event.point, p) > 0.
167 } else {
168 signed_area(other_event.point, self.point, p) > 0.
169 }
170 } else {
171 false
172 }
173 }
174
175 pub fn is_above(&self, p: Coordinate<F>) -> bool {
176 !self.is_below(p)
177 }
178
179 pub fn is_vertical(&self) -> bool {
180 match self.get_other_event() {
181 Some(ref other_event) => self.point.x == other_event.point.x,
182 None => false,
183 }
184 }
185
186 pub fn is_before(&self, other: &SweepEvent<F>) -> bool {
188 self > other
189 }
190
191 pub fn is_after(&self, other: &SweepEvent<F>) -> bool {
193 self < other
194 }
195}
196
197impl<F> PartialEq for SweepEvent<F>
198where
199 F: Float,
200{
201 fn eq(&self, other: &Self) -> bool {
202 self.contour_id == other.contour_id
203 && self.is_left() == other.is_left()
204 && self.point == other.point
205 && self.is_subject == other.is_subject
206 }
207}
208
209impl<F> Eq for SweepEvent<F> where F: Float {}
210
211impl<F> PartialOrd for SweepEvent<F>
212where
213 F: Float,
214{
215 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216 Some(self.cmp(other))
217 }
218}
219
220impl<F> Ord for SweepEvent<F>
221where
222 F: Float,
223{
224 #[inline]
225 fn cmp(&self, other: &Self) -> Ordering {
226 let p1 = self.point;
228 let p2 = other.point;
229
230 if p1.x > p2.x {
231 return Ordering::Less;
232 }
233 if p1.x < p2.x {
234 return Ordering::Greater;
235 }
236 if p1.y > p2.y {
237 return Ordering::Less;
238 }
239 if p1.y < p2.y {
240 return Ordering::Greater;
241 }
242
243 if self.is_left() != other.is_left() {
244 return less_if(self.is_left());
245 }
246
247 if let (Some(other1), Some(other2)) = (self.get_other_event(), other.get_other_event()) {
248 if signed_area(p1, other1.point, other2.point) != 0. {
249 return less_if(!self.is_below(other2.point));
250 }
251 }
252
253 less_if(!self.is_subject && other.is_subject)
254 }
255}
256
257#[cfg(feature = "debug-booleanop")]
258pub trait JsonDebug {
259 fn to_json_debug(&self) -> String;
260 fn to_json_debug_short(&self) -> String;
261}
262
263#[cfg(feature = "debug-booleanop")]
264impl<F> JsonDebug for Rc<SweepEvent<F>>
265where
266 F: Float,
267{
268 fn to_json_debug(&self) -> String {
269 format!(
270 "{{\"self\": {}, \"other\": {}}}",
271 self.to_json_debug_short(),
272 self.get_other_event().unwrap().to_json_debug_short(),
273 )
274 }
275
276 fn to_json_debug_short(&self) -> String {
277 format!(
278 "{{\"addr\": \"{:p}\", \"point\": [{}, {}], \"type\": \"{}\", \"poly\": \"{}\"}}",
279 *self,
280 self.point.x,
281 self.point.y,
282 if self.is_left() { "L" } else { "R" },
283 if self.is_subject { "A" } else { "B" },
284 )
285 }
286}
287
288#[cfg(test)]
289mod test {
290 use super::super::helper::test::xy;
291 use super::*;
292
293 pub fn se_pair(
294 contour_id: u32,
295 x: f64,
296 y: f64,
297 other_x: f64,
298 other_y: f64,
299 is_subject: bool,
300 ) -> (Rc<SweepEvent<f64>>, Rc<SweepEvent<f64>>) {
301 let other = SweepEvent::new_rc(
302 contour_id,
303 Coordinate { x: other_x, y: other_y },
304 false,
305 Weak::new(),
306 is_subject,
307 true,
308 );
309 let event = SweepEvent::new_rc(
310 contour_id,
311 Coordinate { x, y },
312 true,
313 Rc::downgrade(&other),
314 is_subject,
315 true,
316 );
317 assert!(event.is_before(&other));
319
320 (event, other)
321 }
322
323 #[test]
324 pub fn test_is_below() {
325 let other_s1 = SweepEvent::new_rc(0, xy(1, 1), false, Weak::new(), false, true);
326 let s1 = SweepEvent::new_rc(0, xy(0, 0), true, Rc::downgrade(&other_s1), false, true);
327 let s2 = SweepEvent::new_rc(0, xy(0, 0), false, Rc::downgrade(&s1), false, true);
328
329 assert!(s1.is_below(xy(0, 1)));
330 assert!(s1.is_below(xy(1, 2)));
331 assert!(!s1.is_below(xy(0, 0)));
332 assert!(!s1.is_below(xy(5, -1)));
333
334 assert!(!s2.is_below(xy(0, 1)));
335 assert!(!s2.is_below(xy(1, 2)));
336 assert!(!s2.is_below(xy(0, 0)));
337 assert!(!s2.is_below(xy(5, -1)));
338 }
339
340 #[test]
341 pub fn test_is_above() {
342 let other_s1 = SweepEvent::new_rc(0, xy(1, 1), false, Weak::new(), false, true);
343 let s1 = SweepEvent::new_rc(0, xy(0, 0), true, Rc::downgrade(&other_s1), false, true);
344 let s2 = SweepEvent::new_rc(0, xy(0, 1), false, Rc::downgrade(&s1), false, true);
345
346 assert!(!s1.is_above(xy(0, 1)));
347 assert!(!s1.is_above(xy(1, 2)));
348 assert!(s1.is_above(xy(0, 0)));
349 assert!(s1.is_above(xy(5, -1)));
350
351 assert!(s2.is_above(xy(0, 1)));
352 assert!(s2.is_above(xy(1, 2)));
353 assert!(s2.is_above(xy(0, 0)));
354 assert!(s2.is_above(xy(5, -1)));
355 }
356
357 #[test]
358 pub fn test_is_vertical() {
359 let other_s1 = SweepEvent::new_rc(0, xy(0, 1), false, Weak::new(), false, true);
360 let s1 = SweepEvent::new_rc(0, xy(0, 0), true, Rc::downgrade(&other_s1), false, true);
361 let other_s2 = SweepEvent::new_rc(0, xy(0.0001, 1), false, Weak::new(), false, true);
362 let s2 = SweepEvent::new_rc(0, xy(0, 0), true, Rc::downgrade(&other_s2), false, true);
363
364 assert!(s1.is_vertical());
365 assert!(!s2.is_vertical());
366 }
367
368 #[rustfmt::skip]
369 #[test]
370 fn test_order_star_pattern() {
371 let id = 0;
377 let z = 0.;
378
379 let (_av_l, av_r) = se_pair(id, 0., -1., z, z, true); let (_a1_l, a1_r) = se_pair(id, -2., -6., z, z, true);
382 let (_a2_l, a2_r) = se_pair(id, -1., -2., z, z, true);
383 let (_a3_l, a3_r) = se_pair(id, -1., -1., z, z, true);
384 let (_a4_l, a4_r) = se_pair(id, -2., -1., z, z, true);
385 let (_a5_l, a5_r) = se_pair(id, -2., 1., z, z, true);
386 let (_a6_l, a6_r) = se_pair(id, -1., 1., z, z, true);
387 let (_a7_l, a7_r) = se_pair(id, -1., 2., z, z, true);
388 let (_a8_l, a8_r) = se_pair(id, -2., 6., z, z, true);
389
390 let (b1_l, _b1_r) = se_pair(id, z, z, 2., -6., true);
392 let (b2_l, _b2_r) = se_pair(id, z, z, 1., -2., true);
393 let (b3_l, _b3_r) = se_pair(id, z, z, 1., -1., true);
394 let (b4_l, _b4_r) = se_pair(id, z, z, 2., -1., true);
395 let (b5_l, _b5_r) = se_pair(id, z, z, 2., 1., true);
396 let (b6_l, _b6_r) = se_pair(id, z, z, 1., 1., true);
397 let (b7_l, _b7_r) = se_pair(id, z, z, 1., 2., true);
398 let (b8_l, _b8_r) = se_pair(id, z, z, 2., 6., true);
399 let (bv_l, _bv_r) = se_pair(id, z, z, 0., 1., true); let events_expected_order = [
402 av_r, a1_r, a2_r, a3_r, a4_r, a5_r, a6_r, a7_r, a8_r,
403 b1_l, b2_l, b3_l, b4_l, b5_l, b6_l, b7_l, b8_l, bv_l,
404 ];
405
406 for i in 0 .. events_expected_order.len() - 1 {
407 for j in i + 1 .. events_expected_order.len() {
408 assert!(events_expected_order[i].is_before(&events_expected_order[j]));
409 }
410 }
411
412 }
413}