{"version":3,"sources":["/home/runner/work/turf/turf/packages/turf-center-median/dist/cjs/index.cjs","../../index.ts"],"names":[],"mappings":"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","file":"/home/runner/work/turf/turf/packages/turf-center-median/dist/cjs/index.cjs","sourcesContent":[null,"import { FeatureCollection, Feature, Point, Position } from \"geojson\";\nimport { centerMean } from \"@turf/center-mean\";\nimport { distance } from \"@turf/distance\";\nimport { centroid } from \"@turf/centroid\";\nimport { isNumber, point, isObject, featureCollection } from \"@turf/helpers\";\nimport { featureEach } from \"@turf/meta\";\n\n/**\n * Takes a {@link FeatureCollection} of points and calculates the median center,\n * algorithimically. The median center is understood as the point that is\n * requires the least total travel from all other points.\n *\n * Turfjs has four different functions for calculating the center of a set of\n * data. Each is useful depending on circumstance.\n *\n * `@turf/center` finds the simple center of a dataset, by finding the\n * midpoint between the extents of the data. That is, it divides in half the\n * farthest east and farthest west point as well as the farthest north and\n * farthest south.\n *\n * `@turf/center-of-mass` imagines that the dataset is a sheet of paper.\n * The center of mass is where the sheet would balance on a fingertip.\n *\n * `@turf/center-mean` takes the averages of all the coordinates and\n * produces a value that respects that. Unlike `@turf/center`, it is\n * sensitive to clusters and outliers. It lands in the statistical middle of a\n * dataset, not the geographical. It can also be weighted, meaning certain\n * points are more important than others.\n *\n * `@turf/center-median` takes the mean center and tries to find, iteratively,\n * a new point that requires the least amount of travel from all the points in\n * the dataset. It is not as sensitive to outliers as `@turf/center-mean`, but it is\n * attracted to clustered data. It, too, can be weighted.\n *\n * **Bibliography**\n *\n * Harold W. Kuhn and Robert E. Kuenne, β€œAn Efficient Algorithm for the\n * Numerical Solution of the Generalized Weber Problem in Spatial\n * Economics,” _Journal of Regional Science_ 4, no. 2 (1962): 21–33,\n * doi:{@link https://doi.org/10.1111/j.1467-9787.1962.tb00902.x}.\n *\n * James E. Burt, Gerald M. Barber, and David L. Rigby, _Elementary\n * Statistics for Geographers_, 3rd ed., New York: The Guilford\n * Press, 2009, 150–151.\n *\n * @function\n * @param {FeatureCollection} features Any GeoJSON Feature Collection\n * @param {Object} [options={}] Optional parameters\n * @param {string} [options.weight] the property name used to weight the center\n * @param {number} [options.tolerance=0.001] the difference in distance between candidate medians at which point the algorighim stops iterating.\n * @param {number} [options.counter=10] how many attempts to find the median, should the tolerance be insufficient.\n * @returns {Feature} The median center of the collection\n * @example\n * var points = turf.points([[0, 0], [1, 0], [0, 1], [5, 8]]);\n * var medianCenter = turf.centerMedian(points);\n *\n * //addToMap\n * var addToMap = [points, medianCenter]\n */\nfunction centerMedian(\n features: FeatureCollection,\n options: { weight?: string; tolerance?: number; counter?: number } = {}\n): Feature<\n Point,\n {\n medianCandidates: Array;\n [key: string]: any;\n }\n> {\n // Optional params\n options = options || {};\n if (!isObject(options)) throw new Error(\"options is invalid\");\n var counter = options.counter || 10;\n if (!isNumber(counter)) throw new Error(\"counter must be a number\");\n var weightTerm = options.weight;\n\n // Calculate mean center:\n var meanCenter = centerMean(features, { weight: options.weight });\n\n // Calculate center of every feature:\n var centroids = featureCollection([]);\n featureEach(features, function (feature) {\n centroids.features.push(\n centroid(feature, {\n properties: { weight: feature.properties?.[weightTerm!] },\n })\n );\n });\n\n const properties: MedianProperties = {\n tolerance: options.tolerance,\n medianCandidates: [],\n };\n\n return findMedian(\n meanCenter.geometry.coordinates,\n [0, 0],\n centroids,\n properties,\n counter\n ) as Feature<\n Point,\n {\n medianCandidates: Array;\n [key: string]: any;\n }\n >;\n}\n\ninterface MedianProperties {\n tolerance?: number;\n medianCandidates: Position[];\n}\n\n/**\n * Recursive function to find new candidate medians.\n *\n * @private\n * @param {Position} candidateMedian current candidate median\n * @param {Position} previousCandidate the previous candidate median\n * @param {FeatureCollection} centroids the collection of centroids whose median we are determining\n * @param {number} counter how many attempts to try before quitting.\n * @returns {Feature} the median center of the dataset.\n */\nfunction findMedian(\n candidateMedian: Position,\n previousCandidate: Position,\n centroids: FeatureCollection,\n properties: MedianProperties,\n counter: number\n): Feature {\n var tolerance = properties.tolerance || 0.001;\n var candidateXsum = 0;\n var candidateYsum = 0;\n var kSum = 0;\n var centroidCount = 0;\n featureEach(centroids, function (theCentroid) {\n var weightValue = theCentroid.properties?.weight;\n var weight =\n weightValue === undefined || weightValue === null ? 1 : weightValue;\n weight = Number(weight);\n if (!isNumber(weight)) throw new Error(\"weight value must be a number\");\n if (weight > 0) {\n centroidCount += 1;\n var distanceFromCandidate =\n weight * distance(theCentroid, candidateMedian);\n if (distanceFromCandidate === 0) distanceFromCandidate = 1;\n var k = weight / distanceFromCandidate;\n candidateXsum += theCentroid.geometry.coordinates[0] * k;\n candidateYsum += theCentroid.geometry.coordinates[1] * k;\n kSum += k;\n }\n });\n if (centroidCount < 1) throw new Error(\"no features to measure\");\n var candidateX = candidateXsum / kSum;\n var candidateY = candidateYsum / kSum;\n if (\n centroidCount === 1 ||\n counter === 0 ||\n (Math.abs(candidateX - previousCandidate[0]) < tolerance &&\n Math.abs(candidateY - previousCandidate[1]) < tolerance)\n ) {\n return point([candidateX, candidateY], {\n medianCandidates: properties.medianCandidates,\n });\n } else {\n properties.medianCandidates.push([candidateX, candidateY]);\n return findMedian(\n [candidateX, candidateY],\n candidateMedian,\n centroids,\n properties,\n counter - 1\n );\n }\n}\n\nexport { centerMedian };\nexport default centerMedian;\n"]}