'use strict'; var cleanCoords = require('@turf/clean-coords'); var clone = require('@turf/clone'); var meta = require('@turf/meta'); var helpers = require('@turf/helpers'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var cleanCoords__default = /*#__PURE__*/_interopDefaultLegacy(cleanCoords); var clone__default = /*#__PURE__*/_interopDefaultLegacy(clone); /* (c) 2013, Vladimir Agafonkin Simplify.js, a high-performance JS polyline simplification library mourner.github.io/simplify-js */ // to suit your point format, run search/replace for '.x' and '.y'; // for 3D version, see 3d branch (configurability would draw significant performance overhead) // square distance between 2 points function getSqDist(p1, p2) { var dx = p1.x - p2.x, dy = p1.y - p2.y; return dx * dx + dy * dy; } // square distance from a point to a segment function getSqSegDist(p, p1, p2) { var x = p1.x, y = p1.y, dx = p2.x - x, dy = p2.y - y; if (dx !== 0 || dy !== 0) { var 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) { var prevPoint = points[0], newPoints = [prevPoint], point; for (var 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) { var maxSqDist = sqTolerance, index; for (var i = first + 1; i < last; i++) { var 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) { var last = points.length - 1; var 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; } /** * Takes a {@link GeoJSON} object and returns a simplified version. Internally uses * [simplify-js](http://mourner.github.io/simplify-js/) to perform simplification using the Ramer-Douglas-Peucker algorithm. * * @name simplify * @param {GeoJSON} geojson object to be simplified * @param {Object} [options={}] Optional parameters * @param {number} [options.tolerance=1] simplification tolerance * @param {boolean} [options.highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true) * @returns {GeoJSON} a simplified GeoJSON * @example * var geojson = turf.polygon([[ * [-70.603637, -33.399918], * [-70.614624, -33.395332], * [-70.639343, -33.392466], * [-70.659942, -33.394759], * [-70.683975, -33.404504], * [-70.697021, -33.419406], * [-70.701141, -33.434306], * [-70.700454, -33.446339], * [-70.694274, -33.458369], * [-70.682601, -33.465816], * [-70.668869, -33.472117], * [-70.646209, -33.473835], * [-70.624923, -33.472117], * [-70.609817, -33.468107], * [-70.595397, -33.458369], * [-70.587158, -33.442901], * [-70.587158, -33.426283], * [-70.590591, -33.414248], * [-70.594711, -33.406224], * [-70.603637, -33.399918] * ]]); * var options = {tolerance: 0.01, highQuality: false}; * var simplified = turf.simplify(geojson, options); * * //addToMap * var addToMap = [geojson, simplified] */ function simplify$1(geojson, options) { // Optional parameters options = options || {}; if (!helpers.isObject(options)) throw new Error("options is invalid"); var tolerance = options.tolerance !== undefined ? options.tolerance : 1; var highQuality = options.highQuality || false; var mutate = options.mutate || false; if (!geojson) throw new Error("geojson is required"); if (tolerance && tolerance < 0) throw new Error("invalid tolerance"); // Clone geojson to avoid side effects if (mutate !== true) geojson = clone__default['default'](geojson); meta.geomEach(geojson, function (geom) { simplifyGeom(geom, tolerance, highQuality); }); return geojson; } /** * Simplifies a feature's coordinates * * @private * @param {Geometry} geometry to be simplified * @param {number} [tolerance=1] simplification tolerance * @param {boolean} [highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm * @returns {Geometry} output */ function simplifyGeom(geometry, tolerance, highQuality) { var type = geometry.type; // "unsimplyfiable" geometry types if (type === "Point" || type === "MultiPoint") return geometry; // Remove any extra coordinates cleanCoords__default['default'](geometry, true); var coordinates = geometry.coordinates; switch (type) { case "LineString": geometry["coordinates"] = simplifyLine( coordinates, tolerance, highQuality ); break; case "MultiLineString": geometry["coordinates"] = coordinates.map(function (lines) { return simplifyLine(lines, tolerance, highQuality); }); break; case "Polygon": geometry["coordinates"] = simplifyPolygon( coordinates, tolerance, highQuality ); break; case "MultiPolygon": geometry["coordinates"] = coordinates.map(function (rings) { return simplifyPolygon(rings, tolerance, highQuality); }); } return geometry; } /** * Simplifies the coordinates of a LineString with simplify-js * * @private * @param {Array} coordinates to be processed * @param {number} tolerance simplification tolerance * @param {boolean} highQuality whether or not to spend more time to create a higher-quality * @returns {Array>} simplified coords */ function simplifyLine(coordinates, tolerance, highQuality) { return simplify( coordinates.map(function (coord) { return { x: coord[0], y: coord[1], z: coord[2] }; }), tolerance, highQuality ).map(function (coords) { return coords.z ? [coords.x, coords.y, coords.z] : [coords.x, coords.y]; }); } /** * Simplifies the coordinates of a Polygon with simplify-js * * @private * @param {Array} coordinates to be processed * @param {number} tolerance simplification tolerance * @param {boolean} highQuality whether or not to spend more time to create a higher-quality * @returns {Array>>} simplified coords */ function simplifyPolygon(coordinates, tolerance, highQuality) { return coordinates.map(function (ring) { var pts = ring.map(function (coord) { return { x: coord[0], y: coord[1] }; }); if (pts.length < 4) { throw new Error("invalid polygon"); } var simpleRing = simplify(pts, tolerance, highQuality).map(function ( coords ) { return [coords.x, coords.y]; }); //remove 1 percent of tolerance until enough points to make a triangle while (!checkValidity(simpleRing)) { tolerance -= tolerance * 0.01; simpleRing = simplify(pts, tolerance, highQuality).map(function ( coords ) { return [coords.x, coords.y]; }); } if ( simpleRing[simpleRing.length - 1][0] !== simpleRing[0][0] || simpleRing[simpleRing.length - 1][1] !== simpleRing[0][1] ) { simpleRing.push(simpleRing[0]); } return simpleRing; }); } /** * Returns true if ring has at least 3 coordinates and its first coordinate is the same as its last * * @private * @param {Array} ring coordinates to be checked * @returns {boolean} true if valid */ function checkValidity(ring) { if (ring.length < 3) return false; //if the last point is the same as the first, it's not a triangle return !( ring.length === 3 && ring[2][0] === ring[0][0] && ring[2][1] === ring[0][1] ); } module.exports = simplify$1; module.exports.default = simplify$1;