diff --git a/CHANGELOG.md b/CHANGELOG.md index 839d33fb..768d8611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This release has an [MSRV][] of 1.65. - Add `From (f32, f32)` for `Point`. ([#339] by [@rsheeter]) - Add `Rect::overlaps` and `Rect::contains_rect`. ([#347] by [@nils-mathieu]) +- Add `CubicBez::tangents` ([#288] by [@raphlinus]) ### Changed @@ -44,6 +45,7 @@ Note: A changelog was not kept for or before this release [@simoncozens]: https://github.com/simoncozens [@waywardmonkeys]: https://github.com/waywardmonkeys +[#288]: https://github.com/linebender/kurbo/pull/288 [#334]: https://github.com/linebender/kurbo/pull/334 [#339]: https://github.com/linebender/kurbo/pull/339 [#340]: https://github.com/linebender/kurbo/pull/340 diff --git a/src/cubicbez.rs b/src/cubicbez.rs index 16fe485c..4b472fc4 100644 --- a/src/cubicbez.rs +++ b/src/cubicbez.rs @@ -12,7 +12,7 @@ use crate::{Line, QuadSpline, Vec2}; use arrayvec::ArrayVec; use crate::common::{ - solve_quadratic, GAUSS_LEGENDRE_COEFFS_16_HALF, GAUSS_LEGENDRE_COEFFS_24_HALF, + solve_quadratic, solve_quartic, GAUSS_LEGENDRE_COEFFS_16_HALF, GAUSS_LEGENDRE_COEFFS_24_HALF, GAUSS_LEGENDRE_COEFFS_8, GAUSS_LEGENDRE_COEFFS_8_HALF, }; use crate::{ @@ -358,6 +358,27 @@ impl CubicBez { .collect() } + /// Find points on the curve where the tangent line passes through the + /// given point. + /// + /// Result is array of t values such that the tangent line from the curve + /// evaluated at that point goes through the argument point. + pub fn tangents_to_point(&self, p: Point) -> ArrayVec { + let (a, b, c, d_orig) = self.parameters(); + let d = d_orig - p.to_vec2(); + // coefficients of x(t) \cross x'(t) + let c4 = b.cross(a); + let c3 = 2.0 * c.cross(a); + let c2 = c.cross(b) + 3.0 * d.cross(a); + let c1 = 2.0 * d.cross(b); + let c0 = d.cross(c); + solve_quartic(c0, c1, c2, c3, c4) + .iter() + .copied() + .filter(|t| *t >= 0.0 && *t <= 1.0) + .collect() + } + /// Preprocess a cubic Bézier to ease numerical robustness. /// /// If the cubic Bézier segment has zero or near-zero derivatives, perturb