function getScalloppedPath(points, isClosed, radius = 24) {
return scapolledLine(points, isClosed, radius);
function getDirection(pts, index, closed) {
let last = pts.length - 1;
let start = index;
let end = closed && start == last ? 0 : index + 1;
let prev = closed && start == 0 ? last : start - 1;
let next = closed && end == last ? 0 : end + 1;
let isValidSegment =
0 <= start && start <= last && 0 <= end && end <= last && end !== start;
if (!isValidSegment) {
return 1;
}
let pt1 = pts[start];
let pt2 = pts[end];
let ccw = 0.0;
let theta = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x);
if (0 <= prev && prev <= last) {
ccw += getSeparationFromLine(pt1, theta, pts[prev]);
}
if (0 <= next && next <= last) {
ccw += getSeparationFromLine(pt1, theta, pts[next]);
}
return ccw > 0 ? "1" : "0";
}
function scapolledLine(pts, closed, radius) {
let scallopSize = radius;
let lastIndex = pts.length - 1;
let path = [];
let newP = null;
path.push("M", pts[0].x, pts[0].y);
pts.forEach(function (s, currentIndex) {
let stepW = scallopSize;
let lsw = 0;
let isClosingSegment = closed && currentIndex == lastIndex;
let nextIndex = isClosingSegment ? 0 : currentIndex + 1;
let e = pts[nextIndex];
if (!e) {
return;
}
let direction = getDirection(pts, currentIndex, closed);
let dist = distance(s.x, s.y, e.x, e.y);
if (dist === 0) {
return;
}
let angle = getAngle(s.x, s.y, e.x, e.y);
newP = s;
// Number of possible scallops between current pts
let n = dist / stepW,
crumb;
if (dist < stepW * 2) {
stepW = dist - stepW > stepW * 0.38 ? dist / 2 : dist;
} else {
n = n - (n % 1);
crumb = dist - n * stepW;
stepW += crumb / n;
}
// Recalculate possible scallops.
n = dist / stepW;
let aw = stepW / 2;
for (let i = 0; i < n; i++) {
newP = findNewPoint(newP.x, newP.y, angle, stepW);
if (i === n - 1) {
aw = (lsw > 0 ? lsw : stepW) / 2;
}
path.push("A", aw, aw, "0 0 " + direction, newP.x, newP.y);
}
if (isClosingSegment) {
path.push("A", stepW / 2, stepW / 2, "0 0 " + direction, e.x, e.y);
}
});
return path.join(" ");
}
function distance(x1, y1, x2, y2) {
return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
function findNewPoint(x, y, angle, distance) {
let result = {};
result.x = Math.round(Math.cos(angle) * distance + x);
result.y = Math.round(Math.sin(angle) * distance + y);
return result;
}
function getAngle(x1, y1, x2, y2) {
return Math.atan2(y2 - y1, x2 - x1);
}
function getSeparationFromLine(lineOrigin, lineAngle, pt) {
let x = pt.x - lineOrigin.x;
let y = pt.y - lineOrigin.y;
return -x * Math.sin(lineAngle) + y * Math.cos(lineAngle);
}
}