~raph/bezoid

8bfe25c0030d271103988ca2acb3364ce1964dac — Raph Levien 2 years ago c972c4e
Simpler arm length formula

Make arm length ratio dependent on angle (matching circular arc bezier
approximation formula) rather than chord length.
1 files changed, 7 insertions(+), 7 deletions(-)

M src/solve.rs
M src/solve.rs => src/solve.rs +7 -7
@@ 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,