1use crate::scalar::Scalar;
2use crate::segment::Segment;
3use crate::traits::Transformation;
4use crate::{point, Box2D, Point, Vector};
5use crate::{CubicBezierSegment, Line, LineEquation, LineSegment, Triangle};
6use arrayvec::ArrayVec;
7use num_traits::NumCast;
8
9use core::mem;
10use core::ops::Range;
11
12#[derive(Copy, Clone, Debug, PartialEq)]
18#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
19pub struct QuadraticBezierSegment<S> {
20 pub from: Point<S>,
21 pub ctrl: Point<S>,
22 pub to: Point<S>,
23}
24
25impl<S: Scalar> QuadraticBezierSegment<S> {
26 pub fn cast<NewS: NumCast>(self) -> QuadraticBezierSegment<NewS> {
27 QuadraticBezierSegment {
28 from: self.from.cast(),
29 ctrl: self.ctrl.cast(),
30 to: self.to.cast(),
31 }
32 }
33
34 pub fn sample(&self, t: S) -> Point<S> {
36 let t2 = t * t;
37 let one_t = S::ONE - t;
38 let one_t2 = one_t * one_t;
39
40 self.from * one_t2 + self.ctrl.to_vector() * S::TWO * one_t * t + self.to.to_vector() * t2
41 }
42
43 pub fn x(&self, t: S) -> S {
45 let t2 = t * t;
46 let one_t = S::ONE - t;
47 let one_t2 = one_t * one_t;
48
49 self.from.x * one_t2 + self.ctrl.x * S::TWO * one_t * t + self.to.x * t2
50 }
51
52 pub fn y(&self, t: S) -> S {
54 let t2 = t * t;
55 let one_t = S::ONE - t;
56 let one_t2 = one_t * one_t;
57
58 self.from.y * one_t2 + self.ctrl.y * S::TWO * one_t * t + self.to.y * t2
59 }
60
61 #[inline]
62 fn derivative_coefficients(&self, t: S) -> (S, S, S) {
63 (S::TWO * t - S::TWO, -S::FOUR * t + S::TWO, S::TWO * t)
64 }
65
66 pub fn derivative(&self, t: S) -> Vector<S> {
68 let (c0, c1, c2) = self.derivative_coefficients(t);
69 self.from.to_vector() * c0 + self.ctrl.to_vector() * c1 + self.to.to_vector() * c2
70 }
71
72 pub fn dx(&self, t: S) -> S {
74 let (c0, c1, c2) = self.derivative_coefficients(t);
75 self.from.x * c0 + self.ctrl.x * c1 + self.to.x * c2
76 }
77
78 pub fn dy(&self, t: S) -> S {
80 let (c0, c1, c2) = self.derivative_coefficients(t);
81 self.from.y * c0 + self.ctrl.y * c1 + self.to.y * c2
82 }
83
84 pub fn flip(&self) -> Self {
86 QuadraticBezierSegment {
87 from: self.to,
88 ctrl: self.ctrl,
89 to: self.from,
90 }
91 }
92
93 pub fn y_maximum_t(&self) -> S {
97 if let Some(t) = self.local_y_extremum_t() {
98 let y = self.y(t);
99 if y > self.from.y && y > self.to.y {
100 return t;
101 }
102 }
103
104 if self.from.y > self.to.y {
105 S::ZERO
106 } else {
107 S::ONE
108 }
109 }
110
111 pub fn y_minimum_t(&self) -> S {
115 if let Some(t) = self.local_y_extremum_t() {
116 let y = self.y(t);
117 if y < self.from.y && y < self.to.y {
118 return t;
119 }
120 }
121
122 if self.from.y < self.to.y {
123 S::ZERO
124 } else {
125 S::ONE
126 }
127 }
128
129 pub fn local_y_extremum_t(&self) -> Option<S> {
131 let div = self.from.y - S::TWO * self.ctrl.y + self.to.y;
132 if div == S::ZERO {
133 return None;
134 }
135 let t = (self.from.y - self.ctrl.y) / div;
136 if t > S::ZERO && t < S::ONE {
137 return Some(t);
138 }
139
140 None
141 }
142
143 pub fn x_maximum_t(&self) -> S {
147 if let Some(t) = self.local_x_extremum_t() {
148 let x = self.x(t);
149 if x > self.from.x && x > self.to.x {
150 return t;
151 }
152 }
153
154 if self.from.x > self.to.x {
155 S::ZERO
156 } else {
157 S::ONE
158 }
159 }
160
161 pub fn x_minimum_t(&self) -> S {
165 if let Some(t) = self.local_x_extremum_t() {
166 let x = self.x(t);
167 if x < self.from.x && x < self.to.x {
168 return t;
169 }
170 }
171
172 if self.from.x < self.to.x {
173 S::ZERO
174 } else {
175 S::ONE
176 }
177 }
178
179 pub fn local_x_extremum_t(&self) -> Option<S> {
181 let div = self.from.x - S::TWO * self.ctrl.x + self.to.x;
182 if div == S::ZERO {
183 return None;
184 }
185 let t = (self.from.x - self.ctrl.x) / div;
186 if t > S::ZERO && t < S::ONE {
187 return Some(t);
188 }
189
190 None
191 }
192
193 pub fn split_range(&self, t_range: Range<S>) -> Self {
197 let t0 = t_range.start;
198 let t1 = t_range.end;
199
200 let from = self.sample(t0);
201 let to = self.sample(t1);
202 let ctrl = from + (self.ctrl - self.from).lerp(self.to - self.ctrl, t0) * (t1 - t0);
203
204 QuadraticBezierSegment { from, ctrl, to }
205 }
206
207 pub fn split(&self, t: S) -> (QuadraticBezierSegment<S>, QuadraticBezierSegment<S>) {
209 let split_point = self.sample(t);
210
211 (
212 QuadraticBezierSegment {
213 from: self.from,
214 ctrl: self.from.lerp(self.ctrl, t),
215 to: split_point,
216 },
217 QuadraticBezierSegment {
218 from: split_point,
219 ctrl: self.ctrl.lerp(self.to, t),
220 to: self.to,
221 },
222 )
223 }
224
225 pub fn before_split(&self, t: S) -> QuadraticBezierSegment<S> {
227 QuadraticBezierSegment {
228 from: self.from,
229 ctrl: self.from.lerp(self.ctrl, t),
230 to: self.sample(t),
231 }
232 }
233
234 pub fn after_split(&self, t: S) -> QuadraticBezierSegment<S> {
236 QuadraticBezierSegment {
237 from: self.sample(t),
238 ctrl: self.ctrl.lerp(self.to, t),
239 to: self.to,
240 }
241 }
242
243 pub fn to_cubic(&self) -> CubicBezierSegment<S> {
245 CubicBezierSegment {
246 from: self.from,
247 ctrl1: (self.from + self.ctrl.to_vector() * S::TWO) / S::THREE,
248 ctrl2: (self.to + self.ctrl.to_vector() * S::TWO) / S::THREE,
249 to: self.to,
250 }
251 }
252
253 #[inline]
254 pub fn baseline(&self) -> LineSegment<S> {
255 LineSegment {
256 from: self.from,
257 to: self.to,
258 }
259 }
260
261 pub fn is_a_point(&self, tolerance: S) -> bool {
264 let tol2 = tolerance * tolerance;
265 (self.from - self.to).square_length() <= tol2
266 && (self.from - self.ctrl).square_length() <= tol2
267 }
268
269 pub fn is_linear(&self, tolerance: S) -> bool {
272 if self.from == self.to {
273 return true;
274 }
275
276 let d = self
277 .baseline()
278 .to_line()
279 .square_distance_to_point(self.ctrl);
280
281 d <= (tolerance * tolerance * S::FOUR)
282 }
283
284 pub fn fat_line(&self) -> (LineEquation<S>, LineEquation<S>) {
289 let l1 = self.baseline().to_line().equation();
290 let d = S::HALF * l1.signed_distance_to_point(&self.ctrl);
291 let l2 = l1.offset(d);
292 if d >= S::ZERO {
293 (l1, l2)
294 } else {
295 (l2, l1)
296 }
297 }
298
299 #[inline]
301 pub fn transformed<T: Transformation<S>>(&self, transform: &T) -> Self {
302 QuadraticBezierSegment {
303 from: transform.transform_point(self.from),
304 ctrl: transform.transform_point(self.ctrl),
305 to: transform.transform_point(self.to),
306 }
307 }
308
309 pub fn flattening_step(&self, tolerance: S) -> S {
312 let v1 = self.ctrl - self.from;
313 let v2 = self.to - self.from;
314
315 let v1_cross_v2 = v2.x * v1.y - v2.y * v1.x;
316 let h = S::sqrt(v1.x * v1.x + v1.y * v1.y);
317
318 if S::abs(v1_cross_v2 * h) <= S::EPSILON {
319 return S::ONE;
320 }
321
322 let s2inv = h / v1_cross_v2;
323
324 let t = S::TWO * S::sqrt(tolerance * S::abs(s2inv) / S::THREE);
325
326 if t > S::ONE {
327 return S::ONE;
328 }
329
330 t
331 }
332
333 pub fn for_each_flattened<F>(&self, tolerance: S, callback: &mut F)
338 where
339 F: FnMut(&LineSegment<S>),
340 {
341 debug_assert!(tolerance >= S::EPSILON * S::EPSILON);
342
343 let n = flattened_segments_wang(self, tolerance);
344 let step = S::ONE / n;
345 let mut t = step;
346
347 let curve = self.polynomial_form();
348
349 let n = n.to_u32().unwrap_or(1) - 1;
350 let mut from = self.from;
351 for _ in 0..n {
352 let to = curve.sample(t);
353 callback(&LineSegment { from, to });
354 from = to;
355 t += step;
356 }
357
358 callback(&LineSegment { from, to: self.to });
359 }
360
361 pub fn for_each_flattened_with_t<F>(&self, tolerance: S, callback: &mut F)
369 where
370 F: FnMut(&LineSegment<S>, Range<S>),
371 {
372 debug_assert!(tolerance >= S::EPSILON * S::EPSILON);
373
374 let n = flattened_segments_wang(self, tolerance);
375 let step = S::ONE / n;
376 let mut t0 = S::ZERO;
377
378 let curve = self.polynomial_form();
379
380 let n = n.to_u32().unwrap_or(1) - 1;
381 let mut from = self.from;
382 for _ in 0..n {
383 let t1 = t0 + step;
384 let to = curve.sample(t1);
385 callback(&LineSegment { from, to }, t0..t1);
386 from = to;
387 t0 = t1;
388 }
389
390 callback(&LineSegment { from, to: self.to }, t0..S::ONE);
391 }
392
393 pub fn flattened(&self, tolerance: S) -> Flattened<S> {
396 Flattened::new(self, tolerance)
397 }
398 pub fn flattened_t(&self, tolerance: S) -> FlattenedT<S> {
401 FlattenedT::new(self, tolerance)
402 }
403
404 pub fn for_each_monotonic_range<F>(&self, cb: &mut F)
406 where
407 F: FnMut(Range<S>),
408 {
409 let mut t0 = self.local_x_extremum_t();
410 let mut t1 = self.local_y_extremum_t();
411
412 let swap = match (t0, t1) {
413 (Some(tx), Some(ty)) => tx > ty,
414 _ => false,
415 };
416
417 if swap {
418 mem::swap(&mut t0, &mut t1);
419 }
420
421 let mut start = S::ZERO;
422
423 if let Some(t) = t0 {
424 cb(start..t);
425 start = t;
426 }
427
428 if let Some(t) = t1 {
429 if t != start {
431 cb(start..t);
432 start = t
433 }
434 }
435
436 cb(start..S::ONE);
437 }
438
439 pub fn for_each_monotonic<F>(&self, cb: &mut F)
441 where
442 F: FnMut(&QuadraticBezierSegment<S>),
443 {
444 self.for_each_monotonic_range(&mut |range| {
445 let mut sub = self.split_range(range);
446 let min_x = sub.from.x.min(sub.to.x);
449 let max_x = sub.from.x.max(sub.to.x);
450 let min_y = sub.from.y.min(sub.to.y);
451 let max_y = sub.from.y.max(sub.to.y);
452 sub.ctrl.x = sub.ctrl.x.max(min_x).min(max_x);
453 sub.ctrl.y = sub.ctrl.y.max(min_y).min(max_y);
454 cb(&sub);
455 });
456 }
457
458 pub fn for_each_y_monotonic_range<F>(&self, cb: &mut F)
460 where
461 F: FnMut(Range<S>),
462 {
463 match self.local_y_extremum_t() {
464 Some(t) => {
465 cb(S::ZERO..t);
466 cb(t..S::ONE);
467 }
468 None => {
469 cb(S::ZERO..S::ONE);
470 }
471 }
472 }
473
474 pub fn for_each_y_monotonic<F>(&self, cb: &mut F)
476 where
477 F: FnMut(&QuadraticBezierSegment<S>),
478 {
479 match self.local_y_extremum_t() {
480 Some(t) => {
481 let (a, b) = self.split(t);
482 cb(&a);
483 cb(&b);
484 }
485 None => {
486 cb(self);
487 }
488 }
489 }
490
491 pub fn for_each_x_monotonic_range<F>(&self, cb: &mut F)
493 where
494 F: FnMut(Range<S>),
495 {
496 match self.local_x_extremum_t() {
497 Some(t) => {
498 cb(S::ZERO..t);
499 cb(t..S::ONE);
500 }
501 None => {
502 cb(S::ZERO..S::ONE);
503 }
504 }
505 }
506
507 pub fn for_each_x_monotonic<F>(&self, cb: &mut F)
509 where
510 F: FnMut(&QuadraticBezierSegment<S>),
511 {
512 match self.local_x_extremum_t() {
513 Some(t) => {
514 let (mut a, mut b) = self.split(t);
515 let a_min = a.from.x.min(a.to.x);
518 let a_max = a.from.x.max(a.to.x);
519 let b_min = b.from.x.min(b.to.x);
520 let b_max = b.from.x.max(b.to.x);
521 a.ctrl.x = a.ctrl.x.max(a_min).min(a_max);
522 b.ctrl.x = b.ctrl.x.max(b_min).min(b_max);
523 cb(&a);
524 cb(&b);
525 }
526 None => {
527 cb(self);
528 }
529 }
530 }
531
532 pub fn bounding_triangle(&self) -> Triangle<S> {
534 Triangle {
535 a: self.from,
536 b: self.ctrl,
537 c: self.to,
538 }
539 }
540
541 pub fn fast_bounding_box(&self) -> Box2D<S> {
543 let (min_x, max_x) = self.fast_bounding_range_x();
544 let (min_y, max_y) = self.fast_bounding_range_y();
545
546 Box2D {
547 min: point(min_x, min_y),
548 max: point(max_x, max_y),
549 }
550 }
551
552 pub fn fast_bounding_range_x(&self) -> (S, S) {
554 let min_x = self.from.x.min(self.ctrl.x).min(self.to.x);
555 let max_x = self.from.x.max(self.ctrl.x).max(self.to.x);
556
557 (min_x, max_x)
558 }
559
560 pub fn fast_bounding_range_y(&self) -> (S, S) {
562 let min_y = self.from.y.min(self.ctrl.y).min(self.to.y);
563 let max_y = self.from.y.max(self.ctrl.y).max(self.to.y);
564
565 (min_y, max_y)
566 }
567
568 pub fn bounding_box(&self) -> Box2D<S> {
570 let (min_x, max_x) = self.bounding_range_x();
571 let (min_y, max_y) = self.bounding_range_y();
572
573 Box2D {
574 min: point(min_x, min_y),
575 max: point(max_x, max_y),
576 }
577 }
578
579 pub fn bounding_range_x(&self) -> (S, S) {
581 let min_x = self.x(self.x_minimum_t());
582 let max_x = self.x(self.x_maximum_t());
583
584 (min_x, max_x)
585 }
586
587 pub fn bounding_range_y(&self) -> (S, S) {
589 let min_y = self.y(self.y_minimum_t());
590 let max_y = self.y(self.y_maximum_t());
591
592 (min_y, max_y)
593 }
594
595 pub fn is_x_monotonic(&self) -> bool {
597 self.local_x_extremum_t().is_none()
598 }
599
600 pub fn is_y_monotonic(&self) -> bool {
602 self.local_y_extremum_t().is_none()
603 }
604
605 pub fn is_monotonic(&self) -> bool {
607 self.is_x_monotonic() && self.is_y_monotonic()
608 }
609
610 pub fn line_intersections_t(&self, line: &Line<S>) -> ArrayVec<S, 2> {
616 let eqn = line.equation();
619 let i = eqn.a() * self.from.x + eqn.b() * self.from.y;
620 let j = eqn.a() * self.ctrl.x + eqn.b() * self.ctrl.y;
621 let k = eqn.a() * self.to.x + eqn.b() * self.to.y;
622 let a = i - j - j + k;
624 let b = j + j - i - i;
625 let c = i + eqn.c();
626
627 let mut result = ArrayVec::new();
628
629 if a == S::ZERO {
630 let t = c / b;
632 if t >= S::ZERO && t <= S::ONE {
638 result.push(t);
639 return result;
640 }
641 }
642
643 let delta = b * b - S::FOUR * a * c;
644 if delta >= S::ZERO {
645 let sqrt_delta = S::sqrt(delta);
649 let s_sqrt_delta = -b.signum() * sqrt_delta;
650 let mut t1 = (-b + s_sqrt_delta) / (S::TWO * a);
651 let mut t2 = c / (a * t1);
652
653 if t1 > t2 {
654 mem::swap(&mut t1, &mut t2);
655 }
656
657 if t1 >= S::ZERO && t1 <= S::ONE {
658 result.push(t1);
659 }
660
661 if t2 >= S::ZERO && t2 <= S::ONE && t1 != t2 {
662 result.push(t2);
663 }
664 }
665
666 result
667 }
668
669 pub fn line_intersections(&self, line: &Line<S>) -> ArrayVec<Point<S>, 2> {
671 let intersections = self.line_intersections_t(line);
672
673 let mut result = ArrayVec::new();
674 for t in intersections {
675 result.push(self.sample(t));
676 }
677
678 result
679 }
680
681 pub fn line_segment_intersections_t(&self, segment: &LineSegment<S>) -> ArrayVec<(S, S), 2> {
687 if !self
688 .fast_bounding_box()
689 .inflate(S::EPSILON, S::EPSILON)
690 .intersects(&segment.bounding_box().inflate(S::EPSILON, S::EPSILON))
691 {
692 return ArrayVec::new();
693 }
694
695 let intersections = self.line_intersections_t(&segment.to_line());
696
697 let mut result = ArrayVec::new();
698 if intersections.is_empty() {
699 return result;
700 }
701
702 let seg_is_mostly_vertical =
703 S::abs(segment.from.y - segment.to.y) >= S::abs(segment.from.x - segment.to.x);
704 let (seg_long_axis_min, seg_long_axis_max) = if seg_is_mostly_vertical {
705 segment.bounding_range_y()
706 } else {
707 segment.bounding_range_x()
708 };
709
710 for t in intersections {
711 let intersection_xy = if seg_is_mostly_vertical {
712 self.y(t)
713 } else {
714 self.x(t)
715 };
716 if intersection_xy >= seg_long_axis_min && intersection_xy <= seg_long_axis_max {
717 let t2 = (self.sample(t) - segment.from).length() / segment.length();
718 if (t != S::ZERO && t != S::ONE) || (t2 != S::ZERO && t2 != S::ONE) {
720 result.push((t, t2));
721 }
722 }
723 }
724
725 result
726 }
727
728 #[inline]
729 pub fn from(&self) -> Point<S> {
730 self.from
731 }
732
733 #[inline]
734 pub fn to(&self) -> Point<S> {
735 self.to
736 }
737
738 pub fn line_segment_intersections(&self, segment: &LineSegment<S>) -> ArrayVec<Point<S>, 2> {
740 let intersections = self.line_segment_intersections_t(segment);
741
742 let mut result = ArrayVec::new();
743 for (t, _) in intersections {
744 result.push(self.sample(t));
745 }
746
747 result
748 }
749
750 pub fn closest_point(&self, pos: Point<S>) -> S {
752 let a = self.from - pos;
755 let b = self.ctrl - self.from;
756 let c = self.from + self.to.to_vector() - self.ctrl * S::TWO;
757
758 let c0 = c.dot(c);
760 let c1 = b.dot(c) * S::THREE;
761 let c2 = b.dot(b) * S::TWO + a.dot(c);
762 let c3 = a.dot(b);
763
764 let roots = crate::utils::cubic_polynomial_roots(c0, c1, c2, c3);
765
766 let mut sq_dist = a.square_length();
767 let mut t = S::ZERO;
768 let to_dist = (self.to - pos).square_length();
769 if to_dist < sq_dist {
770 sq_dist = to_dist;
771 t = S::ONE
772 }
773 for root in roots {
774 if root >= S::ZERO && root <= S::ONE {
775 let p = self.sample(root);
776 let d = (pos - p).square_length();
777 if d < sq_dist {
778 sq_dist = d;
779 t = root;
780 }
781 }
782 }
783
784 t
785 }
786
787 pub fn distance_to_point(&self, pos: Point<S>) -> S {
789 (self.sample(self.closest_point(pos)) - pos).length()
790 }
791
792 pub fn square_distance_to_point(&self, pos: Point<S>) -> S {
797 (self.sample(self.closest_point(pos)) - pos).square_length()
798 }
799
800 pub fn drag(&self, t: S, new_position: Point<S>) -> Self {
803 let t2 = t * t;
804 let one_t = S::ONE - t;
805 let one_t2 = one_t * one_t;
806
807 let u = t2 / (t2 + one_t2);
808 let c = self.from.lerp(self.to, u);
809
810 let inv_r = S::abs((t2 + one_t2) / (t2 + one_t2 - S::ONE));
811
812 QuadraticBezierSegment {
813 from: self.from,
814 ctrl: new_position + (new_position - c) * inv_r,
815 to: self.to,
816 }
817 }
818
819 pub fn length(&self) -> S {
824 let d2 = self.from - self.ctrl * S::TWO + self.to.to_vector();
827 let d1 = self.ctrl - self.from;
828 let a = d2.square_length();
829 let c = d1.square_length();
830 if a < S::value(1e-4) * c {
831 let v0 = (self.from.to_vector() * S::value(-0.492943519233745)
836 + self.ctrl.to_vector() * S::value(0.430331482911935)
837 + self.to.to_vector() * S::value(0.0626120363218102))
838 .length();
839 let v1 = ((self.to - self.from) * S::value(0.4444444444444444)).length();
840 let v2 = (self.from.to_vector() * S::value(-0.0626120363218102)
841 + self.ctrl.to_vector() * S::value(-0.430331482911935)
842 + self.to.to_vector() * S::value(0.492943519233745))
843 .length();
844 return v0 + v1 + v2;
845 }
846
847 let b = S::TWO * d2.dot(d1);
848
849 let sqr_abc = (a + b + c).sqrt();
850 let a2 = a.powf(-S::HALF);
851 let a32 = a2.powi(3);
852 let c2 = S::TWO * c.sqrt();
853 let ba_c2 = b * a2 + c2;
854
855 let v0 = S::HALF * S::HALF * a2 * a2 * b * (S::TWO * sqr_abc - c2) + sqr_abc;
856
857 if ba_c2 < S::EPSILON {
858 v0
860 } else {
861 v0 + S::HALF
862 * S::HALF
863 * a32
864 * (S::FOUR * c * a - b * b)
865 * (((S::TWO * a + b) * a2 + S::TWO * sqr_abc) / ba_c2).ln()
866 }
867 }
868
869 fn approximate_length(&self, _tolerance: S) -> S {
871 self.length()
872 }
873
874 pub fn to_f32(&self) -> QuadraticBezierSegment<f32> {
875 QuadraticBezierSegment {
876 from: self.from.to_f32(),
877 ctrl: self.ctrl.to_f32(),
878 to: self.to.to_f32(),
879 }
880 }
881
882 pub fn to_f64(&self) -> QuadraticBezierSegment<f64> {
883 QuadraticBezierSegment {
884 from: self.from.to_f64(),
885 ctrl: self.ctrl.to_f64(),
886 to: self.to.to_f64(),
887 }
888 }
889
890 #[inline]
891 pub fn polynomial_form(&self) -> QuadraticBezierPolynomial<S> {
892 let from = self.from.to_vector();
893 let ctrl = self.ctrl.to_vector();
894 let to = self.to.to_vector();
895 QuadraticBezierPolynomial {
896 a0: from,
897 a1: (ctrl - from) * S::TWO,
898 a2: from + to - ctrl * S::TWO,
899 }
900 }
901}
902
903pub struct FlatteningParameters<S> {
907 _marker: core::marker::PhantomData<S>
908}
909
910impl<S: Scalar> FlatteningParameters<S> {
911 pub fn new(_curve: &QuadraticBezierSegment<S>, _tolerance: S) -> Self {
912 Self { _marker: core::marker::PhantomData }
913 }
914}
915
916#[derive(Copy, Clone, Debug, PartialEq)]
921pub struct QuadraticBezierPolynomial<S> {
922 pub a0: Vector<S>,
923 pub a1: Vector<S>,
924 pub a2: Vector<S>,
925}
926
927impl<S: Scalar> QuadraticBezierPolynomial<S> {
928 #[inline(always)]
929 pub fn sample(&self, t: S) -> Point<S> {
930 let mut v = self.a0;
932 let mut t2 = t;
933 v += self.a1 * t2;
934 t2 *= t;
935 v += self.a2 * t2;
936
937 v.to_point()
938 }
939}
940
941fn flattened_segments_wang<S: Scalar>(curve: &QuadraticBezierSegment<S>, tolerance: S) -> S {
944 let from = curve.from.to_vector();
945 let ctrl = curve.ctrl.to_vector();
946 let to = curve.to.to_vector();
947 let l = (from - ctrl * S::TWO + to) * S::TWO;
948 let d = S::ONE / (S::EIGHT * tolerance);
949 let err4 = l.dot(l) * d * d;
950 let err4_f32 = err4.to_f32().unwrap_or(1.0);
951
952 const N: usize = 24;
955 const LUT: [f32; N] = [
956 1.0, 16.0, 81.0, 256.0, 625.0, 1296.0, 2401.0, 4096.0, 6561.0,
957 10000.0, 14641.0, 20736.0, 28561.0, 38416.0, 50625.0, 65536.0,
958 83521.0, 104976.0, 130321.0, 160000.0, 194481.0, 234256.0,
959 279841.0, 331776.0
960 ];
961
962 if err4_f32 <= 331776.0 {
964 #[allow(clippy::needless_range_loop)]
965 for i in 0..N {
966 if err4_f32 <= LUT[i] {
967 return S::from(i + 1).unwrap_or(S::ONE);
968 }
969 }
970 }
971
972 err4.sqrt().sqrt().max(S::ONE)
974}
975
976pub struct Flattened<S> {
980 curve: QuadraticBezierPolynomial<S>,
981 to: Point<S>,
982 segments: u32,
983 step: S,
984 t: S,
985}
986
987impl<S: Scalar> Flattened<S> {
988 #[inline]
989 pub(crate) fn new(curve: &QuadraticBezierSegment<S>, tolerance: S) -> Self {
990 debug_assert!(tolerance >= S::EPSILON * S::EPSILON);
991
992 let n = flattened_segments_wang(curve, tolerance);
993
994 let step = S::ONE / n;
995
996 Flattened {
997 curve: curve.polynomial_form(),
998 to: curve.to,
999 segments: n.to_u32().unwrap_or(1),
1000 step,
1001 t: step
1002 }
1003 }
1004}
1005
1006impl<S: Scalar> Iterator for Flattened<S> {
1007 type Item = Point<S>;
1008
1009 #[inline]
1010 fn next(&mut self) -> Option<Point<S>> {
1011 if self.segments == 0 {
1012 return None;
1013 }
1014
1015 self.segments -= 1;
1016 if self.segments == 0 {
1017 return Some(self.to)
1018 }
1019
1020 let p = self.curve.sample(self.t);
1021 self.t += self.step;
1022
1023 Some(p)
1024 }
1025
1026 #[inline]
1027 fn size_hint(&self) -> (usize, Option<usize>) {
1028 let n = self.segments as usize;
1029 (n, Some(n))
1030 }
1031}
1032
1033pub struct FlattenedT<S> {
1039 segments: u32,
1040 step: S,
1041 t: S,
1042}
1043
1044impl<S: Scalar> FlattenedT<S> {
1045 #[inline]
1046 pub(crate) fn new(curve: &QuadraticBezierSegment<S>, tolerance: S) -> Self {
1047 debug_assert!(tolerance >= S::EPSILON * S::EPSILON);
1048
1049 let n = flattened_segments_wang(curve, tolerance);
1050
1051 let step = S::ONE / n;
1052
1053 FlattenedT {
1054 segments: n.to_u32().unwrap_or(1),
1055 step,
1056 t: step
1057 }
1058 }
1059}
1060
1061impl<S: Scalar> Iterator for FlattenedT<S> {
1062 type Item = S;
1063
1064 #[inline]
1065 fn next(&mut self) -> Option<S> {
1066 if self.segments == 0 {
1067 return None;
1068 }
1069
1070 self.segments -= 1;
1071 if self.segments == 0 {
1072 return Some(S::ONE)
1073 }
1074
1075 let t = self.t;
1076 self.t += self.step;
1077
1078 Some(t)
1079 }
1080
1081 #[inline]
1082 fn size_hint(&self) -> (usize, Option<usize>) {
1083 let n = self.segments as usize;
1084 (n, Some(n))
1085 }
1086}
1087
1088impl<S: Scalar> Segment for QuadraticBezierSegment<S> {
1089 impl_segment!(S);
1090
1091 fn for_each_flattened_with_t(
1092 &self,
1093 tolerance: Self::Scalar,
1094 callback: &mut dyn FnMut(&LineSegment<S>, Range<S>),
1095 ) {
1096 self.for_each_flattened_with_t(tolerance, &mut |s, t| callback(s, t));
1097 }
1098}
1099
1100#[test]
1101fn bounding_box_for_monotonic_quadratic_bezier_segment() {
1102 let a = QuadraticBezierSegment {
1103 from: Point::new(0.0, 0.0),
1104 ctrl: Point::new(0.0, 0.0),
1105 to: Point::new(2.0, 0.0),
1106 };
1107
1108 let expected_aabb = Box2D {
1109 min: point(0.0, 0.0),
1110 max: point(2.0, 0.0),
1111 };
1112
1113 let actual_aabb = a.bounding_box();
1114
1115 assert_eq!(expected_aabb, actual_aabb)
1116}
1117
1118#[test]
1119fn fast_bounding_box_for_quadratic_bezier_segment() {
1120 let a = QuadraticBezierSegment {
1121 from: Point::new(0.0, 0.0),
1122 ctrl: Point::new(1.0, 1.0),
1123 to: Point::new(2.0, 0.0),
1124 };
1125
1126 let expected_aabb = Box2D {
1127 min: point(0.0, 0.0),
1128 max: point(2.0, 1.0),
1129 };
1130
1131 let actual_aabb = a.fast_bounding_box();
1132
1133 assert_eq!(expected_aabb, actual_aabb)
1134}
1135
1136#[test]
1137fn minimum_bounding_box_for_quadratic_bezier_segment() {
1138 let a = QuadraticBezierSegment {
1139 from: Point::new(0.0, 0.0),
1140 ctrl: Point::new(1.0, 1.0),
1141 to: Point::new(2.0, 0.0),
1142 };
1143
1144 let expected_aabb = Box2D {
1145 min: point(0.0, 0.0),
1146 max: point(2.0, 0.5),
1147 };
1148
1149 let actual_aabb = a.bounding_box();
1150
1151 assert_eq!(expected_aabb, actual_aabb)
1152}
1153
1154#[test]
1155fn y_maximum_t_for_simple_segment() {
1156 let a = QuadraticBezierSegment {
1157 from: Point::new(0.0, 0.0),
1158 ctrl: Point::new(1.0, 1.0),
1159 to: Point::new(2.0, 0.0),
1160 };
1161
1162 let expected_y_maximum = 0.5;
1163
1164 let actual_y_maximum = a.y_maximum_t();
1165
1166 assert_eq!(expected_y_maximum, actual_y_maximum)
1167}
1168
1169#[test]
1170fn local_y_extremum_for_simple_segment() {
1171 let a = QuadraticBezierSegment {
1172 from: Point::new(0.0, 0.0),
1173 ctrl: Point::new(1.0, 1.0),
1174 to: Point::new(2.0, 0.0),
1175 };
1176
1177 let expected_y_inflection = 0.5;
1178
1179 match a.local_y_extremum_t() {
1180 Some(actual_y_inflection) => assert_eq!(expected_y_inflection, actual_y_inflection),
1181 None => panic!(),
1182 }
1183}
1184
1185#[test]
1186fn y_minimum_t_for_simple_segment() {
1187 let a = QuadraticBezierSegment {
1188 from: Point::new(0.0, 0.0),
1189 ctrl: Point::new(1.0, -1.0),
1190 to: Point::new(2.0, 0.0),
1191 };
1192
1193 let expected_y_minimum = 0.5;
1194
1195 let actual_y_minimum = a.y_minimum_t();
1196
1197 assert_eq!(expected_y_minimum, actual_y_minimum)
1198}
1199
1200#[test]
1201fn x_maximum_t_for_simple_segment() {
1202 let a = QuadraticBezierSegment {
1203 from: Point::new(0.0, 0.0),
1204 ctrl: Point::new(1.0, 1.0),
1205 to: Point::new(0.0, 2.0),
1206 };
1207
1208 let expected_x_maximum = 0.5;
1209
1210 let actual_x_maximum = a.x_maximum_t();
1211
1212 assert_eq!(expected_x_maximum, actual_x_maximum)
1213}
1214
1215#[test]
1216fn local_x_extremum_for_simple_segment() {
1217 let a = QuadraticBezierSegment {
1218 from: Point::new(0.0, 0.0),
1219 ctrl: Point::new(1.0, 1.0),
1220 to: Point::new(0.0, 2.0),
1221 };
1222
1223 let expected_x_inflection = 0.5;
1224
1225 match a.local_x_extremum_t() {
1226 Some(actual_x_inflection) => assert_eq!(expected_x_inflection, actual_x_inflection),
1227 None => panic!(),
1228 }
1229}
1230
1231#[test]
1232fn x_minimum_t_for_simple_segment() {
1233 let a = QuadraticBezierSegment {
1234 from: Point::new(2.0, 0.0),
1235 ctrl: Point::new(1.0, 1.0),
1236 to: Point::new(2.0, 2.0),
1237 };
1238
1239 let expected_x_minimum = 0.5;
1240
1241 let actual_x_minimum = a.x_minimum_t();
1242
1243 assert_eq!(expected_x_minimum, actual_x_minimum)
1244}
1245
1246#[test]
1247fn length_straight_line() {
1248 let len = QuadraticBezierSegment {
1252 from: Point::new(0.0f64, 0.0),
1253 ctrl: Point::new(1.0, 0.0),
1254 to: Point::new(2.0, 0.0),
1255 }
1256 .length();
1257 assert!((len - 2.0).abs() < 0.000001);
1258
1259 let len = CubicBezierSegment {
1260 from: Point::new(0.0f64, 0.0),
1261 ctrl1: Point::new(1.0, 0.0),
1262 ctrl2: Point::new(1.0, 0.0),
1263 to: Point::new(2.0, 0.0),
1264 }
1265 .approximate_length(0.0001);
1266 assert!((len - 2.0).abs() < 0.000001);
1267}
1268
1269#[test]
1270fn derivatives() {
1271 let c1 = QuadraticBezierSegment {
1272 from: Point::new(1.0, 1.0),
1273 ctrl: Point::new(2.0, 1.0),
1274 to: Point::new(2.0, 2.0),
1275 };
1276
1277 assert_eq!(c1.dy(0.0), 0.0);
1278 assert_eq!(c1.dx(1.0), 0.0);
1279 assert_eq!(c1.dy(0.5), c1.dx(0.5));
1280}
1281
1282#[test]
1283fn fat_line() {
1284 use crate::point;
1285
1286 let c1 = QuadraticBezierSegment {
1287 from: point(1.0f32, 2.0),
1288 ctrl: point(1.0, 3.0),
1289 to: point(11.0, 12.0),
1290 };
1291
1292 let (l1, l2) = c1.fat_line();
1293
1294 for i in 0..100 {
1295 let t = i as f32 / 99.0;
1296 assert!(l1.signed_distance_to_point(&c1.sample(t)) >= -0.000001);
1297 assert!(l2.signed_distance_to_point(&c1.sample(t)) <= 0.000001);
1298 }
1299}
1300
1301#[test]
1302fn is_linear() {
1303 let mut angle = 0.0;
1304 let center = Point::new(1000.0, -700.0);
1305 for _ in 0..100 {
1306 for i in 0..10 {
1307 let (sin, cos) = f64::sin_cos(angle);
1308 let endpoint = Vector::new(cos * 100.0, sin * 100.0);
1309 let curve = QuadraticBezierSegment {
1310 from: center - endpoint,
1311 ctrl: center + endpoint.lerp(-endpoint, i as f64 / 9.0),
1312 to: center + endpoint,
1313 };
1314
1315 assert!(curve.is_linear(1e-10));
1316 }
1317 angle += 0.001;
1318 }
1319}
1320
1321#[test]
1322fn test_flattening() {
1323 use crate::point;
1324
1325 let c1 = QuadraticBezierSegment {
1326 from: point(0.0, 0.0),
1327 ctrl: point(5.0, 0.0),
1328 to: point(5.0, 5.0),
1329 };
1330
1331 let c2 = QuadraticBezierSegment {
1332 from: point(0.0, 0.0),
1333 ctrl: point(50.0, 0.0),
1334 to: point(50.0, 50.0),
1335 };
1336
1337 let c3 = QuadraticBezierSegment {
1338 from: point(0.0, 0.0),
1339 ctrl: point(100.0, 100.0),
1340 to: point(5.0, 0.0),
1341 };
1342
1343 fn check_tolerance(curve: &QuadraticBezierSegment<f64>, tolerance: f64) {
1344 let mut c = curve.clone();
1345 loop {
1346 let t = c.flattening_step(tolerance);
1347 if t >= 1.0 {
1348 break;
1349 }
1350 let (before, after) = c.split(t);
1351 let mid_point = before.sample(0.5);
1352 let distance = before
1353 .baseline()
1354 .to_line()
1355 .equation()
1356 .distance_to_point(&mid_point);
1357 assert!(distance <= tolerance);
1358 c = after;
1359 }
1360 }
1361
1362 check_tolerance(&c1, 1.0);
1363 check_tolerance(&c1, 0.1);
1364 check_tolerance(&c1, 0.01);
1365 check_tolerance(&c1, 0.001);
1366 check_tolerance(&c1, 0.0001);
1367
1368 check_tolerance(&c2, 1.0);
1369 check_tolerance(&c2, 0.1);
1370 check_tolerance(&c2, 0.01);
1371 check_tolerance(&c2, 0.001);
1372 check_tolerance(&c2, 0.0001);
1373
1374 check_tolerance(&c3, 1.0);
1375 check_tolerance(&c3, 0.1);
1376 check_tolerance(&c3, 0.01);
1377 check_tolerance(&c3, 0.001);
1378 check_tolerance(&c3, 0.0001);
1379}
1380
1381#[test]
1382fn test_flattening_empty_curve() {
1383 use crate::point;
1384
1385 let curve = QuadraticBezierSegment {
1386 from: point(0.0, 0.0),
1387 ctrl: point(0.0, 0.0),
1388 to: point(0.0, 0.0),
1389 };
1390
1391 let mut iter = FlattenedT::new(&curve, 0.1);
1392
1393 assert_eq!(iter.next(), Some(1.0));
1394 assert_eq!(iter.next(), None);
1395
1396 let mut count: u32 = 0;
1397 curve.for_each_flattened(0.1, &mut |_| count += 1);
1398 assert_eq!(count, 1);
1399}
1400
1401#[test]
1402fn test_flattening_straight_line() {
1403 use crate::point;
1404
1405 let curve = QuadraticBezierSegment {
1406 from: point(0.0, 0.0),
1407 ctrl: point(10.0, 0.0),
1408 to: point(20.0, 0.0),
1409 };
1410
1411 let mut iter = FlattenedT::new(&curve, 0.1);
1412
1413 assert_eq!(iter.next(), Some(1.0));
1414 assert!(iter.next().is_none());
1415
1416 let mut count: u32 = 0;
1417 curve.for_each_flattened(0.1, &mut |_| count += 1);
1418 assert_eq!(count, 1);
1419}
1420
1421#[test]
1422fn test_flattened_t_values_are_monotonic() {
1423 use crate::point;
1424
1425 let curve = QuadraticBezierSegment {
1427 from: point(0.0f32, 0.0),
1428 ctrl: point(50.0, 100.0),
1429 to: point(100.0, 0.0),
1430 };
1431
1432 let iter = FlattenedT::new(&curve, 0.01);
1433 let count = iter.segments;
1434 assert!(count >= 3, "need at least 3 segments for this test, got {}", count);
1435
1436 let step = 1.0 / count as f32;
1437 let mut iter = FlattenedT::new(&curve, 0.01);
1438 let mut prev = 0.0f32;
1439 let mut n = 0u32;
1440
1441 while let Some(t) = iter.next() {
1442 assert!(t > prev, "t values must be strictly increasing: {} <= {}", t, prev);
1444 prev = t;
1445 n += 1;
1446 }
1447
1448 assert_eq!(n, count);
1450
1451 let first = FlattenedT::new(&curve, 0.01).next().unwrap();
1453 assert!(
1454 (first - step).abs() < 1e-3,
1455 "first t value should be ~{}, got {}",
1456 step, first,
1457 );
1458
1459 assert_eq!(prev, 1.0);
1461}
1462
1463#[test]
1464fn issue_678() {
1465 let points = [
1466 [-7768.80859375f32, -35563.80859375],
1467 [-38463.125, -10941.41796875],
1468 [-21846.12890625, -13518.1953125],
1469 [-11727.439453125, -22080.33203125],
1470 ];
1471
1472 let quadratic = QuadraticBezierSegment {
1473 from: Point::new(points[0][0], points[0][1]),
1474 ctrl: Point::new(points[1][0], points[1][1]),
1475 to: Point::new(points[2][0], points[2][1]),
1476 };
1477
1478 let line = Line {
1479 point: Point::new(points[3][0], points[3][1]),
1480 vector: Vector::new(-0.5, -0.5).normalize(),
1481 };
1482
1483 let intersections = quadratic.line_intersections(&line);
1484 std::println!("{intersections:?}");
1485
1486 assert_eq!(intersections.len(), 1);
1487}
1488
1489#[test]
1490fn line_intersections_t() {
1491 let curve = QuadraticBezierSegment {
1492 from: point(0.0f64, 0.0),
1493 ctrl: point(100.0, 0.0),
1494 to: point(100.0, 500.0),
1495 };
1496 let cubic = curve.to_cubic();
1497
1498 let line = Line {
1499 point: point(0.0, -50.0),
1500 vector: crate::vector(100.0, 500.0),
1501 };
1502
1503 let mut i1 = curve.line_intersections_t(&line);
1504 let mut i2 = curve.to_cubic().line_intersections_t(&line);
1505
1506 use std::cmp::Ordering::{Equal, Greater, Less};
1507 i1.sort_by(|a, b| {
1508 if a == b {
1509 Equal
1510 } else if a > b {
1511 Greater
1512 } else {
1513 Less
1514 }
1515 });
1516 i2.sort_by(|a, b| {
1517 if a == b {
1518 Equal
1519 } else if a > b {
1520 Greater
1521 } else {
1522 Less
1523 }
1524 });
1525
1526 for (t1, t2) in i1.iter().zip(i2.iter()) {
1527 use euclid::approxeq::ApproxEq;
1528 let p1 = curve.sample(*t1);
1529 let p2 = cubic.sample(*t2);
1530 assert!(p1.approx_eq(&p2), "{:?} == {:?}", p1, p2);
1531 }
1532 assert_eq!(i2.len(), 2);
1533 assert_eq!(i1.len(), 2);
1534}
1535
1536#[test]
1537fn line_intersections_degenerate_curve_on_line() {
1538 let curve = QuadraticBezierSegment {
1547 from: point(0.0f64, 0.0),
1548 ctrl: point(1.0, 0.0),
1549 to: point(2.0, 0.0),
1550 };
1551
1552 let line = Line {
1554 point: point(0.0, 0.0),
1555 vector: crate::vector(1.0, 0.0),
1556 };
1557
1558 let intersections = curve.line_intersections_t(&line);
1559
1560 for &t in intersections.iter() {
1562 assert!(
1563 t.is_finite(),
1564 "Expected finite t value, got {:?}", t
1565 );
1566 assert!(
1567 t >= 0.0 && t <= 1.0,
1568 "Expected t in [0, 1], got {:?}", t
1569 );
1570 }
1571
1572 assert!(intersections.is_empty());
1579}
1580
1581#[test]
1582fn drag() {
1583 let curve = QuadraticBezierSegment {
1584 from: point(0.0f32, 0.0),
1585 ctrl: point(100.0, 0.0),
1586 to: point(100.0, 100.0),
1587 };
1588
1589 for t in [0.5, 0.25, 0.1, 0.4, 0.7] {
1590 let target = point(0.0, 10.0);
1591
1592 let dragged = curve.drag(t, target);
1593
1594 use euclid::approxeq::ApproxEq;
1595 let p1 = dragged.sample(t);
1596 assert!(
1597 p1.approx_eq_eps(&target, &point(0.001, 0.001)),
1598 "{:?} == {:?}",
1599 p1,
1600 target
1601 );
1602 }
1603}
1604
1605#[test]
1606fn arc_length() {
1607 let curves = [
1608 QuadraticBezierSegment {
1609 from: point(0.0f64, 0.0),
1610 ctrl: point(100.0, 0.0),
1611 to: point(0.0, 100.0),
1612 },
1613 QuadraticBezierSegment {
1614 from: point(0.0, 0.0),
1615 ctrl: point(100.0, 0.0),
1616 to: point(200.0, 0.0),
1617 },
1618 QuadraticBezierSegment {
1619 from: point(100.0, 0.0),
1620 ctrl: point(0.0, 0.0),
1621 to: point(50.0, 1.0),
1622 },
1623 ];
1624
1625 for (idx, curve) in curves.iter().enumerate() {
1626 let length = curve.length();
1627 let mut accum = 0.0;
1628 curve.for_each_flattened(0.00000001, &mut |line| {
1629 accum += line.length();
1630 });
1631
1632 assert!(
1633 (length - accum).abs() < 0.00001,
1634 "curve {:?}, {:?} == {:?}",
1635 idx,
1636 length,
1637 accum
1638 );
1639 }
1640}