Closed gfox1984 closed 2 years ago
I never received an answer for this, so I'll post the code that I ended up using to compute the SVG path. It's a combination of the code used in ELK and of the answer I received on stackoverflow (see my question for the links). I managed to draw decent splines with that, no matter the number of points received:
function getBezierPathFromPoints(points) {
const [start, ...controlPoints] = points;
const path = [`M ${ptToStr(start)}`];
// if only one point, draw a straight line
if (controlPoints.length === 1) {
path.push(`L ${ptToStr(controlPoints[0])}`);
}
// if there are groups of 3 points, draw cubic bezier curves
else if (controlPoints.length % 3 === 0) {
for (let i = 0; i < controlPoints.length; i = i + 3) {
const [c1, c2, p] = controlPoints.slice(i, i + 3);
path.push(`C ${ptToStr(c1)}, ${ptToStr(c2)}, ${ptToStr(p)}`);
}
}
// if there's an even number of points, draw quadratic curves
else if (controlPoints.length % 2 === 0) {
for (let i = 0; i < controlPoints.length; i = i + 2) {
const [c, p] = controlPoints.slice(i, i + 2);
path.push(`Q ${ptToStr(c)}, ${ptToStr(p)}`);
}
}
// else, add missing points and try again
// https://stackoverflow.com/a/72577667/1010492
else {
for (let i = controlPoints.length - 3; i >= 2; i = i - 2) {
const missingPoint = midPoint(controlPoints[i - 1], controlPoints[i]);
controlPoints.splice(i, 0, missingPoint);
}
return getBezierPathFromPoints([start, ...controlPoints]);
}
return path.join(' ');
}
function midPoint(pt1, pt2) {
return {
x: (pt2.x + pt1.x) / 2,
y: (pt2.y + pt1.y) / 2,
};
}
function ptToStr({ x, y }) {
return `${x} ${y}`;
}
Usage (with an ElkExtendedEdge from elkjs):
const path = edge.sections
.map(({ startPoint, bendPoints, endPoint }) => getBezierPathFromPoints([startPoint, ...bendPoints, endPoint]))
.join(' ');
I receive a list of points from ELK which I would like to convert to a SVG path. The documentation says that bend points "must be interpreted as control points for a piecewise cubic spline" (which I'm using)
The problem is that the number of bend points + end point that I receive is not always a multiple of 3, so I do not have the required 2 control points + end points to draw all the segments in the curve.
After seeking support on the gitter chat, I was shown the code used in your vscode-extension (and also its Java counterpart):
While it works, I don't like that for certain number of points (eg: 4 bend points), the code will start drawing a cubic bezier, and end with a quadratic one, which does not produce a symmetric curve (eg see fiddle):
Another solution proposed was to compute and add extra points when there are not enough points to draw a cubic bezier curve (in pseudo-code):
With this solution, the result is nicer:
But this is odd that sometimes you need to compute extra points (based on some assumptions), and sometimes you can just use the bend points provided. Therefore I'm asking the question: what is the intent of the library? Is it just a bug in the layout engine that sometimes the number of points is not enough to draw a piecewise cubic bezier curve?