// index.ts
import { clone } from "@turf/clone";
import { distance } from "@turf/distance";
import { degreesToRadians, lengthToDegrees } from "@turf/helpers";

// lib/rbush-export.ts
import lib from "rbush";
var rbush = lib;

// index.ts
function clustersDbscan(points, maxDistance, options = {}) {
  if (options.mutate !== true) points = clone(points);
  const minPoints = options.minPoints || 3;
  const latDistanceInDegrees = lengthToDegrees(maxDistance, options.units);
  var tree = new rbush(points.features.length);
  var visited = points.features.map((_) => false);
  var assigned = points.features.map((_) => false);
  var isnoise = points.features.map((_) => false);
  var clusterIds = points.features.map((_) => -1);
  tree.load(
    points.features.map((point, index) => {
      var [x, y] = point.geometry.coordinates;
      return {
        minX: x,
        minY: y,
        maxX: x,
        maxY: y,
        index
      };
    })
  );
  const regionQuery = (index) => {
    const point = points.features[index];
    const [x, y] = point.geometry.coordinates;
    const minY = Math.max(y - latDistanceInDegrees, -90);
    const maxY = Math.min(y + latDistanceInDegrees, 90);
    const lonDistanceInDegrees = function() {
      if (minY < 0 && maxY > 0) {
        return latDistanceInDegrees;
      }
      if (Math.abs(minY) < Math.abs(maxY)) {
        return latDistanceInDegrees / Math.cos(degreesToRadians(maxY));
      } else {
        return latDistanceInDegrees / Math.cos(degreesToRadians(minY));
      }
    }();
    const minX = Math.max(x - lonDistanceInDegrees, -360);
    const maxX = Math.min(x + lonDistanceInDegrees, 360);
    const bbox = { minX, minY, maxX, maxY };
    return tree.search(bbox).filter(
      (neighbor) => {
        const neighborIndex = neighbor.index;
        const neighborPoint = points.features[neighborIndex];
        const distanceInKm = distance(point, neighborPoint, {
          units: "kilometers"
        });
        return distanceInKm <= maxDistance;
      }
    );
  };
  const expandCluster = (clusteredId, neighbors) => {
    for (var i = 0; i < neighbors.length; i++) {
      var neighbor = neighbors[i];
      const neighborIndex = neighbor.index;
      if (!visited[neighborIndex]) {
        visited[neighborIndex] = true;
        const nextNeighbors = regionQuery(neighborIndex);
        if (nextNeighbors.length >= minPoints) {
          neighbors.push(...nextNeighbors);
        }
      }
      if (!assigned[neighborIndex]) {
        assigned[neighborIndex] = true;
        clusterIds[neighborIndex] = clusteredId;
      }
    }
  };
  var nextClusteredId = 0;
  points.features.forEach((_, index) => {
    if (visited[index]) return;
    const neighbors = regionQuery(index);
    if (neighbors.length >= minPoints) {
      const clusteredId = nextClusteredId;
      nextClusteredId++;
      visited[index] = true;
      expandCluster(clusteredId, neighbors);
    } else {
      isnoise[index] = true;
    }
  });
  points.features.forEach((_, index) => {
    var clusterPoint = points.features[index];
    if (!clusterPoint.properties) {
      clusterPoint.properties = {};
    }
    if (clusterIds[index] >= 0) {
      clusterPoint.properties.dbscan = isnoise[index] ? "edge" : "core";
      clusterPoint.properties.cluster = clusterIds[index];
    } else {
      clusterPoint.properties.dbscan = "noise";
    }
  });
  return points;
}
var turf_clusters_dbscan_default = clustersDbscan;
export {
  clustersDbscan,
  turf_clusters_dbscan_default as default
};
//# sourceMappingURL=index.js.map