@loaders.gl/gis 3.1.0 → 3.1.1

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.
Files changed (49) hide show
  1. package/dist/es5/index.js +16 -0
  2. package/dist/es5/index.js.map +1 -1
  3. package/dist/es5/lib/extract-geometry-info.js +204 -0
  4. package/dist/es5/lib/extract-geometry-info.js.map +1 -0
  5. package/dist/es5/lib/flat-geojson-to-binary-types.js +2 -0
  6. package/dist/es5/lib/flat-geojson-to-binary-types.js.map +1 -0
  7. package/dist/es5/lib/flat-geojson-to-binary.js +397 -0
  8. package/dist/es5/lib/flat-geojson-to-binary.js.map +1 -0
  9. package/dist/es5/lib/geojson-to-binary.js +15 -579
  10. package/dist/es5/lib/geojson-to-binary.js.map +1 -1
  11. package/dist/es5/lib/geojson-to-flat-geojson.js +169 -0
  12. package/dist/es5/lib/geojson-to-flat-geojson.js.map +1 -0
  13. package/dist/esm/index.js +2 -0
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/lib/extract-geometry-info.js +105 -0
  16. package/dist/esm/lib/extract-geometry-info.js.map +1 -0
  17. package/dist/esm/lib/flat-geojson-to-binary-types.js +2 -0
  18. package/dist/esm/lib/flat-geojson-to-binary-types.js.map +1 -0
  19. package/dist/esm/lib/flat-geojson-to-binary.js +339 -0
  20. package/dist/esm/lib/flat-geojson-to-binary.js.map +1 -0
  21. package/dist/esm/lib/geojson-to-binary.js +17 -410
  22. package/dist/esm/lib/geojson-to-binary.js.map +1 -1
  23. package/dist/esm/lib/geojson-to-flat-geojson.js +116 -0
  24. package/dist/esm/lib/geojson-to-flat-geojson.js.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +5 -1
  28. package/dist/lib/extract-geometry-info.d.ts +8 -0
  29. package/dist/lib/extract-geometry-info.d.ts.map +1 -0
  30. package/dist/lib/extract-geometry-info.js +96 -0
  31. package/dist/lib/flat-geojson-to-binary-types.d.ts +58 -0
  32. package/dist/lib/flat-geojson-to-binary-types.d.ts.map +1 -0
  33. package/dist/lib/flat-geojson-to-binary-types.js +2 -0
  34. package/dist/lib/flat-geojson-to-binary.d.ts +37 -0
  35. package/dist/lib/flat-geojson-to-binary.d.ts.map +1 -0
  36. package/dist/lib/flat-geojson-to-binary.js +375 -0
  37. package/dist/lib/geojson-to-binary.d.ts +12 -36
  38. package/dist/lib/geojson-to-binary.d.ts.map +1 -1
  39. package/dist/lib/geojson-to-binary.js +18 -360
  40. package/dist/lib/geojson-to-flat-geojson.d.ts +17 -0
  41. package/dist/lib/geojson-to-flat-geojson.d.ts.map +1 -0
  42. package/dist/lib/geojson-to-flat-geojson.js +128 -0
  43. package/package.json +5 -4
  44. package/src/index.ts +2 -0
  45. package/src/lib/extract-geometry-info.ts +101 -0
  46. package/src/lib/flat-geojson-to-binary-types.ts +58 -0
  47. package/src/lib/flat-geojson-to-binary.ts +564 -0
  48. package/src/lib/geojson-to-binary.ts +24 -459
  49. package/src/lib/geojson-to-flat-geojson.ts +171 -0
