Skip to content

Instantly share code, notes, and snippets.

@tunght13488
Last active December 15, 2023 10:13
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tunght13488/6744e77c242cc7a94859 to your computer and use it in GitHub Desktop.
Save tunght13488/6744e77c242cc7a94859 to your computer and use it in GitHub Desktop.
quadratic bezier curve length in javascript
/*
* http://en.wikipedia.org/wiki/B%C3%A9zier_curve
* http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/g
*/
function Point(x, y) {
this.x = x;
this.y = y;
}
function quadraticBezierLength(p0, p1, p2) {
var a = new Point(
p0.x - 2 * p1.x + p2.x,
p0.y - 2 * p1.y + p2.y
);
var b = new Point(
2 * p1.x - 2 * p0.x,
2 * p1.y - 2 * p0.y
);
var A = 4 * (a.x * a.x + a.y * a.y);
var B = 4 * (a.x * b.x + a.y * b.y);
var C = b.x * b.x + b.y * b.y;
var Sabc = 2 * sqrt(A+B+C);
var A_2 = sqrt(A);
var A_32 = 2 * A * A_2;
var C_2 = 2 * sqrt(C);
var BA = B / A_2;
return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + (4 * C * A - B * B) * log((2 * A_2 + BA + Sabc) / (BA + C_2))) / (4 * A_32);
}
@ayadirh
Copy link

ayadirh commented Apr 6, 2021

how do you calculate the length for Bezier Curve in three dimensions? Is this the right approach? @steveruizok @chknoflach

    function quadraticBezierLength(x1, y1, z1, x2, y2, z2, x3, y3, z3) {
          let a, b, c, u
          let v1x = x2 * 2
          let v1y = y2 * 2
          let v1z = z2 * 2
          let d = x1 - v1x + x3
          let d1 = y1 - v1y + y3
          let d2 = z1 - v1z + z3
          let e = v1x - 2 * x1
          let e1 = v1y - 2 * y1
          let e2 = v1z - 2 * z1
          let c1 = (a = 4 * (d * d + d1 * d1 + d2 * d2))
          c1 += b = 4 * (d * e + d1 * e1 + d2 * e2)
          c1 += c = e * e + e1 * e1 + e2 * e2
          c1 = 2 * Math.sqrt(c1)
          let a1 = 2 * a * (u = Math.sqrt(a))
          let u1 = b / u
          a = 4 * c * a - b * b
          c = 2 * Math.sqrt(c)
          return (
            (a1 * c1 + u * b * (c1 - c) + a * Math.log((2 * u + u1 + c1) / (u1 + c))) /
            (4 * a1)
          )
    }

@bczhc
Copy link

bczhc commented May 17, 2021

@chknoflach Yes but in the first case you mentioned, if P0 is (10, 10), P1 is (10.00001, 10.00012), P2 is (20, 20), the divisor will be so small and the division result will be so big, makes a poor precision as a double number. It's annoying for me to process these points data from users drawing on a GUI.

@herrstrietzel
Copy link

herrstrietzel commented Sep 22, 2023

As commented before, we should also check for actually linear commands:

/**
* p0: previous command's final point
* cp1: quadratic bézier control point
* p: final point
*/

function quadraticBezierLength(p0, cp1, p, t = 1) {
    if (t === 0) {
        return 0;
    }

    const interpolate = (p1, p2, t) => {
        let pt = { x: (p2.x - p1.x) * t + p1.x, y: (p2.y - p1.y) * t + p1.y };
        return pt;
    }
    const getLineLength = (p1, p2) => {
        return Math.sqrt(
            (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)
        );
    }

    // is flat/linear 
    let l1 = getLineLength(p0, cp1) + getLineLength(cp1, p);
    let l2 = getLineLength(p0, p);
    if (l1 === l2) {
        let m1 = interpolate(p0, cp1, t);
        let m2 = interpolate(cp1, p, t);
        p = interpolate(m1, m2, t);
        let lengthL;
        lengthL = Math.sqrt((p.x - p0.x) * (p.x - p0.x) + (p.y - p0.y) * (p.y - p0.y));
        return lengthL;
    }

    let a, b, c, d, e, e1, d1, v1x, v1y;

    v1x = cp1.x * 2;
    v1y = cp1.y * 2;
    d = p0.x - v1x + p.x;
    d1 = p0.y - v1y + p.y;
    e = v1x - 2 * p0.x;
    e1 = v1y - 2 * p0.y;
    a = 4 * (d * d + d1 * d1);
    b = 4 * (d * e + d1 * e1);
    c = e * e + e1 * e1;

    const bt = b / (2 * a),
        ct = c / a,
        ut = t + bt,
        k = ct - bt ** 2;

    return (
        (Math.sqrt(a) / 2) *
        (ut * Math.sqrt(ut ** 2 + k) -
            bt * Math.sqrt(bt ** 2 + k) +
            k *
            Math.log((ut + Math.sqrt(ut ** 2 + k)) / (bt + Math.sqrt(bt ** 2 + k))))
    );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment