@maplibre/geojson-vt 6.0.4 → 6.0.5

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.
@@ -95,27 +95,35 @@ function createFeature(id, type, geom, tags) {
95
95
  switch (data.type) {
96
96
  case 'Point':
97
97
  case 'MultiPoint':
98
- case 'LineString':
99
98
  calcLineBBox(feature, data.geom);
100
99
  break;
100
+ case 'LineString':
101
+ calcLineBBox(feature, data.geom.points);
102
+ break;
101
103
  case 'Polygon':
102
104
  // the outer ring (ie [0]) contains all inner rings
103
- calcLineBBox(feature, data.geom[0]);
105
+ calcLineBBox(feature, data.geom[0].points);
104
106
  break;
105
107
  case 'MultiLineString':
106
108
  for (const line of data.geom) {
107
- calcLineBBox(feature, line);
109
+ calcLineBBox(feature, line.points);
108
110
  }
109
111
  break;
110
112
  case 'MultiPolygon':
111
113
  for (const polygon of data.geom) {
112
114
  // the outer ring (ie [0]) contains all inner rings
113
- calcLineBBox(feature, polygon[0]);
115
+ calcLineBBox(feature, polygon[0].points);
114
116
  }
115
117
  break;
116
118
  }
117
119
  return feature;
118
120
  }
