76 lines
3.8 KiB
JavaScript
Executable File
76 lines
3.8 KiB
JavaScript
Executable File
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var clone_1 = __importDefault(require("@turf/clone"));
|
|
var distance_1 = __importDefault(require("@turf/distance"));
|
|
var meta_1 = require("@turf/meta");
|
|
var helpers_1 = require("@turf/helpers");
|
|
var density_clustering_1 = __importDefault(require("density-clustering"));
|
|
/**
|
|
* Takes a set of {@link Point|points} and partition them into clusters according to {@link DBSCAN's|https://en.wikipedia.org/wiki/DBSCAN} data clustering algorithm.
|
|
*
|
|
* @name clustersDbscan
|
|
* @param {FeatureCollection<Point>} points to be clustered
|
|
* @param {number} maxDistance Maximum Distance between any point of the cluster to generate the clusters (kilometers only)
|
|
* @param {Object} [options={}] Optional parameters
|
|
* @param {string} [options.units="kilometers"] in which `maxDistance` is expressed, can be degrees, radians, miles, or kilometers
|
|
* @param {boolean} [options.mutate=false] Allows GeoJSON input to be mutated
|
|
* @param {number} [options.minPoints=3] Minimum number of points to generate a single cluster,
|
|
* points which do not meet this requirement will be classified as an 'edge' or 'noise'.
|
|
* @returns {FeatureCollection<Point>} Clustered Points with an additional two properties associated to each Feature:
|
|
* - {number} cluster - the associated clusterId
|
|
* - {string} dbscan - type of point it has been classified as ('core'|'edge'|'noise')
|
|
* @example
|
|
* // create random points with random z-values in their properties
|
|
* var points = turf.randomPoint(100, {bbox: [0, 30, 20, 50]});
|
|
* var maxDistance = 100;
|
|
* var clustered = turf.clustersDbscan(points, maxDistance);
|
|
*
|
|
* //addToMap
|
|
* var addToMap = [clustered];
|
|
*/
|
|
function clustersDbscan(points, maxDistance, options) {
|
|
// Input validation being handled by Typescript
|
|
// collectionOf(points, 'Point', 'points must consist of a FeatureCollection of only Points');
|
|
// if (maxDistance === null || maxDistance === undefined) throw new Error('maxDistance is required');
|
|
// if (!(Math.sign(maxDistance) > 0)) throw new Error('maxDistance is invalid');
|
|
// if (!(minPoints === undefined || minPoints === null || Math.sign(minPoints) > 0)) throw new Error('options.minPoints is invalid');
|
|
if (options === void 0) { options = {}; }
|
|
// Clone points to prevent any mutations
|
|
if (options.mutate !== true)
|
|
points = clone_1.default(points);
|
|
// Defaults
|
|
options.minPoints = options.minPoints || 3;
|
|
// create clustered ids
|
|
var dbscan = new density_clustering_1.default.DBSCAN();
|
|
var clusteredIds = dbscan.run(meta_1.coordAll(points), helpers_1.convertLength(maxDistance, options.units), options.minPoints, distance_1.default);
|
|
// Tag points to Clusters ID
|
|
var clusterId = -1;
|
|
clusteredIds.forEach(function (clusterIds) {
|
|
clusterId++;
|
|
// assign cluster ids to input points
|
|
clusterIds.forEach(function (idx) {
|
|
var clusterPoint = points.features[idx];
|
|
if (!clusterPoint.properties)
|
|
clusterPoint.properties = {};
|
|
clusterPoint.properties.cluster = clusterId;
|
|
clusterPoint.properties.dbscan = "core";
|
|
});
|
|
});
|
|
// handle noise points, if any
|
|
// edges points are tagged by DBSCAN as both 'noise' and 'cluster' as they can "reach" less than 'minPoints' number of points
|
|
dbscan.noise.forEach(function (noiseId) {
|
|
var noisePoint = points.features[noiseId];
|
|
if (!noisePoint.properties)
|
|
noisePoint.properties = {};
|
|
if (noisePoint.properties.cluster)
|
|
noisePoint.properties.dbscan = "edge";
|
|
else
|
|
noisePoint.properties.dbscan = "noise";
|
|
});
|
|
return points;
|
|
}
|
|
exports.default = clustersDbscan;
|