@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.
- package/dist/dist.dev.js +1289 -807
- package/dist/dist.min.js +1 -1
- package/dist/index.cjs +923 -773
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/lib/parse-mvt.d.ts +1 -1
- package/dist/lib/parse-mvt.js +2 -30
- package/dist/lib/parse-tilejson.d.ts +4 -4
- package/dist/lib/parse-tilejson.d.ts.map +1 -1
- package/dist/lib/parse-tilejson.js +1 -1
- package/dist/lib/utils/geometry-utils.d.ts +38 -1
- package/dist/lib/utils/geometry-utils.d.ts.map +1 -1
- package/dist/lib/utils/geometry-utils.js +65 -6
- package/dist/lib/vector-tile/vector-tile-feature.d.ts +28 -9
- package/dist/lib/vector-tile/vector-tile-feature.d.ts.map +1 -1
- package/dist/lib/vector-tile/vector-tile-feature.js +47 -50
- package/dist/lib/{geojsonvt/clip.d.ts → vector-tiler/features/clip-features.d.ts} +4 -4
- package/dist/lib/vector-tiler/features/clip-features.d.ts.map +1 -0
- package/dist/lib/{geojsonvt/clip.js → vector-tiler/features/clip-features.js} +4 -4
- package/dist/lib/vector-tiler/features/convert-feature.d.ts +18 -0
- package/dist/lib/vector-tiler/features/convert-feature.d.ts.map +1 -0
- package/dist/lib/vector-tiler/features/convert-feature.js +140 -0
- package/dist/lib/vector-tiler/features/proto-feature.d.ts +30 -0
- package/dist/lib/vector-tiler/features/proto-feature.d.ts.map +1 -0
- package/dist/lib/vector-tiler/features/proto-feature.js +52 -0
- package/dist/lib/{geojsonvt/simplify.d.ts → vector-tiler/features/simplify-path.d.ts} +2 -2
- package/dist/lib/vector-tiler/features/simplify-path.d.ts.map +1 -0
- package/dist/lib/{geojsonvt/simplify.js → vector-tiler/features/simplify-path.js} +3 -3
- package/dist/lib/{geojsonvt/wrap.d.ts → vector-tiler/features/wrap-features.d.ts} +5 -5
- package/dist/lib/vector-tiler/features/wrap-features.d.ts.map +1 -0
- package/dist/lib/{geojsonvt/wrap.js → vector-tiler/features/wrap-features.js} +33 -26
- package/dist/lib/vector-tiler/proto-tile.d.ts +40 -0
- package/dist/lib/vector-tiler/proto-tile.d.ts.map +1 -0
- package/dist/lib/vector-tiler/proto-tile.js +138 -0
- package/dist/lib/vector-tiler/tile-to-geojson.d.ts +12 -0
- package/dist/lib/vector-tiler/tile-to-geojson.d.ts.map +1 -0
- package/dist/lib/vector-tiler/tile-to-geojson.js +81 -0
- package/dist/lib/vector-tiler/transform-tile.d.ts +7 -0
- package/dist/lib/vector-tiler/transform-tile.d.ts.map +1 -0
- package/dist/lib/vector-tiler/transform-tile.js +41 -0
- package/dist/mvt-loader.d.ts +1 -1
- package/dist/mvt-loader.js +1 -1
- package/dist/mvt-source.d.ts +35 -18
- package/dist/mvt-source.d.ts.map +1 -1
- package/dist/mvt-source.js +30 -10
- package/dist/mvt-worker.js +101 -56
- package/dist/table-tile-source.d.ts +148 -0
- package/dist/table-tile-source.d.ts.map +1 -0
- package/dist/table-tile-source.js +420 -0
- package/dist/tilejson-loader.js +1 -1
- package/package.json +7 -6
- package/src/index.ts +14 -7
- package/src/lib/parse-mvt.ts +4 -33
- package/src/lib/parse-tilejson.ts +6 -6
- package/src/lib/utils/geometry-utils.ts +66 -1
- package/src/lib/vector-tile/vector-tile-feature.ts +65 -56
- package/src/lib/{geojsonvt/clip.ts → vector-tiler/features/clip-features.ts} +8 -8
- package/src/lib/vector-tiler/features/convert-feature.ts +191 -0
- package/src/lib/vector-tiler/features/proto-feature.ts +104 -0
- package/src/lib/{geojsonvt/simplify.ts → vector-tiler/features/simplify-path.ts} +8 -3
- package/src/lib/{geojsonvt/wrap.ts → vector-tiler/features/wrap-features.ts} +44 -29
- package/src/lib/vector-tiler/proto-tile.ts +217 -0
- package/src/lib/vector-tiler/tile-to-geojson.ts +105 -0
- package/src/lib/vector-tiler/transform-tile.ts +57 -0
- package/src/mvt-source.ts +47 -24
- package/src/table-tile-source.ts +553 -0
- package/src/tilejson-loader.ts +2 -2
- package/dist/geojson-tile-source.d.ts +0 -79
- package/dist/geojson-tile-source.d.ts.map +0 -1
- package/dist/geojson-tile-source.js +0 -319
- package/dist/lib/geojsonvt/clip.d.ts.map +0 -1
- package/dist/lib/geojsonvt/convert.d.ts +0 -10
- package/dist/lib/geojsonvt/convert.d.ts.map +0 -1
- package/dist/lib/geojsonvt/convert.js +0 -132
- package/dist/lib/geojsonvt/feature.d.ts +0 -3
- package/dist/lib/geojsonvt/feature.d.ts.map +0 -1
- package/dist/lib/geojsonvt/feature.js +0 -44
- package/dist/lib/geojsonvt/simplify.d.ts.map +0 -1
- package/dist/lib/geojsonvt/tile.d.ts +0 -38
- package/dist/lib/geojsonvt/tile.d.ts.map +0 -1
- package/dist/lib/geojsonvt/tile.js +0 -123
- package/dist/lib/geojsonvt/transform.d.ts +0 -7
- package/dist/lib/geojsonvt/transform.d.ts.map +0 -1
- package/dist/lib/geojsonvt/transform.js +0 -41
- package/dist/lib/geojsonvt/wrap.d.ts.map +0 -1
- package/src/geojson-tile-source.ts +0 -422
- package/src/lib/geojsonvt/convert.ts +0 -160
- package/src/lib/geojsonvt/feature.ts +0 -47
- package/src/lib/geojsonvt/tile.ts +0 -187
- package/src/lib/geojsonvt/transform.ts +0 -57
- /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
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
81
|
-
|
|
74
|
+
toBinaryFeature(
|
|
75
|
+
coordinates: 'wgs84' | 'local',
|
|
76
|
+
tileIndex?: {x: number; y: number; z: number}
|
|
82
77
|
): FlatFeature {
|
|
83
|
-
|
|
84
|
-
|
|
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(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
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.
|
|
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 {
|
|
7
|
-
import {
|
|
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
|
|
24
|
-
features:
|
|
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
|
-
):
|
|
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:
|
|
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(
|
|
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(
|
|
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
|
|
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)
|
|
49
|
+
if (index - first > 3) simplifyPath(coords, first, index, sqTolerance);
|
|
45
50
|
coords[index + 2] = maxSqDist;
|
|
46
|
-
if (last - index > 3)
|
|
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 {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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
|
|
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
|
|
21
|
+
* @param list of features to be wrapped
|
|
22
22
|
* @param options buffer and extent
|
|
23
23
|
* @returns
|
|
24
24
|
*/
|
|
25
|
-
export function
|
|
25
|
+
export function wrapFeatures(
|
|
26
|
+
features: ProtoFeature[],
|
|
27
|
+
options: WrapFeaturesOptions
|
|
28
|
+
): ProtoFeature[] {
|
|
26
29
|
const buffer = options.buffer / options.extent;
|
|
27
|
-
let merged:
|
|
28
|
-
const left =
|
|
29
|
-
const right =
|
|
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 =
|
|
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:
|
|
52
|
-
const newFeatures:
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
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
|
-
|
|
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(
|
|
94
|
+
newFeatures.push(createProtoFeature(feature.id, type, newGeometry, feature.tags));
|
|
80
95
|
}
|
|
81
96
|
|
|
82
97
|
return newFeatures;
|