@loaders.gl/mvt 4.3.0-alpha.1 → 4.3.0-alpha.3

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 (93) hide show
  1. package/dist/dist.dev.js +1289 -807
  2. package/dist/dist.min.js +1 -1
  3. package/dist/index.cjs +923 -773
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +7 -6
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -2
  8. package/dist/lib/parse-mvt.d.ts +1 -1
  9. package/dist/lib/parse-mvt.js +2 -30
  10. package/dist/lib/parse-tilejson.d.ts +4 -4
  11. package/dist/lib/parse-tilejson.d.ts.map +1 -1
  12. package/dist/lib/parse-tilejson.js +1 -1
  13. package/dist/lib/utils/geometry-utils.d.ts +38 -1
  14. package/dist/lib/utils/geometry-utils.d.ts.map +1 -1
  15. package/dist/lib/utils/geometry-utils.js +65 -6
  16. package/dist/lib/vector-tile/vector-tile-feature.d.ts +28 -9
  17. package/dist/lib/vector-tile/vector-tile-feature.d.ts.map +1 -1
  18. package/dist/lib/vector-tile/vector-tile-feature.js +47 -50
  19. package/dist/lib/{geojsonvt/clip.d.ts → vector-tiler/features/clip-features.d.ts} +4 -4
  20. package/dist/lib/vector-tiler/features/clip-features.d.ts.map +1 -0
  21. package/dist/lib/{geojsonvt/clip.js → vector-tiler/features/clip-features.js} +4 -4
  22. package/dist/lib/vector-tiler/features/convert-feature.d.ts +18 -0
  23. package/dist/lib/vector-tiler/features/convert-feature.d.ts.map +1 -0
  24. package/dist/lib/vector-tiler/features/convert-feature.js +140 -0
  25. package/dist/lib/vector-tiler/features/proto-feature.d.ts +30 -0
  26. package/dist/lib/vector-tiler/features/proto-feature.d.ts.map +1 -0
  27. package/dist/lib/vector-tiler/features/proto-feature.js +52 -0
  28. package/dist/lib/{geojsonvt/simplify.d.ts → vector-tiler/features/simplify-path.d.ts} +2 -2
  29. package/dist/lib/vector-tiler/features/simplify-path.d.ts.map +1 -0
  30. package/dist/lib/{geojsonvt/simplify.js → vector-tiler/features/simplify-path.js} +3 -3
  31. package/dist/lib/{geojsonvt/wrap.d.ts → vector-tiler/features/wrap-features.d.ts} +5 -5
  32. package/dist/lib/vector-tiler/features/wrap-features.d.ts.map +1 -0
  33. package/dist/lib/{geojsonvt/wrap.js → vector-tiler/features/wrap-features.js} +33 -26
  34. package/dist/lib/vector-tiler/proto-tile.d.ts +40 -0
  35. package/dist/lib/vector-tiler/proto-tile.d.ts.map +1 -0
  36. package/dist/lib/vector-tiler/proto-tile.js +138 -0
  37. package/dist/lib/vector-tiler/tile-to-geojson.d.ts +12 -0
  38. package/dist/lib/vector-tiler/tile-to-geojson.d.ts.map +1 -0
  39. package/dist/lib/vector-tiler/tile-to-geojson.js +81 -0
  40. package/dist/lib/vector-tiler/transform-tile.d.ts +7 -0
  41. package/dist/lib/vector-tiler/transform-tile.d.ts.map +1 -0
  42. package/dist/lib/vector-tiler/transform-tile.js +41 -0
  43. package/dist/mvt-loader.d.ts +1 -1
  44. package/dist/mvt-loader.js +1 -1
  45. package/dist/mvt-source.d.ts +35 -18
  46. package/dist/mvt-source.d.ts.map +1 -1
  47. package/dist/mvt-source.js +30 -10
  48. package/dist/mvt-worker.js +101 -56
  49. package/dist/table-tile-source.d.ts +148 -0
  50. package/dist/table-tile-source.d.ts.map +1 -0
  51. package/dist/table-tile-source.js +420 -0
  52. package/dist/tilejson-loader.js +1 -1
  53. package/package.json +7 -6
  54. package/src/index.ts +14 -7
  55. package/src/lib/parse-mvt.ts +4 -33
  56. package/src/lib/parse-tilejson.ts +6 -6
  57. package/src/lib/utils/geometry-utils.ts +66 -1
  58. package/src/lib/vector-tile/vector-tile-feature.ts +65 -56
  59. package/src/lib/{geojsonvt/clip.ts → vector-tiler/features/clip-features.ts} +8 -8
  60. package/src/lib/vector-tiler/features/convert-feature.ts +191 -0
  61. package/src/lib/vector-tiler/features/proto-feature.ts +104 -0
  62. package/src/lib/{geojsonvt/simplify.ts → vector-tiler/features/simplify-path.ts} +8 -3
  63. package/src/lib/{geojsonvt/wrap.ts → vector-tiler/features/wrap-features.ts} +44 -29
  64. package/src/lib/vector-tiler/proto-tile.ts +217 -0
  65. package/src/lib/vector-tiler/tile-to-geojson.ts +105 -0
  66. package/src/lib/vector-tiler/transform-tile.ts +57 -0
  67. package/src/mvt-source.ts +47 -24
  68. package/src/table-tile-source.ts +553 -0
  69. package/src/tilejson-loader.ts +2 -2
  70. package/dist/geojson-tile-source.d.ts +0 -79
  71. package/dist/geojson-tile-source.d.ts.map +0 -1
  72. package/dist/geojson-tile-source.js +0 -319
  73. package/dist/lib/geojsonvt/clip.d.ts.map +0 -1
  74. package/dist/lib/geojsonvt/convert.d.ts +0 -10
  75. package/dist/lib/geojsonvt/convert.d.ts.map +0 -1
  76. package/dist/lib/geojsonvt/convert.js +0 -132
  77. package/dist/lib/geojsonvt/feature.d.ts +0 -3
  78. package/dist/lib/geojsonvt/feature.d.ts.map +0 -1
  79. package/dist/lib/geojsonvt/feature.js +0 -44
  80. package/dist/lib/geojsonvt/simplify.d.ts.map +0 -1
  81. package/dist/lib/geojsonvt/tile.d.ts +0 -38
  82. package/dist/lib/geojsonvt/tile.d.ts.map +0 -1
  83. package/dist/lib/geojsonvt/tile.js +0 -123
  84. package/dist/lib/geojsonvt/transform.d.ts +0 -7
  85. package/dist/lib/geojsonvt/transform.d.ts.map +0 -1
  86. package/dist/lib/geojsonvt/transform.js +0 -41
  87. package/dist/lib/geojsonvt/wrap.d.ts.map +0 -1
  88. package/src/geojson-tile-source.ts +0 -422
  89. package/src/lib/geojsonvt/convert.ts +0 -160
  90. package/src/lib/geojsonvt/feature.ts +0 -47
  91. package/src/lib/geojsonvt/tile.ts +0 -187
  92. package/src/lib/geojsonvt/transform.ts +0 -57
  93. /package/src/lib/{geojsonvt → vector-tiler}/LICENSE +0 -0
