From 8bfe25c0030d271103988ca2acb3364ce1964dac Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 6 Nov 2020 15:01:42 -0800 Subject: [PATCH] Simpler arm length formula Make arm length ratio dependent on angle (matching circular arc bezier approximation formula) rather than chord length. --- src/solve.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/solve.rs b/src/solve.rs index 5bff189..9558ba5 100644 --- a/src/solve.rs +++ b/src/solve.rs @@ -1,6 +1,6 @@ //! Solver from cubic params to curve params. -use druid::kurbo::{CubicBez, ParamCurveArclen, Point}; +use druid::kurbo::Point; use crate::bezoid::CurveParams; @@ -13,8 +13,10 @@ impl Solver { /// (1, 0). pub fn solve(&self, p1: Point, p2: Point) -> CurveParams { println!("({:.3}, {:.3}) ({:.3}, {:.3})", p1.x, p1.y, p2.x, p2.y); - fn inv_arm_len(h: f64, chord: f64) -> f64 { - let a = h * 3.0 * chord.powf(1.0); + fn inv_arm_len(h: f64, th: f64) -> f64 { + // This formula ensures that bezier parameters approximating + // a circular arc map to a bias of 1.0. + let a = h * 1.5 * (th.cos() + 1.0); if a < 1.0 { 2.0 - a.powf(2.0) } else { @@ -23,16 +25,14 @@ impl Solver { } let v1 = p1.to_vec2(); let v2 = Point::new(1.0, 0.0) - p2; - let c = CubicBez::new(Point::ORIGIN, p1, p2, Point::new(1.0, 0.0)); let th0 = v1.atan2(); let th1 = -v2.atan2(); let mut dth = 0.0; - let chord = 1.0 / c.arclen(1e-3); let mut lastxy: Option<(f64, f64)> = None; const N: usize = 10; for i in 0..N { - let bias0 = inv_arm_len(v1.hypot(), chord); - let bias1 = inv_arm_len(v2.hypot(), chord); + let bias0 = inv_arm_len(v1.hypot(), th0); + let bias1 = inv_arm_len(v2.hypot(), th1); let params = CurveParams { k0: th0 + 0.5 * dth, bias0, -- 2.34.2