kCurve

fun List<Vector2>.kCurve(closed: Boolean, polarity: YPolarity = YPolarity.CW_NEGATIVE_Y): ShapeContour(source)

Converts this polyline into a κ-curve, after Yan, Schiller, Wilensky, Carr and Schaefer, "κ-Curves: Interpolation at Local Maximum Curvature" (SIGGRAPH 2017): a curve of quadratic Béziers, one per point, on which every point is where the curvature of its quadratic peaks. Corners of the polyline therefore become the sharpest spots of the curve, and the curve never bends more sharply between the points than at them.

Neighbouring quadratics share their end point, which lies on the line between their middle control points, so the curve is G1 everywhere. Where it divides that line in the ratio of the square roots of the areas of the triangles of the two control polygons, the curvature is continuous too, which makes the curve G2 everywhere except at inflections. Every quadratic passes through its point at the parameter of maximum curvature, where the derivative is perpendicular to the constant second derivative; for given end points that parameter is the only root in 0, 1 of a cubic. The curve is found by the iteration of the paper: update the end points from the areas, the parameters from the cubics, then solve the linear, tridiagonal system that makes every quadratic pass through its point at its parameter, until the control points no longer move.

The first and last point of an open polyline are the end points of the curve rather than curvature maxima.

Not every polyline has a κ-curve: for some erratic points, typically with a point very close to where two quadratics meet, no curve has its curvature maxima at all points, and the iteration doesn't converge (about 1 in 10 random point sets in the tests). The curve then still passes through all points and is G1, but the maxima and the continuity of curvature are only approximate.

Parameters

closed

whether the polyline is closed, the last point should then not repeat the first

polarity

the polarity of the resulting contour