andrewlowndes / perfect-antialiasing

Antialiasing via conservative rasterisation and analytical area computation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

cubicBezierToPoints does not consider the symmetry of control points

defpis opened this issue · comments

Current Behavior

when cubic bezier like this:

const p1 = { x: 0.0, y: 200.0 };
const p2 = { x: 100.0, y: 0.0 };
const p3 = { x: 200.0, y: 400.0 };
const p4 = { x: 300.0, y: 200.0 };

render as follow:

image

Expected Behavior

image

Possible Solution

Add flag first to force recursion for the first time

export const cubicBezierToPoints = (
  bezier: CubicBezier,
  splitThreshold: number
): Array<Point> => {
  const points = [
    { x: bezier.p1.x, y: bezier.p1.y },
    { x: bezier.p4.x, y: bezier.p4.y },
  ];

  const cubicBezierSplit = (
    bezier: CubicBezier,
    min: number,
    max: number,
    insertIndex: number,
    first = false
  ) => {
    const time = lerp(min, max, 0.5);
    const midLerp = lerp2(bezier.p2, bezier.p3, time);

    const pointOnCurve = lerp2(
      lerp2(lerp2(bezier.p1, bezier.p2, time), midLerp, time),
      lerp2(midLerp, lerp2(bezier.p3, bezier.p4, time), time),
      time
    );

    const prevPoint = points[insertIndex - 1];
    const nextPoint = points[insertIndex];

    points.splice(insertIndex, 0, pointOnCurve);

    if (
      dot(
        normalize(sub(prevPoint, pointOnCurve)),
        normalize(sub(nextPoint, pointOnCurve))
      ) > splitThreshold ||
      first
    ) {
      cubicBezierSplit(bezier, time, max, insertIndex + 1);
      cubicBezierSplit(bezier, min, time, insertIndex);
    }
  };

  cubicBezierSplit(bezier, 0, 1, 1, true);

  return points;
};

Closing now #2 has been merged