@loaders.gl/gis 4.0.0-alpha.4 → 4.0.0-alpha.6

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 (75) hide show
  1. package/dist/bundle.d.ts +2 -0
  2. package/dist/bundle.d.ts.map +1 -0
  3. package/dist/bundle.js +2 -2
  4. package/dist/es5/bundle.js +6 -0
  5. package/dist/es5/bundle.js.map +1 -0
  6. package/dist/es5/index.js +59 -0
  7. package/dist/es5/index.js.map +1 -0
  8. package/dist/es5/lib/binary-to-geojson.js +255 -0
  9. package/dist/es5/lib/binary-to-geojson.js.map +1 -0
  10. package/dist/es5/lib/extract-geometry-info.js +167 -0
  11. package/dist/es5/lib/extract-geometry-info.js.map +1 -0
  12. package/dist/es5/lib/flat-geojson-to-binary-types.js +2 -0
  13. package/dist/es5/lib/flat-geojson-to-binary-types.js.map +1 -0
  14. package/dist/es5/lib/flat-geojson-to-binary.js +344 -0
  15. package/dist/es5/lib/flat-geojson-to-binary.js.map +1 -0
  16. package/dist/es5/lib/geojson-to-binary.js +26 -0
  17. package/dist/es5/lib/geojson-to-binary.js.map +1 -0
  18. package/dist/es5/lib/geojson-to-flat-geojson.js +136 -0
  19. package/dist/es5/lib/geojson-to-flat-geojson.js.map +1 -0
  20. package/dist/es5/lib/transform.js +57 -0
  21. package/dist/es5/lib/transform.js.map +1 -0
  22. package/dist/esm/bundle.js +4 -0
  23. package/dist/esm/bundle.js.map +1 -0
  24. package/dist/esm/index.js +6 -0
  25. package/dist/esm/index.js.map +1 -0
  26. package/dist/esm/lib/binary-to-geojson.js +223 -0
  27. package/dist/esm/lib/binary-to-geojson.js.map +1 -0
  28. package/dist/esm/lib/extract-geometry-info.js +84 -0
  29. package/dist/esm/lib/extract-geometry-info.js.map +1 -0
  30. package/dist/esm/lib/flat-geojson-to-binary-types.js +2 -0
  31. package/dist/esm/lib/flat-geojson-to-binary-types.js.map +1 -0
  32. package/dist/esm/lib/flat-geojson-to-binary.js +305 -0
  33. package/dist/esm/lib/flat-geojson-to-binary.js.map +1 -0
  34. package/dist/esm/lib/geojson-to-binary.js +22 -0
  35. package/dist/esm/lib/geojson-to-binary.js.map +1 -0
  36. package/dist/esm/lib/geojson-to-flat-geojson.js +97 -0
  37. package/dist/esm/lib/geojson-to-flat-geojson.js.map +1 -0
  38. package/dist/esm/lib/transform.js +40 -0
  39. package/dist/esm/lib/transform.js.map +1 -0
  40. package/dist/index.d.ts +6 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +18 -4
  43. package/dist/lib/binary-to-geojson.d.ts +21 -0
  44. package/dist/lib/binary-to-geojson.d.ts.map +1 -0
  45. package/dist/lib/binary-to-geojson.js +201 -242
  46. package/dist/lib/extract-geometry-info.d.ts +8 -0
  47. package/dist/lib/extract-geometry-info.d.ts.map +1 -0
  48. package/dist/lib/extract-geometry-info.js +96 -0
  49. package/dist/lib/flat-geojson-to-binary-types.d.ts +58 -0
  50. package/dist/lib/flat-geojson-to-binary-types.d.ts.map +1 -0
  51. package/dist/lib/flat-geojson-to-binary-types.js +2 -0
  52. package/dist/lib/flat-geojson-to-binary.d.ts +37 -0
  53. package/dist/lib/flat-geojson-to-binary.d.ts.map +1 -0
  54. package/dist/lib/flat-geojson-to-binary.js +376 -0
  55. package/dist/lib/geojson-to-binary.d.ts +19 -0
  56. package/dist/lib/geojson-to-binary.d.ts.map +1 -0
  57. package/dist/lib/geojson-to-binary.js +24 -407
  58. package/dist/lib/geojson-to-flat-geojson.d.ts +17 -0
  59. package/dist/lib/geojson-to-flat-geojson.d.ts.map +1 -0
  60. package/dist/lib/geojson-to-flat-geojson.js +128 -0
  61. package/dist/lib/transform.d.ts +19 -0
  62. package/dist/lib/transform.d.ts.map +1 -0
  63. package/dist/lib/transform.js +51 -42
  64. package/package.json +8 -7
  65. package/src/index.ts +2 -0
  66. package/src/lib/extract-geometry-info.ts +101 -0
  67. package/src/lib/flat-geojson-to-binary-types.ts +58 -0
  68. package/src/lib/flat-geojson-to-binary.ts +565 -0
  69. package/src/lib/geojson-to-binary.ts +24 -450
  70. package/src/lib/geojson-to-flat-geojson.ts +171 -0
  71. package/dist/bundle.js.map +0 -1
  72. package/dist/index.js.map +0 -1
  73. package/dist/lib/binary-to-geojson.js.map +0 -1
  74. package/dist/lib/geojson-to-binary.js.map +0 -1
  75. package/dist/lib/transform.js.map +0 -1