@@ -6,7 +6,9 @@
6
6
  import {Feature} from '@loaders.gl/schema';
7
7
  import {FlatFeature, FlatIndexedGeometry, GeojsonGeometryInfo} from '@loaders.gl/schema';
8
8
  import Protobuf from 'pbf';
9
- import {classifyRings, classifyRingsFlat, projectToLngLatFlat} from '../utils/geometry-utils';
9
+ import {classifyRings, classifyRingsFlat} from '../utils/geometry-utils';
10
+ import {projectToLngLat, projectToLngLatFlat} from '../utils/geometry-utils';
11
+ import {convertToLocalCoordinates, convertToLocalCoordinatesFlat} from '../utils/geometry-utils';
10
12
 
11
13
  export class VectorTileFeature {
12
14
  properties: {[x: string]: string | number | boolean | null};
@@ -48,47 +50,45 @@ export class VectorTileFeature {
48
50
  pbf.readFields(readFeature, this, end);
49
51
  }
50
52
 
51
- toGeoJSON(
52
- options: {x: number; y: number; z: number} | ((data: number[], feature: {extent: any}) => void)
53
+ toGeoJSONFeature(
54
+ coordinates: 'wgs84' | 'local',
55
+ tileIndex?: {x: number; y: number; z: number}
53
56
  ): Feature {
54
57
  const coords = this.loadGeometry();
55
58
 
56
- if (typeof options === 'function') {
57
- return _toGeoJSON(this, coords, options);
58
- }
59
- const {x, y, z} = options;
60
- const size = this.extent * Math.pow(2, z);
61
- const x0 = this.extent * x;
62
- const y0 = this.extent * y;
63
-
64
- function project(line: number[]) {
65
- for (let j = 0; j < line.length; j++) {
66
- const p = line[j];
67
- p[0] = ((p[0] + x0) * 360) / size - 180;
68
- const y2 = 180 - ((p[1] + y0) * 360) / size;
69
- p[1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;
70
- }
59
+ switch (coordinates) {
60
+ case 'wgs84':
61
+ return _toGeoJSONFeature(this, coords, (line: number[][]) =>
62
+ projectToLngLat(line, tileIndex!, this.extent)
63
+ );
64
+
65
+ default:
66
+ return _toGeoJSONFeature(this, coords, convertToLocalCoordinates);
71
67
  }
72
- return _toGeoJSON(this, coords, project);
73
68
  }
74
-
75
69
  /**
76
70
  *
77
71
  * @param options
78
72
  * @returns
79
73
  */
80
- toBinaryCoordinates(
81
- options: {x: number; y: number; z: number} | ((data: number[], feature: {extent: any}) => void)
74
+ toBinaryFeature(
75
+ coordinates: 'wgs84' | 'local',
76
+ tileIndex?: {x: number; y: number; z: number}
82
77
  ): FlatFeature {
83
- if (typeof options === 'function') {
84
- return this._toBinaryCoordinates(options);
78
+ const geom = this.loadFlatGeometry();
79
+
80
+ switch (coordinates) {
81
+ case 'wgs84':
82
+ return this._toBinaryCoordinates(geom, (coords: number[]) =>
83
+ projectToLngLatFlat(coords, tileIndex!, this.extent)
84
+ );
85
+
86
+ default:
87
+ return this._toBinaryCoordinates(geom, convertToLocalCoordinatesFlat);
85
88
  }
86
- const tileIndex = options;
87
- return this._toBinaryCoordinates((data: number[]) =>
88
- projectToLngLatFlat(data, tileIndex, this.extent)
89
- );
90
89
  }
91
90
 
91
+ /** Read a bounding box from the feature */
92
92
  // eslint-disable-next-line max-statements
93
93
  bbox() {
94
94
  const pbf = this._pbf;
@@ -135,32 +135,14 @@ export class VectorTileFeature {
135
135
  * @param transform
136
136
  * @returns result
137
137
  */
138
- _toBinaryCoordinates(transform) {
139
- // Expands the protobuf data to an intermediate Flat GeoJSON
140
- // data format, which maps closely to the binary data buffers.
141
- // It is similar to GeoJSON, but rather than storing the coordinates
142
- // in multidimensional arrays, we have a 1D `data` with all the
143
- // coordinates, and then index into this using the `indices`
144
- // parameter, e.g.
145
- //
146
- // geometry: {
147
- // type: 'Point', data: [1,2], indices: [0]
148
- // }
149
- // geometry: {
150
- // type: 'LineString', data: [1,2,3,4,...], indices: [0]
151
- // }
152
- // geometry: {
153
- // type: 'Polygon', data: [1,2,3,4,...], indices: [[0, 2]]
154
- // }
155
- // Thus the indices member lets us look up the relevant range
156
- // from the data array.
157
- // The Multi* versions of the above types share the same data
158
- // structure, just with multiple elements in the indices array
159
- const geom = this.loadFlatGeometry();
138
+ _toBinaryCoordinates(
139
+ geom: FlatIndexedGeometry,
140
+ transform: (data: number[], extent: number) => void
141
+ ) {
160
142
  let geometry;
161
143
 
162
144
  // Apply the supplied transformation to data
163
- transform(geom.data, this);
145
+ transform(geom.data, this.extent);
164
146
 
165
147
  const coordLength = 2;
166
148
 
@@ -259,6 +241,28 @@ export class VectorTileFeature {
259
241
  return lines;
260
242
  }
261
243
 
244
+ /**
245
+ * Expands the protobuf data to an intermediate Flat GeoJSON
246
+ * data format, which maps closely to the binary data buffers.
247
+ * It is similar to GeoJSON, but rather than storing the coordinates
248
+ * in multidimensional arrays, we have a 1D `data` with all the
249
+ * coordinates, and then index into this using the `indices`
250
+ * parameter, e.g.
251
+ *
252
+ * geometry: {
253
+ * type: 'Point', data: [1,2], indices: [0]
254
+ * }
255
+ * geometry: {
256
+ * type: 'LineString', data: [1,2,3,4,...], indices: [0]
257
+ * }
258
+ * geometry: {
259
+ * type: 'Polygon', data: [1,2,3,4,...], indices: [[0, 2]]
260
+ * }
261
+ * Thus the indices member lets us look up the relevant range
262
+ * from the data array.
263
+ * The Multi* versions of the above types share the same data
264
+ * structure, just with multiple elements in the indices array
265
+ */
262
266
  // eslint-disable-next-line complexity, max-statements
263
267
  loadFlatGeometry(): FlatIndexedGeometry {
264
268
  const pbf = this._pbf;
@@ -315,7 +319,11 @@ export class VectorTileFeature {
315
319
  }
316
320
  }
317
321
 
318
- function _toGeoJSON(vtFeature: VectorTileFeature, coords: number[][][], transform): Feature {
322
+ function _toGeoJSONFeature(
323
+ vtFeature: VectorTileFeature,
324
+ coords: number[][][],
325
+ transform: (data: number[][], extent: number) => void
326
+ ): Feature {
319
327
  let type = VectorTileFeature.types[vtFeature.type];
320
328
  let i: number;
321
329
  let j: number;
@@ -328,13 +336,13 @@ function _toGeoJSON(vtFeature: VectorTileFeature, coords: number[][][], transfor
328
336
  points[i] = coords[i][0];
329
337
  }
330
338
  coordinates = points;
331
- transform(coordinates, vtFeature);
339
+ transform(coordinates, vtFeature.extent);
332
340
  break;
333
341
 
334
342
  case 2:
335
343
  coordinates = coords;
336
344
  for (i = 0; i < coordinates.length; i++) {
337
- transform(coordinates[i], vtFeature);
345
+ transform(coordinates[i], vtFeature.extent);
338
346
  }
339
347
  break;
340
348
 
@@ -342,7 +350,7 @@ function _toGeoJSON(vtFeature: VectorTileFeature, coords: number[][][], transfor
342
350
  coordinates = classifyRings(coords);
343
351
  for (i = 0; i < coordinates.length; i++) {
344
352
  for (j = 0; j < coordinates[i].length; j++) {
345
- transform(coordinates[i][j], vtFeature);
353
+ transform(coordinates[i][j], vtFeature.extent);
346
354
  }
347
355
  }
348
356
  break;
@@ -368,7 +376,8 @@ function _toGeoJSON(vtFeature: VectorTileFeature, coords: number[][][], transfor
368
376
  };
369
377
 
370
378
  if (vtFeature.id !== null) {
371
- result.id = vtFeature.id;
379
+ result.properties ||= {};
380
+ result.properties.id = vtFeature.id;
372
381
  }
373
382
 
374
383
  return result;
@@ -3,8 +3,8 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
  // Forked from https://github.com/mapbox/geojson-vt under compatible ISC license
5
5
 
6
- import type {GeoJSONTileFeature} from './tile';
7
- import {createFeature} from './feature';
6
+ import type {ProtoFeature} from './proto-feature';
7
+ import {createProtoFeature} from './proto-feature';
8
8
 
9
9
  /* eslint-disable no-continue */
10
10
 
@@ -20,8 +20,8 @@ import {createFeature} from './feature';
20
20
  * @param minAll and maxAll: minimum and maximum coordinate value for all features
21
21
  */
22
22
  // eslint-disable-next-line max-params, complexity, max-statements
23
- export function clip(
24
- features: GeoJSONTileFeature[],
23
+ export function clipFeatures(
24
+ features: ProtoFeature[],
25
25
  scale: number,
26
26
  k1: number,
27
27
  k2: number,
@@ -29,7 +29,7 @@ export function clip(
29
29
  minAll: number,
30
30
  maxAll: number,
31
31
  options: {lineMetrics: boolean}
32
- ): GeoJSONTileFeature[] | null {
32
+ ): ProtoFeature[] | null {
33
33
  k1 /= scale;
34
34
  k2 /= scale;
35
35
 
@@ -41,7 +41,7 @@ export function clip(
41
41
  return null; // trivial reject
42
42
  }
43
43
 
44
- const clipped: GeoJSONTileFeature[] = [];
44
+ const clipped: ProtoFeature[] = [];
45
45
 
46
46
  for (const feature of features) {
47
47
  const geometry = feature.geometry;
@@ -82,7 +82,7 @@ export function clip(
82
82
  if (newGeometry.length) {
83
83
  if (options.lineMetrics && type === 'LineString') {
84
84
  for (const line of newGeometry) {
85
- clipped.push(createFeature(feature.id, type, line, feature.tags));
85
+ clipped.push(createProtoFeature(feature.id, type, line, feature.tags));
86
86
  }
87
87
  continue;
88
88
  }
@@ -100,7 +100,7 @@ export function clip(
100
100
  type = newGeometry.length === 3 ? 'Point' : 'MultiPoint';
101
101
  }
102
102
 
103
- clipped.push(createFeature(feature.id, type, newGeometry, feature.tags));
103
+ clipped.push(createProtoFeature(feature.id, type, newGeometry, feature.tags));
104
104
  }
105
105
  }
106
106
 
@@ -0,0 +1,191 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ // Forked from https://github.com/mapbox/geojson-vt under compatible ISC license
5
+
6
+ /* eslint-disable */
7
+ // @ts-nocheck
8
+
9
+ import type {Feature, FeatureCollection} from '@loaders.gl/schema';
10
+ import type {ProtoFeature} from './proto-feature';
11
+
12
+ import {createProtoFeature} from './proto-feature';
13
+ import {simplifyPath} from './simplify-path';
14
+
15
+ export type ConvertFeatureOptions = {
16
+ /** max zoom to preserve detail on */
17
+ maxZoom?: number;
18
+ /** simplification tolerance (higher means simpler) */
19
+ tolerance?: number;
20
+ /** tile extent */
21
+ extent?: number;
22
+ /** whether to calculate line metrics */
23
+ lineMetrics?: boolean;
24
+ };
25
+
26
+ /**
27
+ * converts a GeoJSON feature into an intermediate projected JSON vector format
28
+ * with simplification data
29
+ */
30
+ export function convertFeaturesToProtoFeature(
31
+ data: Feature | FeatureCollection,
32
+ options: ConvertFeatureOptions
33
+ ): ProtoFeature[] {
34
+ const protoFeatures = [];
35
+ switch (data.type) {
36
+ case 'FeatureCollection':
37
+ let i = 0;
38
+ for (const feature of data.features) {
39
+ protoFeatures.push(convertFeature(feature, options, i++));
40
+ }
41
+ break;
42
+ case 'Feature':
43
+ protoFeatures.push(convertFeature(data, options));
44
+ break;
45
+ default:
46
+ // single geometry or a geometry collection
47
+ protoFeatures.push(convertFeature({geometry: data}, options));
48
+ }
49
+
50
+ return protoFeatures;
51
+ }
52
+
53
+ /**
54
+ * converts a GeoJSON feature into an intermediate projected JSON vector format
55
+ * with simplification data
56
+ */
57
+ function convertFeature(
58
+ geojson: Feature,
59
+ options: ConvertFeatureOptions,
60
+ index: number
61
+ ): ProtoFeature {
62
+ // GeoJSON geometries can be null, but no vector tile will include them.
63
+ if (!geojson.geometry) {
64
+ return;
65
+ }
66
+
67
+ const coords = geojson.geometry.coordinates;
68
+ const type = geojson.geometry.type;
69
+ const tolerance = Math.pow(options.tolerance / ((1 << options.maxZoom) * options.extent), 2);
70
+ let geometry = [];
71
+ let id = geojson.id;
72
+ if (options.promoteId) {
73
+ id = geojson.properties[options.promoteId];
74
+ } else if (options.generateId) {
75
+ id = index || 0;
76
+ }
77
+
78
+ switch (type) {
79
+ case 'Point':
80
+ convertPoint(coords, geometry);
81
+ break;
82
+
83
+ case 'MultiPoint':
84
+ for (const p of coords) {
85
+ convertPoint(p, geometry);
86
+ }
87
+ break;
88
+
89
+ case 'LineString':
90
+ convertLine(coords, geometry, tolerance, false);
91
+ break;
92
+
93
+ case 'MultiLineString':
94
+ if (options.lineMetrics) {
95
+ // explode into linestrings to be able to track metrics
96
+ for (const line of coords) {
97
+ geometry = [];
98
+ convertLine(line, geometry, tolerance, false);
99
+ features.push(createProtoFeature(id, 'LineString', geometry, geojson.properties));
100
+ }
101
+ return;
102
+ convertLines(coords, geometry, tolerance, false);
103
+ }
104
+ break;
105
+
106
+ case 'Polygon':
107
+ convertLines(coords, geometry, tolerance, true);
108
+ break;
109
+
110
+ case 'MultiPolygon':
111
+ for (const polygon of coords) {
112
+ const newPolygon = [];
113
+ convertLines(polygon, newPolygon, tolerance, true);
114
+ geometry.push(newPolygon);
115
+ }
116
+ break;
117
+
118
+ case 'GeometryCollection':
119
+ for (const singleGeometry of geojson.geometry.geometries) {
120
+ convertFeature(
121
+ features,
122
+ {
123
+ id,
124
+ geometry: singleGeometry,
125
+ properties: geojson.properties
126
+ },
127
+ options,
128
+ index
129
+ );
130
+ }
131
+ break;
132
+
133
+ default:
134
+ throw new Error('Input data is not a valid GeoJSON object.');
135
+ }
136
+
137
+ return createProtoFeature(id, type, geometry, geojson.properties);
138
+ }
139
+
140
+ function convertPoint(coords, out): void {
141
+ out.push(projectX(coords[0]), projectY(coords[1]), 0);
142
+ }
143
+
144
+ function convertLine(ring: number[], out, tolerance: number, isPolygon: boolean): void {
145
+ let x0, y0;
146
+ let size = 0;
147
+
148
+ for (let j = 0; j < ring.length; j++) {
149
+ const x = projectX(ring[j][0]);
150
+ const y = projectY(ring[j][1]);
151
+
152
+ out.push(x, y, 0);
153
+
154
+ if (j > 0) {
155
+ if (isPolygon) {
156
+ size += (x0 * y - x * y0) / 2; // area
157
+ } else {
158
+ size += Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)); // length
159
+ }
160
+ }
161
+ x0 = x;
162
+ y0 = y;
163
+ }
164
+
165
+ const last = out.length - 3;
166
+ out[2] = 1;
167
+ simplifyPath(out, 0, last, tolerance);
168
+ out[last + 2] = 1;
169
+
170
+ out.size = Math.abs(size);
171
+ out.start = 0;
172
+ out.end = out.size;
173
+ }
174
+
175
+ function convertLines(rings: number[][], out, tolerance: number, isPolygon: boolean): void {
176
+ for (let i = 0; i < rings.length; i++) {
177
+ const geom = [];
178
+ convertLine(rings[i], geom, tolerance, isPolygon);
179
+ out.push(geom);
180
+ }
181
+ }
182
+
183
+ function projectX(x: number): number {
184
+ return x / 360 + 0.5;
185
+ }
186
+
187
+ function projectY(y: number): number {
188
+ const sin = Math.sin((y * Math.PI) / 180);
189
+ const y2 = 0.5 - (0.25 * Math.log((1 + sin) / (1 - sin))) / Math.PI;
190
+ return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
191
+ }
@@ -0,0 +1,104 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ // Forked from https://github.com/mapbox/geojson-vt under compatible ISC license
5
+
6
+ export type ProtoFeature = {
7
+ type: 'Point' | 'MultiPoint' | 'LineString' | 'MultiLineString' | 'Polygon' | 'MultiPolygon';
8
+ simplifiedType: 1 | 2 | 3;
9
+ geometry: any[];
10
+
11
+ // book keeping
12
+ id?: string;
13
+ tags?: Record<string, unknown>;
14
+
15
+ /** spatial extents */
16
+ minX: number;
17
+ /** spatial extents */
18
+ maxX: number;
19
+ /** spatial extents */
20
+ minY: number;
21
+ /** spatial extents */
22
+ maxY: number;
23
+ };
24
+
25
+ export type GeoJSONTileGeometry =
26
+ | GeoJSONTilePointGeometry
27
+ | GeoJSONTileLineGeometry
28
+ | GeoJSONTilePolygonGeometry;
29
+
30
+ export type GeoJSONTilePointGeometry = {
31
+ simplifiedType: 1;
32
+ geometry: number[];
33
+ };
34
+
35
+ export type GeoJSONTileLineGeometry = {
36
+ simplifiedType: 1;
37
+ geometry: number[][];
38
+ };
39
+
40
+ export type GeoJSONTilePolygonGeometry = {
41
+ simplifiedType: 1;
42
+ geometry: number[][][];
43
+ };
44
+
45
+ export function createProtoFeature(
46
+ id: any,
47
+ type: 'Point' | 'MultiPoint' | 'LineString' | 'MultiLineString' | 'Polygon' | 'MultiPolygon',
48
+ geometry: any[],
49
+ tags
50
+ ): ProtoFeature {
51
+ const feature: ProtoFeature = {
52
+ // eslint-disable-next-line
53
+ id: id == null ? null : id,
54
+ type,
55
+ simplifiedType: undefined!, // TODO
56
+ geometry,
57
+ tags,
58
+ minX: Infinity,
59
+ minY: Infinity,
60
+ maxX: -Infinity,
61
+ maxY: -Infinity
62
+ };
63
+
64
+ // TODO break out into separate function
65
+ switch (type) {
66
+ case 'Point':
67
+ case 'MultiPoint':
68
+ case 'LineString':
69
+ calcLineBBox(feature, geometry);
70
+ break;
71
+
72
+ case 'MultiLineString':
73
+ for (const line of geometry) {
74
+ calcLineBBox(feature, line);
75
+ }
76
+ break;
77
+
78
+ case 'Polygon':
79
+ // the outer ring (ie [0]) contains all inner rings
80
+ calcLineBBox(feature, geometry[0]);
81
+ break;
82
+
83
+ case 'MultiPolygon':
84
+ for (const polygon of geometry) {
85
+ // the outer ring (ie [0]) contains all inner rings
86
+ calcLineBBox(feature, polygon[0]);
87
+ }
88
+ break;
89
+
90
+ default:
91
+ throw new Error(String(type));
92
+ }
93
+
94
+ return feature;
95
+ }
96
+
97
+ function calcLineBBox(feature, geometry) {
98
+ for (let i = 0; i < geometry.length; i += 3) {
99
+ feature.minX = Math.min(feature.minX, geometry[i]);
100
+ feature.minY = Math.min(feature.minY, geometry[i + 1]);
101
+ feature.maxX = Math.max(feature.maxX, geometry[i]);
102
+ feature.maxY = Math.max(feature.maxY, geometry[i + 1]);
103
+ }
104
+ }
@@ -11,7 +11,12 @@
11
11
  * @param last last coord to simplify
12
12
  * @param sqTolerance tolerance (square distance)
13
13
  */
14
- export function simplify(coords: number[], first: number, last: number, sqTolerance: number): void {
14
+ export function simplifyPath(
15
+ coords: number[],
16
+ first: number,
17
+ last: number,
18
+ sqTolerance: number
19
+ ): void {
15
20
  let maxSqDist = sqTolerance;
16
21
  const mid = (last - first) >> 1;
17
22
  let minPosToMid = last - first;
@@ -41,9 +46,9 @@ export function simplify(coords: number[], first: number, last: number, sqTolera
41
46
  }
42
47
 
43
48
  if (maxSqDist > sqTolerance) {
44
- if (index - first > 3) simplify(coords, first, index, sqTolerance);
49
+ if (index - first > 3) simplifyPath(coords, first, index, sqTolerance);
45
50
  coords[index + 2] = maxSqDist;
46
- if (last - index > 3) simplify(coords, index, last, sqTolerance);
51
+ if (last - index > 3) simplifyPath(coords, index, last, sqTolerance);
47
52
  }
48
53
  }
49
54
 
@@ -3,14 +3,14 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
  // Forked from https://github.com/mapbox/geojson-vt under compatible ISC license
5
5
 
6
- import type {GeoJSONTileFeature} from './tile';
7
- import {clip} from './clip';
8
- import {createFeature} from './feature';
6
+ import type {ProtoFeature} from './proto-feature';
7
+ import {createProtoFeature} from './proto-feature';
8
+ import {clipFeatures} from './clip-features';
9
9
 
10
10
  /**
11
11
  * Options for wrap()
12
12
  */
13
- export type WrapOptions = {
13
+ export type WrapFeaturesOptions = {
14
14
  buffer: number /** number of pixels of buffer for the tile */;
15
15
  extent: number /** extent of each tile */;
16
16
  lineMetrics: boolean;
@@ -18,18 +18,21 @@ export type WrapOptions = {
18
18
 
19
19
  /**
20
20
  * Wrap across antemeridian, by clipping into two tiles, shifting the overflowing x coordinates
21
- * @param features list of features to be wrapped
21
+ * @param list of features to be wrapped
22
22
  * @param options buffer and extent
23
23
  * @returns
24
24
  */
25
- export function wrap(features: GeoJSONTileFeature[], options: WrapOptions) {
25
+ export function wrapFeatures(
26
+ features: ProtoFeature[],
27
+ options: WrapFeaturesOptions
28
+ ): ProtoFeature[] {
26
29
  const buffer = options.buffer / options.extent;
27
- let merged: GeoJSONTileFeature[] = features;
28
- const left = clip(features, 1, -1 - buffer, buffer, 0, -1, 2, options); // left world copy
29
- const right = clip(features, 1, 1 - buffer, 2 + buffer, 0, -1, 2, options); // right world copy
30
+ let merged: ProtoFeature[] = features;
31
+ const left = clipFeatures(features, 1, -1 - buffer, buffer, 0, -1, 2, options); // left world copy
32
+ const right = clipFeatures(features, 1, 1 - buffer, 2 + buffer, 0, -1, 2, options); // right world copy
30
33
 
31
34
  if (left || right) {
32
- merged = clip(features, 1, -buffer, 1 + buffer, 0, -1, 2, options) || []; // center world copy
35
+ merged = clipFeatures(features, 1, -buffer, 1 + buffer, 0, -1, 2, options) || []; // center world copy
33
36
 
34
37
  if (left) {
35
38
  merged = shiftFeatureCoords(left, 1).concat(merged); // merge left into center
@@ -48,8 +51,8 @@ export function wrap(features: GeoJSONTileFeature[], options: WrapOptions) {
48
51
  * @param offset
49
52
  * @returns
50
53
  */
51
- function shiftFeatureCoords(features: GeoJSONTileFeature[], offset: number): GeoJSONTileFeature[] {
52
- const newFeatures: GeoJSONTileFeature[] = [];
54
+ function shiftFeatureCoords(features: ProtoFeature[], offset: number): ProtoFeature[] {
55
+ const newFeatures: ProtoFeature[] = [];
53
56
 
54
57
  for (let i = 0; i < features.length; i++) {
55
58
  const feature = features[i];
@@ -57,26 +60,38 @@ function shiftFeatureCoords(features: GeoJSONTileFeature[], offset: number): Geo
57
60
 
58
61
  let newGeometry;
59
62
 
60
- if (type === 'Point' || type === 'MultiPoint' || type === 'LineString') {
61
- newGeometry = shiftCoords(feature.geometry, offset);
62
- } else if (type === 'MultiLineString' || type === 'Polygon') {
63
- newGeometry = [];
64
- for (const line of feature.geometry) {
65
- newGeometry.push(shiftCoords(line, offset));
66
- }
67
- } else if (type === 'MultiPolygon') {
68
- newGeometry = [];
69
- for (const polygon of feature.geometry) {
70
- const newPolygon: Points = [];
71
- for (const line of polygon) {
72
- // @ts-expect-error TODO
73
- newPolygon.push(shiftCoords(line, offset));
63
+ switch (type) {
64
+ case 'Point':
65
+ case 'MultiPoint':
66
+ case 'LineString':
67
+ newGeometry = shiftCoords(feature.geometry, offset);
68
+ break;
69
+
70
+ case 'MultiLineString':
71
+ case 'Polygon':
72
+ newGeometry = [];
73
+ for (const line of feature.geometry) {
74
+ newGeometry.push(shiftCoords(line, offset));
74
75
  }
75
- newGeometry.push(newPolygon);
76
- }
76
+ break;
77
+
78
+ case 'MultiPolygon':
79
+ newGeometry = [];
80
+ for (const polygon of feature.geometry) {
81
+ const newPolygon: Points = [];
82
+ for (const line of polygon) {
83
+ // @ts-expect-error TODO
84
+ newPolygon.push(shiftCoords(line, offset));
85
+ }
86
+ newGeometry.push(newPolygon);
87
+ }
88
+ break;
89
+
90
+ default:
91
+ throw new Error(String(type));
77
92
  }
78
93
 
79
- newFeatures.push(createFeature(feature.id, type, newGeometry, feature.tags));
94
+ newFeatures.push(createProtoFeature(feature.id, type, newGeometry, feature.tags));
80
95
  }
81
96
 
82
97
  return newFeatures;