elk icon indicating copy to clipboard operation
elk copied to clipboard

How to interpret the bend points used to route edges with splines?

Open gfox1984 opened this issue 2 years ago • 0 comments

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):

     case K_SPLINE: {
            path += `M${points[0].x},${points[0].y}`
            for (let i = 1; i < points.length; i = i + 3) {
                const remainingPoints = points.length - i
                if (remainingPoints === 1) {
                    // if one routing point is left, draw a straight line to there.
                    path += `L${points[i].x},${points[i].y}`
                } else if (remainingPoints === 2) {
                    // if two routing points are left, draw a quadratic bezier curve with those two points.
                    path += `Q${points[i].x},${points[i].y} ${points[i + 1].x},${points[i + 1].y}`
                } else {
                    // if three or more routing points are left, draw a cubic bezier curve with those points.
                    path += `C${points[i].x},${points[i].y} `
                        + `${points[i + 1].x},${points[i + 1].y} `
                        + `${points[i + 2].x},${points[i + 2].y}`
                }
            }
            break
        }

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): image

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):

# First, remove the start point from the list
start <- points.shift

# Then build the missing points, which requires running
# through the point list in reverse, so that data
# at each iteration is unaffected by previous insertions.

i <- points.length - 3
while i >= 2:
  points.insert(i, (points[i-1] + points[i])/2 )
  i <- i - 2

# Now we can walk through the completed point set.
moveTo(start)
for each (c1,c2,p) in points:
  cubicCurveTo(c1, c2, p)

With this solution, the result is nicer: image

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?

gfox1984 avatar Jun 15 '22 10:06 gfox1984