@loaders.gl/mvt 4.3.0-alpha.2 → 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 +777 -688
- package/dist/dist.min.js +1 -1
- package/dist/index.cjs +746 -659
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/lib/parse-tilejson.js +1 -1
- package/dist/lib/utils/geometry-utils.js +1 -1
- package/dist/lib/vector-tiler/{clip.d.ts → features/clip-features.d.ts} +4 -4
- package/dist/lib/vector-tiler/features/clip-features.d.ts.map +1 -0
- package/dist/lib/vector-tiler/{clip.js → features/clip-features.js} +4 -4
- package/dist/lib/vector-tiler/{convert.d.ts → features/convert-feature.d.ts} +7 -7
- 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/vector-tiler/{simplify.d.ts → features/simplify-path.d.ts} +2 -2
- package/dist/lib/vector-tiler/features/simplify-path.d.ts.map +1 -0
- package/dist/lib/vector-tiler/{simplify.js → features/simplify-path.js} +3 -3
- package/dist/lib/vector-tiler/{wrap.d.ts → features/wrap-features.d.ts} +5 -5
- package/dist/lib/vector-tiler/features/wrap-features.d.ts.map +1 -0
- package/dist/lib/vector-tiler/{wrap.js → 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.js +1 -1
- package/dist/mvt-source.d.ts +31 -14
- package/dist/mvt-source.d.ts.map +1 -1
- package/dist/mvt-source.js +26 -6
- package/dist/mvt-worker.js +4 -4
- package/dist/table-tile-source.d.ts +66 -36
- package/dist/table-tile-source.d.ts.map +1 -1
- package/dist/table-tile-source.js +167 -117
- package/dist/tilejson-loader.js +1 -1
- package/package.json +6 -6
- package/src/index.ts +13 -6
- package/src/lib/parse-tilejson.ts +1 -1
- package/src/lib/utils/geometry-utils.ts +1 -1
- package/src/lib/vector-tiler/{clip.ts → features/clip-features.ts} +8 -8
- package/src/lib/vector-tiler/{convert.ts → features/convert-feature.ts} +91 -70
- package/src/lib/vector-tiler/features/proto-feature.ts +104 -0
- package/src/lib/vector-tiler/{simplify.ts → features/simplify-path.ts} +8 -3
- package/src/lib/vector-tiler/{wrap.ts → 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 +42 -18
- package/src/table-tile-source.ts +130 -85
- package/src/tilejson-loader.ts +2 -2
- package/dist/lib/vector-tiler/clip.d.ts.map +0 -1
- package/dist/lib/vector-tiler/convert.d.ts.map +0 -1
- package/dist/lib/vector-tiler/convert.js +0 -139
- package/dist/lib/vector-tiler/feature.d.ts +0 -3
- package/dist/lib/vector-tiler/feature.d.ts.map +0 -1
- package/dist/lib/vector-tiler/feature.js +0 -44
- package/dist/lib/vector-tiler/simplify.d.ts.map +0 -1
- package/dist/lib/vector-tiler/tile.d.ts +0 -38
- package/dist/lib/vector-tiler/tile.d.ts.map +0 -1
- package/dist/lib/vector-tiler/tile.js +0 -123
- package/dist/lib/vector-tiler/transform.d.ts +0 -7
- package/dist/lib/vector-tiler/transform.d.ts.map +0 -1
- package/dist/lib/vector-tiler/transform.js +0 -41
- package/dist/lib/vector-tiler/wrap.d.ts.map +0 -1
- package/src/lib/vector-tiler/feature.ts +0 -47
- package/src/lib/vector-tiler/tile.ts +0 -187
- package/src/lib/vector-tiler/transform.ts +0 -57
|
@@ -7,30 +7,10 @@
|
|
|
7
7
|
// @ts-nocheck
|
|
8
8
|
|
|
9
9
|
import type {Feature, FeatureCollection} from '@loaders.gl/schema';
|
|
10
|
-
import type {
|
|
10
|
+
import type {ProtoFeature} from './proto-feature';
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* converts a GeoJSON feature into an intermediate projected JSON vector format
|
|
17
|
-
* with simplification data
|
|
18
|
-
*/
|
|
19
|
-
export function convert(data: Feature | FeatureCollection, options): TableTileFeature[] {
|
|
20
|
-
const features = [];
|
|
21
|
-
if (data.type === 'FeatureCollection') {
|
|
22
|
-
for (let i = 0; i < data.features.length; i++) {
|
|
23
|
-
convertFeature(features, data.features[i], options, i);
|
|
24
|
-
}
|
|
25
|
-
} else if (data.type === 'Feature') {
|
|
26
|
-
convertFeature(features, data, options);
|
|
27
|
-
} else {
|
|
28
|
-
// single geometry or a geometry collection
|
|
29
|
-
convertFeature(features, {geometry: data}, options);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return features;
|
|
33
|
-
}
|
|
12
|
+
import {createProtoFeature} from './proto-feature';
|
|
13
|
+
import {simplifyPath} from './simplify-path';
|
|
34
14
|
|
|
35
15
|
export type ConvertFeatureOptions = {
|
|
36
16
|
/** max zoom to preserve detail on */
|
|
@@ -43,16 +23,43 @@ export type ConvertFeatureOptions = {
|
|
|
43
23
|
lineMetrics?: boolean;
|
|
44
24
|
};
|
|
45
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
|
+
|
|
46
53
|
/**
|
|
47
54
|
* converts a GeoJSON feature into an intermediate projected JSON vector format
|
|
48
55
|
* with simplification data
|
|
49
56
|
*/
|
|
50
57
|
function convertFeature(
|
|
51
|
-
features: TableTileFeature[],
|
|
52
58
|
geojson: Feature,
|
|
53
59
|
options: ConvertFeatureOptions,
|
|
54
60
|
index: number
|
|
55
|
-
):
|
|
61
|
+
): ProtoFeature {
|
|
62
|
+
// GeoJSON geometries can be null, but no vector tile will include them.
|
|
56
63
|
if (!geojson.geometry) {
|
|
57
64
|
return;
|
|
58
65
|
}
|
|
@@ -67,53 +74,67 @@ function convertFeature(
|
|
|
67
74
|
} else if (options.generateId) {
|
|
68
75
|
id = index || 0;
|
|
69
76
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (options.lineMetrics) {
|
|
80
|
-
// explode into linestrings to be able to track metrics
|
|
81
|
-
for (const line of coords) {
|
|
82
|
-
geometry = [];
|
|
83
|
-
convertLine(line, geometry, tolerance, false);
|
|
84
|
-
features.push(createFeature(id, 'LineString', geometry, geojson.properties));
|
|
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);
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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.');
|
|
114
135
|
}
|
|
115
136
|
|
|
116
|
-
|
|
137
|
+
return createProtoFeature(id, type, geometry, geojson.properties);
|
|
117
138
|
}
|
|
118
139
|
|
|
119
140
|
function convertPoint(coords, out): void {
|
|
@@ -143,7 +164,7 @@ function convertLine(ring: number[], out, tolerance: number, isPolygon: boolean)
|
|
|
143
164
|
|
|
144
165
|
const last = out.length - 3;
|
|
145
166
|
out[2] = 1;
|
|
146
|
-
|
|
167
|
+
simplifyPath(out, 0, last, tolerance);
|
|
147
168
|
out[last + 2] = 1;
|
|
148
169
|
|
|
149
170
|
out.size = Math.abs(size);
|
|
@@ -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: TableTileFeature[], 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: TableTileFeature[], offset: number): Table
|
|
|
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;
|
|
@@ -0,0 +1,217 @@
|
|
|
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
|
+
import type {ProtoFeature} from './features/proto-feature';
|
|
7
|
+
|
|
8
|
+
export type ProtoTile = {
|
|
9
|
+
/** Processed features */
|
|
10
|
+
protoFeatures: ProtoFeature[];
|
|
11
|
+
/** if we slice further down, no need to keep source geometry */
|
|
12
|
+
sourceFeatures: ProtoFeature[] | null;
|
|
13
|
+
|
|
14
|
+
/** Properties */
|
|
15
|
+
tags?: Record<string, string>;
|
|
16
|
+
|
|
17
|
+
/** tile x coordinate */
|
|
18
|
+
x: number;
|
|
19
|
+
/** tile y coordinate */
|
|
20
|
+
y: number;
|
|
21
|
+
/** tile z coordinate */
|
|
22
|
+
z: number;
|
|
23
|
+
|
|
24
|
+
/** spatial extent */
|
|
25
|
+
minX: number;
|
|
26
|
+
/** spatial extent */
|
|
27
|
+
maxX: number;
|
|
28
|
+
/** spatial extent */
|
|
29
|
+
minY: number;
|
|
30
|
+
/** spatial extent */
|
|
31
|
+
maxY: number;
|
|
32
|
+
|
|
33
|
+
/** Whether this tile has been transformed */
|
|
34
|
+
transformed: boolean;
|
|
35
|
+
numPoints: number;
|
|
36
|
+
numSimplified: number;
|
|
37
|
+
/** Number of features in this tile */
|
|
38
|
+
numFeatures: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type CreateTileOptions = {
|
|
42
|
+
maxZoom?: number;
|
|
43
|
+
tolerance: number;
|
|
44
|
+
extent: number;
|
|
45
|
+
lineMetrics: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a tile from features and tile index
|
|
50
|
+
*/
|
|
51
|
+
export function createProtoTile(
|
|
52
|
+
features: ProtoFeature[],
|
|
53
|
+
z,
|
|
54
|
+
tx,
|
|
55
|
+
ty,
|
|
56
|
+
options: CreateTileOptions
|
|
57
|
+
): ProtoTile {
|
|
58
|
+
const tolerance = z === options.maxZoom ? 0 : options.tolerance / ((1 << z) * options.extent);
|
|
59
|
+
const tile: ProtoTile = {
|
|
60
|
+
protoFeatures: [],
|
|
61
|
+
sourceFeatures: null,
|
|
62
|
+
numPoints: 0,
|
|
63
|
+
numSimplified: 0,
|
|
64
|
+
numFeatures: features.length,
|
|
65
|
+
x: tx,
|
|
66
|
+
y: ty,
|
|
67
|
+
z,
|
|
68
|
+
transformed: false,
|
|
69
|
+
minX: 2,
|
|
70
|
+
minY: 1,
|
|
71
|
+
maxX: -1,
|
|
72
|
+
maxY: 0
|
|
73
|
+
};
|
|
74
|
+
for (const feature of features) {
|
|
75
|
+
addProtoFeature(tile, feature, tolerance, options);
|
|
76
|
+
}
|
|
77
|
+
return tile;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// eslint-disable-next-line complexity, max-statements
|
|
81
|
+
function addProtoFeature(
|
|
82
|
+
tile: ProtoTile,
|
|
83
|
+
feature: ProtoFeature,
|
|
84
|
+
tolerance: number,
|
|
85
|
+
options: CreateTileOptions
|
|
86
|
+
) {
|
|
87
|
+
const geometry = feature.geometry;
|
|
88
|
+
const type = feature.type;
|
|
89
|
+
const simplifiedGeometry: number[] = [];
|
|
90
|
+
|
|
91
|
+
tile.minX = Math.min(tile.minX, feature.minX);
|
|
92
|
+
tile.minY = Math.min(tile.minY, feature.minY);
|
|
93
|
+
tile.maxX = Math.max(tile.maxX, feature.maxX);
|
|
94
|
+
tile.maxY = Math.max(tile.maxY, feature.maxY);
|
|
95
|
+
|
|
96
|
+
let simplifiedType: 1 | 2 | 3;
|
|
97
|
+
switch (type) {
|
|
98
|
+
case 'Point':
|
|
99
|
+
case 'MultiPoint':
|
|
100
|
+
simplifiedType = 1;
|
|
101
|
+
for (let i = 0; i < geometry.length; i += 3) {
|
|
102
|
+
simplifiedGeometry.push(geometry[i], geometry[i + 1]);
|
|
103
|
+
tile.numPoints++;
|
|
104
|
+
tile.numSimplified++;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
|
|
108
|
+
case 'LineString':
|
|
109
|
+
simplifiedType = 2;
|
|
110
|
+
addProtoLine(simplifiedGeometry, geometry, tile, tolerance, false, false);
|
|
111
|
+
break;
|
|
112
|
+
|
|
113
|
+
case 'MultiLineString':
|
|
114
|
+
simplifiedType = 2;
|
|
115
|
+
for (let i = 0; i < geometry.length; i++) {
|
|
116
|
+
addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, false, i === 0);
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
|
|
120
|
+
case 'Polygon':
|
|
121
|
+
simplifiedType = 3;
|
|
122
|
+
for (let i = 0; i < geometry.length; i++) {
|
|
123
|
+
addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, true, i === 0);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
case 'MultiPolygon':
|
|
128
|
+
simplifiedType = 3;
|
|
129
|
+
for (let k = 0; k < geometry.length; k++) {
|
|
130
|
+
const polygon = geometry[k];
|
|
131
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
132
|
+
addProtoLine(simplifiedGeometry, polygon[i], tile, tolerance, true, i === 0);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
default:
|
|
138
|
+
throw new Error(`Unknown geometry type: ${type}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (simplifiedGeometry.length) {
|
|
142
|
+
let tags: Record<string, unknown> | null = feature.tags || null;
|
|
143
|
+
|
|
144
|
+
if (type === 'LineString' && options.lineMetrics) {
|
|
145
|
+
tags = {};
|
|
146
|
+
for (const key in feature.tags) {
|
|
147
|
+
tags[key] = feature.tags[key];
|
|
148
|
+
}
|
|
149
|
+
// @ts-expect-error adding fields to arrays
|
|
150
|
+
// eslint-disable-next-line camelcase
|
|
151
|
+
tags.mapbox_clip_start = geometry.start / geometry.size;
|
|
152
|
+
// @ts-expect-error adding fields to arrays
|
|
153
|
+
// eslint-disable-next-line camelcase
|
|
154
|
+
tags.mapbox_clip_end = geometry.end / geometry.size;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const tileFeature: ProtoFeature = {
|
|
158
|
+
geometry: simplifiedGeometry,
|
|
159
|
+
simplifiedType,
|
|
160
|
+
// @ts-expect-error
|
|
161
|
+
tags
|
|
162
|
+
};
|
|
163
|
+
if (feature.id !== null) {
|
|
164
|
+
tileFeature.id = feature.id;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
tile.protoFeatures.push(tileFeature);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// eslint-disable-next-line max-params, max-statements
|
|
172
|
+
function addProtoLine(
|
|
173
|
+
result: any[],
|
|
174
|
+
geometry: any,
|
|
175
|
+
tile: ProtoTile,
|
|
176
|
+
tolerance: number,
|
|
177
|
+
isPolygon: boolean,
|
|
178
|
+
isOuter: boolean
|
|
179
|
+
): void {
|
|
180
|
+
const sqTolerance = tolerance * tolerance;
|
|
181
|
+
|
|
182
|
+
if (tolerance > 0 && geometry.size < (isPolygon ? sqTolerance : tolerance)) {
|
|
183
|
+
tile.numPoints += geometry.length / 3;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const ring: number[] = [];
|
|
188
|
+
|
|
189
|
+
for (let i = 0; i < geometry.length; i += 3) {
|
|
190
|
+
if (tolerance === 0 || geometry[i + 2] > sqTolerance) {
|
|
191
|
+
tile.numSimplified++;
|
|
192
|
+
ring.push(geometry[i], geometry[i + 1]);
|
|
193
|
+
}
|
|
194
|
+
tile.numPoints++;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (isPolygon) rewind(ring, isOuter);
|
|
198
|
+
|
|
199
|
+
result.push(ring);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function rewind(ring: number[], clockwise?: boolean): void {
|
|
203
|
+
let area = 0;
|
|
204
|
+
for (let i = 0, j = ring.length - 2; i < ring.length; j = i, i += 2) {
|
|
205
|
+
area += (ring[i] - ring[j]) * (ring[i + 1] + ring[j + 1]);
|
|
206
|
+
}
|
|
207
|
+
if (area > 0 === clockwise) {
|
|
208
|
+
for (let i = 0, len = ring.length; i < len / 2; i += 2) {
|
|
209
|
+
const x = ring[i];
|
|
210
|
+
const y = ring[i + 1];
|
|
211
|
+
ring[i] = ring[len - 2 - i];
|
|
212
|
+
ring[i + 1] = ring[len - 1 - i];
|
|
213
|
+
ring[len - 2 - i] = x;
|
|
214
|
+
ring[len - 1 - i] = y;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|