1#![allow(non_snake_case)]
2
3use crate::{Point, Line, QuadraticCurve, CubicCurve};
6
7type OptionTuple<T> = (Option<T>, Option<T>, Option<T>);
8
9#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
10pub struct BezierNormalVector { pub x: f64, pub y: f64 }
11
12#[derive(Debug, Clone, PartialEq, PartialOrd)]
13pub enum IntersectionResult {
14 NoIntersection,
15 FoundIntersection(Intersection),
16 Infinite(InfiniteIntersections)
17}
18
19#[derive(Debug, Clone, PartialEq, PartialOrd)]
20pub enum Intersection {
21 LineLine(LineLineIntersection),
22 LineQuad(LineQuadIntersection),
23 LineCubic(LineCubicIntersection),
24 QuadLine(QuadLineIntersection),
25 QuadQuad(Vec<QuadQuadIntersection>),
26 QuadCubic(Vec<QuadCubicIntersection>),
27 CubicLine(CubicLineIntersection),
28 CubicQuad(Vec<CubicQuadIntersection>),
29 CubicCubic(Vec<CubicCubicIntersection>),
30}
31
32#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
35pub enum InfiniteIntersections {
36 LineLine(Line, Line),
37 QuadQuad(QuadraticCurve, QuadraticCurve),
38 QuadCubic(QuadraticCurve, CubicCurve),
39 CubicQuad(CubicCurve, QuadraticCurve),
40 CubicCubic(CubicCurve, CubicCurve),
41}
42
43#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
44pub struct LineLineIntersection {
45 pub t1: f64,
46 pub line1: Line,
47 pub t2: f64,
48 pub line2: Line,
49}
50
51impl LineLineIntersection {
52
53 #[inline]
54 pub fn get_intersection_point_1(&self) -> Point {
55 let new_x = (1.0 - self.t1) * self.line1.0.x + self.t1 * self.line1.1.x;
57 let new_y = (1.0 - self.t1) * self.line1.0.y + self.t1 * self.line1.1.y;
58 Point::new(new_x, new_y)
59 }
60
61 #[inline]
62 pub fn get_intersection_point_2(&self) -> Point {
63 let new_x = (1.0 - self.t2) * self.line2.0.x + self.t2 * self.line2.1.x;
65 let new_y = (1.0 - self.t2) * self.line2.0.y + self.t2 * self.line2.1.y;
66 Point::new(new_x, new_y)
67 }
68}
69
70macro_rules! cubic_line {($structname:ident, $curvetype:ident) => (
71 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
73 pub enum $structname {
74 Intersect1 {
75 curve: $curvetype,
76 line: Line,
77 t_curve_1: f64,
78 t_line_1: f64,
79 },
80 Intersect2 {
81 curve: $curvetype,
82 line: Line,
83 t_curve_1: f64,
84 t_line_1: f64,
85 t_curve_2: f64,
86 t_line_2: f64,
87 },
88 Intersect3 {
89 curve: $curvetype,
90 line: Line,
91 t_curve_1: f64,
92 t_line_1: f64,
93 t_curve_2: f64,
94 t_line_2: f64,
95 t_curve_3: f64,
96 t_line_3: f64,
97 }
98 }
99
100 impl $structname {
101
102 #[inline]
103 pub fn get_curve_t1(&self) -> f64 {
104 use self::$structname::*;
105 match self {
106 Intersect1 { t_curve_1, .. } => *t_curve_1,
107 Intersect2 { t_curve_1, .. } => *t_curve_1,
108 Intersect3 { t_curve_1, .. } => *t_curve_1,
109 }
110 }
111
112 #[inline]
113 pub fn get_curve_t2(&self) -> Option<f64> {
114 use self::$structname::*;
115 match self {
116 Intersect1 { .. } => None,
117 Intersect2 { t_curve_2, .. } => Some(*t_curve_2),
118 Intersect3 { t_curve_2, .. } => Some(*t_curve_2),
119 }
120 }
121
122 #[inline]
123 pub fn get_curve_t3(&self) -> Option<f64> {
124 use self::$structname::*;
125 match self {
126 Intersect1 { .. } => None,
127 Intersect2 { .. } => None,
128 Intersect3 { t_curve_3, .. } => Some(*t_curve_3),
129 }
130 }
131
132 #[inline]
133 pub fn get_line_t1(&self) -> f64 {
134 use self::$structname::*;
135 match self {
136 Intersect1 { t_line_1, .. } => *t_line_1,
137 Intersect2 { t_line_1, .. } => *t_line_1,
138 Intersect3 { t_line_1, .. } => *t_line_1,
139 }
140 }
141
142 #[inline]
143 pub fn get_line_t2(&self) -> Option<f64> {
144 use self::$structname::*;
145 match self {
146 Intersect1 { .. } => None,
147 Intersect2 { t_line_2, .. } => Some(*t_line_2),
148 Intersect3 { t_line_2, .. } => Some(*t_line_2),
149 }
150 }
151
152 #[inline]
153 pub fn get_line_t3(&self) -> Option<f64> {
154 use self::$structname::*;
155 match self {
156 Intersect1 { .. } => None,
157 Intersect2 { .. } => None,
158 Intersect3 { t_line_3, .. } => Some(*t_line_3),
159 }
160 }
161
162 #[inline]
163 pub fn get_intersection_point_1(&self) -> Point {
164 use self::$structname::*;
165 match self {
166 Intersect1 { line, t_line_1, .. } => lerp(line.0, line.1, *t_line_1),
167 Intersect2 { line, t_line_1, .. } => lerp(line.0, line.1, *t_line_1),
168 Intersect3 { line, t_line_1, .. } => lerp(line.0, line.1, *t_line_1),
169 }
170 }
171
172 #[inline]
173 pub fn get_intersection_point_2(&self) -> Option<Point> {
174 use self::$structname::*;
175 match self {
176 Intersect1 { .. } => None,
177 Intersect2 { line, t_line_2, .. } => Some(lerp(line.0, line.1, *t_line_2)),
178 Intersect3 { line, t_line_2, .. } => Some(lerp(line.0, line.1, *t_line_2)),
179 }
180 }
181
182 #[inline]
183 pub fn get_intersection_point_3(&self) -> Option<Point> {
184 use self::$structname::*;
185 match self {
186 Intersect1 { .. } => None,
187 Intersect2 { .. } => None,
188 Intersect3 { line, t_line_3, .. } => Some(lerp(line.0, line.1, *t_line_3)),
189 }
190 }
191 }
192)}
193
194cubic_line!(LineQuadIntersection, QuadraticCurve);
195cubic_line!(LineCubicIntersection, CubicCurve);
196
197macro_rules! cubic_cubic {($structname:ident, $curvetype:ident, $evaluate_fn:ident) => (
198 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
199 pub struct $structname {
200 pub t1: f64,
201 pub curve1: $curvetype,
202 pub t2: f64,
203 pub curve2: $curvetype,
204 }
205
206 impl $structname {
207 pub fn get_intersection_point_1(&self) -> Point {
208 $evaluate_fn(self.curve1, self.t1)
209 }
210
211 pub fn get_intersection_point_2(&self) -> Point {
212 $evaluate_fn(self.curve2, self.t2)
213 }
214 }
215)}
216
217cubic_line!(QuadLineIntersection, QuadraticCurve);
218cubic_cubic!(QuadQuadIntersection, QuadraticCurve, quadratic_evaluate);
219
220#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
221pub struct QuadCubicIntersection {
222 pub t1: f64,
223 pub curve1: QuadraticCurve,
224 pub t2: f64,
225 pub curve2: CubicCurve,
226}
227
228impl QuadCubicIntersection {
229 pub fn get_intersection_point_1(&self) -> Point {
230 quadratic_evaluate(self.curve1, self.t1)
231 }
232
233 pub fn get_intersection_point_2(&self) -> Point {
234 evaluate(self.curve2, self.t2)
235 }
236}
237
238cubic_line!(CubicLineIntersection, CubicCurve);
239
240#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
241pub struct CubicQuadIntersection {
242 pub t1: f64,
243 pub curve1: CubicCurve,
244 pub t2: f64,
245 pub curve2: QuadraticCurve,
246}
247
248impl CubicQuadIntersection {
249 pub fn get_intersection_point_1(&self) -> Point {
250 evaluate(self.curve1, self.t1)
251 }
252
253 pub fn get_intersection_point_2(&self) -> Point {
254 quadratic_evaluate(self.curve2, self.t2)
255 }
256}
257
258cubic_cubic!(CubicCubicIntersection, CubicCurve, evaluate);
259
260pub(crate) fn line_line_intersect(line1: Line, line2: Line) -> IntersectionResult {
261 use self::{Intersection::*, IntersectionResult::*};
262
263 if line1 == line2 {
264 return Infinite(InfiniteIntersections::LineLine(line1, line2));
265 }
266
267 if line1.0 == line1.1 || line2.0 == line2.1 {
268 return NoIntersection;
269 }
270
271 match do_line_line_intersect(line1, line2) {
272 None => NoIntersection,
273 Some(s) => FoundIntersection(LineLine(s)),
274 }
275}
276
277pub(crate) fn line_quad_intersect(line1: Line, curve1: QuadraticCurve) -> IntersectionResult {
278 use self::{Intersection::*, LineQuadIntersection::*, IntersectionResult::*};
279
280 if line1.0 == line1.1 || (curve1.0 == curve1.1 && curve1.1 == curve1.2) {
281 return NoIntersection;
282 }
283
284 match do_curve_line_intersect(quadratic_to_cubic_curve(curve1), line1) {
285 (Some((t_line_1, t_curve_1)), None, None) =>
286 FoundIntersection(LineQuad(Intersect1 {
287 curve: curve1,
288 line: line1,
289 t_curve_1,
290 t_line_1,
291 })),
292 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), None) =>
293 FoundIntersection(LineQuad(Intersect2 {
294 curve: curve1,
295 line: line1,
296 t_curve_1,
297 t_line_1,
298 t_curve_2,
299 t_line_2,
300 })),
301 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), Some((t_line_3, t_curve_3))) =>
302 FoundIntersection(LineQuad(Intersect3 {
303 curve: curve1,
304 line: line1,
305 t_curve_1,
306 t_line_1,
307 t_curve_2,
308 t_line_2,
309 t_curve_3,
310 t_line_3,
311 })),
312 _ => NoIntersection,
313 }
314}
315
316pub(crate) fn line_cubic_intersect(line1: Line, curve1: CubicCurve) -> IntersectionResult {
317 use self::{Intersection::*, LineCubicIntersection::*, IntersectionResult::*};
318
319 if line1.0 == line1.1 || (curve1.0 == curve1.1 && curve1.1 == curve1.2 && curve1.2 == curve1.3) {
320 return NoIntersection;
321 }
322
323 match do_curve_line_intersect(curve1, line1) {
324 (Some((t_line_1, t_curve_1)), None, None) =>
325 FoundIntersection(LineCubic(Intersect1 {
326 curve: curve1,
327 line: line1,
328 t_curve_1,
329 t_line_1,
330 })),
331 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), None) =>
332 FoundIntersection(LineCubic(Intersect2 {
333 curve: curve1,
334 line: line1,
335 t_curve_1,
336 t_line_1,
337 t_curve_2,
338 t_line_2,
339 })),
340 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), Some((t_line_3, t_curve_3))) =>
341 FoundIntersection(LineCubic(Intersect3 {
342 curve: curve1,
343 line: line1,
344 t_curve_1,
345 t_line_1,
346 t_curve_2,
347 t_line_2,
348 t_curve_3,
349 t_line_3,
350 })),
351 _ => NoIntersection,
352 }
353}
354
355pub(crate) fn quad_line_intersect(curve1: QuadraticCurve, line1: Line) -> IntersectionResult {
356 use self::{Intersection::*, QuadLineIntersection::*, IntersectionResult::*};
357
358 if line1.0 == line1.1 || (curve1.0 == curve1.1 && curve1.1 == curve1.2) {
359 return NoIntersection;
360 }
361
362 match do_curve_line_intersect(quadratic_to_cubic_curve(curve1), line1) {
363 (Some((t_line_1, t_curve_1)), None, None) =>
364 FoundIntersection(QuadLine(Intersect1 {
365 curve: curve1,
366 line: line1,
367 t_curve_1,
368 t_line_1,
369 })),
370 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), None) =>
371 FoundIntersection(QuadLine(Intersect2 {
372 curve: curve1,
373 line: line1,
374 t_curve_1,
375 t_line_1,
376 t_curve_2,
377 t_line_2,
378 })),
379 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), Some((t_line_3, t_curve_3))) =>
380 FoundIntersection(QuadLine(Intersect3 {
381 curve: curve1,
382 line: line1,
383 t_curve_1,
384 t_line_1,
385 t_curve_2,
386 t_line_2,
387 t_curve_3,
388 t_line_3,
389 })),
390 _ => NoIntersection,
391 }
392}
393
394pub(crate) fn quad_quad_intersect(curve1: QuadraticCurve, curve2: QuadraticCurve) -> IntersectionResult {
395 use self::{Intersection::*, IntersectionResult::*};
396
397 if curve1 == curve2 {
398 return Infinite(InfiniteIntersections::QuadQuad(curve1, curve2));
399 }
400
401 if (curve1.0 == curve1.1 && curve1.1 == curve1.2) || (curve2.0 == curve2.1 && curve2.1 == curve2.2) {
402 return NoIntersection;
403 }
404
405 match do_curve_curve_intersect(quadratic_to_cubic_curve(curve1), quadratic_to_cubic_curve(curve2)) {
406 None => NoIntersection,
407 Some(s) => {
408 FoundIntersection(QuadQuad(s
409 .into_iter()
410 .map(|c| QuadQuadIntersection { curve1, curve2, t1: c.t1, t2: c.t2 })
411 .collect())
412 )
413 }
414 }
415}
416
417pub(crate) fn quad_cubic_intersect(curve1: QuadraticCurve, curve2: CubicCurve) -> IntersectionResult {
418 use self::{Intersection::*, IntersectionResult::*};
419
420 if (curve1.0 == curve1.1 && curve1.1 == curve1.2) || (curve2.0 == curve2.1 && curve2.1 == curve2.2 && curve2.2 == curve2.3) {
421 return NoIntersection;
422 }
423
424 let curve1_new = quadratic_to_cubic_curve(curve1);
425
426 if curve1_new == curve2 {
427 return Infinite(InfiniteIntersections::QuadCubic(curve1, curve2));
428 }
429
430 match do_curve_curve_intersect(curve1_new, curve2) {
431 None => NoIntersection,
432 Some(s) => {
433 FoundIntersection(QuadCubic(s
434 .into_iter()
435 .map(|c| QuadCubicIntersection { curve1, curve2, t1: c.t1, t2: c.t2 })
436 .collect())
437 )
438 }
439 }
440}
441
442pub(crate) fn cubic_line_intersect(curve1: CubicCurve, line1: Line) -> IntersectionResult {
443
444 use self::{Intersection::*, CubicLineIntersection::*, IntersectionResult::*};
445
446 if line1.0 == line1.1 || (curve1.0 == curve1.1 && curve1.1 == curve1.2 && curve1.2 == curve1.3) {
447 return NoIntersection;
448 }
449
450 match do_curve_line_intersect(curve1, line1) {
451 (Some((t_line_1, t_curve_1)), None, None) =>
452 FoundIntersection(CubicLine(Intersect1 {
453 curve: curve1,
454 line: line1,
455 t_curve_1,
456 t_line_1,
457 })),
458 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), None) =>
459 FoundIntersection(CubicLine(Intersect2 {
460 curve: curve1,
461 line: line1,
462 t_curve_1,
463 t_line_1,
464 t_curve_2,
465 t_line_2,
466 })),
467 (Some((t_line_1, t_curve_1)), Some((t_line_2, t_curve_2)), Some((t_line_3, t_curve_3))) =>
468 FoundIntersection(CubicLine(Intersect3 {
469 curve: curve1,
470 line: line1,
471 t_curve_1,
472 t_line_1,
473 t_curve_2,
474 t_line_2,
475 t_curve_3,
476 t_line_3,
477 })),
478 _ => NoIntersection,
479 }
480}
481
482pub(crate) fn cubic_quad_intersect(curve1: CubicCurve, curve2: QuadraticCurve) -> IntersectionResult {
483 use self::{Intersection::*, IntersectionResult::*};
484
485 if (curve1.0 == curve1.1 && curve1.1 == curve1.2 && curve1.2 == curve1.3) || (curve2.0 == curve2.1 && curve2.1 == curve2.2) {
486 return NoIntersection;
487 }
488
489 let curve2_new = quadratic_to_cubic_curve(curve2);
490
491 if curve2_new == curve1 {
492 return Infinite(InfiniteIntersections::CubicQuad(curve1, curve2));
493 }
494
495 match do_curve_curve_intersect(curve1, curve2_new) {
496 None => NoIntersection,
497 Some(s) => {
498 FoundIntersection(CubicQuad(s
499 .into_iter()
500 .map(|c| CubicQuadIntersection { curve1, curve2, t1: c.t1, t2: c.t2 })
501 .collect())
502 )
503 }
504 }
505}
506
507pub(crate) fn cubic_cubic_intersect(curve1: CubicCurve, curve2: CubicCurve) -> IntersectionResult {
508 use self::{Intersection::*, IntersectionResult::*};
509
510 if curve1 == curve2 {
511 return Infinite(InfiniteIntersections::CubicCubic(curve1, curve2));
512 }
513
514 if (curve1.0 == curve1.1 && curve1.1 == curve1.2) || (curve2.0 == curve2.1 && curve2.1 == curve2.2) {
515 return NoIntersection;
516 }
517
518 match do_curve_curve_intersect(curve1, curve2) {
519 None => NoIntersection,
520 Some(s) => FoundIntersection(CubicCubic(s)),
521 }
522}
523
524#[inline]
525pub(crate) fn split_line(line: Line, t: f64) -> (Line, Line) {
526 let t = t.max(0.0).min(1.0);
527 let split_point = lerp(line.0, line.1, t);
528 (
529 (line.0, split_point),
530 (split_point, line.1),
531 )
532}
533
534#[inline]
535pub(crate) fn split_quad(curve: QuadraticCurve, t: f64) -> (QuadraticCurve, QuadraticCurve) {
536 let t = t.max(0.0).min(1.0);
537 let p = quad_hull_points(curve, t);
538 ((p[0], p[3], p[5]), (p[5], p[4], p[2]))
539}
540
541#[inline]
542pub(crate) fn split_cubic(curve: CubicCurve, t: f64) -> (CubicCurve, CubicCurve) {
543 let t = t.max(0.0).min(1.0);
544 subdivide(curve, t)
545}
546
547#[inline]
554fn do_line_line_intersect(
555 (a, b): Line,
556 (c, d): Line,
557) -> Option<LineLineIntersection> {
558
559 let (original_a, original_b) = (a, b);
560 let (original_c, original_d) = (c, d);
561
562 let b = Point::new(b.x - a.x, b.y - a.y);
564 let mut c = Point::new(c.x - a.x, c.y - a.y);
565 let mut d = Point::new(d.x - a.x, d.y - a.y);
566
567 let dist_ab = (b.x*b.x + b.y*b.y).sqrt();
569
570 let cos_b = b.x / dist_ab;
572 let sin_b = b.y / dist_ab;
573
574 let new_x = c.x * cos_b + c.y * sin_b;
576 c.y = c.y * cos_b - c.x * sin_b;
577 c.x = new_x;
578
579 let new_x = d.x * cos_b + d.y * sin_b;
580 d.y = d.y * cos_b - d.x * sin_b;
581 d.x = new_x;
582
583 if c.y == d.y {
585 return None;
586 }
587
588 let t = d.x + (c.x - d.x) * d.y / (d.y - c.y);
590
591 let new_x = original_a.x + t * cos_b;
592 let new_y = original_a.y + t * sin_b;
593
594 let t1 = (
596 ((new_x - original_a.x) / (original_b.x - original_a.x)) +
597 ((new_y - original_a.y) / (original_b.y - original_a.y))
598 ) / 2.0;
599
600 let t2 = (
602 ((new_x - original_c.x) / (original_d.x - original_c.x)) +
603 ((new_y - original_c.y) / (original_d.y - original_c.y))
604 ) / 2.0;
605
606 Some(LineLineIntersection {
607 t1,
608 line1: (original_a, original_b),
609 t2,
610 line2: (original_c, original_d),
611 })
612}
613
614#[inline]
619fn do_curve_line_intersect(
620 (a1, a2, a3, a4): CubicCurve,
621 (b1, b2): Line,
622) -> OptionTuple<(f64, f64)> {
623
624 let numbers = [a1.x, a1.y, a2.x, a2.y, a3.x, a3.y, a4.x, a4.y, b1.x, b1.y, b2.x, b2.y];
628 let mut lowest_number = 0.0_f64;
629 for n in &numbers { lowest_number = lowest_number.min(*n); }
630 let smallest_number_abs = lowest_number.abs();
631 let multiplier = if smallest_number_abs != 0.0 { 100.0 / smallest_number_abs } else { 100.0 };
632
633 let a1 = Point::new(round_3(a1.x * multiplier), round_3(a1.y * multiplier));
634 let a2 = Point::new(round_3(a2.x * multiplier), round_3(a2.y * multiplier));
635 let a3 = Point::new(round_3(a3.x * multiplier), round_3(a3.y * multiplier));
636 let a4 = Point::new(round_3(a4.x * multiplier), round_3(a4.y * multiplier));
637 let b1 = Point::new(round_3(b1.x * multiplier), round_3(b1.y * multiplier));
638 let b2 = Point::new(round_3(b2.x * multiplier), round_3(b2.y * multiplier));
639
640 #[inline]
641 fn round_3(input: f64) -> f64 {
642 ((input * 1000.0_f64) as u64) as f64 / 1000.0_f64
643 }
644
645 let A = b2.y - b1.y; let B = b1.x - b2.x; let C = b1.x * (b1.y - b2.y) + b1.y * (b2.x - b1.x); let bx = bezier_coeffs(a1.x, a2.x, a3.x, a4.x);
650 let by = bezier_coeffs(a1.y, a2.y, a3.y, a4.y);
651
652 let p_0 = A * bx.0 + B * by.0; let p_1 = A * bx.1 + B * by.1; let p_2 = A * bx.2 + B * by.2; let p_3 = A * bx.3 + B * by.3 + C; let r = cubic_roots(p_0, p_1, p_2, p_3);
658
659 let mut intersections = (None, None, None);
660
661 macro_rules! unroll_loop {($index:tt) => ({
663 if let Some(t) = r.$index {
664
665 let final_x = bx.0* t * t * t + bx.1 * t * t + bx.2 * t + bx.3;
666 let final_y = by.0* t * t * t + by.1 * t * t + by.2 * t + by.3;
667
668 let x_dist = b2.x - b1.x;
672 let y_dist = b2.y - b1.y;
673
674 let t_line = if x_dist != 0.0 {
675 (final_x - b1.x) / x_dist
677 } else {
678 (final_y - b1.y) / y_dist
679 };
680
681 intersections.$index = if !t.is_sign_positive() || t > 1.0 || !t_line.is_sign_positive() || t_line > 1.0 {
682 None
683 } else {
684 Some((t_line as f64, t as f64))
685 }
686 }
687 })}
688
689 unroll_loop!(0);
690 unroll_loop!(1);
691 unroll_loop!(2);
692
693 intersections
694}
695
696fn do_curve_curve_intersect(a: CubicCurve, b: CubicCurve) -> Option<Vec<CubicCubicIntersection>> {
698
699 let intersections = curve_intersections_inner(a, b, 0.0, 1.0, 0.0, 1.0, 1.0, false, 0, 32, 0.8);
700
701 if intersections.is_empty() {
702 None
703 } else {
704 Some(intersections)
705 }
706}
707
708
709
710#[inline(always)]
718fn quad_hull_points(curve: QuadraticCurve, t: f64) -> [Point;6] {
719 let (p0, p1, p2) = curve;
720
721 let p3 = lerp(p0, p1, t);
723 let p4 = lerp(p1, p2, t);
724
725 let p5 = lerp(p3, p4, t);
727
728 [p0, p1, p2, p3, p4, p5]
729}
730
731#[inline]
733pub(crate) fn cubic_bezier_normal(curve: CubicCurve, t: f64) -> BezierNormalVector {
734
735 let weight_1_x = 3.0 * (curve.1.x - curve.0.x);
745 let weight_1_y = 3.0 * (curve.1.y - curve.0.y);
746
747 let weight_2_x = 3.0 * (curve.2.x - curve.1.x);
748 let weight_2_y = 3.0 * (curve.2.y - curve.1.y);
749
750 let weight_3_x = 3.0 * (curve.3.x - curve.2.x);
751 let weight_3_y = 3.0 * (curve.3.y - curve.2.y);
752
753 let mut tangent = quadratic_evaluate((
757 Point { x: weight_1_x, y: weight_1_y },
758 Point { x: weight_2_x, y: weight_2_y },
759 Point { x: weight_3_x, y: weight_3_y },
760 ), t);
761
762 let tangent_length = (tangent.x.powi(2) + tangent.y.powi(2)).sqrt();
764 tangent.x /= tangent_length;
765 tangent.y /= tangent_length;
766
767 BezierNormalVector {
774 x: -tangent.y,
775 y: tangent.x,
776 }
777}
778
779#[inline]
781pub(crate) fn quadratic_bezier_normal(curve: QuadraticCurve, t: f64) -> BezierNormalVector {
782 cubic_bezier_normal(quadratic_to_cubic_curve(curve), t)
783}
784
785#[inline]
787pub(crate) fn line_normal(line: Line, _t: f64) -> BezierNormalVector {
788 let diff_x = line.1.x - line.0.x;
791 let diff_y = line.1.y - line.0.y;
792 let line_length = (diff_x.powi(2) + diff_y.powi(2)).sqrt();
793 BezierNormalVector {
794 x: -diff_y / line_length,
795 y: diff_x / line_length,
796 }
797}
798
799#[inline]
800fn quadratic_evaluate(curve: QuadraticCurve, t: f64) -> Point {
801 let one_minus = 1.0 - t;
802 let one_minus_square = one_minus.powi(2);
803
804 let t_pow2 = t.powi(2);
805
806 let x = one_minus_square * curve.0.x
807 + 2.0 * one_minus * t * curve.1.x
808 + 3.0 * t_pow2 * curve.2.x;
809
810 let y = one_minus_square * curve.0.y
811 + 2.0 * one_minus * t * curve.1.y
812 + 3.0 * t_pow2 * curve.2.y;
813
814 Point { x, y }
815}
816
817#[inline(always)]
819fn cubic_roots(a: f64, b: f64, c: f64, d: f64) -> (Option<f64>, Option<f64>, Option<f64>) {
820
821 use std::f64::consts::PI;
822
823 if is_zero(a) {
825 if is_zero(b) {
826 let p = -1.0 * (d / c);
829
830 let ret = (
831 if !p.is_sign_positive() || p > 1.0 { None } else { Some(p) },
832 None,
833 None
834 );
835
836 let ret = sort_special(ret);
837
838 return ret;
839 } else {
840 let d_q = c.powi(2) - 4.0 * b * d;
842
843 if d_q.is_sign_positive() {
844 let d_q = d_q.sqrt();
845
846 let m = -1.0 * (d_q + c) / (2.0 * b);
847 let n = (d_q - c) / (2.0 * b);
848
849 let ret = (
850 if !m.is_sign_positive() || m > 1.0 { None } else { Some(m) },
851 if !n.is_sign_positive() || n > 1.0 { None } else { Some(n) },
852 None,
853 );
854
855 let ret = sort_special(ret);
856
857 return ret;
858 }
859 }
860 }
861
862 let A = b / a;
863 let B = c / a;
864 let C = d / a;
865
866 let Q = (3.0 * B - (A*A)) / 9.0;
867 let R = (9.0 * A * B - 27.0 * C - 2.0 * (A*A*A)) / 54.0;
868 let D = Q*Q*Q + R*R; let ret = if D.is_sign_positive() {
871
872 const ONE_THIRD: f64 = 1.0 / 3.0;
874
875 let D_sqrt = D.sqrt();
876 let S = sign(R + D_sqrt) * (R + D_sqrt).abs().powf(ONE_THIRD);
877 let T = sign(R - D_sqrt) * (R - D_sqrt).abs().powf(ONE_THIRD);
878
879 let m = -A / 3.0 + (S + T); let n = -A / 3.0 - (S + T) / 2.0; let p = -A / 3.0 - (S + T) / 2.0; let mut ret = (
884 if !m.is_sign_positive() || m > 1.0 { None } else { Some(m) },
885 if !n.is_sign_positive() || n > 1.0 { None } else { Some(n) },
886 if !p.is_sign_positive() || p > 1.0 { None } else { Some(p) },
887 );
888
889 let imaginary = (3.0_f64.sqrt() * (S - T) / 2.0).abs(); if !is_zero(imaginary) {
893 ret.1 = None;
894 ret.2 = None;
895 }
896
897 ret
898 } else {
899
900 let th = (R / (-1.0 * Q.powi(3)).sqrt()).acos();
901 let minus_q_sqrt = (-1.0 * Q).sqrt();
902
903 let m = 2.0 * minus_q_sqrt * (th / 3.0).cos() - A / 3.0;
904 let n = 2.0 * minus_q_sqrt * ((th + 2.0 * PI) / 3.0).cos() - A / 3.0;
905 let p = 2.0 * minus_q_sqrt * ((th + 4.0 * PI) / 3.0).cos() - A / 3.0;
906
907 (
909 if !m.is_sign_positive() || m > 1.0 { None } else { Some(m) },
910 if !n.is_sign_positive() || n > 1.0 { None } else { Some(n) },
911 if !p.is_sign_positive() || p > 1.0 { None } else { Some(p) },
912 )
913 };
914
915 let ret = sort_special(ret);
917
918 ret
919}
920
921#[inline]
922fn sign(a: f64) -> f64 {
923 if a.is_sign_positive() { 1.0 } else { -1.0 }
924}
925
926#[inline]
927fn bezier_coeffs(a: f64, b: f64, c: f64, d: f64) -> (f64, f64, f64, f64) {
928 (
929 -a + 3.0*b + -3.0*c + d,
930 3.0*a - 6.0*b + 3.0*c,
931 -3.0*a + 3.0*b,
932 a
933 )
934}
935
936#[inline]
938fn sort_special(a: OptionTuple<f64>) -> OptionTuple<f64> {
939 match a {
940 (None, None, None) => (None, None, None),
941 (Some(a), None, None) |
942 (None, Some(a), None) |
943 (None, None, Some(a)) => (Some(a), None, None),
944 (Some(a), Some(b), None) |
945 (None, Some(a), Some(b)) |
946 (Some(b), None, Some(a)) => (Some(a.min(b)), Some(a.max(b)), None),
947 (Some(a), Some(b), Some(c)) => {
948 let new_a = a.min(b).min(c);
949 let new_b = if a < b && b < c { b } else if b < c && c < a { c } else { a };
950 let new_c = a.max(b).max(c);
951 (Some(new_a), Some(new_b), Some(new_c))
952 }
953 }
954}
955
956#[inline]
958fn quadratic_to_cubic_curve(c: QuadraticCurve) -> CubicCurve {
959 const TWO_THIRDS: f64 = 2.0 / 3.0;
960
961 let c1_x = c.0.x + TWO_THIRDS * (c.1.x - c.0.x);
962 let c1_y = c.0.y + TWO_THIRDS * (c.1.y - c.0.y);
963
964 let c2_x = c.2.x + TWO_THIRDS * (c.1.x - c.2.x);
965 let c2_y = c.2.y + TWO_THIRDS * (c.1.y - c.2.y);
966
967 (c.0, Point::new(c1_x, c1_y), Point::new(c2_x, c2_y), c.2)
968}
969
970const TOLERANCE:f64 = 1e-5;
977const EPSILON: f64 = 1e-10;
978
979#[inline]
980fn is_zero(val: f64) -> bool {
981 val.abs() <= EPSILON
982}
983
984#[inline]
986fn signed_distance(px: f64, py: f64, mut vx: f64, mut vy: f64, x: f64, y: f64) -> f64 {
987 vx -= px;
988 vy -= py;
989 if is_zero(vx) {
990 if vy.is_sign_positive() { px - x } else { x - px }
991 } else if is_zero(vy) {
992 if vx.is_sign_positive() { y - py } else { py - y }
993 } else {
994 (vx * (y - py) - vy * (x - px)) / (vx * vx + vy * vy).sqrt()
995 }
996}
997
998#[inline]
1011fn convex_hull(dq0: f64, dq1: f64, dq2: f64, dq3: f64) -> [Vec<[f64;2]>;2] {
1012
1013 let p0 = [0.0, dq0];
1014 let p1 = [1.0 / 3.0, dq1];
1015 let p2 = [2.0 / 3.0, dq2];
1016 let p3 = [1.0, dq3];
1017
1018 let dist1 = signed_distance(0.0, dq0, 1.0, dq3, 1.0 / 3.0, dq1);
1020 let dist2 = signed_distance(0.0, dq0, 1.0, dq3, 2.0 / 3.0, dq2);
1021
1022 let (mut hull, flip) = if dist1 * dist2 < 0.0 {
1024 let hull = [vec![p0, p1, p3], vec![p0, p2, p3]];
1030 let flip = dist1 < 0.0;
1031 (hull, flip)
1032 } else {
1033 let (cross, pmax) = if dist1.abs() > dist2.abs() {
1039 let cross = (dq3 - dq2 - (dq3 - dq0) / 3.0) * (2.0 * (dq3 - dq2) - dq3 + dq1) / 3.0;
1042 (cross, p1)
1043 } else {
1044 let cross = (dq1 - dq0 + (dq0 - dq3) / 3.0) * (-2.0 * (dq0 - dq1) + dq0 - dq2) / 3.0;
1048 (cross, p2)
1049 };
1050
1051 let distZero = is_zero(dist1) || is_zero(dist2);
1052
1053 let hull = if cross < 0.0 || distZero {
1056 [vec![p0, pmax, p3], vec![p0, p3]]
1057 } else {
1058 [vec![p0, p1, p2, p3], vec![p0, p3]]
1059 };
1060
1061 let flip = if is_zero(dist1) { !dist2.is_sign_positive() } else { !dist1.is_sign_positive() };
1062
1063 (hull, flip)
1064 };
1065
1066 if flip {
1067 hull.reverse();
1068 }
1069
1070 hull
1071}
1072
1073#[inline]
1075fn clip_convex_hull(hullTop: &[[f64;2]], hullBottom: &[[f64;2]], dMin: f64, dMax: f64) -> Option<f64> {
1076 if hullTop[0][1] < dMin {
1077 clip_convex_hull_part(hullTop, true, dMin)
1080 } else if hullBottom[0][1] > dMax {
1081 clip_convex_hull_part(hullBottom, false, dMax)
1084 } else {
1085 Some(hullTop[0][0])
1087 }
1088}
1089
1090#[inline]
1091fn clip_convex_hull_part(part: &[[f64;2]], top: bool, threshold: f64) -> Option<f64> {
1092 let mut pxpy = part[0];
1093
1094 for [qx, qy] in part.iter().copied() {
1095 let [px, py] = pxpy;
1096 let a = if top { qy >= threshold } else { qy <= threshold };
1097 if a {
1098 return Some(px + (threshold - py) * (qx - px) / (qy - py));
1099 }
1100 pxpy = [qx, qy];
1101 }
1102
1103 None
1105}
1106
1107#[inline]
1110fn get_fatline((p0, p1, p2, p3): CubicCurve) -> (f64, f64) {
1111
1112 let d1 = signed_distance(p0.x, p0.y, p3.x, p3.y, p1.x, p1.y);
1115 let d2 = signed_distance(p0.x, p0.y, p3.x, p3.y, p2.x, p2.y);
1116 let factor = if (d1 * d2).is_sign_positive() { 3.0 / 4.0 } else { 4.0 / 9.0 }; let dMin = factor * 0.0_f64.min(d1).min(d2);
1118 let dMax = factor * 0.0_f64.max(d1).max(d2);
1119
1120 (dMin, dMax)
1122}
1123
1124#[inline]
1125fn subdivide((p1, c1, c2, p2): CubicCurve, t: f64) -> (CubicCurve, CubicCurve) {
1126
1127 let u = 1.0 - t;
1129
1130 let p3x = u * p1.x + t * c1.x;
1132 let p3y = u * p1.y + t * c1.y;
1133 let p4x = u * c1.x + t * c2.x;
1134 let p4y = u * c1.y + t * c2.y;
1135 let p5x = u * c2.x + t * p2.x;
1136 let p5y = u * c2.y + t * p2.y;
1137
1138 let p6x = u * p3x + t * p4x;
1140 let p6y = u * p3y + t * p4y;
1141 let p7x = u * p4x + t * p5x;
1142 let p7y = u * p4y + t * p5y;
1143
1144 let p8x = u * p6x + t * p7x;
1146 let p8y = u * p6y + t * p7y;
1147
1148 (
1150 (p1, Point::new(p3x, p3y), Point::new(p6x, p6y), Point::new(p8x, p8y)),
1151 (Point::new(p8x, p8y), Point::new(p7x, p7y), Point::new(p5x, p5y), p2)
1152 )
1153}
1154
1155#[inline]
1157fn get_part(mut v: CubicCurve, t1: f64, t2: f64) -> CubicCurve {
1158
1159 if t1.is_sign_positive() {
1160 v = subdivide(v, t1).1; }
1162
1163 if t2 < 1.0 {
1165 v = subdivide(v, (t2 - t1) / (1.0 - t1)).0; }
1167
1168 v
1169}
1170
1171#[inline]
1173fn evaluate((p1, c1, c2, p2): CubicCurve, t: f64) -> Point {
1174
1175 if t < TOLERANCE || t > (1.0 - TOLERANCE) {
1177 let is_zero = t < TOLERANCE;
1178 let x = if is_zero { p1.x } else { p2.x };
1179 let y = if is_zero { p1.y } else { p2.y };
1180 Point::new(x, y)
1181 } else {
1182 let cx = 3.0 * (c1.x - p1.x);
1184 let bx = 3.0 * (c2.x - c1.x) - cx;
1185 let ax = p2.x - p1.x - cx - bx;
1186
1187 let cy = 3.0 * (c1.y - p1.y);
1188 let by = 3.0 * (c2.y - c1.y) - cy;
1189 let ay = p2.y - p1.y - cy - by;
1190
1191 let x = ((ax * t + bx) * t + cx) * t + p1.x;
1193 let y = ((ay * t + by) * t + cy) * t + p1.y;
1194
1195 Point::new(x, y)
1196 }
1197}
1198
1199#[inline]
1201fn curve_intersections_inner(
1202 mut v1: CubicCurve,
1203 v2: CubicCurve,
1204 tMin: f64,
1205 tMax: f64,
1206 uMin: f64,
1207 uMax: f64,
1208 oldTDiff: f64,
1209 reverse: bool,
1210 recursion: usize,
1211 recursionLimit: usize,
1212 tLimit: f64
1213) -> Vec<CubicCubicIntersection> {
1214
1215 if recursion > recursionLimit {
1222 return Vec::new();
1223 }
1224
1225 let (dMin, dMax) = get_fatline(v2);
1230
1231 let dp0 = signed_distance(v2.0.x, v2.0.y, v2.3.x, v2.3.y, v1.0.x, v1.0.y);
1235 let dp1 = signed_distance(v2.0.x, v2.0.y, v2.3.x, v2.3.y, v1.1.x, v1.1.y);
1236 let dp2 = signed_distance(v2.0.x, v2.0.y, v2.3.x, v2.3.y, v1.2.x, v1.2.y);
1237 let dp3 = signed_distance(v2.0.x, v2.0.y, v2.3.x, v2.3.y, v1.3.x, v1.3.y);
1238
1239 let (tMinNew, tMaxNew, tDiff) = if v2.0.x == v2.3.x && uMax - uMin <= EPSILON && recursion > 4 {
1242 let tNew = (tMax + tMin) / 2.0;
1246 (tNew, tNew, 0.0)
1247 } else {
1248 let [mut top, mut bottom] = convex_hull(dp0, dp1, dp2, dp3);
1250
1251 let tMinClip = clip_convex_hull(&top, &bottom, dMin, dMax);
1253 top.reverse();
1254 bottom.reverse();
1255 let tMaxClip = clip_convex_hull(&top, &bottom, dMin, dMax);
1256
1257 let (tMinClip, tMaxClip) = match (tMinClip, tMaxClip) {
1259 (Some(min), Some(max)) => (min, max),
1260 _ => return Vec::new(),
1261 };
1262
1263 v1 = get_part(v1, tMinClip, tMaxClip);
1265
1266 let tDiff = tMaxClip - tMinClip;
1269 let tMinNew = tMax * tMinClip + tMin * (1.0 - tMinClip);
1270 let tMaxNew = tMax * tMaxClip + tMin * (1.0 - tMaxClip);
1271
1272 (tMinNew, tMaxNew, tDiff)
1273 };
1274
1275 if oldTDiff > tLimit && tDiff > tLimit {
1277 if tMaxNew - tMinNew > uMax - uMin {
1279 let parts = subdivide(v1, 0.5);
1280 let t = tMinNew + (tMaxNew - tMinNew) / 2.0;
1281 let mut intersections = Vec::new();
1282 intersections.append(&mut curve_intersections_inner(v2, parts.0, uMin, uMax, tMinNew, t, tDiff, !reverse, recursion + 1, recursionLimit, tLimit));
1283 intersections.append(&mut curve_intersections_inner(v2, parts.1, uMin, uMax, t, tMaxNew, tDiff, !reverse, recursion + 1, recursionLimit, tLimit));
1284 intersections
1285 } else {
1286 let parts = subdivide(v2, 0.5);
1287 let t = uMin + (uMax - uMin) / 2.0;
1288 let mut intersections = Vec::new();
1289 intersections.append(&mut curve_intersections_inner(parts.0, v1, uMin, t, tMinNew, tMaxNew, tDiff, !reverse, recursion + 1, recursionLimit, tLimit));
1290 intersections.append(&mut curve_intersections_inner(parts.1, v1, t, uMax, tMinNew, tMaxNew, tDiff, !reverse, recursion + 1, recursionLimit, tLimit));
1291 intersections
1292 }
1293 } else if (uMax - uMin).max(tMaxNew - tMinNew) < TOLERANCE {
1294 let t1 = tMinNew + (tMaxNew - tMinNew) / 2.0;
1296 let t2 = uMin + (uMax - uMin) / 2.0;
1297 if reverse {
1298 vec![CubicCubicIntersection {
1299 t1: t2,
1300 curve1: v2,
1301 t2: t1,
1302 curve2: v1,
1303 }]
1304 } else {
1305 vec![CubicCubicIntersection {
1306 t1,
1307 curve1: v1,
1308 t2,
1309 curve2: v2,
1310 }]
1311 }
1312 } else {
1313 curve_intersections_inner(v2, v1, uMin, uMax, tMinNew, tMaxNew, tDiff, !reverse, recursion + 1, recursionLimit, tLimit)
1315 }
1316}
1317
1318#[inline(always)]
1319fn lerp(p1: Point, p2: Point, t: f64) -> Point {
1320 let new_x = (1.0 - t) * p1.x + t * p2.x;
1321 let new_y = (1.0 - t) * p1.y + t * p2.y;
1322 Point::new(new_x, new_y)
1323}