@@ -0,0 +1,565 @@
1
+ /* eslint-disable indent */
2
+ import {earcut} from '@math.gl/polygon';
3
+ import type {
4
+ BinaryAttribute,
5
+ BinaryFeatures,
6
+ FlatFeature,
7
+ FlatPoint,
8
+ FlatLineString,
9
+ FlatPolygon,
10
+ GeojsonGeometryInfo,
11
+ TypedArray
12
+ } from '@loaders.gl/schema';
13
+ import {PropArrayConstructor, Lines, Points, Polygons} from './flat-geojson-to-binary-types';
14
+
15
+ /**
16
+ * Convert binary features to flat binary arrays. Similar to
17
+ * `geojsonToBinary` helper function, except that it expects
18
+ * a binary representation of the feature data, which enables
19
+ * 2X-3X speed increase in parse speed, compared to using
20
+ * geoJSON. See `binary-vector-tile/VectorTileFeature` for
21
+ * data format detais
22
+ *
23
+ * @param features
24
+ * @param geometryInfo
25
+ * @param options
26
+ * @returns filled arrays
27
+ */
28
+ export function flatGeojsonToBinary(
29
+ features: FlatFeature[],
30
+ geometryInfo: GeojsonGeometryInfo,
31
+ options?: FlatGeojsonToBinaryOptions
32
+ ) {
33
+ const propArrayTypes = extractNumericPropTypes(features);
34
+ const numericPropKeys = Object.keys(propArrayTypes).filter((k) => propArrayTypes[k] !== Array);
35
+ return fillArrays(
36
+ features,
37
+ {
38
+ propArrayTypes,
39
+ ...geometryInfo
40
+ },
41
+ {
42
+ numericPropKeys: (options && options.numericPropKeys) || numericPropKeys,
43
+ PositionDataType: options ? options.PositionDataType : Float32Array
44
+ }
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Options for `flatGeojsonToBinary`
50
+ */
51
+ export type FlatGeojsonToBinaryOptions = {
52
+ numericPropKeys?: string[];
53
+ PositionDataType?: Float32ArrayConstructor | Float64ArrayConstructor;
54
+ };
55
+
56
+ export const TEST_EXPORTS = {
57
+ extractNumericPropTypes
58
+ };
59
+
60
+ /**
61
+ * Extracts properties that are always numeric
62
+ *
63
+ * @param features
64
+ * @returns object with numeric types
65
+ */
66
+ function extractNumericPropTypes(features: FlatFeature[]): {
67
+ [key: string]: PropArrayConstructor;
68
+ } {
69
+ const propArrayTypes = {};
70
+ for (const feature of features) {
71
+ if (feature.properties) {
72
+ for (const key in feature.properties) {
73
+ // If property has not been seen before, or if property has been numeric
74
+ // in all previous features, check if numeric in this feature
75
+ // If not numeric, Array is stored to prevent rechecking in the future
76
+ // Additionally, detects if 64 bit precision is required
77
+ const val = feature.properties[key];
78
+ propArrayTypes[key] = deduceArrayType(val, propArrayTypes[key]);
79
+ }
80
+ }
81
+ }
82
+
83
+ return propArrayTypes;
84
+ }
85
+
86
+ /**
87
+ * Fills coordinates into pre-allocated typed arrays
88
+ *
89
+ * @param features
90
+ * @param geometryInfo
91
+ * @param options
92
+ * @returns an accessor object with value and size keys
93
+ */
94
+ // eslint-disable-next-line complexity
95
+ function fillArrays(
96
+ features: FlatFeature[],
97
+ geometryInfo: GeojsonGeometryInfo & {
98
+ propArrayTypes: {[key: string]: PropArrayConstructor};
99
+ },
100
+ options: FlatGeojsonToBinaryOptions
101
+ ) {
102
+ const {
103
+ pointPositionsCount,
104
+ pointFeaturesCount,
105
+ linePositionsCount,
106
+ linePathsCount,
107
+ lineFeaturesCount,
108
+ polygonPositionsCount,
109
+ polygonObjectsCount,
110
+ polygonRingsCount,
111
+ polygonFeaturesCount,
112
+ propArrayTypes,
113
+ coordLength
114
+ } = geometryInfo;
115
+ const {numericPropKeys = [], PositionDataType = Float32Array} = options;
116
+ const hasGlobalId = features[0] && 'id' in features[0];
117
+ const GlobalFeatureIdsDataType = features.length > 65535 ? Uint32Array : Uint16Array;
118
+ const points: Points = {
119
+ type: 'Point',
120
+ positions: new PositionDataType(pointPositionsCount * coordLength),
121
+ globalFeatureIds: new GlobalFeatureIdsDataType(pointPositionsCount),
122
+ featureIds:
123
+ pointFeaturesCount > 65535
124
+ ? new Uint32Array(pointPositionsCount)
125
+ : new Uint16Array(pointPositionsCount),
126
+ numericProps: {},
127
+ properties: [],
128
+ fields: []
129
+ };
130
+ const lines: Lines = {
131
+ type: 'LineString',
132
+ pathIndices:
133
+ linePositionsCount > 65535
134
+ ? new Uint32Array(linePathsCount + 1)
135
+ : new Uint16Array(linePathsCount + 1),
136
+ positions: new PositionDataType(linePositionsCount * coordLength),
137
+ globalFeatureIds: new GlobalFeatureIdsDataType(linePositionsCount),
138
+ featureIds:
139
+ lineFeaturesCount > 65535
140
+ ? new Uint32Array(linePositionsCount)
141
+ : new Uint16Array(linePositionsCount),
142
+ numericProps: {},
143
+ properties: [],
144
+ fields: []
145
+ };
146
+ const polygons: Polygons = {
147
+ type: 'Polygon',
148
+ polygonIndices:
149
+ polygonPositionsCount > 65535
150
+ ? new Uint32Array(polygonObjectsCount + 1)
151
+ : new Uint16Array(polygonObjectsCount + 1),
152
+ primitivePolygonIndices:
153
+ polygonPositionsCount > 65535
154
+ ? new Uint32Array(polygonRingsCount + 1)
155
+ : new Uint16Array(polygonRingsCount + 1),
156
+ positions: new PositionDataType(polygonPositionsCount * coordLength),
157
+ triangles: [],
158
+ globalFeatureIds: new GlobalFeatureIdsDataType(polygonPositionsCount),
159
+ featureIds:
160
+ polygonFeaturesCount > 65535
161
+ ? new Uint32Array(polygonPositionsCount)
162
+ : new Uint16Array(polygonPositionsCount),
163
+ numericProps: {},
164
+ properties: [],
165
+ fields: []
166
+ };
167
+
168
+ // Instantiate numeric properties arrays; one value per vertex
169
+ for (const object of [points, lines, polygons]) {
170
+ for (const propName of numericPropKeys) {
171
+ // If property has been numeric in all previous features in which the property existed, check
172
+ // if numeric in this feature
173
+ const T = propArrayTypes[propName];
174
+ object.numericProps[propName] = new T(object.positions.length / coordLength) as TypedArray;
175
+ }
176
+ }
177
+
178
+ // Set last element of path/polygon indices as positions length
179
+ lines.pathIndices[linePathsCount] = linePositionsCount;
180
+ polygons.polygonIndices[polygonObjectsCount] = polygonPositionsCount;
181
+ polygons.primitivePolygonIndices[polygonRingsCount] = polygonPositionsCount;
182
+
183
+ const indexMap = {
184
+ pointPosition: 0,
185
+ pointFeature: 0,
186
+ linePosition: 0,
187
+ linePath: 0,
188
+ lineFeature: 0,
189
+ polygonPosition: 0,
190
+ polygonObject: 0,
191
+ polygonRing: 0,
192
+ polygonFeature: 0,
193
+ feature: 0
194
+ };
195
+
196
+ for (const feature of features) {
197
+ const geometry = feature.geometry;
198
+ const properties = feature.properties || {};
199
+
200
+ switch (geometry.type) {
201
+ case 'Point':
202
+ handlePoint(geometry, points, indexMap, coordLength, properties);
203
+ points.properties.push(keepStringProperties(properties, numericPropKeys));
204
+ if (hasGlobalId) {
205
+ points.fields.push({id: feature.id});
206
+ }
207
+ indexMap.pointFeature++;
208
+ break;
209
+ case 'LineString':
210
+ handleLineString(geometry, lines, indexMap, coordLength, properties);
211
+ lines.properties.push(keepStringProperties(properties, numericPropKeys));
212
+ if (hasGlobalId) {
213
+ lines.fields.push({id: feature.id});
214
+ }
215
+ indexMap.lineFeature++;
216
+ break;
217
+ case 'Polygon':
218
+ handlePolygon(geometry, polygons, indexMap, coordLength, properties);
219
+ polygons.properties.push(keepStringProperties(properties, numericPropKeys));
220
+ if (hasGlobalId) {
221
+ polygons.fields.push({id: feature.id});
222
+ }
223
+ indexMap.polygonFeature++;
224
+ break;
225
+ default:
226
+ throw new Error('Invalid geometry type');
227
+ }
228
+
229
+ indexMap.feature++;
230
+ }
231
+
232
+ // Wrap each array in an accessor object with value and size keys
233
+ return makeAccessorObjects(points, lines, polygons, coordLength);
234
+ }
235
+
236
+ /**
237
+ * Fills (Multi)Point coordinates into points object of arrays
238
+ *
239
+ * @param geometry
240
+ * @param points
241
+ * @param indexMap
242
+ * @param coordLength
243
+ * @param properties
244
+ */
245
+ function handlePoint(
246
+ geometry: FlatPoint,
247
+ points: Points,
248
+ indexMap: {
249
+ pointPosition: number;
250
+ pointFeature: number;
251
+ linePosition?: number;
252
+ linePath?: number;
253
+ lineFeature?: number;
254
+ polygonPosition?: number;
255
+ polygonObject?: number;
256
+ polygonRing?: number;
257
+ polygonFeature?: number;
258
+ feature: number;
259
+ },
260
+ coordLength: number,
261
+ properties: {[x: string]: string | number | boolean | null}
262
+ ): void {
263
+ points.positions.set(geometry.data, indexMap.pointPosition * coordLength);
264
+
265
+ const nPositions = geometry.data.length / coordLength;
266
+ fillNumericProperties(points, properties, indexMap.pointPosition, nPositions);
267
+ points.globalFeatureIds.fill(
268
+ indexMap.feature,
269
+ indexMap.pointPosition,
270
+ indexMap.pointPosition + nPositions
271
+ );
272
+ points.featureIds.fill(
273
+ indexMap.pointFeature,
274
+ indexMap.pointPosition,
275
+ indexMap.pointPosition + nPositions
276
+ );
277
+
278
+ indexMap.pointPosition += nPositions;
279
+ }
280
+
281
+ /**
282
+ * Fills (Multi)LineString coordinates into lines object of arrays
283
+ *
284
+ * @param geometry
285
+ * @param lines
286
+ * @param indexMap
287
+ * @param coordLength
288
+ * @param properties
289
+ */
290
+ function handleLineString(
291
+ geometry: FlatLineString,
292
+ lines: Lines,
293
+ indexMap: {
294
+ pointPosition?: number;
295
+ pointFeature?: number;
296
+ linePosition: number;
297
+ linePath: number;
298
+ lineFeature: number;
299
+ polygonPosition?: number;
300
+ polygonObject?: number;
301
+ polygonRing?: number;
302
+ polygonFeature?: number;
303
+ feature: number;
304
+ },
305
+ coordLength: number,
306
+ properties: {[x: string]: string | number | boolean | null}
307
+ ): void {
308
+ lines.positions.set(geometry.data, indexMap.linePosition * coordLength);
309
+
310
+ const nPositions = geometry.data.length / coordLength;
311
+ fillNumericProperties(lines, properties, indexMap.linePosition, nPositions);
312
+
313
+ lines.globalFeatureIds.fill(
314
+ indexMap.feature,
315
+ indexMap.linePosition,
316
+ indexMap.linePosition + nPositions
317
+ );
318
+ lines.featureIds.fill(
319
+ indexMap.lineFeature,
320
+ indexMap.linePosition,
321
+ indexMap.linePosition + nPositions
322
+ );
323
+
324
+ for (let i = 0, il = geometry.indices.length; i < il; ++i) {
325
+ // Extract range of data we are working with, defined by start
326
+ // and end indices (these index into the geometry.data array)
327
+ const start = geometry.indices[i];
328
+ const end =
329
+ i === il - 1
330
+ ? geometry.data.length // last line, so read to end of data
331
+ : geometry.indices[i + 1]; // start index for next line
332
+
333
+ lines.pathIndices[indexMap.linePath++] = indexMap.linePosition;
334
+ indexMap.linePosition += (end - start) / coordLength;
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Fills (Multi)Polygon coordinates into polygons object of arrays
340
+ *
341
+ * @param geometry
342
+ * @param polygons
343
+ * @param indexMap
344
+ * @param coordLength
345
+ * @param properties
346
+ */
347
+ function handlePolygon(
348
+ geometry: FlatPolygon,
349
+ polygons: Polygons,
350
+ indexMap: {
351
+ pointPosition?: number;
352
+ pointFeature?: number;
353
+ linePosition?: number;
354
+ linePath?: number;
355
+ lineFeature?: number;
356
+ polygonPosition: number;
357
+ polygonObject: number;
358
+ polygonRing: number;
359
+ polygonFeature: number;
360
+ feature: number;
361
+ },
362
+ coordLength: number,
363
+ properties: {[x: string]: string | number | boolean | null}
364
+ ): void {
365
+ polygons.positions.set(geometry.data, indexMap.polygonPosition * coordLength);
366
+
367
+ const nPositions = geometry.data.length / coordLength;
368
+ fillNumericProperties(polygons, properties, indexMap.polygonPosition, nPositions);
369
+ polygons.globalFeatureIds.fill(
370
+ indexMap.feature,
371
+ indexMap.polygonPosition,
372
+ indexMap.polygonPosition + nPositions
373
+ );
374
+ polygons.featureIds.fill(
375
+ indexMap.polygonFeature,
376
+ indexMap.polygonPosition,
377
+ indexMap.polygonPosition + nPositions
378
+ );
379
+
380
+ // Unlike Point & LineString geometry.indices is a 2D array
381
+ for (let l = 0, ll = geometry.indices.length; l < ll; ++l) {
382
+ const startPosition = indexMap.polygonPosition;
383
+ polygons.polygonIndices[indexMap.polygonObject++] = startPosition;
384
+
385
+ const areas = geometry.areas[l];
386
+ const indices = geometry.indices[l];
387
+ const nextIndices = geometry.indices[l + 1];
388
+
389
+ for (let i = 0, il = indices.length; i < il; ++i) {
390
+ const start = indices[i];
391
+ const end =
392
+ i === il - 1
393
+ ? // last line, so either read to:
394
+ nextIndices === undefined
395
+ ? geometry.data.length // end of data (no next indices)
396
+ : nextIndices[0] // start of first line in nextIndices
397
+ : indices[i + 1]; // start index for next line
398
+
399
+ polygons.primitivePolygonIndices[indexMap.polygonRing++] = indexMap.polygonPosition;
400
+ indexMap.polygonPosition += (end - start) / coordLength;
401
+ }
402
+
403
+ const endPosition = indexMap.polygonPosition;
404
+ triangulatePolygon(polygons, areas, indices, {startPosition, endPosition, coordLength});
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Triangulate polygon using earcut
410
+ *
411
+ * @param polygons
412
+ * @param areas
413
+ * @param indices
414
+ * @param param3
415
+ */
416
+ function triangulatePolygon(
417
+ polygons: Polygons,
418
+ areas: number[],
419
+ indices: number[],
420
+ {
421
+ startPosition,
422
+ endPosition,
423
+ coordLength
424
+ }: {startPosition: number; endPosition: number; coordLength: number}
425
+ ): void {
426
+ const start = startPosition * coordLength;
427
+ const end = endPosition * coordLength;
428
+
429
+ // Extract positions and holes for just this polygon
430
+ const polygonPositions = polygons.positions.subarray(start, end);
431
+
432
+ // Holes are referenced relative to outer polygon
433
+ const offset = indices[0];
434
+ const holes = indices.slice(1).map((n: number) => (n - offset) / coordLength);
435
+
436
+ // Compute triangulation
437
+ // @ts-expect-error TODO can earcut handle binary arrays? Add tests?
438
+ const triangles = earcut(polygonPositions, holes, coordLength, areas);
439
+
440
+ // Indices returned by triangulation are relative to start
441
+ // of polygon, so we need to offset
442
+ for (let t = 0, tl = triangles.length; t < tl; ++t) {
443
+ polygons.triangles.push(startPosition + triangles[t]);
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Wraps an object containing array into accessors
449
+ *
450
+ * @param obj
451
+ * @param size
452
+ */
453
+ function wrapProps(
454
+ obj: {[key: string]: TypedArray},
455
+ size: number
456
+ ): {[key: string]: BinaryAttribute} {
457
+ const returnObj = {};
458
+ for (const key in obj) {
459
+ returnObj[key] = {value: obj[key], size};
460
+ }
461
+ return returnObj;
462
+ }
463
+
464
+ /**
465
+ * Wrap each array in an accessor object with value and size keys
466
+ *
467
+ * @param points
468
+ * @param lines
469
+ * @param polygons
470
+ * @param coordLength
471
+ * @returns object
472
+ */
473
+ function makeAccessorObjects(
474
+ points: Points,
475
+ lines: Lines,
476
+ polygons: Polygons,
477
+ coordLength: number
478
+ ): BinaryFeatures {
479
+ return {
480
+ points: {
481
+ ...points,
482
+ positions: {value: points.positions, size: coordLength},
483
+ globalFeatureIds: {value: points.globalFeatureIds, size: 1},
484
+ featureIds: {value: points.featureIds, size: 1},
485
+ numericProps: wrapProps(points.numericProps, 1)
486
+ },
487
+ lines: {
488
+ ...lines,
489
+ positions: {value: lines.positions, size: coordLength},
490
+ pathIndices: {value: lines.pathIndices, size: 1},
491
+ globalFeatureIds: {value: lines.globalFeatureIds, size: 1},
492
+ featureIds: {value: lines.featureIds, size: 1},
493
+ numericProps: wrapProps(lines.numericProps, 1)
494
+ },
495
+ polygons: {
496
+ ...polygons,
497
+ positions: {value: polygons.positions, size: coordLength},
498
+ polygonIndices: {value: polygons.polygonIndices, size: 1},
499
+ primitivePolygonIndices: {value: polygons.primitivePolygonIndices, size: 1},
500
+ triangles: {value: new Uint32Array(polygons.triangles), size: 1},
501
+ globalFeatureIds: {value: polygons.globalFeatureIds, size: 1},
502
+ featureIds: {value: polygons.featureIds, size: 1},
503
+ numericProps: wrapProps(polygons.numericProps, 1)
504
+ }
505
+ };
506
+ }
507
+
508
+ /**
509
+ * Add numeric properties to object
510
+ *
511
+ * @param object
512
+ * @param properties
513
+ * @param index
514
+ * @param length
515
+ */
516
+ function fillNumericProperties(
517
+ object: Points | Lines | Polygons,
518
+ properties: {[x: string]: string | number | boolean | null},
519
+ index: number,
520
+ length: number
521
+ ): void {
522
+ for (const numericPropName in object.numericProps) {
523
+ if (numericPropName in properties) {
524
+ const value = properties[numericPropName] as number;
525
+ object.numericProps[numericPropName].fill(value, index, index + length);
526
+ }
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Keep string properties in object
532
+ *
533
+ * @param properties
534
+ * @param numericKeys
535
+ * @returns object
536
+ */
537
+ function keepStringProperties(
538
+ properties: {[x: string]: string | number | boolean | null},
539
+ numericKeys: string[]
540
+ ) {
541
+ const props = {};
542
+ for (const key in properties) {
543
+ if (!numericKeys.includes(key)) {
544
+ props[key] = properties[key];
545
+ }
546
+ }
547
+ return props;
548
+ }
549
+
550
+ /**
551
+ *
552
+ * Deduce correct array constructor to use for a given value
553
+ *
554
+ * @param x value to test
555
+ * @param constructor previous constructor deduced
556
+ * @returns PropArrayConstructor
557
+ */
558
+ function deduceArrayType(x: any, constructor: PropArrayConstructor): PropArrayConstructor {
559
+ if (constructor === Array || !Number.isFinite(x)) {
560
+ return Array;
561
+ }
562
+
563
+ // If this or previous value required 64bits use Float64Array
564
+ return constructor === Float64Array || Math.fround(x) !== x ? Float64Array : Float32Array;
565
+ }