123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- 'use strict';
- var meta = require('@turf/meta');
- var helpers = require('@turf/helpers');
- /**
- * Smooths a {@link Polygon} or {@link MultiPolygon}. Based on [Chaikin's algorithm](http://graphics.cs.ucdavis.edu/education/CAGDNotes/Chaikins-Algorithm/Chaikins-Algorithm.html).
- * Warning: may create degenerate polygons.
- *
- * @name polygonSmooth
- * @param {FeatureCollection|Feature<Polygon|MultiPolygon>} inputPolys (Multi)Polygon(s) to smooth
- * @param {Object} [options={}] Optional parameters
- * @param {string} [options.iterations=1] THe number of times to smooth the polygon. A higher value means a smoother polygon.
- * @returns {FeatureCollection<Polygon>} FeatureCollection containing the smoothed polygon/poylgons
- * @example
- * var polygon = turf.polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
- *
- * var smoothed = turf.polygonSmooth(polygon, {iterations: 3})
- *
- * //addToMap
- * var addToMap = [smoothed, polygon];
- */
- function polygonSmooth(inputPolys, options) {
- var outPolys = [];
- // Optional parameters
- var iterations = options.iterations || 1;
- if (!inputPolys) throw new Error("inputPolys is required");
- meta.geomEach(inputPolys, function (geom, geomIndex, properties) {
- var outCoords;
- var poly;
- var tempOutput;
- switch (geom.type) {
- case "Polygon":
- outCoords = [[]];
- for (var i = 0; i < iterations; i++) {
- tempOutput = [[]];
- poly = geom;
- if (i > 0) poly = helpers.polygon(outCoords).geometry;
- processPolygon(poly, tempOutput);
- outCoords = tempOutput.slice(0);
- }
- outPolys.push(helpers.polygon(outCoords, properties));
- break;
- case "MultiPolygon":
- outCoords = [[[]]];
- for (var y = 0; y < iterations; y++) {
- tempOutput = [[[]]];
- poly = geom;
- if (y > 0) poly = helpers.multiPolygon(outCoords).geometry;
- processMultiPolygon(poly, tempOutput);
- outCoords = tempOutput.slice(0);
- }
- outPolys.push(helpers.multiPolygon(outCoords, properties));
- break;
- default:
- throw new Error("geometry is invalid, must be Polygon or MultiPolygon");
- }
- });
- return helpers.featureCollection(outPolys);
- }
- /**
- * @param {poly} poly to process
- * @param {poly} tempOutput to place the results in
- * @private
- */
- function processPolygon(poly, tempOutput) {
- var prevGeomIndex = 0;
- var subtractCoordIndex = 0;
- meta.coordEach(
- poly,
- function (
- currentCoord,
- coordIndex,
- featureIndex,
- multiFeatureIndex,
- geometryIndex
- ) {
- if (geometryIndex > prevGeomIndex) {
- prevGeomIndex = geometryIndex;
- subtractCoordIndex = coordIndex;
- tempOutput.push([]);
- }
- var realCoordIndex = coordIndex - subtractCoordIndex;
- var p1 = poly.coordinates[geometryIndex][realCoordIndex + 1];
- var p0x = currentCoord[0];
- var p0y = currentCoord[1];
- var p1x = p1[0];
- var p1y = p1[1];
- tempOutput[geometryIndex].push([
- 0.75 * p0x + 0.25 * p1x,
- 0.75 * p0y + 0.25 * p1y,
- ]);
- tempOutput[geometryIndex].push([
- 0.25 * p0x + 0.75 * p1x,
- 0.25 * p0y + 0.75 * p1y,
- ]);
- },
- true
- );
- tempOutput.forEach(function (ring) {
- ring.push(ring[0]);
- });
- }
- /**
- * @param {poly} poly to process
- * @param {poly} tempOutput to place the results in
- * @private
- */
- function processMultiPolygon(poly, tempOutput) {
- var prevGeomIndex = 0;
- var subtractCoordIndex = 0;
- var prevMultiIndex = 0;
- meta.coordEach(
- poly,
- function (
- currentCoord,
- coordIndex,
- featureIndex,
- multiFeatureIndex,
- geometryIndex
- ) {
- if (multiFeatureIndex > prevMultiIndex) {
- prevMultiIndex = multiFeatureIndex;
- subtractCoordIndex = coordIndex;
- tempOutput.push([[]]);
- }
- if (geometryIndex > prevGeomIndex) {
- prevGeomIndex = geometryIndex;
- subtractCoordIndex = coordIndex;
- tempOutput[multiFeatureIndex].push([]);
- }
- var realCoordIndex = coordIndex - subtractCoordIndex;
- var p1 =
- poly.coordinates[multiFeatureIndex][geometryIndex][realCoordIndex + 1];
- var p0x = currentCoord[0];
- var p0y = currentCoord[1];
- var p1x = p1[0];
- var p1y = p1[1];
- tempOutput[multiFeatureIndex][geometryIndex].push([
- 0.75 * p0x + 0.25 * p1x,
- 0.75 * p0y + 0.25 * p1y,
- ]);
- tempOutput[multiFeatureIndex][geometryIndex].push([
- 0.25 * p0x + 0.75 * p1x,
- 0.25 * p0y + 0.75 * p1y,
- ]);
- },
- true
- );
- tempOutput.forEach(function (poly) {
- poly.forEach(function (ring) {
- ring.push(ring[0]);
- });
- });
- }
- module.exports = polygonSmooth;
- module.exports.default = polygonSmooth;
|