Skip to content

Commit

Permalink
Find tangents from point to cubic Bézier (#288)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphlinus authored Aug 22, 2024
1 parent 65c6eb3 commit 987b6ff
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -45,6 +46,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
Expand Down
23 changes: 22 additions & 1 deletion src/cubicbez.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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<f64, 4> {
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
Expand Down

0 comments on commit 987b6ff

Please sign in to comment.