| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 | import distance from "@turf/distance";import { feature, featureCollection } from "@turf/helpers";import { featureEach } from "@turf/meta";import tin from "@turf/tin";import dissolve from "./lib/turf-dissolve.js";/** * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon. * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries. * * @name concave * @param {FeatureCollection<Point>} points input points * @param {Object} [options={}] Optional parameters * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the * hull to become concave. * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull) * @example * var points = turf.featureCollection([ *   turf.point([-63.601226, 44.642643]), *   turf.point([-63.591442, 44.651436]), *   turf.point([-63.580799, 44.648749]), *   turf.point([-63.573589, 44.641788]), *   turf.point([-63.587665, 44.64533]), *   turf.point([-63.595218, 44.64765]) * ]); * var options = {units: 'miles', maxEdge: 1}; * * var hull = turf.concave(points, options); * * //addToMap * var addToMap = [points, hull] */function concave(points, options) {    if (options === void 0) { options = {}; }    var maxEdge = options.maxEdge || Infinity;    var cleaned = removeDuplicates(points);    var tinPolys = tin(cleaned);    // calculate length of all edges and area of all triangles    // and remove triangles that fail the max length test    tinPolys.features = tinPolys.features.filter(function (triangle) {        var pt1 = triangle.geometry.coordinates[0][0];        var pt2 = triangle.geometry.coordinates[0][1];        var pt3 = triangle.geometry.coordinates[0][2];        var dist1 = distance(pt1, pt2, options);        var dist2 = distance(pt2, pt3, options);        var dist3 = distance(pt1, pt3, options);        return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;    });    if (tinPolys.features.length < 1) {        return null;    }    // merge the adjacent triangles    var dissolved = dissolve(tinPolys);    // geojson-dissolve always returns a MultiPolygon    if (dissolved.coordinates.length === 1) {        dissolved.coordinates = dissolved.coordinates[0];        dissolved.type = "Polygon";    }    return feature(dissolved);}/** * Removes duplicated points in a collection returning a new collection * * @private * @param {FeatureCollection<Point>} points to be cleaned * @returns {FeatureCollection<Point>} cleaned set of points */function removeDuplicates(points) {    var cleaned = [];    var existing = {};    featureEach(points, function (pt) {        if (!pt.geometry) {            return;        }        var key = pt.geometry.coordinates.join("-");        if (!Object.prototype.hasOwnProperty.call(existing, key)) {            cleaned.push(pt);            existing[key] = true;        }    });    return featureCollection(cleaned);}export default concave;
 |