2
votes

Is there a SVG API in JS allowing to get Bezier and Spline point coordinates once they are generated?

I want to control a production machine that will follow the curve path. I need to know: 1) length along the path, or along each portion of the path. 2) at every specified distance along the path, know the radius of curvature. One way I can imagine I can compute radius of curvature is to compare tengent (or path direction) from an adjacent point to another.

But do I really need to generate my own JS for drawing thes curves if I want to be able to "read" path curve specifications?

At worst, I would need to collect coordinates of all pixels generated. Thanks

2
There is an API for path elements that includes getting the xy coordinates as a function of length. You can invert that to get length as a function of xy using a binary search. You can also build your path with path elements, and get the length of each component quite easily. - Cool Blue

2 Answers

2
votes
  1. total path length: SVG API: path.getTotalLength()
  2. length along the path: SVG API:path.getPointAtLength(...), which you probably want to base on the total length
  3. radius of curvature at a point: there is no baked in API, so you're going to have to roll your own by trivially fitting a circle to your point and the points before and after it.

We construct three points:

var p1 = path.getPointAtLength(n - e),
    p2 = path.getPointAtLength(n),
    p3 = path.getPointAtLength(n + e);

where e is some small value. Then, we know that a circle that passes through all three points has each point on the circle, at the same distance (obviously), and we also know that if we construct chords between the points, then the lines through the center of those chords (perpendicular to them) will intersect at the circle's center.

So that's how you find a circle through any three points: we need to find the chords p1--p2 and p2--p3, find their midpoints, construct some lines through those midpoints perpendicular to each chord, and then their intersection is the center of our circle and we're done. We'll know the radius of curvature at our original point. So:

// chords p1--p2 and p2--p3
var dx1 = (p2.x - p1.x), dy1 = (p2.y - p1.y),
    dx2 = (p3.x - p2.x), dy2 = (p3.y - p2.y);

// chord midpoints
var mx1 = (p1.x + p2.x)/2, my1 = (p1.y + p2.y)/2,
    mx2 = (p2.x + p3.x)/2, my2 = (p2.y + p3.y)/2;

// chord normals
var nx1 = -dy1, ny1 = dx1
    nx2 = -dy2, ny2 = dx2;

// chord midpoint offsets along the normals
var ox1 = mx1 + dx1p, oy1 = my1 + dy1p,
    ox2 = mx2 + dx2p, oy2 = my2 + dy2p;

And then we can use the common line intersection test to find the circle's midpoint:

// line-line-intersection using a flat 8 coordinate values
function lli8(x1,y1,x2,y2,x3,y3,x4,y4) {
  var nx=(x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4),
      ny=(x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4),
      d=(x1-x2)*(y3-y4)-(y1-y2)*(x3-x4);
  if(d==0) { return false; }
  return { x: nx/d, y: ny/d };
}

which we call as lli8(mx1, my1, ox1, oy1, mx2, my2, ox2, oy2), which because we know the center of the circle through these three points, gives us the radius for the point we were originally interested in.

0
votes

Path elements have a getPointAtLength() method you can call. You pass it a length along the curve and it will return the x and y.

var path = document.getElementById("test");
var point = path.getPointAtLength(300);
alert("x=" + point.x + " y=" + point.y);
<svg>
  <path id="test" d="M 0,0 C 0,150 300,0 300,150" fill="none" stroke="black"/>
</svg>