@turf/concave 7.0.0-alpha.2 → 7.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,26 +57,21 @@ Returns **([Feature][8]<([Polygon][9] | [MultiPolygon][10])> | null)** a concave
57
57
 
58
58
  [10]: https://tools.ietf.org/html/rfc7946#section-3.1.7
59
59
 
60
- <!-- This file is automatically generated. Please don't edit it directly:
61
- if you find an error, edit the source file (likely index.js), and re-run
62
- ./scripts/generate-readmes in the turf project. -->
60
+ <!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->
63
61
 
64
62
  ---
65
63
 
66
- This module is part of the [Turfjs project](http://turfjs.org/), an open source
67
- module collection dedicated to geographic algorithms. It is maintained in the
68
- [Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create
69
- PRs and issues.
64
+ This module is part of the [Turfjs project](https://turfjs.org/), an open source module collection dedicated to geographic algorithms. It is maintained in the [Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create PRs and issues.
70
65
 
71
66
  ### Installation
72
67
 
73
- Install this module individually:
68
+ Install this single module individually:
74
69
 
75
70
  ```sh
76
71
  $ npm install @turf/concave
77
72
  ```
78
73
 
79
- Or install the Turf module that includes it as a function:
74
+ Or install the all-encompassing @turf/turf module that includes all modules as functions:
80
75
 
81
76
  ```sh
82
77
  $ npm install @turf/turf
@@ -0,0 +1,198 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// index.ts
2
+ var _distance = require('@turf/distance');
3
+ var _helpers = require('@turf/helpers');
4
+ var _meta = require('@turf/meta');
5
+ var _tin = require('@turf/tin');
6
+
7
+ // lib/turf-dissolve.ts
8
+ var _clone = require('@turf/clone');
9
+
10
+ var _invariant = require('@turf/invariant');
11
+
12
+
13
+ // lib/turf-line-dissolve.ts
14
+
15
+
16
+
17
+
18
+ function lineDissolve(geojson, options = {}) {
19
+ options = options || {};
20
+ if (!_helpers.isObject.call(void 0, options)) {
21
+ throw new Error("options is invalid");
22
+ }
23
+ const mutate = options.mutate;
24
+ if (_invariant.getType.call(void 0, geojson) !== "FeatureCollection") {
25
+ throw new Error("geojson must be a FeatureCollection");
26
+ }
27
+ if (!geojson.features.length) {
28
+ throw new Error("geojson is empty");
29
+ }
30
+ if (mutate === false || mutate === void 0) {
31
+ geojson = _clone.clone.call(void 0, geojson);
32
+ }
33
+ const result = [];
34
+ const lastLine = _meta.lineReduce.call(void 0,
35
+ geojson,
36
+ (previousLine, currentLine) => {
37
+ const merged = mergeLineStrings(previousLine, currentLine);
38
+ if (merged) {
39
+ return merged;
40
+ } else {
41
+ result.push(previousLine);
42
+ return currentLine;
43
+ }
44
+ }
45
+ );
46
+ if (lastLine) {
47
+ result.push(lastLine);
48
+ }
49
+ if (!result.length) {
50
+ return null;
51
+ } else if (result.length === 1) {
52
+ return result[0];
53
+ } else {
54
+ return _helpers.multiLineString.call(void 0,
55
+ result.map((line) => {
56
+ return line.coordinates;
57
+ })
58
+ );
59
+ }
60
+ }
61
+ function coordId(coord) {
62
+ return coord[0].toString() + "," + coord[1].toString();
63
+ }
64
+ function mergeLineStrings(a, b) {
65
+ const coords1 = a.geometry.coordinates;
66
+ const coords2 = b.geometry.coordinates;
67
+ const s1 = coordId(coords1[0]);
68
+ const e1 = coordId(coords1[coords1.length - 1]);
69
+ const s2 = coordId(coords2[0]);
70
+ const e2 = coordId(coords2[coords2.length - 1]);
71
+ let coords;
72
+ if (s1 === e2) {
73
+ coords = coords2.concat(coords1.slice(1));
74
+ } else if (s2 === e1) {
75
+ coords = coords1.concat(coords2.slice(1));
76
+ } else if (s1 === s2) {
77
+ coords = coords1.slice(1).reverse().concat(coords2);
78
+ } else if (e1 === e2) {
79
+ coords = coords1.concat(coords2.reverse().slice(1));
80
+ } else {
81
+ return null;
82
+ }
83
+ return _helpers.lineString.call(void 0, coords);
84
+ }
85
+
86
+ // lib/turf-polygon-dissolve.ts
87
+
88
+
89
+
90
+
91
+ var _topojsonclient = require('topojson-client');
92
+ var _topojsonserver = require('topojson-server');
93
+ function polygonDissolve(geojson, options = {}) {
94
+ if (_invariant.getType.call(void 0, geojson) !== "FeatureCollection") {
95
+ throw new Error("geojson must be a FeatureCollection");
96
+ }
97
+ if (!geojson.features.length) {
98
+ throw new Error("geojson is empty");
99
+ }
100
+ if (options.mutate === false || options.mutate === void 0) {
101
+ geojson = _clone.clone.call(void 0, geojson);
102
+ }
103
+ const geoms = [];
104
+ _meta.flattenEach.call(void 0, geojson, (feature2) => {
105
+ geoms.push(feature2.geometry);
106
+ });
107
+ const topo = _topojsonserver.topology.call(void 0, { geoms: _helpers.geometryCollection.call(void 0, geoms).geometry });
108
+ const merged = _topojsonclient.merge.call(void 0, topo, topo.objects.geoms.geometries);
109
+ return merged;
110
+ }
111
+
112
+ // lib/turf-dissolve.ts
113
+ function dissolve(geojson, options = {}) {
114
+ options = options || {};
115
+ if (!_helpers.isObject.call(void 0, options)) {
116
+ throw new Error("options is invalid");
117
+ }
118
+ const mutate = options.mutate;
119
+ if (_invariant.getType.call(void 0, geojson) !== "FeatureCollection") {
120
+ throw new Error("geojson must be a FeatureCollection");
121
+ }
122
+ if (!geojson.features.length) {
123
+ throw new Error("geojson is empty");
124
+ }
125
+ if (mutate === false || mutate === void 0) {
126
+ geojson = _clone.clone.call(void 0, geojson);
127
+ }
128
+ const type = getHomogenousType(geojson);
129
+ if (!type) {
130
+ throw new Error("geojson must be homogenous");
131
+ }
132
+ const data = geojson;
133
+ switch (type) {
134
+ case "LineString":
135
+ return lineDissolve(data, options);
136
+ case "Polygon":
137
+ return polygonDissolve(data, options);
138
+ default:
139
+ throw new Error(type + " is not supported");
140
+ }
141
+ }
142
+ function getHomogenousType(geojson) {
143
+ const types = {};
144
+ _meta.flattenEach.call(void 0, geojson, (feature2) => {
145
+ types[feature2.geometry.type] = true;
146
+ });
147
+ const keys = Object.keys(types);
148
+ if (keys.length === 1) {
149
+ return keys[0];
150
+ }
151
+ return null;
152
+ }
153
+
154
+ // index.ts
155
+ function concave(points, options = {}) {
156
+ const maxEdge = options.maxEdge || Infinity;
157
+ const cleaned = removeDuplicates(points);
158
+ const tinPolys = _tin.tin.call(void 0, cleaned);
159
+ tinPolys.features = tinPolys.features.filter((triangle) => {
160
+ const pt1 = triangle.geometry.coordinates[0][0];
161
+ const pt2 = triangle.geometry.coordinates[0][1];
162
+ const pt3 = triangle.geometry.coordinates[0][2];
163
+ const dist1 = _distance.distance.call(void 0, pt1, pt2, options);
164
+ const dist2 = _distance.distance.call(void 0, pt2, pt3, options);
165
+ const dist3 = _distance.distance.call(void 0, pt1, pt3, options);
166
+ return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;
167
+ });
168
+ if (tinPolys.features.length < 1) {
169
+ return null;
170
+ }
171
+ const dissolved = dissolve(tinPolys);
172
+ if (dissolved.coordinates.length === 1) {
173
+ dissolved.coordinates = dissolved.coordinates[0];
174
+ dissolved.type = "Polygon";
175
+ }
176
+ return _helpers.feature.call(void 0, dissolved);
177
+ }
178
+ function removeDuplicates(points) {
179
+ const cleaned = [];
180
+ const existing = {};
181
+ _meta.featureEach.call(void 0, points, (pt) => {
182
+ if (!pt.geometry) {
183
+ return;
184
+ }
185
+ const key = pt.geometry.coordinates.join("-");
186
+ if (!Object.prototype.hasOwnProperty.call(existing, key)) {
187
+ cleaned.push(pt);
188
+ existing[key] = true;
189
+ }
190
+ });
191
+ return _helpers.featureCollection.call(void 0, cleaned);
192
+ }
193
+ var turf_concave_default = concave;
194
+
195
+
196
+
197
+ exports.concave = concave; exports.default = turf_concave_default;
198
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../index.ts","../../lib/turf-dissolve.ts","../../lib/turf-line-dissolve.ts","../../lib/turf-polygon-dissolve.ts"],"names":["clone","isObject","getType","flattenEach","feature"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,SAAS,yBAAyB;AAS3C,SAAS,mBAAmB;AAC5B,SAAS,WAAW;;;ACHpB,SAAS,SAAAA,cAAa;AACtB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,WAAAC,gBAAe;AACxB,SAAS,eAAAC,oBAAmB;;;ACL5B,SAAS,aAAa;AACtB,SAAS,UAAU,YAAY,uBAAuB;AACtD,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAW3B,SAAS,aACP,SACA,UAAgC,CAAC,GACa;AAE9C,YAAU,WAAW,CAAC;AACtB,MAAI,CAAC,SAAS,OAAO,GAAG;AACtB,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACA,QAAM,SAAS,QAAQ;AAGvB,MAAI,QAAQ,OAAO,MAAM,qBAAqB;AAC5C,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AACA,MAAI,CAAC,QAAQ,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AAGA,MAAI,WAAW,SAAS,WAAW,QAAW;AAC5C,cAAU,MAAM,OAAO;AAAA,EACzB;AAEA,QAAM,SAAgB,CAAC;AACvB,QAAM,WAAW;AAAA,IACf;AAAA,IACA,CAAC,cAAmB,gBAAqB;AAGvC,YAAM,SAAS,iBAAiB,cAAc,WAAW;AAGzD,UAAI,QAAQ;AACV,eAAO;AAAA,MAET,OAAO;AACL,eAAO,KAAK,YAAY;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,WAAO,KAAK,QAAQ;AAAA,EACtB;AAGA,MAAI,CAAC,OAAO,QAAQ;AAClB,WAAO;AAAA,EAET,WAAW,OAAO,WAAW,GAAG;AAC9B,WAAO,OAAO,CAAC;AAAA,EAEjB,OAAO;AACL,WAAO;AAAA,MACL,OAAO,IAAI,CAAC,SAAS;AACnB,eAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGA,SAAS,QAAQ,OAAiB;AAChC,SAAO,MAAM,CAAC,EAAE,SAAS,IAAI,MAAM,MAAM,CAAC,EAAE,SAAS;AACvD;AAUA,SAAS,iBAAiB,GAAwB,GAAwB;AACxE,QAAM,UAAU,EAAE,SAAS;AAC3B,QAAM,UAAU,EAAE,SAAS;AAE3B,QAAM,KAAK,QAAQ,QAAQ,CAAC,CAAC;AAC7B,QAAM,KAAK,QAAQ,QAAQ,QAAQ,SAAS,CAAC,CAAC;AAC9C,QAAM,KAAK,QAAQ,QAAQ,CAAC,CAAC;AAC7B,QAAM,KAAK,QAAQ,QAAQ,QAAQ,SAAS,CAAC,CAAC;AAG9C,MAAI;AACJ,MAAI,OAAO,IAAI;AACb,aAAS,QAAQ,OAAO,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC1C,WAAW,OAAO,IAAI;AACpB,aAAS,QAAQ,OAAO,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC1C,WAAW,OAAO,IAAI;AACpB,aAAS,QAAQ,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,OAAO;AAAA,EACpD,WAAW,OAAO,IAAI;AACpB,aAAS,QAAQ,OAAO,QAAQ,QAAQ,EAAE,MAAM,CAAC,CAAC;AAAA,EACpD,OAAO;AACL,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,MAAM;AAC1B;;;ACvHA,SAAS,SAAAH,cAAa;AACtB,SAAS,0BAA0B;AACnC,SAAS,WAAAE,gBAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,gBAAgB;AAUzB,SAAS,gBACP,SACA,UAAgC,CAAC,GACO;AAExC,MAAIA,SAAQ,OAAO,MAAM,qBAAqB;AAC5C,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AACA,MAAI,CAAC,QAAQ,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AAIA,MAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAW;AAC5D,cAAUF,OAAM,OAAO;AAAA,EACzB;AAEA,QAAM,QAAe,CAAC;AACtB,cAAY,SAAS,CAACI,aAAY;AAChC,UAAM,KAAKA,SAAQ,QAAQ;AAAA,EAC7B,CAAC;AACD,QAAM,OAAY,SAAS,EAAE,OAAO,mBAAmB,KAAK,EAAE,SAAS,CAAC;AACxE,QAAM,SAAc,MAAM,MAAM,KAAK,QAAQ,MAAM,UAAU;AAC7D,SAAO;AACT;;;AFhBA,SAAS,SACP,SAGA,UAEI,CAAC,GACkE;AAEvE,YAAU,WAAW,CAAC;AACtB,MAAI,CAACH,UAAS,OAAO,GAAG;AACtB,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACA,QAAM,SAAS,QAAQ;AAGvB,MAAIC,SAAQ,OAAO,MAAM,qBAAqB;AAC5C,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AACA,MAAI,CAAC,QAAQ,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AAIA,MAAI,WAAW,SAAS,WAAW,QAAW;AAC5C,cAAUF,OAAM,OAAO;AAAA,EACzB;AAGA,QAAM,OAAO,kBAAkB,OAAO;AACtC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAGA,QAAM,OAAY;AAElB,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,aAAa,MAAM,OAAO;AAAA,IACnC,KAAK;AACH,aAAO,gBAAgB,MAAM,OAAO;AAAA,IACtC;AACE,YAAM,IAAI,MAAM,OAAO,mBAAmB;AAAA,EAC9C;AACF;AASA,SAAS,kBAAkB,SAAc;AACvC,QAAM,QAAoC,CAAC;AAC3C,EAAAG,aAAY,SAAS,CAACC,aAAY;AAChC,UAAMA,SAAQ,SAAS,IAAI,IAAI;AAAA,EACjC,CAAC;AACD,QAAM,OAAO,OAAO,KAAK,KAAK;AAC9B,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,KAAK,CAAC;AAAA,EACf;AACA,SAAO;AACT;;;ADjDA,SAAS,QACP,QACA,UAA+C,CAAC,GACR;AACxC,QAAM,UAAU,QAAQ,WAAW;AAEnC,QAAM,UAAU,iBAAiB,MAAM;AAEvC,QAAM,WAAW,IAAI,OAAO;AAG5B,WAAS,WAAW,SAAS,SAAS,OAAO,CAAC,aAAa;AACzD,UAAM,MAAM,SAAS,SAAS,YAAY,CAAC,EAAE,CAAC;AAC9C,UAAM,MAAM,SAAS,SAAS,YAAY,CAAC,EAAE,CAAC;AAC9C,UAAM,MAAM,SAAS,SAAS,YAAY,CAAC,EAAE,CAAC;AAC9C,UAAM,QAAQ,SAAS,KAAK,KAAK,OAAO;AACxC,UAAM,QAAQ,SAAS,KAAK,KAAK,OAAO;AACxC,UAAM,QAAQ,SAAS,KAAK,KAAK,OAAO;AACxC,WAAO,SAAS,WAAW,SAAS,WAAW,SAAS;AAAA,EAC1D,CAAC;AAED,MAAI,SAAS,SAAS,SAAS,GAAG;AAChC,WAAO;AAAA,EACT;AAGA,QAAM,YAAiB,SAAS,QAAQ;AAGxC,MAAI,UAAU,YAAY,WAAW,GAAG;AACtC,cAAU,cAAc,UAAU,YAAY,CAAC;AAC/C,cAAU,OAAO;AAAA,EACnB;AACA,SAAO,QAAQ,SAAS;AAC1B;AASA,SAAS,iBACP,QAC0B;AAC1B,QAAM,UAAiC,CAAC;AACxC,QAAM,WAAuC,CAAC;AAE9C,cAAY,QAAQ,CAAC,OAAO;AAC1B,QAAI,CAAC,GAAG,UAAU;AAChB;AAAA,IACF;AACA,UAAM,MAAM,GAAG,SAAS,YAAY,KAAK,GAAG;AAC5C,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,UAAU,GAAG,GAAG;AACxD,cAAQ,KAAK,EAAE;AACf,eAAS,GAAG,IAAI;AAAA,IAClB;AAAA,EACF,CAAC;AACD,SAAO,kBAAkB,OAAO;AAClC;AAGA,IAAO,uBAAQ","sourcesContent":["import { distance } from \"@turf/distance\";\nimport { feature, featureCollection } from \"@turf/helpers\";\nimport {\n Feature,\n FeatureCollection,\n MultiPolygon,\n Point,\n Polygon,\n} from \"geojson\";\nimport { Units } from \"@turf/helpers\";\nimport { featureEach } from \"@turf/meta\";\nimport { tin } from \"@turf/tin\";\nimport { dissolve } from \"./lib/turf-dissolve.js\";\n\n/**\n * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.\n * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.\n *\n * @name concave\n * @param {FeatureCollection<Point>} points input points\n * @param {Object} [options={}] Optional parameters\n * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the\n * hull to become concave.\n * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers\n * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)\n * @example\n * var points = turf.featureCollection([\n * turf.point([-63.601226, 44.642643]),\n * turf.point([-63.591442, 44.651436]),\n * turf.point([-63.580799, 44.648749]),\n * turf.point([-63.573589, 44.641788]),\n * turf.point([-63.587665, 44.64533]),\n * turf.point([-63.595218, 44.64765])\n * ]);\n * var options = {units: 'miles', maxEdge: 1};\n *\n * var hull = turf.concave(points, options);\n *\n * //addToMap\n * var addToMap = [points, hull]\n */\nfunction concave(\n points: FeatureCollection<Point>,\n options: { maxEdge?: number; units?: Units } = {}\n): Feature<Polygon | MultiPolygon> | null {\n const maxEdge = options.maxEdge || Infinity;\n\n const cleaned = removeDuplicates(points);\n\n const tinPolys = tin(cleaned);\n // calculate length of all edges and area of all triangles\n // and remove triangles that fail the max length test\n tinPolys.features = tinPolys.features.filter((triangle) => {\n const pt1 = triangle.geometry.coordinates[0][0];\n const pt2 = triangle.geometry.coordinates[0][1];\n const pt3 = triangle.geometry.coordinates[0][2];\n const dist1 = distance(pt1, pt2, options);\n const dist2 = distance(pt2, pt3, options);\n const dist3 = distance(pt1, pt3, options);\n return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;\n });\n\n if (tinPolys.features.length < 1) {\n return null;\n }\n\n // merge the adjacent triangles\n const dissolved: any = dissolve(tinPolys);\n\n // geojson-dissolve always returns a MultiPolygon\n if (dissolved.coordinates.length === 1) {\n dissolved.coordinates = dissolved.coordinates[0];\n dissolved.type = \"Polygon\";\n }\n return feature(dissolved);\n}\n\n/**\n * Removes duplicated points in a collection returning a new collection\n *\n * @private\n * @param {FeatureCollection<Point>} points to be cleaned\n * @returns {FeatureCollection<Point>} cleaned set of points\n */\nfunction removeDuplicates(\n points: FeatureCollection<Point>\n): FeatureCollection<Point> {\n const cleaned: Array<Feature<Point>> = [];\n const existing: { [key: string]: boolean } = {};\n\n featureEach(points, (pt) => {\n if (!pt.geometry) {\n return;\n }\n const key = pt.geometry.coordinates.join(\"-\");\n if (!Object.prototype.hasOwnProperty.call(existing, key)) {\n cleaned.push(pt);\n existing[key] = true;\n }\n });\n return featureCollection(cleaned);\n}\n\nexport { concave };\nexport default concave;\n","import {\n Feature,\n FeatureCollection,\n LineString,\n MultiLineString,\n MultiPolygon,\n Polygon,\n} from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { isObject } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { flattenEach } from \"@turf/meta\";\nimport { lineDissolve } from \"./turf-line-dissolve.js\";\nimport { polygonDissolve } from \"./turf-polygon-dissolve.js\";\n\n/**\n * Transform function: attempts to dissolve geojson objects where possible\n * [GeoJSON] -> GeoJSON geometry\n *\n * @private\n * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features\n */\nfunction dissolve(\n geojson: FeatureCollection<\n LineString | MultiLineString | Polygon | MultiPolygon\n >,\n options: {\n mutate?: boolean;\n } = {}\n): Feature<LineString | MultiLineString | Polygon | MultiPolygon> | null {\n // Optional parameters\n options = options || {};\n if (!isObject(options)) {\n throw new Error(\"options is invalid\");\n }\n const mutate = options.mutate;\n\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n // Topojson modifies in place, so we need to deep clone first\n if (mutate === false || mutate === undefined) {\n geojson = clone(geojson);\n }\n\n // Assert homogenity\n const type = getHomogenousType(geojson);\n if (!type) {\n throw new Error(\"geojson must be homogenous\");\n }\n\n // Data => Typescript hack\n const data: any = geojson;\n\n switch (type) {\n case \"LineString\":\n return lineDissolve(data, options);\n case \"Polygon\":\n return polygonDissolve(data, options);\n default:\n throw new Error(type + \" is not supported\");\n }\n}\n\n/**\n * Checks if GeoJSON is Homogenous\n *\n * @private\n * @param {GeoJSON} geojson GeoJSON\n * @returns {string|null} Homogenous type or null if multiple types\n */\nfunction getHomogenousType(geojson: any) {\n const types: { [key: string]: boolean } = {};\n flattenEach(geojson, (feature) => {\n types[feature.geometry.type] = true;\n });\n const keys = Object.keys(types);\n if (keys.length === 1) {\n return keys[0];\n }\n return null;\n}\n\nexport { dissolve };\nexport default dissolve;\n","import {\n Feature,\n FeatureCollection,\n LineString,\n MultiLineString,\n} from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { isObject, lineString, multiLineString } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { lineReduce } from \"@turf/meta\";\n\n/**\n * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.\n * [LineString] -> LineString|MultiLineString\n *\n * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<LineString|MultiLineString>} Dissolved lines\n */\nfunction lineDissolve(\n geojson: FeatureCollection<LineString | MultiLineString>,\n options: { mutate?: boolean } = {}\n): Feature<LineString | MultiLineString> | null {\n // Optional parameters\n options = options || {};\n if (!isObject(options)) {\n throw new Error(\"options is invalid\");\n }\n const mutate = options.mutate;\n\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n if (mutate === false || mutate === undefined) {\n geojson = clone(geojson);\n }\n\n const result: any[] = [];\n const lastLine = lineReduce(\n geojson,\n (previousLine: any, currentLine: any) => {\n // Attempt to merge this LineString with the other LineStrings, updating\n // the reference as it is merged with others and grows.\n const merged = mergeLineStrings(previousLine, currentLine);\n\n // Accumulate the merged LineString\n if (merged) {\n return merged;\n // Put the unmerged LineString back into the list\n } else {\n result.push(previousLine);\n return currentLine;\n }\n }\n );\n // Append the last line\n if (lastLine) {\n result.push(lastLine);\n }\n\n // Return null if no lines were dissolved\n if (!result.length) {\n return null;\n // Return LineString if only 1 line was dissolved\n } else if (result.length === 1) {\n return result[0];\n // Return MultiLineString if multiple lines were dissolved with gaps\n } else {\n return multiLineString(\n result.map((line) => {\n return line.coordinates;\n })\n );\n }\n}\n\n// [Number, Number] -> String\nfunction coordId(coord: number[]) {\n return coord[0].toString() + \",\" + coord[1].toString();\n}\n\n/**\n * LineString, LineString -> LineString\n *\n * @private\n * @param {Feature<LineString>} a line1\n * @param {Feature<LineString>} b line2\n * @returns {Feature<LineString>|null} Merged LineString\n */\nfunction mergeLineStrings(a: Feature<LineString>, b: Feature<LineString>) {\n const coords1 = a.geometry.coordinates;\n const coords2 = b.geometry.coordinates;\n\n const s1 = coordId(coords1[0]);\n const e1 = coordId(coords1[coords1.length - 1]);\n const s2 = coordId(coords2[0]);\n const e2 = coordId(coords2[coords2.length - 1]);\n\n // TODO: handle case where more than one of these is true!\n let coords;\n if (s1 === e2) {\n coords = coords2.concat(coords1.slice(1));\n } else if (s2 === e1) {\n coords = coords1.concat(coords2.slice(1));\n } else if (s1 === s2) {\n coords = coords1.slice(1).reverse().concat(coords2);\n } else if (e1 === e2) {\n coords = coords1.concat(coords2.reverse().slice(1));\n } else {\n return null;\n }\n\n return lineString(coords);\n}\n\nexport { lineDissolve };\nexport default lineDissolve;\n","import { Feature, FeatureCollection, MultiPolygon, Polygon } from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { geometryCollection } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { flattenEach } from \"@turf/meta\";\nimport { merge } from \"topojson-client\";\nimport { topology } from \"topojson-server\";\n\n/**\n * Dissolves all overlapping (Multi)Polygon\n *\n * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons\n */\nfunction polygonDissolve(\n geojson: FeatureCollection<Polygon | MultiPolygon>,\n options: { mutate?: boolean } = {}\n): Feature<Polygon | MultiPolygon> | null {\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n // Topojson modifies in place, so we need to deep clone first\n if (options.mutate === false || options.mutate === undefined) {\n geojson = clone(geojson);\n }\n\n const geoms: any[] = [];\n flattenEach(geojson, (feature) => {\n geoms.push(feature.geometry);\n });\n const topo: any = topology({ geoms: geometryCollection(geoms).geometry });\n const merged: any = merge(topo, topo.objects.geoms.geometries);\n return merged;\n}\n\nexport { polygonDissolve };\nexport default polygonDissolve;\n"]}
@@ -0,0 +1,36 @@
1
+ import { FeatureCollection, Point, Feature, Polygon, MultiPolygon } from 'geojson';
2
+ import { Units } from '@turf/helpers';
3
+
4
+ /**
5
+ * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.
6
+ * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.
7
+ *
8
+ * @name concave
9
+ * @param {FeatureCollection<Point>} points input points
10
+ * @param {Object} [options={}] Optional parameters
11
+ * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the
12
+ * hull to become concave.
13
+ * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
14
+ * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)
15
+ * @example
16
+ * var points = turf.featureCollection([
17
+ * turf.point([-63.601226, 44.642643]),
18
+ * turf.point([-63.591442, 44.651436]),
19
+ * turf.point([-63.580799, 44.648749]),
20
+ * turf.point([-63.573589, 44.641788]),
21
+ * turf.point([-63.587665, 44.64533]),
22
+ * turf.point([-63.595218, 44.64765])
23
+ * ]);
24
+ * var options = {units: 'miles', maxEdge: 1};
25
+ *
26
+ * var hull = turf.concave(points, options);
27
+ *
28
+ * //addToMap
29
+ * var addToMap = [points, hull]
30
+ */
31
+ declare function concave(points: FeatureCollection<Point>, options?: {
32
+ maxEdge?: number;
33
+ units?: Units;
34
+ }): Feature<Polygon | MultiPolygon> | null;
35
+
36
+ export { concave, concave as default };
@@ -1,5 +1,6 @@
1
- import { Feature, FeatureCollection, MultiPolygon, Point, Polygon } from "geojson";
2
- import { Units } from "@turf/helpers";
1
+ import { FeatureCollection, Point, Feature, Polygon, MultiPolygon } from 'geojson';
2
+ import { Units } from '@turf/helpers';
3
+
3
4
  /**
4
5
  * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.
5
6
  * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.
@@ -31,4 +32,5 @@ declare function concave(points: FeatureCollection<Point>, options?: {
31
32
  maxEdge?: number;
32
33
  units?: Units;
33
34
  }): Feature<Polygon | MultiPolygon> | null;
34
- export default concave;
35
+
36
+ export { concave, concave as default };
@@ -0,0 +1,198 @@
1
+ // index.ts
2
+ import { distance } from "@turf/distance";
3
+ import { feature, featureCollection } from "@turf/helpers";
4
+ import { featureEach } from "@turf/meta";
5
+ import { tin } from "@turf/tin";
6
+
7
+ // lib/turf-dissolve.ts
8
+ import { clone as clone3 } from "@turf/clone";
9
+ import { isObject as isObject2 } from "@turf/helpers";
10
+ import { getType as getType3 } from "@turf/invariant";
11
+ import { flattenEach as flattenEach2 } from "@turf/meta";
12
+
13
+ // lib/turf-line-dissolve.ts
14
+ import { clone } from "@turf/clone";
15
+ import { isObject, lineString, multiLineString } from "@turf/helpers";
16
+ import { getType } from "@turf/invariant";
17
+ import { lineReduce } from "@turf/meta";
18
+ function lineDissolve(geojson, options = {}) {
19
+ options = options || {};
20
+ if (!isObject(options)) {
21
+ throw new Error("options is invalid");
22
+ }
23
+ const mutate = options.mutate;
24
+ if (getType(geojson) !== "FeatureCollection") {
25
+ throw new Error("geojson must be a FeatureCollection");
26
+ }
27
+ if (!geojson.features.length) {
28
+ throw new Error("geojson is empty");
29
+ }
30
+ if (mutate === false || mutate === void 0) {
31
+ geojson = clone(geojson);
32
+ }
33
+ const result = [];
34
+ const lastLine = lineReduce(
35
+ geojson,
36
+ (previousLine, currentLine) => {
37
+ const merged = mergeLineStrings(previousLine, currentLine);
38
+ if (merged) {
39
+ return merged;
40
+ } else {
41
+ result.push(previousLine);
42
+ return currentLine;
43
+ }
44
+ }
45
+ );
46
+ if (lastLine) {
47
+ result.push(lastLine);
48
+ }
49
+ if (!result.length) {
50
+ return null;
51
+ } else if (result.length === 1) {
52
+ return result[0];
53
+ } else {
54
+ return multiLineString(
55
+ result.map((line) => {
56
+ return line.coordinates;
57
+ })
58
+ );
59
+ }
60
+ }
61
+ function coordId(coord) {
62
+ return coord[0].toString() + "," + coord[1].toString();
63
+ }
64
+ function mergeLineStrings(a, b) {
65
+ const coords1 = a.geometry.coordinates;
66
+ const coords2 = b.geometry.coordinates;
67
+ const s1 = coordId(coords1[0]);
68
+ const e1 = coordId(coords1[coords1.length - 1]);
69
+ const s2 = coordId(coords2[0]);
70
+ const e2 = coordId(coords2[coords2.length - 1]);
71
+ let coords;
72
+ if (s1 === e2) {
73
+ coords = coords2.concat(coords1.slice(1));
74
+ } else if (s2 === e1) {
75
+ coords = coords1.concat(coords2.slice(1));
76
+ } else if (s1 === s2) {
77
+ coords = coords1.slice(1).reverse().concat(coords2);
78
+ } else if (e1 === e2) {
79
+ coords = coords1.concat(coords2.reverse().slice(1));
80
+ } else {
81
+ return null;
82
+ }
83
+ return lineString(coords);
84
+ }
85
+
86
+ // lib/turf-polygon-dissolve.ts
87
+ import { clone as clone2 } from "@turf/clone";
88
+ import { geometryCollection } from "@turf/helpers";
89
+ import { getType as getType2 } from "@turf/invariant";
90
+ import { flattenEach } from "@turf/meta";
91
+ import { merge } from "topojson-client";
92
+ import { topology } from "topojson-server";
93
+ function polygonDissolve(geojson, options = {}) {
94
+ if (getType2(geojson) !== "FeatureCollection") {
95
+ throw new Error("geojson must be a FeatureCollection");
96
+ }
97
+ if (!geojson.features.length) {
98
+ throw new Error("geojson is empty");
99
+ }
100
+ if (options.mutate === false || options.mutate === void 0) {
101
+ geojson = clone2(geojson);
102
+ }
103
+ const geoms = [];
104
+ flattenEach(geojson, (feature2) => {
105
+ geoms.push(feature2.geometry);
106
+ });
107
+ const topo = topology({ geoms: geometryCollection(geoms).geometry });
108
+ const merged = merge(topo, topo.objects.geoms.geometries);
109
+ return merged;
110
+ }
111
+
112
+ // lib/turf-dissolve.ts
113
+ function dissolve(geojson, options = {}) {
114
+ options = options || {};
115
+ if (!isObject2(options)) {
116
+ throw new Error("options is invalid");
117
+ }
118
+ const mutate = options.mutate;
119
+ if (getType3(geojson) !== "FeatureCollection") {
120
+ throw new Error("geojson must be a FeatureCollection");
121
+ }
122
+ if (!geojson.features.length) {
123
+ throw new Error("geojson is empty");
124
+ }
125
+ if (mutate === false || mutate === void 0) {
126
+ geojson = clone3(geojson);
127
+ }
128
+ const type = getHomogenousType(geojson);
129
+ if (!type) {
130
+ throw new Error("geojson must be homogenous");
131
+ }
132
+ const data = geojson;
133
+ switch (type) {
134
+ case "LineString":
135
+ return lineDissolve(data, options);
136
+ case "Polygon":
137
+ return polygonDissolve(data, options);
138
+ default:
139
+ throw new Error(type + " is not supported");
140
+ }
141
+ }
142
+ function getHomogenousType(geojson) {
143
+ const types = {};
144
+ flattenEach2(geojson, (feature2) => {
145
+ types[feature2.geometry.type] = true;
146
+ });
147
+ const keys = Object.keys(types);
148
+ if (keys.length === 1) {
149
+ return keys[0];
150
+ }
151
+ return null;
152
+ }
153
+
154
+ // index.ts
155
+ function concave(points, options = {}) {
156
+ const maxEdge = options.maxEdge || Infinity;
157
+ const cleaned = removeDuplicates(points);
158
+ const tinPolys = tin(cleaned);
159
+ tinPolys.features = tinPolys.features.filter((triangle) => {
160
+ const pt1 = triangle.geometry.coordinates[0][0];
161
+ const pt2 = triangle.geometry.coordinates[0][1];
162
+ const pt3 = triangle.geometry.coordinates[0][2];
163
+ const dist1 = distance(pt1, pt2, options);
164
+ const dist2 = distance(pt2, pt3, options);
165
+ const dist3 = distance(pt1, pt3, options);
166
+ return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;
167
+ });
168
+ if (tinPolys.features.length < 1) {
169
+ return null;
170
+ }
171
+ const dissolved = dissolve(tinPolys);
172
+ if (dissolved.coordinates.length === 1) {
173
+ dissolved.coordinates = dissolved.coordinates[0];
174
+ dissolved.type = "Polygon";
175
+ }
176
+ return feature(dissolved);
177
+ }
178
+ function removeDuplicates(points) {
179
+ const cleaned = [];
180
+ const existing = {};
181
+ featureEach(points, (pt) => {
182
+ if (!pt.geometry) {
183
+ return;
184
+ }
185
+ const key = pt.geometry.coordinates.join("-");
186
+ if (!Object.prototype.hasOwnProperty.call(existing, key)) {
187
+ cleaned.push(pt);
188
+ existing[key] = true;
189
+ }
190
+ });
191
+ return featureCollection(cleaned);
192
+ }
193
+ var turf_concave_default = concave;
194
+ export {
195
+ concave,
196
+ turf_concave_default as default
197
+ };
198
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../index.ts","../../lib/turf-dissolve.ts","../../lib/turf-line-dissolve.ts","../../lib/turf-polygon-dissolve.ts"],"sourcesContent":["import { distance } from \"@turf/distance\";\nimport { feature, featureCollection } from \"@turf/helpers\";\nimport {\n Feature,\n FeatureCollection,\n MultiPolygon,\n Point,\n Polygon,\n} from \"geojson\";\nimport { Units } from \"@turf/helpers\";\nimport { featureEach } from \"@turf/meta\";\nimport { tin } from \"@turf/tin\";\nimport { dissolve } from \"./lib/turf-dissolve.js\";\n\n/**\n * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.\n * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.\n *\n * @name concave\n * @param {FeatureCollection<Point>} points input points\n * @param {Object} [options={}] Optional parameters\n * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the\n * hull to become concave.\n * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers\n * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)\n * @example\n * var points = turf.featureCollection([\n * turf.point([-63.601226, 44.642643]),\n * turf.point([-63.591442, 44.651436]),\n * turf.point([-63.580799, 44.648749]),\n * turf.point([-63.573589, 44.641788]),\n * turf.point([-63.587665, 44.64533]),\n * turf.point([-63.595218, 44.64765])\n * ]);\n * var options = {units: 'miles', maxEdge: 1};\n *\n * var hull = turf.concave(points, options);\n *\n * //addToMap\n * var addToMap = [points, hull]\n */\nfunction concave(\n points: FeatureCollection<Point>,\n options: { maxEdge?: number; units?: Units } = {}\n): Feature<Polygon | MultiPolygon> | null {\n const maxEdge = options.maxEdge || Infinity;\n\n const cleaned = removeDuplicates(points);\n\n const tinPolys = tin(cleaned);\n // calculate length of all edges and area of all triangles\n // and remove triangles that fail the max length test\n tinPolys.features = tinPolys.features.filter((triangle) => {\n const pt1 = triangle.geometry.coordinates[0][0];\n const pt2 = triangle.geometry.coordinates[0][1];\n const pt3 = triangle.geometry.coordinates[0][2];\n const dist1 = distance(pt1, pt2, options);\n const dist2 = distance(pt2, pt3, options);\n const dist3 = distance(pt1, pt3, options);\n return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;\n });\n\n if (tinPolys.features.length < 1) {\n return null;\n }\n\n // merge the adjacent triangles\n const dissolved: any = dissolve(tinPolys);\n\n // geojson-dissolve always returns a MultiPolygon\n if (dissolved.coordinates.length === 1) {\n dissolved.coordinates = dissolved.coordinates[0];\n dissolved.type = \"Polygon\";\n }\n return feature(dissolved);\n}\n\n/**\n * Removes duplicated points in a collection returning a new collection\n *\n * @private\n * @param {FeatureCollection<Point>} points to be cleaned\n * @returns {FeatureCollection<Point>} cleaned set of points\n */\nfunction removeDuplicates(\n points: FeatureCollection<Point>\n): FeatureCollection<Point> {\n const cleaned: Array<Feature<Point>> = [];\n const existing: { [key: string]: boolean } = {};\n\n featureEach(points, (pt) => {\n if (!pt.geometry) {\n return;\n }\n const key = pt.geometry.coordinates.join(\"-\");\n if (!Object.prototype.hasOwnProperty.call(existing, key)) {\n cleaned.push(pt);\n existing[key] = true;\n }\n });\n return featureCollection(cleaned);\n}\n\nexport { concave };\nexport default concave;\n","import {\n Feature,\n FeatureCollection,\n LineString,\n MultiLineString,\n MultiPolygon,\n Polygon,\n} from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { isObject } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { flattenEach } from \"@turf/meta\";\nimport { lineDissolve } from \"./turf-line-dissolve.js\";\nimport { polygonDissolve } from \"./turf-polygon-dissolve.js\";\n\n/**\n * Transform function: attempts to dissolve geojson objects where possible\n * [GeoJSON] -> GeoJSON geometry\n *\n * @private\n * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features\n */\nfunction dissolve(\n geojson: FeatureCollection<\n LineString | MultiLineString | Polygon | MultiPolygon\n >,\n options: {\n mutate?: boolean;\n } = {}\n): Feature<LineString | MultiLineString | Polygon | MultiPolygon> | null {\n // Optional parameters\n options = options || {};\n if (!isObject(options)) {\n throw new Error(\"options is invalid\");\n }\n const mutate = options.mutate;\n\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n // Topojson modifies in place, so we need to deep clone first\n if (mutate === false || mutate === undefined) {\n geojson = clone(geojson);\n }\n\n // Assert homogenity\n const type = getHomogenousType(geojson);\n if (!type) {\n throw new Error(\"geojson must be homogenous\");\n }\n\n // Data => Typescript hack\n const data: any = geojson;\n\n switch (type) {\n case \"LineString\":\n return lineDissolve(data, options);\n case \"Polygon\":\n return polygonDissolve(data, options);\n default:\n throw new Error(type + \" is not supported\");\n }\n}\n\n/**\n * Checks if GeoJSON is Homogenous\n *\n * @private\n * @param {GeoJSON} geojson GeoJSON\n * @returns {string|null} Homogenous type or null if multiple types\n */\nfunction getHomogenousType(geojson: any) {\n const types: { [key: string]: boolean } = {};\n flattenEach(geojson, (feature) => {\n types[feature.geometry.type] = true;\n });\n const keys = Object.keys(types);\n if (keys.length === 1) {\n return keys[0];\n }\n return null;\n}\n\nexport { dissolve };\nexport default dissolve;\n","import {\n Feature,\n FeatureCollection,\n LineString,\n MultiLineString,\n} from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { isObject, lineString, multiLineString } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { lineReduce } from \"@turf/meta\";\n\n/**\n * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.\n * [LineString] -> LineString|MultiLineString\n *\n * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<LineString|MultiLineString>} Dissolved lines\n */\nfunction lineDissolve(\n geojson: FeatureCollection<LineString | MultiLineString>,\n options: { mutate?: boolean } = {}\n): Feature<LineString | MultiLineString> | null {\n // Optional parameters\n options = options || {};\n if (!isObject(options)) {\n throw new Error(\"options is invalid\");\n }\n const mutate = options.mutate;\n\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n if (mutate === false || mutate === undefined) {\n geojson = clone(geojson);\n }\n\n const result: any[] = [];\n const lastLine = lineReduce(\n geojson,\n (previousLine: any, currentLine: any) => {\n // Attempt to merge this LineString with the other LineStrings, updating\n // the reference as it is merged with others and grows.\n const merged = mergeLineStrings(previousLine, currentLine);\n\n // Accumulate the merged LineString\n if (merged) {\n return merged;\n // Put the unmerged LineString back into the list\n } else {\n result.push(previousLine);\n return currentLine;\n }\n }\n );\n // Append the last line\n if (lastLine) {\n result.push(lastLine);\n }\n\n // Return null if no lines were dissolved\n if (!result.length) {\n return null;\n // Return LineString if only 1 line was dissolved\n } else if (result.length === 1) {\n return result[0];\n // Return MultiLineString if multiple lines were dissolved with gaps\n } else {\n return multiLineString(\n result.map((line) => {\n return line.coordinates;\n })\n );\n }\n}\n\n// [Number, Number] -> String\nfunction coordId(coord: number[]) {\n return coord[0].toString() + \",\" + coord[1].toString();\n}\n\n/**\n * LineString, LineString -> LineString\n *\n * @private\n * @param {Feature<LineString>} a line1\n * @param {Feature<LineString>} b line2\n * @returns {Feature<LineString>|null} Merged LineString\n */\nfunction mergeLineStrings(a: Feature<LineString>, b: Feature<LineString>) {\n const coords1 = a.geometry.coordinates;\n const coords2 = b.geometry.coordinates;\n\n const s1 = coordId(coords1[0]);\n const e1 = coordId(coords1[coords1.length - 1]);\n const s2 = coordId(coords2[0]);\n const e2 = coordId(coords2[coords2.length - 1]);\n\n // TODO: handle case where more than one of these is true!\n let coords;\n if (s1 === e2) {\n coords = coords2.concat(coords1.slice(1));\n } else if (s2 === e1) {\n coords = coords1.concat(coords2.slice(1));\n } else if (s1 === s2) {\n coords = coords1.slice(1).reverse().concat(coords2);\n } else if (e1 === e2) {\n coords = coords1.concat(coords2.reverse().slice(1));\n } else {\n return null;\n }\n\n return lineString(coords);\n}\n\nexport { lineDissolve };\nexport default lineDissolve;\n","import { Feature, FeatureCollection, MultiPolygon, Polygon } from \"geojson\";\nimport { clone } from \"@turf/clone\";\nimport { geometryCollection } from \"@turf/helpers\";\nimport { getType } from \"@turf/invariant\";\nimport { flattenEach } from \"@turf/meta\";\nimport { merge } from \"topojson-client\";\nimport { topology } from \"topojson-server\";\n\n/**\n * Dissolves all overlapping (Multi)Polygon\n *\n * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve\n * @param {Object} [options={}] Optional parameters\n * @param {boolean} [options.mutate=false] Prevent input mutation\n * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons\n */\nfunction polygonDissolve(\n geojson: FeatureCollection<Polygon | MultiPolygon>,\n options: { mutate?: boolean } = {}\n): Feature<Polygon | MultiPolygon> | null {\n // Validation\n if (getType(geojson) !== \"FeatureCollection\") {\n throw new Error(\"geojson must be a FeatureCollection\");\n }\n if (!geojson.features.length) {\n throw new Error(\"geojson is empty\");\n }\n\n // Clone geojson to avoid side effects\n // Topojson modifies in place, so we need to deep clone first\n if (options.mutate === false || options.mutate === undefined) {\n geojson = clone(geojson);\n }\n\n const geoms: any[] = [];\n flattenEach(geojson, (feature) => {\n geoms.push(feature.geometry);\n });\n const topo: any = topology({ geoms: geometryCollection(geoms).geometry });\n const merged: any = merge(topo, topo.objects.geoms.geometries);\n return merged;\n}\n\nexport { polygonDissolve };\nexport default polygonDissolve;\n"],"mappings":"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","names":["clone","isObject","getType","flattenEach","clone","getType","feature","isObject","getType","clone","flattenEach","feature"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turf/concave",
3
- "version": "7.0.0-alpha.2",
3
+ "version": "7.1.0-alpha.7+0ce6ecca0",
4
4
  "description": "turf concave module",
5
5
  "author": "Turf Authors",
6
6
  "contributors": [
@@ -33,53 +33,58 @@
33
33
  "concave",
34
34
  "geometry"
35
35
  ],
36
- "main": "dist/js/index.js",
37
- "module": "dist/es/index.js",
36
+ "type": "module",
37
+ "main": "dist/cjs/index.cjs",
38
+ "module": "dist/esm/index.js",
39
+ "types": "dist/esm/index.d.ts",
38
40
  "exports": {
39
41
  "./package.json": "./package.json",
40
42
  ".": {
41
- "types": "./dist/js/index.d.ts",
42
- "import": "./dist/es/index.js",
43
- "require": "./dist/js/index.js"
43
+ "import": {
44
+ "types": "./dist/esm/index.d.ts",
45
+ "default": "./dist/esm/index.js"
46
+ },
47
+ "require": {
48
+ "types": "./dist/cjs/index.d.cts",
49
+ "default": "./dist/cjs/index.cjs"
50
+ }
44
51
  }
45
52
  },
46
- "types": "dist/js/index.d.ts",
47
53
  "sideEffects": false,
48
54
  "files": [
49
55
  "dist"
50
56
  ],
51
57
  "scripts": {
52
- "bench": "tsx bench.js",
53
- "build": "npm-run-all build:*",
54
- "build:es": "tsc --outDir dist/es --module esnext --declaration false && echo '{\"type\":\"module\"}' > dist/es/package.json",
55
- "build:js": "tsc",
56
- "docs": "tsx ../../scripts/generate-readmes",
57
- "test": "npm-run-all test:*",
58
- "test:tape": "tsx test.js"
58
+ "bench": "tsx bench.ts",
59
+ "build": "tsup --config ../../tsup.config.ts",
60
+ "docs": "tsx ../../scripts/generate-readmes.ts",
61
+ "test": "npm-run-all --npm-path npm test:*",
62
+ "test:tape": "tsx test.ts"
59
63
  },
60
64
  "devDependencies": {
61
- "@types/tape": "*",
62
- "@types/topojson-client": "^3.0.0",
63
- "@types/topojson-server": "^3.0.0",
64
- "benchmark": "*",
65
- "load-json-file": "*",
66
- "npm-run-all": "*",
67
- "tape": "*",
68
- "tslint": "*",
69
- "tsx": "*",
70
- "typescript": "*",
71
- "write-json-file": "*"
65
+ "@types/benchmark": "^2.1.5",
66
+ "@types/tape": "^4.2.32",
67
+ "@types/topojson-client": "3.1.3",
68
+ "@types/topojson-server": "3.0.3",
69
+ "benchmark": "^2.1.4",
70
+ "load-json-file": "^7.0.1",
71
+ "npm-run-all": "^4.1.5",
72
+ "tape": "^5.7.2",
73
+ "tsup": "^8.0.1",
74
+ "tsx": "^4.6.2",
75
+ "typescript": "^5.2.2",
76
+ "write-json-file": "^5.0.0"
72
77
  },
73
78
  "dependencies": {
74
- "@turf/clone": "^7.0.0-alpha.2",
75
- "@turf/distance": "^7.0.0-alpha.2",
76
- "@turf/helpers": "^7.0.0-alpha.2",
77
- "@turf/invariant": "^7.0.0-alpha.2",
78
- "@turf/meta": "^7.0.0-alpha.2",
79
- "@turf/tin": "^7.0.0-alpha.2",
79
+ "@turf/clone": "^7.1.0-alpha.7+0ce6ecca0",
80
+ "@turf/distance": "^7.1.0-alpha.7+0ce6ecca0",
81
+ "@turf/helpers": "^7.1.0-alpha.7+0ce6ecca0",
82
+ "@turf/invariant": "^7.1.0-alpha.7+0ce6ecca0",
83
+ "@turf/meta": "^7.1.0-alpha.7+0ce6ecca0",
84
+ "@turf/tin": "^7.1.0-alpha.7+0ce6ecca0",
80
85
  "topojson-client": "3.x",
81
86
  "topojson-server": "3.x",
82
- "tslib": "^2.3.0"
87
+ "tslib": "^2.6.2"
83
88
  },
84
- "gitHead": "dd35b52725945b4fa29a98d9a550733e06cc222e"
89
+ "gitHead": "0ce6ecca05829690270fec6d6bed2003495fe0ea"
85
90
  }
package/dist/es/index.js DELETED
@@ -1,82 +0,0 @@
1
- import distance from "@turf/distance";
2
- import { feature, featureCollection } from "@turf/helpers";
3
- import { featureEach } from "@turf/meta";
4
- import tin from "@turf/tin";
5
- import dissolve from "./lib/turf-dissolve.js";
6
- /**
7
- * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.
8
- * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.
9
- *
10
- * @name concave
11
- * @param {FeatureCollection<Point>} points input points
12
- * @param {Object} [options={}] Optional parameters
13
- * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the
14
- * hull to become concave.
15
- * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
16
- * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)
17
- * @example
18
- * var points = turf.featureCollection([
19
- * turf.point([-63.601226, 44.642643]),
20
- * turf.point([-63.591442, 44.651436]),
21
- * turf.point([-63.580799, 44.648749]),
22
- * turf.point([-63.573589, 44.641788]),
23
- * turf.point([-63.587665, 44.64533]),
24
- * turf.point([-63.595218, 44.64765])
25
- * ]);
26
- * var options = {units: 'miles', maxEdge: 1};
27
- *
28
- * var hull = turf.concave(points, options);
29
- *
30
- * //addToMap
31
- * var addToMap = [points, hull]
32
- */
33
- function concave(points, options = {}) {
34
- const maxEdge = options.maxEdge || Infinity;
35
- const cleaned = removeDuplicates(points);
36
- const tinPolys = tin(cleaned);
37
- // calculate length of all edges and area of all triangles
38
- // and remove triangles that fail the max length test
39
- tinPolys.features = tinPolys.features.filter((triangle) => {
40
- const pt1 = triangle.geometry.coordinates[0][0];
41
- const pt2 = triangle.geometry.coordinates[0][1];
42
- const pt3 = triangle.geometry.coordinates[0][2];
43
- const dist1 = distance(pt1, pt2, options);
44
- const dist2 = distance(pt2, pt3, options);
45
- const dist3 = distance(pt1, pt3, options);
46
- return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;
47
- });
48
- if (tinPolys.features.length < 1) {
49
- return null;
50
- }
51
- // merge the adjacent triangles
52
- const dissolved = dissolve(tinPolys);
53
- // geojson-dissolve always returns a MultiPolygon
54
- if (dissolved.coordinates.length === 1) {
55
- dissolved.coordinates = dissolved.coordinates[0];
56
- dissolved.type = "Polygon";
57
- }
58
- return feature(dissolved);
59
- }
60
- /**
61
- * Removes duplicated points in a collection returning a new collection
62
- *
63
- * @private
64
- * @param {FeatureCollection<Point>} points to be cleaned
65
- * @returns {FeatureCollection<Point>} cleaned set of points
66
- */
67
- function removeDuplicates(points) {
68
- const cleaned = [];
69
- const existing = {};
70
- featureEach(points, (pt) => {
71
- if (!pt.geometry) {
72
- return;
73
- }
74
- const key = pt.geometry.coordinates.join("-");
75
- if (!Object.prototype.hasOwnProperty.call(existing, key)) {
76
- cleaned.push(pt);
77
- existing[key] = true;
78
- }
79
- });
80
- return featureCollection(cleaned);
81
- }
82
- export default concave;
@@ -1,70 +0,0 @@
1
- import clone from "@turf/clone";
2
- import { isObject } from "@turf/helpers";
3
- import { getType } from "@turf/invariant";
4
- import { flattenEach } from "@turf/meta";
5
- import lineDissolve from "./turf-line-dissolve.js";
6
- import polygonDissolve from "./turf-polygon-dissolve.js";
7
- /**
8
- * Transform function: attempts to dissolve geojson objects where possible
9
- * [GeoJSON] -> GeoJSON geometry
10
- *
11
- * @private
12
- * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved
13
- * @param {Object} [options={}] Optional parameters
14
- * @param {boolean} [options.mutate=false] Prevent input mutation
15
- * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features
16
- */
17
- function dissolve(geojson, options = {}) {
18
- // Optional parameters
19
- options = options || {};
20
- if (!isObject(options)) {
21
- throw new Error("options is invalid");
22
- }
23
- const mutate = options.mutate;
24
- // Validation
25
- if (getType(geojson) !== "FeatureCollection") {
26
- throw new Error("geojson must be a FeatureCollection");
27
- }
28
- if (!geojson.features.length) {
29
- throw new Error("geojson is empty");
30
- }
31
- // Clone geojson to avoid side effects
32
- // Topojson modifies in place, so we need to deep clone first
33
- if (mutate === false || mutate === undefined) {
34
- geojson = clone(geojson);
35
- }
36
- // Assert homogenity
37
- const type = getHomogenousType(geojson);
38
- if (!type) {
39
- throw new Error("geojson must be homogenous");
40
- }
41
- // Data => Typescript hack
42
- const data = geojson;
43
- switch (type) {
44
- case "LineString":
45
- return lineDissolve(data, options);
46
- case "Polygon":
47
- return polygonDissolve(data, options);
48
- default:
49
- throw new Error(type + " is not supported");
50
- }
51
- }
52
- /**
53
- * Checks if GeoJSON is Homogenous
54
- *
55
- * @private
56
- * @param {GeoJSON} geojson GeoJSON
57
- * @returns {string|null} Homogenous type or null if multiple types
58
- */
59
- function getHomogenousType(geojson) {
60
- const types = {};
61
- flattenEach(geojson, (feature) => {
62
- types[feature.geometry.type] = true;
63
- });
64
- const keys = Object.keys(types);
65
- if (keys.length === 1) {
66
- return keys[0];
67
- }
68
- return null;
69
- }
70
- export default dissolve;
@@ -1,104 +0,0 @@
1
- import clone from "@turf/clone";
2
- import { isObject, lineString, multiLineString } from "@turf/helpers";
3
- import { getType } from "@turf/invariant";
4
- import { lineReduce } from "@turf/meta";
5
- /**
6
- * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.
7
- * [LineString] -> LineString|MultiLineString
8
- *
9
- * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve
10
- * @param {Object} [options={}] Optional parameters
11
- * @param {boolean} [options.mutate=false] Prevent input mutation
12
- * @returns {Feature<LineString|MultiLineString>} Dissolved lines
13
- */
14
- function lineDissolve(geojson, options = {}) {
15
- // Optional parameters
16
- options = options || {};
17
- if (!isObject(options)) {
18
- throw new Error("options is invalid");
19
- }
20
- const mutate = options.mutate;
21
- // Validation
22
- if (getType(geojson) !== "FeatureCollection") {
23
- throw new Error("geojson must be a FeatureCollection");
24
- }
25
- if (!geojson.features.length) {
26
- throw new Error("geojson is empty");
27
- }
28
- // Clone geojson to avoid side effects
29
- if (mutate === false || mutate === undefined) {
30
- geojson = clone(geojson);
31
- }
32
- const result = [];
33
- const lastLine = lineReduce(geojson, (previousLine, currentLine) => {
34
- // Attempt to merge this LineString with the other LineStrings, updating
35
- // the reference as it is merged with others and grows.
36
- const merged = mergeLineStrings(previousLine, currentLine);
37
- // Accumulate the merged LineString
38
- if (merged) {
39
- return merged;
40
- // Put the unmerged LineString back into the list
41
- }
42
- else {
43
- result.push(previousLine);
44
- return currentLine;
45
- }
46
- });
47
- // Append the last line
48
- if (lastLine) {
49
- result.push(lastLine);
50
- }
51
- // Return null if no lines were dissolved
52
- if (!result.length) {
53
- return null;
54
- // Return LineString if only 1 line was dissolved
55
- }
56
- else if (result.length === 1) {
57
- return result[0];
58
- // Return MultiLineString if multiple lines were dissolved with gaps
59
- }
60
- else {
61
- return multiLineString(result.map((line) => {
62
- return line.coordinates;
63
- }));
64
- }
65
- }
66
- // [Number, Number] -> String
67
- function coordId(coord) {
68
- return coord[0].toString() + "," + coord[1].toString();
69
- }
70
- /**
71
- * LineString, LineString -> LineString
72
- *
73
- * @private
74
- * @param {Feature<LineString>} a line1
75
- * @param {Feature<LineString>} b line2
76
- * @returns {Feature<LineString>|null} Merged LineString
77
- */
78
- function mergeLineStrings(a, b) {
79
- const coords1 = a.geometry.coordinates;
80
- const coords2 = b.geometry.coordinates;
81
- const s1 = coordId(coords1[0]);
82
- const e1 = coordId(coords1[coords1.length - 1]);
83
- const s2 = coordId(coords2[0]);
84
- const e2 = coordId(coords2[coords2.length - 1]);
85
- // TODO: handle case where more than one of these is true!
86
- let coords;
87
- if (s1 === e2) {
88
- coords = coords2.concat(coords1.slice(1));
89
- }
90
- else if (s2 === e1) {
91
- coords = coords1.concat(coords2.slice(1));
92
- }
93
- else if (s1 === s2) {
94
- coords = coords1.slice(1).reverse().concat(coords2);
95
- }
96
- else if (e1 === e2) {
97
- coords = coords1.concat(coords2.reverse().slice(1));
98
- }
99
- else {
100
- return null;
101
- }
102
- return lineString(coords);
103
- }
104
- export default lineDissolve;
@@ -1,35 +0,0 @@
1
- import clone from "@turf/clone";
2
- import { geometryCollection } from "@turf/helpers";
3
- import { getType } from "@turf/invariant";
4
- import { flattenEach } from "@turf/meta";
5
- import { merge } from "topojson-client";
6
- import { topology } from "topojson-server";
7
- /**
8
- * Dissolves all overlapping (Multi)Polygon
9
- *
10
- * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve
11
- * @param {Object} [options={}] Optional parameters
12
- * @param {boolean} [options.mutate=false] Prevent input mutation
13
- * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons
14
- */
15
- export default function polygonDissolve(geojson, options = {}) {
16
- // Validation
17
- if (getType(geojson) !== "FeatureCollection") {
18
- throw new Error("geojson must be a FeatureCollection");
19
- }
20
- if (!geojson.features.length) {
21
- throw new Error("geojson is empty");
22
- }
23
- // Clone geojson to avoid side effects
24
- // Topojson modifies in place, so we need to deep clone first
25
- if (options.mutate === false || options.mutate === undefined) {
26
- geojson = clone(geojson);
27
- }
28
- const geoms = [];
29
- flattenEach(geojson, (feature) => {
30
- geoms.push(feature.geometry);
31
- });
32
- const topo = topology({ geoms: geometryCollection(geoms).geometry });
33
- const merged = merge(topo, topo.objects.geoms.geometries);
34
- return merged;
35
- }
@@ -1 +0,0 @@
1
- {"type":"module"}
package/dist/js/index.js DELETED
@@ -1,85 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const distance_1 = tslib_1.__importDefault(require("@turf/distance"));
5
- const helpers_1 = require("@turf/helpers");
6
- const meta_1 = require("@turf/meta");
7
- const tin_1 = tslib_1.__importDefault(require("@turf/tin"));
8
- const turf_dissolve_1 = tslib_1.__importDefault(require("./lib/turf-dissolve"));
9
- /**
10
- * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.
11
- * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.
12
- *
13
- * @name concave
14
- * @param {FeatureCollection<Point>} points input points
15
- * @param {Object} [options={}] Optional parameters
16
- * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the
17
- * hull to become concave.
18
- * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
19
- * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)
20
- * @example
21
- * var points = turf.featureCollection([
22
- * turf.point([-63.601226, 44.642643]),
23
- * turf.point([-63.591442, 44.651436]),
24
- * turf.point([-63.580799, 44.648749]),
25
- * turf.point([-63.573589, 44.641788]),
26
- * turf.point([-63.587665, 44.64533]),
27
- * turf.point([-63.595218, 44.64765])
28
- * ]);
29
- * var options = {units: 'miles', maxEdge: 1};
30
- *
31
- * var hull = turf.concave(points, options);
32
- *
33
- * //addToMap
34
- * var addToMap = [points, hull]
35
- */
36
- function concave(points, options = {}) {
37
- const maxEdge = options.maxEdge || Infinity;
38
- const cleaned = removeDuplicates(points);
39
- const tinPolys = tin_1.default(cleaned);
40
- // calculate length of all edges and area of all triangles
41
- // and remove triangles that fail the max length test
42
- tinPolys.features = tinPolys.features.filter((triangle) => {
43
- const pt1 = triangle.geometry.coordinates[0][0];
44
- const pt2 = triangle.geometry.coordinates[0][1];
45
- const pt3 = triangle.geometry.coordinates[0][2];
46
- const dist1 = distance_1.default(pt1, pt2, options);
47
- const dist2 = distance_1.default(pt2, pt3, options);
48
- const dist3 = distance_1.default(pt1, pt3, options);
49
- return dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge;
50
- });
51
- if (tinPolys.features.length < 1) {
52
- return null;
53
- }
54
- // merge the adjacent triangles
55
- const dissolved = turf_dissolve_1.default(tinPolys);
56
- // geojson-dissolve always returns a MultiPolygon
57
- if (dissolved.coordinates.length === 1) {
58
- dissolved.coordinates = dissolved.coordinates[0];
59
- dissolved.type = "Polygon";
60
- }
61
- return helpers_1.feature(dissolved);
62
- }
63
- /**
64
- * Removes duplicated points in a collection returning a new collection
65
- *
66
- * @private
67
- * @param {FeatureCollection<Point>} points to be cleaned
68
- * @returns {FeatureCollection<Point>} cleaned set of points
69
- */
70
- function removeDuplicates(points) {
71
- const cleaned = [];
72
- const existing = {};
73
- meta_1.featureEach(points, (pt) => {
74
- if (!pt.geometry) {
75
- return;
76
- }
77
- const key = pt.geometry.coordinates.join("-");
78
- if (!Object.prototype.hasOwnProperty.call(existing, key)) {
79
- cleaned.push(pt);
80
- existing[key] = true;
81
- }
82
- });
83
- return helpers_1.featureCollection(cleaned);
84
- }
85
- exports.default = concave;
@@ -1,15 +0,0 @@
1
- import { Feature, FeatureCollection, LineString, MultiLineString, MultiPolygon, Polygon } from "geojson";
2
- /**
3
- * Transform function: attempts to dissolve geojson objects where possible
4
- * [GeoJSON] -> GeoJSON geometry
5
- *
6
- * @private
7
- * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved
8
- * @param {Object} [options={}] Optional parameters
9
- * @param {boolean} [options.mutate=false] Prevent input mutation
10
- * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features
11
- */
12
- declare function dissolve(geojson: FeatureCollection<LineString | MultiLineString | Polygon | MultiPolygon>, options?: {
13
- mutate?: boolean;
14
- }): Feature<LineString | MultiLineString | Polygon | MultiPolygon> | null;
15
- export default dissolve;
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const clone_1 = tslib_1.__importDefault(require("@turf/clone"));
5
- const helpers_1 = require("@turf/helpers");
6
- const invariant_1 = require("@turf/invariant");
7
- const meta_1 = require("@turf/meta");
8
- const turf_line_dissolve_1 = tslib_1.__importDefault(require("./turf-line-dissolve"));
9
- const turf_polygon_dissolve_1 = tslib_1.__importDefault(require("./turf-polygon-dissolve"));
10
- /**
11
- * Transform function: attempts to dissolve geojson objects where possible
12
- * [GeoJSON] -> GeoJSON geometry
13
- *
14
- * @private
15
- * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved
16
- * @param {Object} [options={}] Optional parameters
17
- * @param {boolean} [options.mutate=false] Prevent input mutation
18
- * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features
19
- */
20
- function dissolve(geojson, options = {}) {
21
- // Optional parameters
22
- options = options || {};
23
- if (!helpers_1.isObject(options)) {
24
- throw new Error("options is invalid");
25
- }
26
- const mutate = options.mutate;
27
- // Validation
28
- if (invariant_1.getType(geojson) !== "FeatureCollection") {
29
- throw new Error("geojson must be a FeatureCollection");
30
- }
31
- if (!geojson.features.length) {
32
- throw new Error("geojson is empty");
33
- }
34
- // Clone geojson to avoid side effects
35
- // Topojson modifies in place, so we need to deep clone first
36
- if (mutate === false || mutate === undefined) {
37
- geojson = clone_1.default(geojson);
38
- }
39
- // Assert homogenity
40
- const type = getHomogenousType(geojson);
41
- if (!type) {
42
- throw new Error("geojson must be homogenous");
43
- }
44
- // Data => Typescript hack
45
- const data = geojson;
46
- switch (type) {
47
- case "LineString":
48
- return turf_line_dissolve_1.default(data, options);
49
- case "Polygon":
50
- return turf_polygon_dissolve_1.default(data, options);
51
- default:
52
- throw new Error(type + " is not supported");
53
- }
54
- }
55
- /**
56
- * Checks if GeoJSON is Homogenous
57
- *
58
- * @private
59
- * @param {GeoJSON} geojson GeoJSON
60
- * @returns {string|null} Homogenous type or null if multiple types
61
- */
62
- function getHomogenousType(geojson) {
63
- const types = {};
64
- meta_1.flattenEach(geojson, (feature) => {
65
- types[feature.geometry.type] = true;
66
- });
67
- const keys = Object.keys(types);
68
- if (keys.length === 1) {
69
- return keys[0];
70
- }
71
- return null;
72
- }
73
- exports.default = dissolve;
@@ -1,14 +0,0 @@
1
- import { Feature, FeatureCollection, LineString, MultiLineString } from "geojson";
2
- /**
3
- * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.
4
- * [LineString] -> LineString|MultiLineString
5
- *
6
- * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve
7
- * @param {Object} [options={}] Optional parameters
8
- * @param {boolean} [options.mutate=false] Prevent input mutation
9
- * @returns {Feature<LineString|MultiLineString>} Dissolved lines
10
- */
11
- declare function lineDissolve(geojson: FeatureCollection<LineString | MultiLineString>, options?: {
12
- mutate?: boolean;
13
- }): Feature<LineString | MultiLineString> | null;
14
- export default lineDissolve;
@@ -1,107 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const clone_1 = tslib_1.__importDefault(require("@turf/clone"));
5
- const helpers_1 = require("@turf/helpers");
6
- const invariant_1 = require("@turf/invariant");
7
- const meta_1 = require("@turf/meta");
8
- /**
9
- * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.
10
- * [LineString] -> LineString|MultiLineString
11
- *
12
- * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve
13
- * @param {Object} [options={}] Optional parameters
14
- * @param {boolean} [options.mutate=false] Prevent input mutation
15
- * @returns {Feature<LineString|MultiLineString>} Dissolved lines
16
- */
17
- function lineDissolve(geojson, options = {}) {
18
- // Optional parameters
19
- options = options || {};
20
- if (!helpers_1.isObject(options)) {
21
- throw new Error("options is invalid");
22
- }
23
- const mutate = options.mutate;
24
- // Validation
25
- if (invariant_1.getType(geojson) !== "FeatureCollection") {
26
- throw new Error("geojson must be a FeatureCollection");
27
- }
28
- if (!geojson.features.length) {
29
- throw new Error("geojson is empty");
30
- }
31
- // Clone geojson to avoid side effects
32
- if (mutate === false || mutate === undefined) {
33
- geojson = clone_1.default(geojson);
34
- }
35
- const result = [];
36
- const lastLine = meta_1.lineReduce(geojson, (previousLine, currentLine) => {
37
- // Attempt to merge this LineString with the other LineStrings, updating
38
- // the reference as it is merged with others and grows.
39
- const merged = mergeLineStrings(previousLine, currentLine);
40
- // Accumulate the merged LineString
41
- if (merged) {
42
- return merged;
43
- // Put the unmerged LineString back into the list
44
- }
45
- else {
46
- result.push(previousLine);
47
- return currentLine;
48
- }
49
- });
50
- // Append the last line
51
- if (lastLine) {
52
- result.push(lastLine);
53
- }
54
- // Return null if no lines were dissolved
55
- if (!result.length) {
56
- return null;
57
- // Return LineString if only 1 line was dissolved
58
- }
59
- else if (result.length === 1) {
60
- return result[0];
61
- // Return MultiLineString if multiple lines were dissolved with gaps
62
- }
63
- else {
64
- return helpers_1.multiLineString(result.map((line) => {
65
- return line.coordinates;
66
- }));
67
- }
68
- }
69
- // [Number, Number] -> String
70
- function coordId(coord) {
71
- return coord[0].toString() + "," + coord[1].toString();
72
- }
73
- /**
74
- * LineString, LineString -> LineString
75
- *
76
- * @private
77
- * @param {Feature<LineString>} a line1
78
- * @param {Feature<LineString>} b line2
79
- * @returns {Feature<LineString>|null} Merged LineString
80
- */
81
- function mergeLineStrings(a, b) {
82
- const coords1 = a.geometry.coordinates;
83
- const coords2 = b.geometry.coordinates;
84
- const s1 = coordId(coords1[0]);
85
- const e1 = coordId(coords1[coords1.length - 1]);
86
- const s2 = coordId(coords2[0]);
87
- const e2 = coordId(coords2[coords2.length - 1]);
88
- // TODO: handle case where more than one of these is true!
89
- let coords;
90
- if (s1 === e2) {
91
- coords = coords2.concat(coords1.slice(1));
92
- }
93
- else if (s2 === e1) {
94
- coords = coords1.concat(coords2.slice(1));
95
- }
96
- else if (s1 === s2) {
97
- coords = coords1.slice(1).reverse().concat(coords2);
98
- }
99
- else if (e1 === e2) {
100
- coords = coords1.concat(coords2.reverse().slice(1));
101
- }
102
- else {
103
- return null;
104
- }
105
- return helpers_1.lineString(coords);
106
- }
107
- exports.default = lineDissolve;
@@ -1,12 +0,0 @@
1
- import { Feature, FeatureCollection, MultiPolygon, Polygon } from "geojson";
2
- /**
3
- * Dissolves all overlapping (Multi)Polygon
4
- *
5
- * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve
6
- * @param {Object} [options={}] Optional parameters
7
- * @param {boolean} [options.mutate=false] Prevent input mutation
8
- * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons
9
- */
10
- export default function polygonDissolve(geojson: FeatureCollection<Polygon | MultiPolygon>, options?: {
11
- mutate?: boolean;
12
- }): Feature<Polygon | MultiPolygon> | null;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const clone_1 = tslib_1.__importDefault(require("@turf/clone"));
5
- const helpers_1 = require("@turf/helpers");
6
- const invariant_1 = require("@turf/invariant");
7
- const meta_1 = require("@turf/meta");
8
- const topojson_client_1 = require("topojson-client");
9
- const topojson_server_1 = require("topojson-server");
10
- /**
11
- * Dissolves all overlapping (Multi)Polygon
12
- *
13
- * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve
14
- * @param {Object} [options={}] Optional parameters
15
- * @param {boolean} [options.mutate=false] Prevent input mutation
16
- * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons
17
- */
18
- function polygonDissolve(geojson, options = {}) {
19
- // Validation
20
- if (invariant_1.getType(geojson) !== "FeatureCollection") {
21
- throw new Error("geojson must be a FeatureCollection");
22
- }
23
- if (!geojson.features.length) {
24
- throw new Error("geojson is empty");
25
- }
26
- // Clone geojson to avoid side effects
27
- // Topojson modifies in place, so we need to deep clone first
28
- if (options.mutate === false || options.mutate === undefined) {
29
- geojson = clone_1.default(geojson);
30
- }
31
- const geoms = [];
32
- meta_1.flattenEach(geojson, (feature) => {
33
- geoms.push(feature.geometry);
34
- });
35
- const topo = topojson_server_1.topology({ geoms: helpers_1.geometryCollection(geoms).geometry });
36
- const merged = topojson_client_1.merge(topo, topo.objects.geoms.geometries);
37
- return merged;
38
- }
39
- exports.default = polygonDissolve;