From fa59407aec7a334c50064e59881db895ae0018c8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 12 Aug 2016 21:32:03 +0300 Subject: [PATCH] Import adapted version of simplify.js for path simplifications. --- src/uxbox/util/geom/path_impl_simplify.js | 122 ++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/uxbox/util/geom/path_impl_simplify.js diff --git a/src/uxbox/util/geom/path_impl_simplify.js b/src/uxbox/util/geom/path_impl_simplify.js new file mode 100644 index 000000000..b6956d70f --- /dev/null +++ b/src/uxbox/util/geom/path_impl_simplify.js @@ -0,0 +1,122 @@ +/** + * Simplify.js, a high-performance JS polyline simplification library. + * + * Is a modified and google closure adapted implementation of + * https://github.com/mourner/simplify-js + * + * @author Vladimir Agafonkin, 2013 + * @author Andrey Antukh , 2016 + * @license BSD License + */ + +"use strict"; + +goog.provide("uxbox.util.geom.path_impl_simplify"); + +goog.scope(function() { + const self = uxbox.util.geom.path_impl_simplify; + + // square distance between 2 points + function getSqDist(p1, p2) { + const dx = p1.x - p2.x; + const dy = p1.y - p2.y; + return dx * dx + dy * dy; + } + + // square distance from a point to a segment + function getSqSegDist(p, p1, p2) { + let x = p1.x; + let y = p1.y; + let dx = p2.x - x; + let dy = p2.y - y; + + if (dx !== 0 || dy !== 0) { + const t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy); + + if (t > 1) { + x = p2.x; + y = p2.y; + + } else if (t > 0) { + x += dx * t; + y += dy * t; + } + } + + dx = p.x - x; + dy = p.y - 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]; + let 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 (prevPoint !== point) { + newPoints.push(point); + } + + return newPoints; + } + + function simplifyDPStep(points, first, last, sqTolerance, simplified) { + let maxSqDist = sqTolerance; + let index; + + for (let i = first + 1; i < last; i++) { + let 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) { + let last = points.length - 1; + + let 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) { + if (points.length <= 2) { + return points; + } + + var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1; + points = highestQuality ? points : simplifyRadialDist(points, sqTolerance); + points = simplifyDouglasPeucker(points, sqTolerance); + return points; + } + + self.simplify = simplify; +});