-
Notifications
You must be signed in to change notification settings - Fork 937
/
index.ts
99 lines (87 loc) · 3.33 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { Feature, GeoJsonProperties, Point, Position } from "geojson";
import { convex } from "@turf/convex";
import { centroid } from "@turf/centroid";
import { point } from "@turf/helpers";
import { getType, getCoord } from "@turf/invariant";
import { coordEach } from "@turf/meta";
/**
* Takes any {@link Feature} or a {@link FeatureCollection} and returns its [center of mass](https://en.wikipedia.org/wiki/Center_of_mass) using this formula: [Centroid of Polygon](https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon).
*
* @name centerOfMass
* @param {GeoJSON} geojson GeoJSON to be centered
* @param {Object} [options={}] Optional Parameters
* @param {Object} [options.properties={}] Translate Properties to Feature
* @returns {Feature<Point>} the center of mass
* @example
* var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
*
* var center = turf.centerOfMass(polygon);
*
* //addToMap
* var addToMap = [polygon, center]
*/
function centerOfMass<P extends GeoJsonProperties = GeoJsonProperties>(
geojson: any,
options: {
properties?: P;
} = {}
): Feature<Point, P> {
switch (getType(geojson)) {
case "Point":
return point(getCoord(geojson), options.properties);
case "Polygon":
var coords: Position[] = [];
coordEach(geojson, function (coord) {
coords.push(coord);
});
// First, we neutralize the feature (set it around coordinates [0,0]) to prevent rounding errors
// We take any point to translate all the points around 0
var centre = centroid(geojson, { properties: options.properties });
var translation = centre.geometry.coordinates;
var sx = 0;
var sy = 0;
var sArea = 0;
var i, pi, pj, xi, xj, yi, yj, a;
var neutralizedPoints = coords.map(function (point) {
return [point[0] - translation[0], point[1] - translation[1]];
});
for (i = 0; i < coords.length - 1; i++) {
// pi is the current point
pi = neutralizedPoints[i];
xi = pi[0];
yi = pi[1];
// pj is the next point (pi+1)
pj = neutralizedPoints[i + 1];
xj = pj[0];
yj = pj[1];
// a is the common factor to compute the signed area and the final coordinates
a = xi * yj - xj * yi;
// sArea is the sum used to compute the signed area
sArea += a;
// sx and sy are the sums used to compute the final coordinates
sx += (xi + xj) * a;
sy += (yi + yj) * a;
}
// Shape has no area: fallback on turf.centroid
if (sArea === 0) {
return centre;
} else {
// Compute the signed area, and factorize 1/6A
var area = sArea * 0.5;
var areaFactor = 1 / (6 * area);
// Compute the final coordinates, adding back the values that have been neutralized
return point(
[translation[0] + areaFactor * sx, translation[1] + areaFactor * sy],
options.properties
);
}
default:
// Not a polygon: Compute the convex hull and work with that
var hull = convex(geojson);
if (hull) return centerOfMass(hull, { properties: options.properties });
// Hull is empty: fallback on the centroid
else return centroid(geojson, { properties: options.properties });
}
}
export { centerOfMass };
export default centerOfMass;