/* (c) 2017, Vladimir Agafonkin Simplify.js, a high-performance JS polyline simplification library mourner.github.io/simplify-js */ { // square distance between 2 points function getSqDist([x1, y1], [x2, y2]) { const dx = x1 - x2; const dy = y1 - y2; return dx * dx + dy * dy; } // square distance from a point to a segment function getSqSegDist([x1, y1], [x, y], [x2, y2]) { let dx = x2 - x; let dy = y2 - y; if (dx !== 0 || dy !== 0) { const t = ((x1 - x) * dx + (y1 - y) * dy) / (dx * dx + dy * dy); if (t > 1) { x = x2; y = y2; } else if (t > 0) { x += dx * t; y += dy * t; } } dx = x1 - x; dy = y1 - y; return dx * dx + dy * dy; } // rest of the code doesn't care about point format // basic distance-based simplification function simplifyRadialDist(points, sqTolerance) { let prevPoint = points[0]; const newPoints = [prevPoint]; let point; for (let i = 1, len = points.length; i < len; i++) { point = points[i]; if (getSqDist(point, prevPoint) > sqTolerance) { newPoints.push(point); prevPoint = point; } } if (point && prevPoint !== point) newPoints.push(point); return newPoints; } function simplifyDPStep(points, first, last, sqTolerance, simplified) { let maxSqDist = sqTolerance; let index = first; for (let i = first + 1; i < last; i++) { const sqDist = getSqSegDist(points[i], points[first], points[last]); if (sqDist > maxSqDist) { index = i; maxSqDist = sqDist; } } if (maxSqDist > sqTolerance) { if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified); simplified.push(points[index]); if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified); } } // simplification using Ramer-Douglas-Peucker algorithm function simplifyDouglasPeucker(points, sqTolerance) { const last = points.length - 1; const simplified = [points[0]]; simplifyDPStep(points, 0, last, sqTolerance, simplified); simplified.push(points[last]); return simplified; } // both algorithms combined for awesome performance function simplify(points, tolerance, highestQuality = false) { if (points.length <= 2) return points; const sqTolerance = tolerance * tolerance; points = highestQuality ? points : simplifyRadialDist(points, sqTolerance); points = simplifyDouglasPeucker(points, sqTolerance); return points; } window.simplify = simplify; }