itowns 2.44.3-next.3 → 2.44.3-next.31
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/CODING.md +1 -1
- package/CONTRIBUTORS.md +1 -0
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/itowns.js +1 -1
- package/dist/itowns.js.LICENSE.txt +0 -2
- package/dist/itowns.js.map +1 -1
- package/dist/itowns_widgets.js +1 -1
- package/dist/itowns_widgets.js.map +1 -1
- package/examples/3dtiles_loader.html +109 -45
- package/examples/config.json +3 -10
- package/examples/entwine_3d_loader.html +3 -1
- package/examples/entwine_simple_loader.html +1 -1
- package/examples/images/itowns_logo.svg +123 -0
- package/examples/js/plugins/COGParser.js +1 -1
- package/examples/jsm/OGC3DTilesHelper.js +1 -1
- package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
- package/examples/source_file_geojson_3d.html +0 -1
- package/examples/source_file_kml_raster_usgs.html +0 -1
- package/examples/source_stream_wfs_raster.html +0 -7
- package/examples/vector_tile_mapbox_raster.html +91 -0
- package/lib/Controls/GlobeControls.js +45 -28
- package/lib/Controls/StateControl.js +5 -2
- package/lib/Converter/Feature2Mesh.js +10 -4
- package/lib/Converter/Feature2Texture.js +6 -1
- package/lib/Converter/convertToTile.js +3 -8
- package/lib/Converter/textureConverter.js +3 -4
- package/lib/Core/Deprecated/Undeprecator.js +0 -1
- package/lib/Core/Feature.js +1 -2
- package/lib/Core/Geographic/Coordinates.js +143 -132
- package/lib/Core/Geographic/Crs.js +140 -145
- package/lib/Core/Geographic/Extent.js +72 -267
- package/lib/Core/Geographic/GeoidGrid.js +1 -1
- package/lib/Core/Math/Ellipsoid.js +62 -21
- package/lib/Core/Prefab/Globe/Atmosphere.js +4 -8
- package/lib/Core/Prefab/Globe/GlobeLayer.js +22 -15
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
- package/lib/Core/Prefab/GlobeView.js +2 -7
- package/lib/Core/Prefab/Planar/PlanarLayer.js +17 -11
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
- package/lib/Core/Prefab/TileBuilder.js +27 -32
- package/lib/Core/Prefab/computeBufferTileGeometry.js +189 -130
- package/lib/Core/Style.js +60 -42
- package/lib/Core/Tile/Tile.js +219 -0
- package/lib/Core/Tile/TileGrid.js +43 -0
- package/lib/Core/TileGeometry.js +112 -28
- package/lib/Core/TileMesh.js +3 -3
- package/lib/Core/View.js +15 -8
- package/lib/Layer/C3DTilesLayer.js +20 -16
- package/lib/Layer/ColorLayer.js +35 -9
- package/lib/Layer/CopcLayer.js +5 -0
- package/lib/Layer/ElevationLayer.js +39 -7
- package/lib/Layer/EntwinePointTileLayer.js +12 -5
- package/lib/Layer/FeatureGeometryLayer.js +20 -6
- package/lib/Layer/GeometryLayer.js +42 -11
- package/lib/Layer/LabelLayer.js +45 -27
- package/lib/Layer/Layer.js +83 -57
- package/lib/Layer/OGC3DTilesLayer.js +81 -30
- package/lib/Layer/OrientedImageLayer.js +11 -5
- package/lib/Layer/PointCloudLayer.js +74 -30
- package/lib/Layer/Potree2Layer.js +7 -2
- package/lib/Layer/PotreeLayer.js +8 -3
- package/lib/Layer/RasterLayer.js +12 -2
- package/lib/Layer/TiledGeometryLayer.js +69 -13
- package/lib/Main.js +2 -2
- package/lib/Parser/GeoJsonParser.js +1 -1
- package/lib/Parser/VectorTileParser.js +42 -29
- package/lib/Parser/XbilParser.js +14 -2
- package/lib/Provider/Fetcher.js +5 -1
- package/lib/Provider/URLBuilder.js +22 -11
- package/lib/Renderer/Camera.js +1 -1
- package/lib/Renderer/Label2DRenderer.js +9 -7
- package/lib/Renderer/OBB.js +11 -13
- package/lib/Renderer/PointsMaterial.js +1 -1
- package/lib/Renderer/RasterTile.js +1 -2
- package/lib/Renderer/SphereHelper.js +0 -6
- package/lib/Source/CopcSource.js +13 -2
- package/lib/Source/EntwinePointTileSource.js +14 -4
- package/lib/Source/FileSource.js +1 -4
- package/lib/Source/Source.js +1 -4
- package/lib/Source/TMSSource.js +10 -9
- package/lib/Source/VectorTilesSource.js +32 -22
- package/lib/Source/WFSSource.js +15 -10
- package/lib/Source/WMSSource.js +56 -18
- package/lib/Source/WMTSSource.js +13 -7
- package/lib/Utils/CameraUtils.js +1 -1
- package/lib/Utils/gui/C3DTilesStyle.js +2 -3
- package/lib/Utils/placeObjectOnGround.js +0 -1
- package/package.json +13 -6
- package/examples/3dtiles_25d.html +0 -120
- package/examples/3dtiles_basic.html +0 -94
- package/examples/3dtiles_batch_table.html +0 -86
- package/examples/3dtiles_ion.html +0 -126
- package/examples/3dtiles_pointcloud.html +0 -95
- package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
|
@@ -3,14 +3,52 @@ export function getBufferIndexSize(segments, noSkirt) {
|
|
|
3
3
|
const triangles = segments * segments * 2 + (noSkirt ? 0 : 4 * segments * 2);
|
|
4
4
|
return triangles * 3;
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
function getUintArrayConstructor(highestValue) {
|
|
7
|
+
let picked = null;
|
|
8
|
+
if (highestValue < 2 ** 8) {
|
|
9
|
+
picked = Uint8Array;
|
|
10
|
+
} else if (highestValue < 2 ** 16) {
|
|
11
|
+
picked = Uint16Array;
|
|
12
|
+
} else if (highestValue < 2 ** 32) {
|
|
13
|
+
picked = Uint32Array;
|
|
14
|
+
} else {
|
|
15
|
+
throw new Error('Value is too high');
|
|
16
|
+
}
|
|
17
|
+
return picked;
|
|
18
|
+
}
|
|
19
|
+
function allocateIndexBuffer(nVertex, nSeg, params) {
|
|
20
|
+
if (!params.buildIndexAndUv_0) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const indexBufferSize = getBufferIndexSize(nSeg, params.disableSkirt);
|
|
24
|
+
const indexConstructor = getUintArrayConstructor(nVertex);
|
|
25
|
+
const tileLen = indexBufferSize;
|
|
26
|
+
const skirtLen = 4 * nSeg;
|
|
27
|
+
const indexBuffer = new ArrayBuffer((
|
|
28
|
+
// Tile
|
|
29
|
+
tileLen
|
|
30
|
+
// Skirt
|
|
31
|
+
+ (params.disableSkirt ? 0 : skirtLen)) * indexConstructor.BYTES_PER_ELEMENT);
|
|
32
|
+
const index = new indexConstructor(indexBuffer);
|
|
33
|
+
const skirt = !params.disableSkirt ? index.subarray(tileLen, tileLen + skirtLen) : undefined;
|
|
34
|
+
return {
|
|
35
|
+
index,
|
|
36
|
+
skirt
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function allocateBuffers(nVertex, nSeg, builder, params) {
|
|
40
|
+
const {
|
|
41
|
+
index,
|
|
42
|
+
skirt
|
|
43
|
+
} = allocateIndexBuffer(nVertex, nSeg, params) ?? {};
|
|
44
|
+
return {
|
|
45
|
+
index,
|
|
46
|
+
skirt,
|
|
47
|
+
position: new Float32Array(nVertex * 3),
|
|
48
|
+
normal: new Float32Array(nVertex * 3),
|
|
49
|
+
// 2 UV set per tile: wgs84 (uv[0]) and pseudo-mercator (pm, uv[1])
|
|
50
|
+
// - wgs84: 1 texture per tile because tiles are using wgs84
|
|
51
|
+
// projection
|
|
14
52
|
// - pm: use multiple textures per tile.
|
|
15
53
|
// +-------------------------+
|
|
16
54
|
// | |
|
|
@@ -24,142 +62,157 @@ export default function computeBuffers(params) {
|
|
|
24
62
|
// +-------------------------+
|
|
25
63
|
// * u = wgs84.u
|
|
26
64
|
// * v = textureid + v in builder texture
|
|
27
|
-
uvs: []
|
|
65
|
+
uvs: [params.buildIndexAndUv_0 ? new Float32Array(nVertex * 2) : undefined, builder.computeExtraOffset !== undefined ? new Float32Array(nVertex) : undefined]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function computeUv0(uv, id, u, v) {
|
|
69
|
+
uv[id * 2 + 0] = u;
|
|
70
|
+
uv[id * 2 + 1] = v;
|
|
71
|
+
}
|
|
72
|
+
function initComputeUv1(value) {
|
|
73
|
+
return (uv, id) => {
|
|
74
|
+
uv[id] = value;
|
|
28
75
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
76
|
+
}
|
|
77
|
+
/** Compute buffers describing a tile according to a builder and its params. */
|
|
78
|
+
// TODO: Split this even further into subfunctions
|
|
79
|
+
export function computeBuffers(builder, params) {
|
|
80
|
+
// n seg, n+1 vert + <- skirt, n verts per side
|
|
81
|
+
// <---------------> / |
|
|
82
|
+
// +---+---+---+---+ |
|
|
83
|
+
// | / | / | / | / | | Vertices:
|
|
84
|
+
// +---+---+---+---+ - + tile = (n + 1)^2
|
|
85
|
+
// | / | / | / | / | | skirt = 4n
|
|
86
|
+
// +---+---+---+---+ - +
|
|
87
|
+
// | / | / | / | / | | Segments:
|
|
88
|
+
// +---+---+---+---+ - + tile = 2 * n * (n + 1) + n^2
|
|
89
|
+
// | / | / | / | / | | skirt = 2n * 4
|
|
90
|
+
// +---+---+---+---+ |
|
|
91
|
+
const nSeg = Math.max(2, params.segments);
|
|
92
|
+
const nVertex = nSeg + 1;
|
|
93
|
+
const nTileVertex = nVertex ** 2;
|
|
94
|
+
const nSkirtVertex = params.disableSkirt ? 0 : 4 * nSeg;
|
|
95
|
+
const nTotalVertex = nTileVertex + nSkirtVertex;
|
|
96
|
+
|
|
97
|
+
// Computer should combust before this happens
|
|
98
|
+
if (nTotalVertex > 2 ** 32) {
|
|
37
99
|
throw new Error('Tile segments count is too big');
|
|
38
100
|
}
|
|
39
|
-
outBuffers
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (params.buildIndexAndUv_0) {
|
|
48
|
-
if (nVertex < 2 ** 8) {
|
|
49
|
-
outBuffers.index = new Uint8Array(bufferIndexSize);
|
|
50
|
-
} else if (nVertex < 2 ** 16) {
|
|
51
|
-
outBuffers.index = new Uint16Array(bufferIndexSize);
|
|
52
|
-
} else if (nVertex < 2 ** 32) {
|
|
53
|
-
outBuffers.index = new Uint32Array(bufferIndexSize);
|
|
101
|
+
const outBuffers = allocateBuffers(nTotalVertex, nSeg, builder, params);
|
|
102
|
+
const computeUvs = [params.buildIndexAndUv_0 ? computeUv0 : () => {}];
|
|
103
|
+
params = builder.prepare(params);
|
|
104
|
+
for (let y = 0; y <= nSeg; y++) {
|
|
105
|
+
const v = y / nSeg;
|
|
106
|
+
params.coordinates.y = builder.vProject(v, params.extent);
|
|
107
|
+
if (builder.computeExtraOffset !== undefined) {
|
|
108
|
+
computeUvs[1] = initComputeUv1(builder.computeExtraOffset(params));
|
|
54
109
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const widthSegments = Math.max(2, Math.floor(nSeg) || 2);
|
|
62
|
-
const heightSegments = Math.max(2, Math.floor(nSeg) || 2);
|
|
63
|
-
let idVertex = 0;
|
|
64
|
-
const vertices = [];
|
|
65
|
-
let skirt = [];
|
|
66
|
-
const skirtEnd = [];
|
|
67
|
-
builder.prepare(params);
|
|
68
|
-
for (let y = 0; y <= heightSegments; y++) {
|
|
69
|
-
const verticesRow = [];
|
|
70
|
-
const v = y / heightSegments;
|
|
71
|
-
builder.vProjecte(v, params);
|
|
72
|
-
if (uvCount > 1) {
|
|
73
|
-
const u = builder.computeUvs[1](params);
|
|
74
|
-
computeUvs[1] = id => {
|
|
75
|
-
outBuffers.uvs[1][id] = u;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
for (let x = 0; x <= widthSegments; x++) {
|
|
79
|
-
const u = x / widthSegments;
|
|
80
|
-
const id_m3 = idVertex * 3;
|
|
81
|
-
builder.uProjecte(u, params);
|
|
82
|
-
const vertex = builder.vertexPosition(params, params.projected);
|
|
83
|
-
const normal = builder.vertexNormal(params);
|
|
110
|
+
for (let x = 0; x <= nSeg; x++) {
|
|
111
|
+
const u = x / nSeg;
|
|
112
|
+
const id_m3 = (y * nVertex + x) * 3;
|
|
113
|
+
params.coordinates.x = builder.uProject(u, params.extent);
|
|
114
|
+
const vertex = builder.vertexPosition(params.coordinates);
|
|
115
|
+
const normal = builder.vertexNormal();
|
|
84
116
|
|
|
85
117
|
// move geometry to center world
|
|
86
118
|
vertex.sub(params.center);
|
|
87
119
|
|
|
88
120
|
// align normal to z axis
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
121
|
+
// HACK: this check style is not great
|
|
122
|
+
if ('quatNormalToZ' in params) {
|
|
123
|
+
const quat = params.quatNormalToZ;
|
|
124
|
+
vertex.applyQuaternion(quat);
|
|
125
|
+
normal.applyQuaternion(quat);
|
|
92
126
|
}
|
|
93
127
|
vertex.toArray(outBuffers.position, id_m3);
|
|
94
128
|
normal.toArray(outBuffers.normal, id_m3);
|
|
95
|
-
for (const computeUv of computeUvs) {
|
|
96
|
-
computeUv
|
|
97
|
-
|
|
98
|
-
if (!params.disableSkirt) {
|
|
99
|
-
if (y !== 0 && y !== heightSegments) {
|
|
100
|
-
if (x === widthSegments) {
|
|
101
|
-
skirt.push(idVertex);
|
|
102
|
-
} else if (x === 0) {
|
|
103
|
-
skirtEnd.push(idVertex);
|
|
104
|
-
}
|
|
129
|
+
for (const [index, computeUv] of computeUvs.entries()) {
|
|
130
|
+
if (computeUv !== undefined) {
|
|
131
|
+
computeUv(outBuffers.uvs[index], y * nVertex + x, u, v);
|
|
105
132
|
}
|
|
106
133
|
}
|
|
107
|
-
verticesRow.push(idVertex);
|
|
108
|
-
idVertex++;
|
|
109
|
-
}
|
|
110
|
-
vertices.push(verticesRow);
|
|
111
|
-
if (y === 0) {
|
|
112
|
-
skirt = skirt.concat(verticesRow);
|
|
113
|
-
} else if (y === heightSegments) {
|
|
114
|
-
skirt = skirt.concat(verticesRow.slice().reverse());
|
|
115
134
|
}
|
|
116
135
|
}
|
|
117
|
-
|
|
118
|
-
|
|
136
|
+
|
|
137
|
+
// Fill skirt index buffer
|
|
138
|
+
if (params.buildIndexAndUv_0 && !params.disableSkirt) {
|
|
139
|
+
for (let x = 0; x < nVertex; x++) {
|
|
140
|
+
// -------->
|
|
141
|
+
// 0---1---2
|
|
142
|
+
// | / | / | [0-9] = assign order
|
|
143
|
+
// +---+---+
|
|
144
|
+
// | / | / |
|
|
145
|
+
// +---+---+
|
|
146
|
+
outBuffers.skirt[x] = x;
|
|
147
|
+
// +---+---+
|
|
148
|
+
// | / | / | [0-9] = assign order
|
|
149
|
+
// +---+---x x = skipped for now
|
|
150
|
+
// | / | / |
|
|
151
|
+
// 0---1---2
|
|
152
|
+
// <--------
|
|
153
|
+
outBuffers.skirt[2 * nVertex - 2 + x] = nVertex ** 2 - (x + 1);
|
|
154
|
+
}
|
|
155
|
+
for (let y = 1; y < nVertex - 1; y++) {
|
|
156
|
+
// +---+---s |
|
|
157
|
+
// | / | / | | o = stored vertices
|
|
158
|
+
// +---+---o | s = already stored
|
|
159
|
+
// | / | / | |
|
|
160
|
+
// +---+---s v
|
|
161
|
+
outBuffers.skirt[nVertex - 1 + y] = y * nVertex + (nVertex - 1);
|
|
162
|
+
// ^ s---+---+
|
|
163
|
+
// | | / | / | o = stored vertices
|
|
164
|
+
// | o---+---+ s = already stored
|
|
165
|
+
// | | / | / |
|
|
166
|
+
// | s---+---+
|
|
167
|
+
outBuffers.skirt[3 * nVertex - 3 + y] = nVertex * (nVertex - 1 - y);
|
|
168
|
+
}
|
|
119
169
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
outBuffers.index[
|
|
124
|
-
|
|
170
|
+
|
|
171
|
+
/** Copy passed indices at the desired index of the output index buffer. */
|
|
172
|
+
function bufferizeTri(id, va, vb, vc) {
|
|
173
|
+
outBuffers.index[id + 0] = va;
|
|
174
|
+
outBuffers.index[id + 1] = vb;
|
|
175
|
+
outBuffers.index[id + 2] = vc;
|
|
125
176
|
}
|
|
126
|
-
let idVertex2 = 0;
|
|
127
177
|
if (params.buildIndexAndUv_0) {
|
|
128
|
-
for (let y = 0; y <
|
|
129
|
-
for (let x = 0; x <
|
|
130
|
-
const v1 =
|
|
131
|
-
const v2 =
|
|
132
|
-
const v3 =
|
|
133
|
-
const v4 =
|
|
134
|
-
|
|
135
|
-
|
|
178
|
+
for (let y = 0; y < nSeg; y++) {
|
|
179
|
+
for (let x = 0; x < nSeg; x++) {
|
|
180
|
+
const v1 = y * nVertex + (x + 1);
|
|
181
|
+
const v2 = y * nVertex + x;
|
|
182
|
+
const v3 = (y + 1) * nVertex + x;
|
|
183
|
+
const v4 = (y + 1) * nVertex + (x + 1);
|
|
184
|
+
const id = (y * nSeg + x) * 6;
|
|
185
|
+
bufferizeTri(id, /**/v4, v2, v1);
|
|
186
|
+
bufferizeTri(id + 3, v4, v3, v2);
|
|
136
187
|
}
|
|
137
188
|
}
|
|
138
189
|
}
|
|
139
|
-
const iStart = idVertex;
|
|
140
190
|
|
|
141
|
-
//
|
|
142
|
-
// The size of the skirt is now a ratio of the size of the tile.
|
|
143
|
-
// To be perfect it should depend on the real elevation delta but too heavy
|
|
144
|
-
|
|
145
|
-
|
|
191
|
+
// PERF: Beware skirt's size influences performance
|
|
192
|
+
// INFO: The size of the skirt is now a ratio of the size of the tile.
|
|
193
|
+
// To be perfect it should depend on the real elevation delta but too heavy
|
|
194
|
+
// to compute
|
|
195
|
+
if (params.buildIndexAndUv_0 && !params.disableSkirt) {
|
|
196
|
+
// We compute the actual size of tile segment to use later for
|
|
197
|
+
// the skirt.
|
|
146
198
|
const segmentSize = new THREE.Vector3().fromArray(outBuffers.position).distanceTo(new THREE.Vector3().fromArray(outBuffers.position, 3));
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
id
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
199
|
+
const buildSkirt = {
|
|
200
|
+
index: (id, v1, v2, v3, v4) => {
|
|
201
|
+
bufferizeTri(id, v1, v2, v3);
|
|
202
|
+
bufferizeTri(id + 3, v1, v3, v4);
|
|
203
|
+
return id + 6;
|
|
204
|
+
},
|
|
205
|
+
uv: (buf, idTo, idFrom) => {
|
|
206
|
+
buf[idTo * 2 + 0] = buf[idFrom * 2 + 0];
|
|
207
|
+
buf[idTo * 2 + 1] = buf[idFrom * 2 + 1];
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Alias for readability
|
|
212
|
+
const start = nTileVertex;
|
|
213
|
+
for (let i = 0; i < outBuffers.skirt.length; i++) {
|
|
214
|
+
const id = outBuffers.skirt[i];
|
|
215
|
+
const id_m3 = (start + i) * 3;
|
|
163
216
|
const id2_m3 = id * 3;
|
|
164
217
|
outBuffers.position[id_m3 + 0] = outBuffers.position[id2_m3 + 0] - outBuffers.normal[id2_m3 + 0] * segmentSize;
|
|
165
218
|
outBuffers.position[id_m3 + 1] = outBuffers.position[id2_m3 + 1] - outBuffers.normal[id2_m3 + 1] * segmentSize;
|
|
@@ -167,17 +220,23 @@ export default function computeBuffers(params) {
|
|
|
167
220
|
outBuffers.normal[id_m3 + 0] = outBuffers.normal[id2_m3 + 0];
|
|
168
221
|
outBuffers.normal[id_m3 + 1] = outBuffers.normal[id2_m3 + 1];
|
|
169
222
|
outBuffers.normal[id_m3 + 2] = outBuffers.normal[id2_m3 + 2];
|
|
170
|
-
|
|
171
|
-
if (
|
|
172
|
-
outBuffers.uvs[1][
|
|
223
|
+
buildSkirt.uv(outBuffers.uvs[0], start + i, id);
|
|
224
|
+
if (outBuffers.uvs[1] !== undefined) {
|
|
225
|
+
outBuffers.uvs[1][start + i] = outBuffers.uvs[1][id];
|
|
173
226
|
}
|
|
174
|
-
const idf = (i + 1) % skirt.length;
|
|
175
|
-
const v2 =
|
|
176
|
-
const v3 = idf === 0 ?
|
|
177
|
-
const v4 = skirt[idf];
|
|
178
|
-
|
|
179
|
-
idVertex++;
|
|
227
|
+
const idf = (i + 1) % outBuffers.skirt.length;
|
|
228
|
+
const v2 = start + i;
|
|
229
|
+
const v3 = idf === 0 ? start : start + i + 1;
|
|
230
|
+
const v4 = outBuffers.skirt[idf];
|
|
231
|
+
buildSkirt.index(6 * nSeg ** 2 + i * 6, id, v2, v3, v4);
|
|
180
232
|
}
|
|
181
233
|
}
|
|
182
|
-
|
|
234
|
+
|
|
235
|
+
// Dropping skirt view
|
|
236
|
+
return {
|
|
237
|
+
index: outBuffers.index,
|
|
238
|
+
position: outBuffers.position,
|
|
239
|
+
uvs: outBuffers.uvs,
|
|
240
|
+
normal: outBuffers.normal
|
|
241
|
+
};
|
|
183
242
|
}
|
package/lib/Core/Style.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FEATURE_TYPES } from "./Feature.js";
|
|
2
2
|
import Cache from "./Scheduler/Cache.js";
|
|
3
3
|
import Fetcher from "../Provider/Fetcher.js";
|
|
4
|
-
import * as
|
|
4
|
+
import * as maplibre from '@maplibre/maplibre-gl-style-spec';
|
|
5
5
|
import { Color } from 'three';
|
|
6
6
|
import { deltaE } from "../Renderer/Color.js";
|
|
7
7
|
import Coordinates from "./Geographic/Coordinates.js";
|
|
@@ -73,8 +73,8 @@ function rgba2rgb(orig) {
|
|
|
73
73
|
}
|
|
74
74
|
function readVectorProperty(property, options) {
|
|
75
75
|
if (property != undefined) {
|
|
76
|
-
if (
|
|
77
|
-
return
|
|
76
|
+
if (maplibre.expression.isExpression(property)) {
|
|
77
|
+
return maplibre.expression.createExpression(property, options).value;
|
|
78
78
|
} else {
|
|
79
79
|
return property;
|
|
80
80
|
}
|
|
@@ -90,18 +90,18 @@ async function loadImage(source) {
|
|
|
90
90
|
}
|
|
91
91
|
return (await promise).image;
|
|
92
92
|
}
|
|
93
|
-
function cropImage(img) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
canvas.width =
|
|
99
|
-
canvas.height =
|
|
93
|
+
function cropImage(img, cropValues) {
|
|
94
|
+
const x = cropValues.x || 0;
|
|
95
|
+
const y = cropValues.y || 0;
|
|
96
|
+
const width = cropValues.width || img.naturalWidth;
|
|
97
|
+
const height = cropValues.height || img.naturalHeight;
|
|
98
|
+
canvas.width = width;
|
|
99
|
+
canvas.height = height;
|
|
100
100
|
const ctx = canvas.getContext('2d', {
|
|
101
101
|
willReadFrequently: true
|
|
102
102
|
});
|
|
103
|
-
ctx.drawImage(img,
|
|
104
|
-
return ctx.getImageData(0, 0,
|
|
103
|
+
ctx.drawImage(img, x, y, width, height, 0, 0, width, height);
|
|
104
|
+
return ctx.getImageData(0, 0, width, height);
|
|
105
105
|
}
|
|
106
106
|
function replaceWhitePxl(imgd, color, id) {
|
|
107
107
|
if (!color) {
|
|
@@ -166,7 +166,7 @@ function defineStyleProperty(style, category, parameter, userValue, defaultValue
|
|
|
166
166
|
return readExpression(dataValue, style.context);
|
|
167
167
|
}
|
|
168
168
|
if (defaultValue instanceof Function) {
|
|
169
|
-
return defaultValue(style.context.properties, style.context);
|
|
169
|
+
return defaultValue(style.context.properties, style.context) ?? defaultValue;
|
|
170
170
|
}
|
|
171
171
|
return defaultValue;
|
|
172
172
|
},
|
|
@@ -294,15 +294,12 @@ function _addIcon(icon, domElement, opt) {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/**
|
|
297
|
-
* An object that can contain any properties (
|
|
297
|
+
* An object that can contain any properties (zoom, fill, stroke, point,
|
|
298
298
|
* text or/and icon) and sub properties of a Style.<br/>
|
|
299
299
|
* Used for the instanciation of a {@link Style}.
|
|
300
300
|
*
|
|
301
301
|
* @typedef {Object} StyleOptions
|
|
302
302
|
*
|
|
303
|
-
* @property {Number} [order] - Order of the features that will be associated to
|
|
304
|
-
* the style. It can helps sorting and prioritizing features if needed.
|
|
305
|
-
*
|
|
306
303
|
* @property {Object} [zoom] - Level on which to display the feature
|
|
307
304
|
* @property {Number} [zoom.max] - max level
|
|
308
305
|
* @property {Number} [zoom.min] - min level
|
|
@@ -460,8 +457,6 @@ function _addIcon(icon, domElement, opt) {
|
|
|
460
457
|
* The first parameter of functions used to set `Style` properties is always an object containing
|
|
461
458
|
* the properties of the features displayed with the current `Style` instance.
|
|
462
459
|
*
|
|
463
|
-
* @property {Number} order - Order of the features that will be associated to
|
|
464
|
-
* the style. It can helps sorting and prioritizing features if needed.
|
|
465
460
|
* @property {Object} fill - Polygons and fillings style.
|
|
466
461
|
* @property {String|Function|THREE.Color} fill.color - Defines the main color of the filling. Can be
|
|
467
462
|
* any [valid color
|
|
@@ -611,14 +606,13 @@ function _addIcon(icon, domElement, opt) {
|
|
|
611
606
|
class Style {
|
|
612
607
|
/**
|
|
613
608
|
* @param {StyleOptions} [params={}] An object that contain any properties
|
|
614
|
-
* (
|
|
609
|
+
* (zoom, fill, stroke, point, text or/and icon)
|
|
615
610
|
* and sub properties of a Style ({@link StyleOptions}).
|
|
616
611
|
*/
|
|
617
612
|
constructor() {
|
|
618
613
|
let params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
619
614
|
this.isStyle = true;
|
|
620
615
|
this.context = new StyleContext();
|
|
621
|
-
this.order = params.order || 0;
|
|
622
616
|
params.zoom = params.zoom || {};
|
|
623
617
|
params.fill = params.fill || {};
|
|
624
618
|
params.stroke = params.stroke || {};
|
|
@@ -783,14 +777,12 @@ class Style {
|
|
|
783
777
|
* set Style from vector tile layer properties.
|
|
784
778
|
* @param {Object} layer vector tile layer.
|
|
785
779
|
* @param {Object} sprites vector tile layer.
|
|
786
|
-
* @param {Number} [order=0]
|
|
787
780
|
* @param {Boolean} [symbolToCircle=false]
|
|
788
781
|
*
|
|
789
782
|
* @returns {StyleOptions} containing all properties for itowns.Style
|
|
790
783
|
*/
|
|
791
784
|
static setFromVectorTileLayer(layer, sprites) {
|
|
792
|
-
let
|
|
793
|
-
let symbolToCircle = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
785
|
+
let symbolToCircle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
794
786
|
const style = {
|
|
795
787
|
fill: {},
|
|
796
788
|
stroke: {},
|
|
@@ -800,7 +792,6 @@ class Style {
|
|
|
800
792
|
};
|
|
801
793
|
layer.layout = layer.layout || {};
|
|
802
794
|
layer.paint = layer.paint || {};
|
|
803
|
-
style.order = order;
|
|
804
795
|
if (layer.type === 'fill') {
|
|
805
796
|
const {
|
|
806
797
|
color,
|
|
@@ -832,7 +823,8 @@ class Style {
|
|
|
832
823
|
style.stroke.color = color;
|
|
833
824
|
style.stroke.opacity = opacity;
|
|
834
825
|
style.stroke.width = 1.0;
|
|
835
|
-
|
|
826
|
+
} else {
|
|
827
|
+
style.stroke.width = 0.0;
|
|
836
828
|
}
|
|
837
829
|
} else if (layer.type === 'line') {
|
|
838
830
|
const prepare = readVectorProperty(layer.paint['line-color'], {
|
|
@@ -858,6 +850,8 @@ class Style {
|
|
|
858
850
|
style.point.opacity = opacity;
|
|
859
851
|
style.point.radius = readVectorProperty(layer.paint['circle-radius']);
|
|
860
852
|
} else if (layer.type === 'symbol') {
|
|
853
|
+
// if symbol we shouldn't draw stroke but defaut value is 1.
|
|
854
|
+
style.stroke.width = 0.0;
|
|
861
855
|
// overlapping order
|
|
862
856
|
style.text.zOrder = readVectorProperty(layer.layout['symbol-z-order']);
|
|
863
857
|
if (style.text.zOrder == 'auto') {
|
|
@@ -878,7 +872,7 @@ class Style {
|
|
|
878
872
|
|
|
879
873
|
// content
|
|
880
874
|
style.text.field = readVectorProperty(layer.layout['text-field']);
|
|
881
|
-
style.text.wrap = readVectorProperty(layer.layout['text-max-width']);
|
|
875
|
+
style.text.wrap = readVectorProperty(layer.layout['text-max-width']); // Units ems
|
|
882
876
|
style.text.spacing = readVectorProperty(layer.layout['text-letter-spacing']);
|
|
883
877
|
style.text.transform = readVectorProperty(layer.layout['text-transform']);
|
|
884
878
|
style.text.justify = readVectorProperty(layer.layout['text-justify']);
|
|
@@ -905,6 +899,12 @@ class Style {
|
|
|
905
899
|
// additional icon
|
|
906
900
|
const iconImg = readVectorProperty(layer.layout['icon-image']);
|
|
907
901
|
if (iconImg) {
|
|
902
|
+
const cropValueDefault = {
|
|
903
|
+
x: 0,
|
|
904
|
+
y: 0,
|
|
905
|
+
width: 1,
|
|
906
|
+
height: 1
|
|
907
|
+
};
|
|
908
908
|
try {
|
|
909
909
|
style.icon.id = iconImg;
|
|
910
910
|
if (iconImg.stops) {
|
|
@@ -917,9 +917,15 @@ class Style {
|
|
|
917
917
|
if (stop[1].includes('{')) {
|
|
918
918
|
cropValues = function (p) {
|
|
919
919
|
const id = stop[1].replace(/\{(.+?)\}/g, (a, b) => p[b] || '').trim();
|
|
920
|
-
cropValues
|
|
920
|
+
if (cropValues === undefined) {
|
|
921
|
+
// const warning = `WARNING: "${id}" not found in sprite file`;
|
|
922
|
+
sprites[id] = cropValueDefault; // or return cropValueDefault;
|
|
923
|
+
}
|
|
921
924
|
return sprites[id];
|
|
922
925
|
};
|
|
926
|
+
} else if (cropValues === undefined) {
|
|
927
|
+
// const warning = `WARNING: "${stop[1]}" not found in sprite file`;
|
|
928
|
+
cropValues = cropValueDefault;
|
|
923
929
|
}
|
|
924
930
|
return [stop[0], cropValues];
|
|
925
931
|
})
|
|
@@ -927,24 +933,33 @@ class Style {
|
|
|
927
933
|
style.icon.cropValues = iconCropValue;
|
|
928
934
|
} else {
|
|
929
935
|
style.icon.cropValues = sprites[iconImg];
|
|
930
|
-
if (iconImg
|
|
936
|
+
if (iconImg.includes('{')) {
|
|
931
937
|
style.icon.cropValues = function (p) {
|
|
932
938
|
const id = iconImg.replace(/\{(.+?)\}/g, (a, b) => p[b] || '').trim();
|
|
933
|
-
|
|
939
|
+
if (sprites[id] === undefined) {
|
|
940
|
+
// const warning = `WARNING: "${id}" not found in sprite file`;
|
|
941
|
+
sprites[id] = cropValueDefault; // or return cropValueDefault;
|
|
942
|
+
}
|
|
934
943
|
return sprites[id];
|
|
935
944
|
};
|
|
945
|
+
} else if (sprites[iconImg] === undefined) {
|
|
946
|
+
// const warning = `WARNING: "${iconImg}" not found in sprite file`;
|
|
947
|
+
style.icon.cropValues = cropValueDefault;
|
|
936
948
|
}
|
|
937
949
|
}
|
|
938
950
|
style.icon.source = sprites.source;
|
|
939
|
-
style.icon.size = readVectorProperty(layer.layout['icon-size'])
|
|
951
|
+
style.icon.size = readVectorProperty(layer.layout['icon-size']) ?? 1;
|
|
940
952
|
const {
|
|
941
953
|
color,
|
|
942
954
|
opacity
|
|
943
955
|
} = rgba2rgb(readVectorProperty(layer.paint['icon-color'], {
|
|
944
956
|
type: 'color'
|
|
945
957
|
}));
|
|
946
|
-
style
|
|
947
|
-
|
|
958
|
+
// https://docs.mapbox.com/style-spec/reference/layers/#paint-symbol-icon-color
|
|
959
|
+
if (iconImg.sdf) {
|
|
960
|
+
style.icon.color = color;
|
|
961
|
+
}
|
|
962
|
+
style.icon.opacity = readVectorProperty(layer.paint['icon-opacity']) ?? (opacity !== undefined && opacity);
|
|
948
963
|
} catch (err) {
|
|
949
964
|
err.message = `VTlayer '${layer.id}': argument sprites must not be null when using layer.layout['icon-image']`;
|
|
950
965
|
throw err;
|
|
@@ -970,28 +985,27 @@ class Style {
|
|
|
970
985
|
* @param {Boolean} canBeFilled - true if feature.type == FEATURE_TYPES.POLYGON.
|
|
971
986
|
*/
|
|
972
987
|
applyToCanvasPolygon(txtrCtx, polygon, invCtxScale, canBeFilled) {
|
|
973
|
-
const context = this.context;
|
|
974
988
|
// draw line or edge of polygon
|
|
975
|
-
if (this.stroke) {
|
|
989
|
+
if (this.stroke.width > 0) {
|
|
976
990
|
// TO DO add possibility of using a pattern (https://github.com/iTowns/itowns/issues/2210)
|
|
977
|
-
this._applyStrokeToPolygon(txtrCtx, invCtxScale, polygon
|
|
991
|
+
this._applyStrokeToPolygon(txtrCtx, invCtxScale, polygon);
|
|
978
992
|
}
|
|
979
993
|
|
|
980
994
|
// fill inside of polygon
|
|
981
|
-
if (canBeFilled && this.fill) {
|
|
995
|
+
if (canBeFilled && (this.fill.pattern || this.fill.color)) {
|
|
982
996
|
// canBeFilled can be move to StyleContext in the later PR
|
|
983
|
-
this._applyFillToPolygon(txtrCtx, invCtxScale, polygon
|
|
997
|
+
this._applyFillToPolygon(txtrCtx, invCtxScale, polygon);
|
|
984
998
|
}
|
|
985
999
|
}
|
|
986
1000
|
_applyStrokeToPolygon(txtrCtx, invCtxScale, polygon) {
|
|
987
1001
|
if (txtrCtx.strokeStyle !== this.stroke.color) {
|
|
988
1002
|
txtrCtx.strokeStyle = this.stroke.color;
|
|
989
1003
|
}
|
|
990
|
-
const width =
|
|
1004
|
+
const width = this.stroke.width * invCtxScale;
|
|
991
1005
|
if (txtrCtx.lineWidth !== width) {
|
|
992
1006
|
txtrCtx.lineWidth = width;
|
|
993
1007
|
}
|
|
994
|
-
const alpha = this.stroke.opacity
|
|
1008
|
+
const alpha = this.stroke.opacity;
|
|
995
1009
|
if (alpha !== txtrCtx.globalAlpha && typeof alpha == 'number') {
|
|
996
1010
|
txtrCtx.globalAlpha = alpha;
|
|
997
1011
|
}
|
|
@@ -1006,7 +1020,9 @@ class Style {
|
|
|
1006
1020
|
// need doc for the txtrCtx.fillStyle.src that seems to always be undefined
|
|
1007
1021
|
if (this.fill.pattern) {
|
|
1008
1022
|
let img = this.fill.pattern;
|
|
1009
|
-
const cropValues =
|
|
1023
|
+
const cropValues = {
|
|
1024
|
+
...this.fill.pattern.cropValues
|
|
1025
|
+
};
|
|
1010
1026
|
if (this.fill.pattern.source) {
|
|
1011
1027
|
img = await loadImage(this.fill.pattern.source);
|
|
1012
1028
|
}
|
|
@@ -1074,7 +1090,9 @@ class Style {
|
|
|
1074
1090
|
if (!this.icon.cropValues && !this.icon.color) {
|
|
1075
1091
|
icon.src = this.icon.source;
|
|
1076
1092
|
} else {
|
|
1077
|
-
const cropValues =
|
|
1093
|
+
const cropValues = {
|
|
1094
|
+
...this.icon.cropValues
|
|
1095
|
+
};
|
|
1078
1096
|
const color = this.icon.color;
|
|
1079
1097
|
const id = this.icon.id || this.icon.source;
|
|
1080
1098
|
const img = await loadImage(this.icon.source);
|