121
+ function optimizeLineMemory(line) {
122
+ const lineImmutable = line;
123
+ if (line.points.length > 64) {
124
+ lineImmutable.points = new Float64Array(line.points);
125
+ }
126
+ }
119
127
  function calcLineBBox(feature, geom) {
120
128
  for (let i = 0; i < geom.length; i += 3) {
121
129
  feature.minX = Math.min(feature.minX, geom[i]);
@@ -213,7 +221,7 @@ function convertMultiPointFeature(features, id, geom, properties) {
213
221
  features.push(createFeature(id, 'MultiPoint', out, properties));
214
222
  }
215
223
  function convertLineStringFeature(features, id, geom, tolerance, properties) {
216
- const out = [];
224
+ const out = { points: [] };
217
225
  convertLine(geom.coordinates, out, tolerance, false);
218
226
  features.push(createFeature(id, 'LineString', out, properties));
219
227
  }
@@ -221,7 +229,7 @@ function convertMultiLineStringFeature(features, id, geom, tolerance, options, p
221
229
  if (options.lineMetrics) {
222
230
  // explode into linestrings to be able to track metrics
223
231
  for (const line of geom.coordinates) {
224
- const out = [];
232
+ const out = { points: [] };
225
233
  convertLine(line, out, tolerance, false);
226
234
  features.push(createFeature(id, 'LineString', out, properties));
227
235
  }
@@ -252,7 +260,7 @@ function convertLine(ring, out, tolerance, isPolygon) {
252
260
  for (let j = 0; j < ring.length; j++) {
253
261
  const x = projectX(ring[j][0]);
254
262
  const y = projectY(ring[j][1]);
255
- out.push(x, y, 0);
263
+ out.points.push(x, y, 0);
256
264
  if (j > 0) {
257
265
  if (isPolygon) {
258
266
  size += (x0 * y - x * y0) / 2; // area
@@ -264,18 +272,19 @@ function convertLine(ring, out, tolerance, isPolygon) {
264
272
  x0 = x;
265
273
  y0 = y;
266
274
  }
267
- const last = out.length - 3;
268
- out[2] = 1;
275
+ const last = out.points.length - 3;
276
+ out.points[2] = 1;
269
277
  if (tolerance > 0)
270
- simplify(out, 0, last, tolerance);
271
- out[last + 2] = 1;
278
+ simplify(out.points, 0, last, tolerance);
279
+ out.points[last + 2] = 1;
280
+ optimizeLineMemory(out);
272
281
  out.size = Math.abs(size);
273
282
  out.start = 0;
274
283
  out.end = out.size;
275
284
  }
276
285
  function convertLines(rings, out, tolerance, isPolygon) {
277
286
  for (let i = 0; i < rings.length; i++) {
278
- const geom = [];
287
+ const geom = { points: [] };
279
288
  convertLine(rings[i], geom, tolerance, isPolygon);
280
289
  out.push(geom);
281
290
  }
@@ -331,21 +340,25 @@ function geometryToGeoJSON(feature) {
331
340
  coordinates: unprojectPoint(geometry[0], geometry[1])
332
341
  };
333
342
  case 'MultiPoint':
334
- case 'LineString':
335
343
  return {
336
344
  type: type,
337
345
  coordinates: unprojectPoints(geometry)
338
346
  };
347
+ case 'LineString':
348
+ return {
349
+ type: type,
350
+ coordinates: unprojectPoints(geometry.points)
351
+ };
339
352
  case 'MultiLineString':
340
353
  case 'Polygon':
341
354
  return {
342
355
  type: type,
343
- coordinates: geometry.map(ring => unprojectPoints(ring))
356
+ coordinates: geometry.map(ring => unprojectPoints(ring.points))
344
357
  };
345
358
  case 'MultiPolygon':
346
359
  return {
347
360
  type: type,
348
- coordinates: geometry.map(polygon => polygon.map(ring => unprojectPoints(ring)))
361
+ coordinates: geometry.map(polygon => polygon.map(ring => unprojectPoints(ring.points)))
349
362
  };
350
363
  }
351
364
  }
@@ -510,12 +523,12 @@ function clipLine(geom, newGeom, start, end, axis, isPolygon, trackMetrics) {
510
523
  const intersect = axis === AxisType.X ? intersectX : intersectY;
511
524
  let len = geom.start;
512
525
  let segLen, t;
513
- for (let i = 0; i < geom.length - 3; i += 3) {
514
- const ax = geom[i];
515
- const ay = geom[i + 1];
516
- const az = geom[i + 2];
517
- const bx = geom[i + 3];
518
- const by = geom[i + 4];
526
+ for (let i = 0; i < geom.points.length - 3; i += 3) {
527
+ const ax = geom.points[i];
528
+ const ay = geom.points[i + 1];
529
+ const az = geom.points[i + 2];
530
+ const bx = geom.points[i + 3];
531
+ const by = geom.points[i + 4];
519
532
  const a = axis === AxisType.X ? ax : ay;
520
533
  const b = axis === AxisType.X ? bx : by;
521
534
  let exited = false;
@@ -538,7 +551,7 @@ function clipLine(geom, newGeom, start, end, axis, isPolygon, trackMetrics) {
538
551
  }
539
552
  }
540
553
  else {
541
- addPoint(slice, ax, ay, az);
554
+ addPoint(slice.points, ax, ay, az);
542
555
  }
543
556
  if (b < start && a >= start) {
544
557
  // <--|--- | or <--|-----|--- (line exits the clip region on the left)
@@ -560,29 +573,31 @@ function clipLine(geom, newGeom, start, end, axis, isPolygon, trackMetrics) {
560
573
  len += segLen;
561
574
  }
562
575
  // add the last point
563
- let last = geom.length - 3;
564
- const ax = geom[last];
565
- const ay = geom[last + 1];
566
- const az = geom[last + 2];
576
+ let last = geom.points.length - 3;
577
+ const ax = geom.points[last];
578
+ const ay = geom.points[last + 1];
579
+ const az = geom.points[last + 2];
567
580
  const a = axis === AxisType.X ? ax : ay;
568
581
  if (a >= start && a <= end)
569
- addPoint(slice, ax, ay, az);
582
+ addPoint(slice.points, ax, ay, az);
570
583
  // close the polygon if its endpoints are not the same after clipping
571
- last = slice.length - 3;
572
- if (isPolygon && last >= 3 && (slice[last] !== slice[0] || slice[last + 1] !== slice[1])) {
573
- addPoint(slice, slice[0], slice[1], slice[2]);
584
+ last = slice.points.length - 3;
585
+ if (isPolygon && last >= 3 && (slice.points[last] !== slice.points[0] || slice.points[last + 1] !== slice.points[1])) {
586
+ addPoint(slice.points, slice.points[0], slice.points[1], slice.points[2]);
574
587
  }
575
588
  // add the final slice
576
- if (slice.length) {
589
+ if (slice.points.length) {
590
+ optimizeLineMemory(slice);
577
591
  newGeom.push(slice);
578
592
  }
579
593
  }
580
594
  function newSlice(line) {
581
- const slice = [];
582
- slice.size = line.size;
583
- slice.start = line.start;
584
- slice.end = line.end;
585
- return slice;
595
+ return {
596
+ points: [],
597
+ size: line.size,
598
+ start: line.start,
599
+ end: line.end
600
+ };
586
601
  }
587
602
  function clipLines(geom, newGeom, start, end, axis, isPolygon) {
588
603
  for (const line of geom) {
@@ -594,12 +609,12 @@ function addPoint(out, x, y, z) {
594
609
  }
595
610
  function intersectX(out, ax, ay, bx, by, x) {
596
611
  const t = (x - ax) / (bx - ax);
597
- addPoint(out, x, ay + (by - ay) * t, 1);
612
+ addPoint(out.points, x, ay + (by - ay) * t, 1);
598
613
  return t;
599
614
  }
600
615
  function intersectY(out, ax, ay, bx, by, y) {
601
616
  const t = (y - ay) / (by - ay);
602
- addPoint(out, ax + (bx - ax) * t, y, 1);
617
+ addPoint(out.points, ax + (bx - ax) * t, y, 1);
603
618
  return t;
604
619
  }
605
620
 
@@ -622,9 +637,13 @@ function shiftFeatureCoords(features, offset) {
622
637
  for (const feature of features) {
623
638
  switch (feature.type) {
624
639
  case 'Point':
625
- case 'MultiPoint':
640
+ case 'MultiPoint': {
641
+ const newGeometry = shiftPointCoords(feature.geometry, offset);
642
+ newFeatures.push(createFeature(feature.id, feature.type, newGeometry, feature.tags));
643
+ continue;
644
+ }
626
645
  case 'LineString': {
627
- const newGeometry = shiftCoords(feature.geometry, offset);
646
+ const newGeometry = shiftLineCoords(feature.geometry, offset);
628
647
  newFeatures.push(createFeature(feature.id, feature.type, newGeometry, feature.tags));
629
648
  continue;
630
649
  }
@@ -632,7 +651,7 @@ function shiftFeatureCoords(features, offset) {
632
651
  case 'Polygon': {
633
652
  const newGeometry = [];
634
653
  for (const line of feature.geometry) {
635
- newGeometry.push(shiftCoords(line, offset));
654
+ newGeometry.push(shiftLineCoords(line, offset));
636
655
  }
637
656
  newFeatures.push(createFeature(feature.id, feature.type, newGeometry, feature.tags));
638
657
  continue;
@@ -642,7 +661,7 @@ function shiftFeatureCoords(features, offset) {
642
661
  for (const polygon of feature.geometry) {
643
662
  const newPolygon = [];
644
663
  for (const line of polygon) {
645
- newPolygon.push(shiftCoords(line, offset));
664
+ newPolygon.push(shiftLineCoords(line, offset));
646
665
  }
647
666
  newGeometry.push(newPolygon);
648
667
  }
@@ -653,17 +672,27 @@ function shiftFeatureCoords(features, offset) {
653
672
  }
654
673
  return newFeatures;
655
674
  }
656
- function shiftCoords(points, offset) {
657
- const newPoints = [];
658
- newPoints.size = points.size;
659
- if (points.start !== undefined) {
660
- newPoints.start = points.start;
661
- newPoints.end = points.end;
675
+ function shiftPointCoords(coords, offset) {
676
+ const newCoords = [];
677
+ for (let i = 0; i < coords.length; i += 3) {
678
+ newCoords.push(coords[i] + offset, coords[i + 1], coords[i + 2]);
662
679
  }
663
- for (let i = 0; i < points.length; i += 3) {
664
- newPoints.push(points[i] + offset, points[i + 1], points[i + 2]);
680
+ return newCoords;
681
+ }
682
+ function shiftLineCoords(line, offset) {
683
+ const newLine = {
684
+ points: [],
685
+ size: line.size
686
+ };
687
+ if (line.start !== undefined) {
688
+ newLine.start = line.start;
689
+ newLine.end = line.end;
665
690
  }
666
- return newPoints;
691
+ for (let i = 0; i < line.points.length; i += 3) {
692
+ newLine.points.push(line.points[i] + offset, line.points[i + 1], line.points[i + 2]);
693
+ }
694
+ optimizeLineMemory(newLine);
695
+ return newLine;
667
696
  }
668
697
 
669
698
  /**
@@ -675,7 +704,7 @@ function shiftCoords(points, offset) {
675
704
  */
676
705
  function applySourceDiff(source, dataDiff, options) {
677
706
  // convert diff to sets/maps for o(1) lookups
678
- const diff = diffToHashed(dataDiff);
707
+ const diff = diffToHashed(dataDiff, options);
679
708
  // collection for features that will be affected by this update and used to invalidate tiles
680
709
  let affected = [];
681
710
  if (diff.removeAll) {
@@ -786,7 +815,7 @@ function applyPropertyUpdates(tags, update) {
786
815
  /**
787
816
  * Convert a GeoJSON Source Diff to an idempotent hashed representation using Sets and Maps
788
817
  */
789
- function diffToHashed(diff) {
818
+ function diffToHashed(diff, options) {
790
819
  if (!diff)
791
820
  return {
792
821
  remove: new Set(),
@@ -796,7 +825,7 @@ function diffToHashed(diff) {
796
825
  const hashed = {
797
826
  removeAll: diff.removeAll,
798
827
  remove: new Set(diff.remove || []),
799
- add: new Map(diff.add?.map(feature => [feature.id, feature])),
828
+ add: new Map(diff.add?.map(feature => [options.promoteId ? feature.properties[options.promoteId] : feature.id, feature])),
800
829
  update: new Map(diff.update?.map(update => [update.id, update]))
801
830
  };
802
831
  return hashed;
@@ -1374,14 +1403,14 @@ function addMultiPolygonTileFeature(tile, feature, tolerance) {
1374
1403
  function addLine(result, geom, tile, tolerance, isPolygon, isOuter) {
1375
1404
  const sqTolerance = tolerance * tolerance;
1376
1405
  if (tolerance > 0 && (geom.size < (isPolygon ? sqTolerance : tolerance))) {
1377
- tile.numPoints += geom.length / 3;
1406
+ tile.numPoints += geom.points.length / 3;
1378
1407
  return;
1379
1408
  }
1380
1409
  const ring = [];
1381
- for (let i = 0; i < geom.length; i += 3) {
1382
- if (tolerance === 0 || geom[i + 2] > sqTolerance) {
1410
+ for (let i = 0; i < geom.points.length; i += 3) {
1411
+ if (tolerance === 0 || geom.points[i + 2] > sqTolerance) {
1383
1412
  tile.numSimplified++;
1384
- ring.push(geom[i], geom[i + 1]);
1413
+ ring.push(geom.points[i], geom.points[i + 1]);
1385
1414
  }
1386
1415
  tile.numPoints++;
1387
1416
  }