1use crate::geom::x_segment::XSegment;
2use i_float::fix_vec::FixVec;
3use i_float::int::point::IntPoint;
4use i_float::triangle::Triangle;
5use i_float::u128::UInt128;
6
7pub(super) type CollinearMask = u8;
8
9pub(super) trait EndMask {
10 fn is_target_a(&self) -> bool;
11 fn is_target_b(&self) -> bool;
12 fn is_other_a(&self) -> bool;
13 fn is_other_b(&self) -> bool;
14
15 fn new(target_a: bool, target_b: bool, other_a: bool, other_b: bool) -> Self;
16}
17
18const TARGET_A: u8 = 0b0001;
19const TARGET_B: u8 = 0b0010;
20const OTHER_A: u8 = 0b0100;
21const OTHER_B: u8 = 0b1000;
22
23impl EndMask for CollinearMask {
24 #[inline(always)]
25 fn is_target_a(&self) -> bool {
26 self & TARGET_A == TARGET_A
27 }
28
29 #[inline(always)]
30 fn is_target_b(&self) -> bool {
31 self & TARGET_B == TARGET_B
32 }
33
34 #[inline(always)]
35 fn is_other_a(&self) -> bool {
36 self & OTHER_A == OTHER_A
37 }
38
39 #[inline(always)]
40 fn is_other_b(&self) -> bool {
41 self & OTHER_B == OTHER_B
42 }
43
44 #[inline(always)]
45 fn new(target_a: bool, target_b: bool, other_a: bool, other_b: bool) -> Self {
46 let a0 = target_a as u8;
47 let b0 = (target_b as u8) << 1;
48 let a1 = (other_a as u8) << 2;
49 let b1 = (other_b as u8) << 3;
50
51 a0 | b0 | a1 | b1
52 }
53}
54
55pub(super) struct CrossResult {
56 pub(super) point: IntPoint,
57 pub(super) cross_type: CrossType,
58 pub(super) is_round: bool,
59}
60
61pub(super) enum CrossType {
62 Pure,
63 TargetEnd,
64 OtherEnd,
65 Overlay,
66}
67
68pub(super) struct CrossSolver {}
69
70impl CrossSolver {
71 pub(super) fn cross(target: &XSegment, other: &XSegment, radius: i64) -> Option<CrossResult> {
72 let a0b0a1 = Triangle::clock_direction_point(target.a, target.b, other.a);
73 let a0b0b1 = Triangle::clock_direction_point(target.a, target.b, other.b);
74
75 let a1b1a0 = Triangle::clock_direction_point(other.a, other.b, target.a);
76 let a1b1b0 = Triangle::clock_direction_point(other.a, other.b, target.b);
77
78 let s = (1 & (a0b0a1 + 1)) + (1 & (a0b0b1 + 1)) + (1 & (a1b1a0 + 1)) + (1 & (a1b1b0 + 1));
79
80 if s == 4 {
81 return Some(CrossResult {
82 point: IntPoint::ZERO,
83 cross_type: CrossType::Overlay,
84 is_round: false,
85 });
86 }
87
88 let is_not_cross = a0b0a1 == a0b0b1 || a1b1a0 == a1b1b0;
89
90 if s > 1 || is_not_cross {
91 return None;
92 }
93
94 if s != 0 {
95 return if a0b0a1 == 0 {
96 Some(CrossResult {
97 point: other.a,
98 cross_type: CrossType::OtherEnd,
99 is_round: false,
100 })
101 } else if a0b0b1 == 0 {
102 Some(CrossResult {
103 point: other.b,
104 cross_type: CrossType::OtherEnd,
105 is_round: false,
106 })
107 } else if a1b1a0 == 0 {
108 Some(CrossResult {
109 point: target.a,
110 cross_type: CrossType::TargetEnd,
111 is_round: false,
112 })
113 } else {
114 Some(CrossResult {
115 point: target.b,
116 cross_type: CrossType::TargetEnd,
117 is_round: false,
118 })
119 };
120 }
121
122 Self::middle_cross(target, other, radius)
123 }
124
125 pub(super) fn collinear(target: &XSegment, other: &XSegment) -> CollinearMask {
126 let a0 = FixVec::new_point(target.a);
127 let b0 = FixVec::new_point(target.b);
128 let a1 = FixVec::new_point(other.a);
129 let b1 = FixVec::new_point(other.b);
130
131 let v1 = b1 - a1;
132
133 let aa0 = (a0 - a1).dot_product(v1).signum();
134 let ab0 = (a0 - b1).dot_product(v1).signum();
135 let ba0 = (b0 - a1).dot_product(v1).signum();
136 let bb0 = (b0 - b1).dot_product(v1).signum();
137
138 let aa1 = -aa0;
139 let ab1 = -ba0;
140 let ba1 = -ab0;
141 let bb1 = -bb0;
142
143 let is_target_a = aa0 == -ab0 && aa0 != 0;
144 let is_target_b = ba0 == -bb0 && ba0 != 0;
145
146 let is_other_a = aa1 == -ab1 && aa1 != 0;
147 let is_other_b = ba1 == -bb1 && ba1 != 0;
148
149 CollinearMask::new(is_target_a, is_target_b, is_other_a, is_other_b)
150 }
151
152 fn middle_cross(target: &XSegment, other: &XSegment, radius: i64) -> Option<CrossResult> {
153 let p = CrossSolver::cross_point(target, other);
154
155 if Triangle::is_line_point(target.a, p, target.b) && Triangle::is_line_point(other.a, p, other.b) {
156 return Some(CrossResult {
157 point: p,
158 cross_type: CrossType::Pure,
159 is_round: false,
160 });
161 }
162
163 let ra0 = target.a.sqr_distance(p);
167 let rb0 = target.b.sqr_distance(p);
168
169 let ra1 = other.a.sqr_distance(p);
170 let rb1 = other.b.sqr_distance(p);
171
172 if ra0 <= radius || ra1 <= radius || rb0 <= radius || rb1 <= radius {
173 let r0 = ra0.min(rb0);
174 let r1 = ra1.min(rb1);
175
176 if r0 <= r1 {
177 let p = if ra0 < rb0 { target.a } else { target.b };
178 if Triangle::is_not_line_point(other.a, p, other.b) {
180 return Some(CrossResult {
181 point: p,
182 cross_type: CrossType::TargetEnd,
183 is_round: true,
184 });
185 }
186 } else {
187 let p = if ra1 < rb1 { other.a } else { other.b };
188
189 if Triangle::is_not_line_point(target.a, p, target.b) {
191 return Some(CrossResult {
192 point: p,
193 cross_type: CrossType::OtherEnd,
194 is_round: true,
195 });
196 }
197 }
198 }
199
200 Some(CrossResult {
201 point: p,
202 cross_type: CrossType::Pure,
203 is_round: true,
204 })
205 }
206
207 fn cross_point(target: &XSegment, other: &XSegment) -> IntPoint {
208 let a0x = target.a.x as i64;
241 let a0y = target.a.y as i64;
242
243 let a1x = target.b.x as i64 - a0x;
244 let b0x = other.a.x as i64 - a0x;
245 let b1x = other.b.x as i64 - a0x;
246
247 let a1y = target.b.y as i64 - a0y;
250 let b0y = other.a.y as i64 - a0y;
251 let b1y = other.b.y as i64 - a0y;
252
253 let dy_b = b0y - b1y;
254 let dx_b = b0x - b1x;
255
256 let xy_b = b0x * b1y - b0y * b1x;
258
259 let x0: i64;
260 let y0: i64;
261
262 if a1x == 0 {
265 x0 = 0;
267 y0 = xy_b / dx_b;
268 } else if a1y == 0 {
269 y0 = 0;
271 x0 = -xy_b / dy_b;
272 } else {
273 let div = a1y * dx_b - a1x * dy_b;
275
276 let s = div.signum() * xy_b.signum();
278 let sx = a1x.signum() * s;
279 let sy = a1y.signum() * s;
280
281 let uxy_b = xy_b.unsigned_abs();
283 let udiv = div.unsigned_abs();
284
285 let kx = UInt128::multiply(a1x.unsigned_abs(), uxy_b);
286 let ky = UInt128::multiply(a1y.unsigned_abs(), uxy_b);
287
288 let ux = kx.divide_with_rounding(udiv);
289 let uy = ky.divide_with_rounding(udiv);
290
291 x0 = sx * ux as i64;
293 y0 = sy * uy as i64;
294 }
295
296 let x = (x0 + a0x) as i32;
297 let y = (y0 + a0y) as i32;
298
299 IntPoint::new(x, y)
300 }
301}
302
303const LAST_BIT_INDEX: usize = 63;
304
305trait RoundDivide {
306 fn divide_with_rounding(&self, divisor: u64) -> u64;
307}
308
309impl RoundDivide for UInt128 {
310 fn divide_with_rounding(&self, divisor: u64) -> u64 {
311 if self.high == 0 {
312 let result = self.low / divisor;
313 let remainder = self.low - result * divisor;
314 return if remainder >= (divisor + 1) >> 1 {
315 result + 1
316 } else {
317 result
318 };
319 }
320
321 let dn = divisor.leading_zeros();
322 let norm_divisor = divisor << dn;
323 let mut norm_dividend_high = (self.high << dn) | (self.low >> (u64::BITS - dn));
324 let mut norm_dividend_low = self.low << dn;
325
326 let mut quotient = 0;
327 let one = 1 << LAST_BIT_INDEX;
328
329 for _ in 0..u64::BITS {
330 let bit = (norm_dividend_high & one) != 0;
331 norm_dividend_high = (norm_dividend_high << 1) | (norm_dividend_low >> LAST_BIT_INDEX);
332 norm_dividend_low <<= 1;
333 quotient <<= 1;
334 if norm_dividend_high >= norm_divisor || bit {
335 norm_dividend_high = norm_dividend_high.wrapping_sub(norm_divisor);
336 quotient |= 1;
337 }
338 }
339
340 let remainder = (norm_dividend_high << (u64::BITS - dn)) | (norm_dividend_low >> dn);
342 if remainder >= (divisor + 1) >> 1 {
343 quotient += 1;
344 }
345
346 quotient
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use crate::geom::x_segment::XSegment;
353 use crate::split::cross_solver::{CrossSolver, CrossType};
354 use i_float::int::point::IntPoint;
355
356 impl XSegment {
357 fn new(a: IntPoint, b: IntPoint) -> Self {
358 Self { a, b }
359 }
360 }
361
362 #[test]
363 fn test_simple_cross() {
364 let s: i32 = 1024;
365
366 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s, 0));
367 let eb = XSegment::new(IntPoint::new(0, -s), IntPoint::new(0, s));
368
369 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
370
371 match result.cross_type {
372 CrossType::Pure => {
373 assert_eq!(IntPoint::ZERO, result.point);
374 }
375 _ => {
376 panic!("Fail cross result");
377 }
378 }
379 }
380
381 #[test]
382 fn test_big_cross_1() {
383 let s: i32 = 1024_000_000;
384
385 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s, 0));
386 let eb = XSegment::new(IntPoint::new(0, -s), IntPoint::new(0, s));
387
388 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
389
390 match result.cross_type {
391 CrossType::Pure => {
392 assert_eq!(IntPoint::ZERO, result.point);
393 }
394 _ => {
395 panic!("Fail cross result");
396 }
397 }
398 }
399
400 #[test]
401 fn test_big_cross_2() {
402 let s: i32 = 1024_000_000;
403
404 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s, 0));
405 let eb = XSegment::new(IntPoint::new(1024, -s), IntPoint::new(1024, s));
406
407 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
408
409 match result.cross_type {
410 CrossType::Pure => {
411 assert_eq!(IntPoint::new(1024, 0), result.point);
412 }
413 _ => {
414 panic!("Fail cross result");
415 }
416 }
417 }
418
419 #[test]
420 fn test_big_cross_3() {
421 let s: i32 = 1024_000_000;
422 let q: i32 = s / 2;
423
424 let ea = XSegment::new(IntPoint::new(-s, -s), IntPoint::new(s, s));
425 let eb = XSegment::new(IntPoint::new(q, -s), IntPoint::new(q, s));
426
427 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
428
429 match result.cross_type {
430 CrossType::Pure => {
431 assert_eq!(IntPoint::new(512_000_000, 512_000_000), result.point);
432 }
433 _ => {
434 panic!("Fail cross result");
435 }
436 }
437 }
438
439 #[test]
440 fn test_left_end() {
441 let s: i32 = 1024_000_000;
442
443 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s, 0));
444 let eb = XSegment::new(IntPoint::new(-s, -s), IntPoint::new(-s, s));
445
446 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
447
448 match result.cross_type {
449 CrossType::TargetEnd => {
450 assert_eq!(IntPoint::new(-s, 0), result.point);
451 }
452 _ => {
453 panic!("Fail cross result");
454 }
455 }
456 }
457
458 #[test]
459 fn test_right_end() {
460 let s: i32 = 1024_000_000;
461
462 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s, 0));
463 let eb = XSegment::new(IntPoint::new(s, -s), IntPoint::new(s, s));
464
465 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
466
467 match result.cross_type {
468 CrossType::TargetEnd => {
469 assert_eq!(IntPoint::new(s, 0), result.point);
470 }
471 _ => {
472 panic!("Fail cross result");
473 }
474 }
475 }
476
477 #[test]
478 fn test_left_top() {
479 let s: i32 = 1024_000_000;
480
481 let ea = XSegment::new(IntPoint::new(-s, s), IntPoint::new(s, s));
482 let eb = XSegment::new(IntPoint::new(-s, s), IntPoint::new(-s, -s));
483
484 let result = CrossSolver::cross(&ea, &eb, 2);
485 debug_assert!(result.is_none());
486 }
487
488 #[test]
489 fn test_real_case_1() {
490 let ea = XSegment::new(IntPoint::new(7256, -14637), IntPoint::new(7454, -15045));
491 let eb = XSegment::new(IntPoint::new(7343, -14833), IntPoint::new(7506, -15144));
492
493 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
494
495 match result.cross_type {
496 CrossType::Pure => {}
497 _ => {
498 panic!("Fail cross result");
499 }
500 }
501 }
502
503 #[test]
504 fn test_real_case_2() {
505 let ea = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(-1024000, 0));
506 let eb = XSegment::new(IntPoint::new(-8571363, 1513719), IntPoint::new(-1023948, -10239));
507
508 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
509
510 match result.cross_type {
511 CrossType::Pure => {
512 assert_eq!(IntPoint::new(-1048691, -5244), result.point);
513 }
514 _ => {
515 panic!("Fail cross result");
516 }
517 }
518 }
519
520 #[test]
521 fn test_real_case_3() {
522 let ea = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(513224, -5243));
523 let eb = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(513224, -5243));
524
525 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
526
527 match result.cross_type {
528 CrossType::Overlay => {
529 assert_eq!(IntPoint::ZERO, result.point);
530 }
531 _ => {
532 panic!("Fail cross result");
533 }
534 }
535 }
536
537 #[test]
538 fn test_real_case_4() {
539 let ea = XSegment::new(
540 IntPoint::new(-276659431, 380789039),
541 IntPoint::new(-221915258, 435533212),
542 );
543 let eb = XSegment::new(
544 IntPoint::new(-276659432, 380789038),
545 IntPoint::new(-276659430, 380789040),
546 );
547
548 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
549
550 match result.cross_type {
551 CrossType::Overlay => {
552 assert_eq!(IntPoint::ZERO, result.point);
553 }
554 _ => {
555 panic!("Fail cross result");
556 }
557 }
558 }
559
560 #[test]
561 fn test_penetration() {
562 let s: i32 = 1024;
563
564 let ea = XSegment::new(IntPoint::new(-s, 0), IntPoint::new(s / 2, 0));
565 let eb = XSegment::new(IntPoint::new(0, 0), IntPoint::new(s, 0));
566
567 let result = CrossSolver::cross(&ea, &eb, 2).unwrap();
568
569 match result.cross_type {
570 CrossType::Overlay => {
571 assert_eq!(IntPoint::ZERO, result.point);
572 }
573 _ => {
574 panic!("Fail cross result");
575 }
576 }
577 }
578}