@@ -1,366 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TEST_EXPORTS = exports.geojsonToBinary = void 0;
4
- /** Convert GeoJSON features to flat binary arrays */
5
- function geojsonToBinary(features, options = {}) {
6
- const firstPassData = firstPass(features);
7
- return secondPass(features, firstPassData, {
8
- coordLength: options.coordLength || firstPassData.coordLength,
9
- numericPropKeys: options.numericPropKeys || firstPassData.numericPropKeys,
3
+ exports.geojsonToBinary = void 0;
4
+ const extract_geometry_info_1 = require("./extract-geometry-info");
5
+ const geojson_to_flat_geojson_1 = require("./geojson-to-flat-geojson");
6
+ const flat_geojson_to_binary_1 = require("./flat-geojson-to-binary");
7
+ /**
8
+ * Convert GeoJSON features to flat binary arrays
9
+ *
10
+ * @param features
11
+ * @param options
12
+ * @returns features in binary format, grouped by geometry type
13
+ */
14
+ function geojsonToBinary(features, options = { fixRingWinding: true }) {
15
+ const geometryInfo = (0, extract_geometry_info_1.extractGeometryInfo)(features);
16
+ const coordLength = geometryInfo.coordLength;
17
+ const { fixRingWinding } = options;
18
+ const flatFeatures = (0, geojson_to_flat_geojson_1.geojsonToFlatGeojson)(features, { coordLength, fixRingWinding });
19
+ return (0, flat_geojson_to_binary_1.flatGeojsonToBinary)(flatFeatures, geometryInfo, {
20
+ numericPropKeys: options.numericPropKeys,
10
21
  PositionDataType: options.PositionDataType || Float32Array
11
22
  });
12
23
  }
13
24
  exports.geojsonToBinary = geojsonToBinary;
14
- exports.TEST_EXPORTS = {
15
- firstPass,
16
- secondPass
17
- };
18
- /**
19
- * Initial scan over GeoJSON features
20
- * Counts number of coordinates of each geometry type and
21
- * keeps track of the max coordinate dimensions
22
- */
23
- // eslint-disable-next-line complexity, max-statements
24
- function firstPass(features) {
25
- // Counts the number of _positions_, so [x, y, z] counts as one
26
- let pointPositionsCount = 0;
27
- let pointFeaturesCount = 0;
28
- let linePositionsCount = 0;
29
- let linePathsCount = 0;
30
- let lineFeaturesCount = 0;
31
- let polygonPositionsCount = 0;
32
- let polygonObjectsCount = 0;
33
- let polygonRingsCount = 0;
34
- let polygonFeaturesCount = 0;
35
- const coordLengths = new Set();
36
- const propArrayTypes = {};
37
- for (const feature of features) {
38
- const geometry = feature.geometry;
39
- switch (geometry.type) {
40
- case 'Point':
41
- pointFeaturesCount++;
42
- pointPositionsCount++;
43
- coordLengths.add(geometry.coordinates.length);
44
- break;
45
- case 'MultiPoint':
46
- pointFeaturesCount++;
47
- pointPositionsCount += geometry.coordinates.length;
48
- for (const point of geometry.coordinates) {
49
- coordLengths.add(point.length);
50
- }
51
- break;
52
- case 'LineString':
53
- lineFeaturesCount++;
54
- linePositionsCount += geometry.coordinates.length;
55
- linePathsCount++;
56
- for (const coord of geometry.coordinates) {
57
- coordLengths.add(coord.length);
58
- }
59
- break;
60
- case 'MultiLineString':
61
- lineFeaturesCount++;
62
- for (const line of geometry.coordinates) {
63
- linePositionsCount += line.length;
64
- linePathsCount++;
65
- // eslint-disable-next-line max-depth
66
- for (const coord of line) {
67
- coordLengths.add(coord.length);
68
- }
69
- }
70
- break;
71
- case 'Polygon':
72
- polygonFeaturesCount++;
73
- polygonObjectsCount++;
74
- polygonRingsCount += geometry.coordinates.length;
75
- polygonPositionsCount += flatten(geometry.coordinates).length;
76
- for (const coord of flatten(geometry.coordinates)) {
77
- coordLengths.add(coord.length);
78
- }
79
- break;
80
- case 'MultiPolygon':
81
- polygonFeaturesCount++;
82
- for (const polygon of geometry.coordinates) {
83
- polygonObjectsCount++;
84
- polygonRingsCount += polygon.length;
85
- polygonPositionsCount += flatten(polygon).length;
86
- // eslint-disable-next-line max-depth
87
- for (const coord of flatten(polygon)) {
88
- coordLengths.add(coord.length);
89
- }
90
- }
91
- break;
92
- default:
93
- throw new Error(`Unsupported geometry type: ${geometry.type}`);
94
- }
95
- if (feature.properties) {
96
- for (const key in feature.properties) {
97
- const val = feature.properties[key];
98
- // If property has not been seen before, or if property has been numeric
99
- // in all previous features, check if numeric in this feature
100
- // If not numeric, Array is stored to prevent rechecking in the future
101
- // Additionally, detects if 64 bit precision is required
102
- propArrayTypes[key] = deduceArrayType(val, propArrayTypes[key]);
103
- }
104
- }
105
- }
106
- return {
107
- coordLength: coordLengths.size > 0 ? Math.max(...coordLengths) : 2,
108
- pointPositionsCount,
109
- pointFeaturesCount,
110
- linePositionsCount,
111
- linePathsCount,
112
- lineFeaturesCount,
113
- polygonPositionsCount,
114
- polygonObjectsCount,
115
- polygonRingsCount,
116
- polygonFeaturesCount,
117
- // Array of keys whose values are always numeric
118
- numericPropKeys: Object.keys(propArrayTypes).filter((k) => propArrayTypes[k] !== Array),
119
- propArrayTypes
120
- };
121
- }
122
- /**
123
- * Second scan over GeoJSON features
124
- * Fills coordinates into pre-allocated typed arrays
125
- */
126
- // eslint-disable-next-line complexity
127
- function secondPass(features, firstPassData, options) {
128
- const { pointPositionsCount, pointFeaturesCount, linePositionsCount, linePathsCount, lineFeaturesCount, polygonPositionsCount, polygonObjectsCount, polygonRingsCount, propArrayTypes, polygonFeaturesCount } = firstPassData;
129
- const { coordLength, numericPropKeys, PositionDataType = Float32Array } = options;
130
- const GlobalFeatureIdsDataType = features.length > 65535 ? Uint32Array : Uint16Array;
131
- const points = {
132
- // @ts-ignore Typescript doesn't like dynamic constructors
133
- positions: new PositionDataType(pointPositionsCount * coordLength),
134
- globalFeatureIds: new GlobalFeatureIdsDataType(pointPositionsCount),
135
- featureIds: pointFeaturesCount > 65535
136
- ? new Uint32Array(pointPositionsCount)
137
- : new Uint16Array(pointPositionsCount),
138
- numericProps: {},
139
- properties: Array(),
140
- fields: Array()
141
- };
142
- const lines = {
143
- // @ts-ignore Typescript doesn't like dynamic constructors
144
- positions: new PositionDataType(linePositionsCount * coordLength),
145
- pathIndices: linePositionsCount > 65535
146
- ? new Uint32Array(linePathsCount + 1)
147
- : new Uint16Array(linePathsCount + 1),
148
- globalFeatureIds: new GlobalFeatureIdsDataType(linePositionsCount),
149
- featureIds: lineFeaturesCount > 65535
150
- ? new Uint32Array(linePositionsCount)
151
- : new Uint16Array(linePositionsCount),
152
- numericProps: {},
153
- properties: Array(),
154
- fields: Array()
155
- };
156
- const polygons = {
157
- // @ts-ignore Typescript doesn't like dynamic constructors
158
- positions: new PositionDataType(polygonPositionsCount * coordLength),
159
- polygonIndices: polygonPositionsCount > 65535
160
- ? new Uint32Array(polygonObjectsCount + 1)
161
- : new Uint16Array(polygonObjectsCount + 1),
162
- primitivePolygonIndices: polygonPositionsCount > 65535
163
- ? new Uint32Array(polygonRingsCount + 1)
164
- : new Uint16Array(polygonRingsCount + 1),
165
- globalFeatureIds: new GlobalFeatureIdsDataType(polygonPositionsCount),
166
- featureIds: polygonFeaturesCount > 65535
167
- ? new Uint32Array(polygonPositionsCount)
168
- : new Uint16Array(polygonPositionsCount),
169
- numericProps: {},
170
- properties: Array(),
171
- fields: Array()
172
- };
173
- // Instantiate numeric properties arrays; one value per vertex
174
- for (const object of [points, lines, polygons]) {
175
- for (const propName of numericPropKeys || []) {
176
- // If property has been numeric in all previous features in which the property existed, check
177
- // if numeric in this feature
178
- const TypedArray = propArrayTypes[propName];
179
- object.numericProps[propName] = new TypedArray(object.positions.length / coordLength);
180
- }
181
- }
182
- // Set last element of path/polygon indices as positions length
183
- lines.pathIndices[linePathsCount] = linePositionsCount;
184
- polygons.polygonIndices[polygonObjectsCount] = polygonPositionsCount;
185
- polygons.primitivePolygonIndices[polygonRingsCount] = polygonPositionsCount;
186
- const indexMap = {
187
- pointPosition: 0,
188
- pointFeature: 0,
189
- linePosition: 0,
190
- linePath: 0,
191
- lineFeature: 0,
192
- polygonPosition: 0,
193
- polygonObject: 0,
194
- polygonRing: 0,
195
- polygonFeature: 0,
196
- feature: 0
197
- };
198
- for (const feature of features) {
199
- const geometry = feature.geometry;
200
- const properties = feature.properties || {};
201
- switch (geometry.type) {
202
- case 'Point':
203
- handlePoint(geometry.coordinates, points, indexMap, coordLength, properties);
204
- points.properties.push(keepStringProperties(properties, numericPropKeys));
205
- indexMap.pointFeature++;
206
- break;
207
- case 'MultiPoint':
208
- handleMultiPoint(geometry.coordinates, points, indexMap, coordLength, properties);
209
- points.properties.push(keepStringProperties(properties, numericPropKeys));
210
- indexMap.pointFeature++;
211
- break;
212
- case 'LineString':
213
- handleLineString(geometry.coordinates, lines, indexMap, coordLength, properties);
214
- lines.properties.push(keepStringProperties(properties, numericPropKeys));
215
- indexMap.lineFeature++;
216
- break;
217
- case 'MultiLineString':
218
- handleMultiLineString(geometry.coordinates, lines, indexMap, coordLength, properties);
219
- lines.properties.push(keepStringProperties(properties, numericPropKeys));
220
- indexMap.lineFeature++;
221
- break;
222
- case 'Polygon':
223
- handlePolygon(geometry.coordinates, polygons, indexMap, coordLength, properties);
224
- polygons.properties.push(keepStringProperties(properties, numericPropKeys));
225
- indexMap.polygonFeature++;
226
- break;
227
- case 'MultiPolygon':
228
- handleMultiPolygon(geometry.coordinates, polygons, indexMap, coordLength, properties);
229
- polygons.properties.push(keepStringProperties(properties, numericPropKeys));
230
- indexMap.polygonFeature++;
231
- break;
232
- default:
233
- throw new Error('Invalid geometry type');
234
- }
235
- indexMap.feature++;
236
- }
237
- // Wrap each array in an accessor object with value and size keys
238
- return makeAccessorObjects(points, lines, polygons, coordLength);
239
- }
240
- /** Fills Point coordinates into points object of arrays */
241
- function handlePoint(coords, points, indexMap, coordLength, properties) {
242
- points.positions.set(coords, indexMap.pointPosition * coordLength);
243
- points.globalFeatureIds[indexMap.pointPosition] = indexMap.feature;
244
- points.featureIds[indexMap.pointPosition] = indexMap.pointFeature;
245
- fillNumericProperties(points, properties, indexMap.pointPosition, 1);
246
- indexMap.pointPosition++;
247
- }
248
- /** Fills MultiPoint coordinates into points object of arrays */
249
- function handleMultiPoint(coords, points, indexMap, coordLength, properties) {
250
- for (const point of coords) {
251
- handlePoint(point, points, indexMap, coordLength, properties);
252
- }
253
- }
254
- /** Fills LineString coordinates into lines object of arrays */
255
- function handleLineString(coords, lines, indexMap, coordLength, properties) {
256
- lines.pathIndices[indexMap.linePath] = indexMap.linePosition;
257
- indexMap.linePath++;
258
- fillCoords(lines.positions, coords, indexMap.linePosition, coordLength);
259
- const nPositions = coords.length;
260
- fillNumericProperties(lines, properties, indexMap.linePosition, nPositions);
261
- lines.globalFeatureIds.set(new Uint32Array(nPositions).fill(indexMap.feature), indexMap.linePosition);
262
- lines.featureIds.set(new Uint32Array(nPositions).fill(indexMap.lineFeature), indexMap.linePosition);
263
- indexMap.linePosition += nPositions;
264
- }
265
- /** Fills MultiLineString coordinates into lines object of arrays */
266
- function handleMultiLineString(coords, lines, indexMap, coordLength, properties) {
267
- for (const line of coords) {
268
- handleLineString(line, lines, indexMap, coordLength, properties);
269
- }
270
- }
271
- /** Fills Polygon coordinates into polygons object of arrays */
272
- function handlePolygon(coords, polygons, indexMap, coordLength, properties) {
273
- polygons.polygonIndices[indexMap.polygonObject] = indexMap.polygonPosition;
274
- indexMap.polygonObject++;
275
- for (const ring of coords) {
276
- polygons.primitivePolygonIndices[indexMap.polygonRing] = indexMap.polygonPosition;
277
- indexMap.polygonRing++;
278
- fillCoords(polygons.positions, ring, indexMap.polygonPosition, coordLength);
279
- const nPositions = ring.length;
280
- fillNumericProperties(polygons, properties, indexMap.polygonPosition, nPositions);
281
- polygons.globalFeatureIds.set(new Uint32Array(nPositions).fill(indexMap.feature), indexMap.polygonPosition);
282
- polygons.featureIds.set(new Uint32Array(nPositions).fill(indexMap.polygonFeature), indexMap.polygonPosition);
283
- indexMap.polygonPosition += nPositions;
284
- }
285
- }
286
- /** Fills MultiPolygon coordinates into polygons object of arrays */
287
- function handleMultiPolygon(coords, polygons, indexMap, coordLength, properties) {
288
- for (const polygon of coords) {
289
- handlePolygon(polygon, polygons, indexMap, coordLength, properties);
290
- }
291
- }
292
- /** Wrap each array in an accessor object with value and size keys */
293
- function makeAccessorObjects(points, lines, polygons, coordLength) {
294
- const returnObj = {
295
- points: {
296
- ...points,
297
- positions: { value: points.positions, size: coordLength },
298
- globalFeatureIds: { value: points.globalFeatureIds, size: 1 },
299
- featureIds: { value: points.featureIds, size: 1 },
300
- type: 'Point'
301
- },
302
- lines: {
303
- ...lines,
304
- pathIndices: { value: lines.pathIndices, size: 1 },
305
- positions: { value: lines.positions, size: coordLength },
306
- globalFeatureIds: { value: lines.globalFeatureIds, size: 1 },
307
- featureIds: { value: lines.featureIds, size: 1 },
308
- type: 'LineString'
309
- },
310
- polygons: {
311
- ...polygons,
312
- polygonIndices: { value: polygons.polygonIndices, size: 1 },
313
- primitivePolygonIndices: { value: polygons.primitivePolygonIndices, size: 1 },
314
- positions: { value: polygons.positions, size: coordLength },
315
- globalFeatureIds: { value: polygons.globalFeatureIds, size: 1 },
316
- featureIds: { value: polygons.featureIds, size: 1 },
317
- type: 'Polygon'
318
- }
319
- };
320
- for (const geomType in returnObj) {
321
- for (const numericProp in returnObj[geomType].numericProps) {
322
- returnObj[geomType].numericProps[numericProp] = {
323
- value: returnObj[geomType].numericProps[numericProp],
324
- size: 1
325
- };
326
- }
327
- }
328
- return returnObj;
329
- }
330
- /** Add numeric properties to object */
331
- function fillNumericProperties(object, properties, index, length) {
332
- for (const numericPropName in object.numericProps) {
333
- if (numericPropName in properties) {
334
- object.numericProps[numericPropName].set(new Array(length).fill(properties[numericPropName]), index);
335
- }
336
- }
337
- }
338
- /** Keep string properties in object */
339
- function keepStringProperties(properties, numericKeys) {
340
- const props = {};
341
- for (const key in properties) {
342
- if (!numericKeys.includes(key)) {
343
- props[key] = properties[key];
344
- }
345
- }
346
- return props;
347
- }
348
- /** @param coords is expected to be a list of arrays, each with length 2-3 */
349
- function fillCoords(array, coords, startVertex, coordLength) {
350
- let index = startVertex * coordLength;
351
- for (const coord of coords) {
352
- array.set(coord, index);
353
- index += coordLength;
354
- }
355
- }
356
- // TODO - how does this work? Different `coordinates` have different nesting
357
- function flatten(arrays) {
358
- return [].concat(...arrays);
359
- }
360
- function deduceArrayType(x, constructor) {
361
- if (constructor === Array || !Number.isFinite(x)) {
362
- return Array;
363
- }
364
- // If this or previous value required 64bits use Float64Array
365
- return constructor === Float64Array || Math.fround(x) !== x ? Float64Array : Float32Array;
366
- }
@@ -0,0 +1,17 @@
1
+ import { Feature, FlatFeature } from '@loaders.gl/schema';
2
+ /**
3
+ * Options for `geojsonToFlatGeojson`
4
+ */
5
+ export declare type GeojsonToFlatGeojsonOptions = {
6
+ coordLength: number;
7
+ fixRingWinding: boolean;
8
+ };
9
+ /**
10
+ * Convert GeoJSON features to Flat GeoJSON features
11
+ *
12
+ * @param features
13
+ * @param options
14
+ * @returns an Array of Flat GeoJSON features
15
+ */
16
+ export declare function geojsonToFlatGeojson(features: Feature[], options?: GeojsonToFlatGeojsonOptions): FlatFeature[];
17
+ //# sourceMappingURL=geojson-to-flat-geojson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geojson-to-flat-geojson.d.ts","sourceRoot":"","sources":["../../src/lib/geojson-to-flat-geojson.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,OAAO,EAAY,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAElE;;GAEG;AACH,oBAAY,2BAA2B,GAAG;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AASF;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,GAAE,2BAAoE,GAC5E,WAAW,EAAE,CAEf"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.geojsonToFlatGeojson = void 0;
4
+ const polygon_1 = require("@math.gl/polygon");
5
+ /**
6
+ * Convert GeoJSON features to Flat GeoJSON features
7
+ *
8
+ * @param features
9
+ * @param options
10
+ * @returns an Array of Flat GeoJSON features
11
+ */
12
+ function geojsonToFlatGeojson(features, options = { coordLength: 2, fixRingWinding: true }) {
13
+ return features.map((feature) => flattenFeature(feature, options));
14
+ }
15
+ exports.geojsonToFlatGeojson = geojsonToFlatGeojson;
16
+ /**
17
+ * Helper function to copy Point values from `coordinates` into `data` & `indices`
18
+ *
19
+ * @param coordinates
20
+ * @param data
21
+ * @param indices
22
+ * @param options
23
+ */
24
+ function flattenPoint(coordinates, data, indices, options) {
25
+ indices.push(data.length);
26
+ data.push(...coordinates);
27
+ // Pad up to coordLength
28
+ for (let i = coordinates.length; i < options.coordLength; i++) {
29
+ data.push(0);
30
+ }
31
+ }
32
+ /**
33
+ * Helper function to copy LineString values from `coordinates` into `data` & `indices`
34
+ *
35
+ * @param coordinates
36
+ * @param data
37
+ * @param indices
38
+ * @param options
39
+ */
40
+ function flattenLineString(coordinates, data, indices, options) {
41
+ indices.push(data.length);
42
+ for (const c of coordinates) {
43
+ data.push(...c);
44
+ // Pad up to coordLength
45
+ for (let i = c.length; i < options.coordLength; i++) {
46
+ data.push(0);
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Helper function to copy Polygon values from `coordinates` into `data` & `indices` & `areas`
52
+ *
53
+ * @param coordinates
54
+ * @param data
55
+ * @param indices
56
+ * @param areas
57
+ * @param options
58
+ */
59
+ function flattenPolygon(coordinates, data, indices, areas, options) {
60
+ let count = 0;
61
+ const ringAreas = [];
62
+ const polygons = [];
63
+ for (const lineString of coordinates) {
64
+ const lineString2d = lineString.map((p) => p.slice(0, 2));
65
+ let area = (0, polygon_1.getPolygonSignedArea)(lineString2d.flat());
66
+ const ccw = area < 0;
67
+ // Exterior ring must be CCW and interior rings CW
68
+ if (options.fixRingWinding && ((count === 0 && !ccw) || (count > 0 && ccw))) {
69
+ lineString.reverse();
70
+ area = -area;
71
+ }
72
+ ringAreas.push(area);
73
+ flattenLineString(lineString, data, polygons, options);
74
+ count++;
75
+ }
76
+ if (count > 0) {
77
+ areas.push(ringAreas);
78
+ indices.push(polygons);
79
+ }
80
+ }
81
+ /**
82
+ * Flatten single GeoJSON feature into Flat GeoJSON
83
+ *
84
+ * @param feature
85
+ * @param options
86
+ * @returns A Flat GeoJSON feature
87
+ */
88
+ function flattenFeature(feature, options) {
89
+ const { geometry } = feature;
90
+ if (geometry.type === 'GeometryCollection') {
91
+ throw new Error('GeometryCollection type not supported');
92
+ }
93
+ const data = [];
94
+ const indices = [];
95
+ let areas;
96
+ let type;
97
+ switch (geometry.type) {
98
+ case 'Point':
99
+ type = 'Point';
100
+ flattenPoint(geometry.coordinates, data, indices, options);
101
+ break;
102
+ case 'MultiPoint':
103
+ type = 'Point';
104
+ geometry.coordinates.map((c) => flattenPoint(c, data, indices, options));
105
+ break;
106
+ case 'LineString':
107
+ type = 'LineString';
108
+ flattenLineString(geometry.coordinates, data, indices, options);
109
+ break;
110
+ case 'MultiLineString':
111
+ type = 'LineString';
112
+ geometry.coordinates.map((c) => flattenLineString(c, data, indices, options));
113
+ break;
114
+ case 'Polygon':
115
+ type = 'Polygon';
116
+ areas = [];
117
+ flattenPolygon(geometry.coordinates, data, indices, areas, options);
118
+ break;
119
+ case 'MultiPolygon':
120
+ type = 'Polygon';
121
+ areas = [];
122
+ geometry.coordinates.map((c) => flattenPolygon(c, data, indices, areas, options));
123
+ break;
124
+ default:
125
+ throw new Error(`Unknown type: ${type}`);
126
+ }
127
+ return { ...feature, geometry: { type, indices, data, areas } };
128
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loaders.gl/gis",
3
3
  "description": "Helpers for GIS category data",
4
- "version": "3.1.0",
4
+ "version": "3.1.1",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -24,13 +24,14 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
- "@loaders.gl/loader-utils": "3.1.0",
28
- "@loaders.gl/schema": "3.1.0",
27
+ "@loaders.gl/loader-utils": "3.1.1",
28
+ "@loaders.gl/schema": "3.1.1",
29
29
  "@mapbox/vector-tile": "^1.3.1",
30
+ "@math.gl/polygon": "^3.5.1",
30
31
  "pbf": "^3.2.1"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@math.gl/proj4": "^3.5.1"
34
35
  },
35
- "gitHead": "b02a011b5a6d6aa6c5870819045c70db168cb930"
36
+ "gitHead": "ed3c238bcb68ab5a2d4ddc64319f6f4c02a20df7"
36
37
  }
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  // Types from `@loaders.gl/schema`
2
2
 
3
3
  // Functions
4
+ export {flatGeojsonToBinary} from './lib/flat-geojson-to-binary';
4
5
  export {geojsonToBinary} from './lib/geojson-to-binary';
6
+ export {geojsonToFlatGeojson} from './lib/geojson-to-flat-geojson';
5
7
  export {binaryToGeojson, binaryToGeoJson, binaryToGeometry} from './lib/binary-to-geojson';
6
8
  export {transformBinaryCoords, transformGeoJsonCoords} from './lib/transform';
@@ -0,0 +1,101 @@
1
+ import {Feature, GeojsonGeometryInfo} from '@loaders.gl/schema';
2
+
3
+ /**
4
+ * Initial scan over GeoJSON features
5
+ * Counts number of coordinates of each geometry type and
6
+ * keeps track of the max coordinate dimensions
7
+ */
8
+ // eslint-disable-next-line complexity, max-statements
9
+ export function extractGeometryInfo(features: Feature[]): GeojsonGeometryInfo {
10
+ // Counts the number of _positions_, so [x, y, z] counts as one
11
+ let pointPositionsCount = 0;
12
+ let pointFeaturesCount = 0;
13
+ let linePositionsCount = 0;
14
+ let linePathsCount = 0;
15
+ let lineFeaturesCount = 0;
16
+ let polygonPositionsCount = 0;
17
+ let polygonObjectsCount = 0;
18
+ let polygonRingsCount = 0;
19
+ let polygonFeaturesCount = 0;
20
+ const coordLengths = new Set<number>();
21
+
22
+ for (const feature of features) {
23
+ const geometry = feature.geometry;
24
+ switch (geometry.type) {
25
+ case 'Point':
26
+ pointFeaturesCount++;
27
+ pointPositionsCount++;
28
+ coordLengths.add(geometry.coordinates.length);
29
+ break;
30
+ case 'MultiPoint':
31
+ pointFeaturesCount++;
32
+ pointPositionsCount += geometry.coordinates.length;
33
+ for (const point of geometry.coordinates) {
34
+ coordLengths.add(point.length);
35
+ }
36
+ break;
37
+ case 'LineString':
38
+ lineFeaturesCount++;
39
+ linePositionsCount += geometry.coordinates.length;
40
+ linePathsCount++;
41
+
42
+ for (const coord of geometry.coordinates) {
43
+ coordLengths.add(coord.length);
44
+ }
45
+ break;
46
+ case 'MultiLineString':
47
+ lineFeaturesCount++;
48
+ for (const line of geometry.coordinates) {
49
+ linePositionsCount += line.length;
50
+ linePathsCount++;
51
+
52
+ // eslint-disable-next-line max-depth
53
+ for (const coord of line) {
54
+ coordLengths.add(coord.length);
55
+ }
56
+ }
57
+ break;
58
+ case 'Polygon':
59
+ polygonFeaturesCount++;
60
+ polygonObjectsCount++;
61
+ polygonRingsCount += geometry.coordinates.length;
62
+ const flattened = geometry.coordinates.flat();
63
+ polygonPositionsCount += flattened.length;
64
+
65
+ for (const coord of flattened) {
66
+ coordLengths.add(coord.length);
67
+ }
68
+ break;
69
+ case 'MultiPolygon':
70
+ polygonFeaturesCount++;
71
+ for (const polygon of geometry.coordinates) {
72
+ polygonObjectsCount++;
73
+ polygonRingsCount += polygon.length;
74
+ const flattened = polygon.flat();
75
+ polygonPositionsCount += flattened.length;
76
+
77
+ // eslint-disable-next-line max-depth
78
+ for (const coord of flattened) {
79
+ coordLengths.add(coord.length);
80
+ }
81
+ }
82
+ break;
83
+ default:
84
+ throw new Error(`Unsupported geometry type: ${geometry.type}`);
85
+ }
86
+ }
87
+
88
+ return {
89
+ coordLength: coordLengths.size > 0 ? Math.max(...coordLengths) : 2,
90
+
91
+ pointPositionsCount,
92
+ pointFeaturesCount,
93
+ linePositionsCount,
94
+ linePathsCount,
95
+ lineFeaturesCount,
96
+ polygonPositionsCount,
97
+ polygonObjectsCount,
98
+ polygonRingsCount,
99
+ polygonFeaturesCount
100
+ };
101
+ }