@loaders.gl/tiles 4.2.0-alpha.4 → 4.2.0-alpha.6
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/constants.js +34 -32
- package/dist/dist.dev.js +679 -449
- package/dist/dist.min.js +9 -0
- package/dist/index.cjs +265 -326
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +10 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts +1 -1
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js +45 -35
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.js +38 -22
- package/dist/tileset/format-i3s/i3s-tile-manager.d.ts +1 -1
- package/dist/tileset/format-i3s/i3s-tile-manager.d.ts.map +1 -1
- package/dist/tileset/format-i3s/i3s-tile-manager.js +68 -69
- package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts +2 -2
- package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts.map +1 -1
- package/dist/tileset/format-i3s/i3s-tileset-traverser.js +79 -57
- package/dist/tileset/helpers/3d-tiles-options.d.ts +1 -1
- package/dist/tileset/helpers/3d-tiles-options.d.ts.map +1 -1
- package/dist/tileset/helpers/3d-tiles-options.js +3 -4
- package/dist/tileset/helpers/bounding-volume.js +269 -128
- package/dist/tileset/helpers/frame-state.d.ts +1 -1
- package/dist/tileset/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset/helpers/frame-state.js +114 -95
- package/dist/tileset/helpers/i3s-lod.d.ts +2 -2
- package/dist/tileset/helpers/i3s-lod.d.ts.map +1 -1
- package/dist/tileset/helpers/i3s-lod.js +68 -39
- package/dist/tileset/helpers/tiles-3d-lod.js +97 -85
- package/dist/tileset/helpers/transform-utils.js +45 -44
- package/dist/tileset/helpers/zoom.d.ts +1 -1
- package/dist/tileset/helpers/zoom.d.ts.map +1 -1
- package/dist/tileset/helpers/zoom.js +70 -40
- package/dist/tileset/tile-3d.d.ts +7 -6
- package/dist/tileset/tile-3d.d.ts.map +1 -1
- package/dist/tileset/tile-3d.js +608 -399
- package/dist/tileset/tileset-3d.d.ts +7 -6
- package/dist/tileset/tileset-3d.d.ts.map +1 -1
- package/dist/tileset/tileset-3d.js +739 -597
- package/dist/tileset/tileset-cache.d.ts +2 -2
- package/dist/tileset/tileset-cache.d.ts.map +1 -1
- package/dist/tileset/tileset-cache.js +65 -48
- package/dist/tileset/tileset-traverser.d.ts +3 -3
- package/dist/tileset/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset/tileset-traverser.js +282 -220
- package/dist/types.js +0 -1
- package/dist/utils/doubly-linked-list-node.js +17 -9
- package/dist/utils/doubly-linked-list.d.ts +1 -1
- package/dist/utils/doubly-linked-list.d.ts.map +1 -1
- package/dist/utils/doubly-linked-list.js +83 -56
- package/dist/utils/managed-array.js +140 -76
- package/package.json +10 -9
- package/src/tileset/tile-3d.ts +1 -1
- package/src/tileset/tileset-3d.ts +1 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-tile-manager.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-tileset-traverser.js.map +0 -1
- package/dist/tileset/helpers/3d-tiles-options.js.map +0 -1
- package/dist/tileset/helpers/bounding-volume.js.map +0 -1
- package/dist/tileset/helpers/frame-state.js.map +0 -1
- package/dist/tileset/helpers/i3s-lod.js.map +0 -1
- package/dist/tileset/helpers/tiles-3d-lod.js.map +0 -1
- package/dist/tileset/helpers/transform-utils.js.map +0 -1
- package/dist/tileset/helpers/zoom.js.map +0 -1
- package/dist/tileset/tile-3d.js.map +0 -1
- package/dist/tileset/tileset-3d.js.map +0 -1
- package/dist/tileset/tileset-cache.js.map +0 -1
- package/dist/tileset/tileset-traverser.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils/doubly-linked-list-node.js.map +0 -1
- package/dist/utils/doubly-linked-list.js.map +0 -1
- package/dist/utils/managed-array.js.map +0 -1
|
@@ -3,107 +3,126 @@ import { CullingVolume, Plane } from '@math.gl/culling';
|
|
|
3
3
|
import { Ellipsoid } from '@math.gl/geospatial';
|
|
4
4
|
const scratchVector = new Vector3();
|
|
5
5
|
const scratchPosition = new Vector3();
|
|
6
|
-
const cullingVolume = new CullingVolume([
|
|
6
|
+
const cullingVolume = new CullingVolume([
|
|
7
|
+
new Plane(),
|
|
8
|
+
new Plane(),
|
|
9
|
+
new Plane(),
|
|
10
|
+
new Plane(),
|
|
11
|
+
new Plane(),
|
|
12
|
+
new Plane()
|
|
13
|
+
]);
|
|
14
|
+
// Extracts a frame state appropriate for tile culling from a deck.gl viewport
|
|
15
|
+
// TODO - this could likely be generalized and merged back into deck.gl for other culling scenarios
|
|
7
16
|
export function getFrameState(viewport, frameNumber) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
cameraUp,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
width,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
17
|
+
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
18
|
+
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
19
|
+
const { cameraDirection, cameraUp, height } = viewport;
|
|
20
|
+
const { metersPerUnit } = viewport.distanceScales;
|
|
21
|
+
// TODO - Ellipsoid.eastNorthUpToFixedFrame() breaks on raw array, create a Vector.
|
|
22
|
+
// TODO - Ellipsoid.eastNorthUpToFixedFrame() takes a cartesian, is that intuitive?
|
|
23
|
+
const viewportCenterCartesian = worldToCartesian(viewport, viewport.center);
|
|
24
|
+
const enuToFixedTransform = Ellipsoid.WGS84.eastNorthUpToFixedFrame(viewportCenterCartesian);
|
|
25
|
+
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
26
|
+
const cameraPositionCartesian = Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, new Vector3());
|
|
27
|
+
// These should still be normalized as the transform has scale 1 (goes from meters to meters)
|
|
28
|
+
const cameraDirectionCartesian = new Vector3(
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
enuToFixedTransform.transformAsVector(new Vector3(cameraDirection).scale(metersPerUnit))).normalize();
|
|
31
|
+
const cameraUpCartesian = new Vector3(
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
enuToFixedTransform.transformAsVector(new Vector3(cameraUp).scale(metersPerUnit))).normalize();
|
|
34
|
+
commonSpacePlanesToWGS84(viewport);
|
|
35
|
+
const ViewportClass = viewport.constructor;
|
|
36
|
+
const { longitude, latitude, width, bearing, zoom } = viewport;
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
const topDownViewport = new ViewportClass({
|
|
39
|
+
longitude,
|
|
40
|
+
latitude,
|
|
41
|
+
height,
|
|
42
|
+
width,
|
|
43
|
+
bearing,
|
|
44
|
+
zoom,
|
|
45
|
+
pitch: 0
|
|
46
|
+
});
|
|
47
|
+
// TODO: make a file/class for frameState and document what needs to be attached to this so that traversal can function
|
|
48
|
+
return {
|
|
49
|
+
camera: {
|
|
50
|
+
position: cameraPositionCartesian,
|
|
51
|
+
direction: cameraDirectionCartesian,
|
|
52
|
+
up: cameraUpCartesian
|
|
53
|
+
},
|
|
54
|
+
viewport,
|
|
55
|
+
topDownViewport,
|
|
56
|
+
height,
|
|
57
|
+
cullingVolume,
|
|
58
|
+
frameNumber, // TODO: This can be the same between updates, what number is unique for between updates?
|
|
59
|
+
sseDenominator: 1.15 // Assumes fovy = 60 degrees
|
|
60
|
+
};
|
|
53
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Limit `tiles` array length with `maximumTilesSelected` number.
|
|
64
|
+
* The criteria for this filtering is distance of a tile center
|
|
65
|
+
* to the `frameState.viewport`'s longitude and latitude
|
|
66
|
+
* @param tiles - tiles array to filter
|
|
67
|
+
* @param frameState - frameState to calculate distances
|
|
68
|
+
* @param maximumTilesSelected - maximal amount of tiles in the output array
|
|
69
|
+
* @returns new tiles array
|
|
70
|
+
*/
|
|
54
71
|
export function limitSelectedTiles(tiles, frameState, maximumTilesSelected) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
longitude: viewportLongitude,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
tuples.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
unselectedTiles
|
|
78
|
-
}
|
|
79
|
-
return [selectedTiles, unselectedTiles];
|
|
72
|
+
if (maximumTilesSelected === 0 || tiles.length <= maximumTilesSelected) {
|
|
73
|
+
return [tiles, []];
|
|
74
|
+
}
|
|
75
|
+
// Accumulate distances in couples array: [tileIndex: number, distanceToViewport: number]
|
|
76
|
+
const tuples = [];
|
|
77
|
+
const { longitude: viewportLongitude, latitude: viewportLatitude } = frameState.viewport;
|
|
78
|
+
for (const [index, tile] of tiles.entries()) {
|
|
79
|
+
const [longitude, latitude] = tile.header.mbs;
|
|
80
|
+
const deltaLon = Math.abs(viewportLongitude - longitude);
|
|
81
|
+
const deltaLat = Math.abs(viewportLatitude - latitude);
|
|
82
|
+
const distance = Math.sqrt(deltaLat * deltaLat + deltaLon * deltaLon);
|
|
83
|
+
tuples.push([index, distance]);
|
|
84
|
+
}
|
|
85
|
+
const tuplesSorted = tuples.sort((a, b) => a[1] - b[1]);
|
|
86
|
+
const selectedTiles = [];
|
|
87
|
+
for (let i = 0; i < maximumTilesSelected; i++) {
|
|
88
|
+
selectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
89
|
+
}
|
|
90
|
+
const unselectedTiles = [];
|
|
91
|
+
for (let i = maximumTilesSelected; i < tuplesSorted.length; i++) {
|
|
92
|
+
unselectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
93
|
+
}
|
|
94
|
+
return [selectedTiles, unselectedTiles];
|
|
80
95
|
}
|
|
81
96
|
function commonSpacePlanesToWGS84(viewport) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
// Extract frustum planes based on current view.
|
|
98
|
+
const frustumPlanes = viewport.getFrustumPlanes();
|
|
99
|
+
// Get the near/far plane centers
|
|
100
|
+
const nearCenterCommon = closestPointOnPlane(frustumPlanes.near, viewport.cameraPosition);
|
|
101
|
+
const nearCenterCartesian = worldToCartesian(viewport, nearCenterCommon);
|
|
102
|
+
const cameraCartesian = worldToCartesian(viewport, viewport.cameraPosition, scratchPosition);
|
|
103
|
+
let i = 0;
|
|
104
|
+
cullingVolume.planes[i++].fromPointNormal(nearCenterCartesian, scratchVector.copy(nearCenterCartesian).subtract(cameraCartesian));
|
|
105
|
+
for (const dir in frustumPlanes) {
|
|
106
|
+
if (dir === 'near') {
|
|
107
|
+
continue; // eslint-disable-line no-continue
|
|
108
|
+
}
|
|
109
|
+
const plane = frustumPlanes[dir];
|
|
110
|
+
const posCommon = closestPointOnPlane(plane, nearCenterCommon, scratchPosition);
|
|
111
|
+
const cartesianPos = worldToCartesian(viewport, posCommon, scratchPosition);
|
|
112
|
+
cullingVolume.planes[i++].fromPointNormal(cartesianPos,
|
|
113
|
+
// Want the normal to point into the frustum since that's what culling expects
|
|
114
|
+
scratchVector.copy(nearCenterCartesian).subtract(cartesianPos));
|
|
91
115
|
}
|
|
92
|
-
const plane = frustumPlanes[dir];
|
|
93
|
-
const posCommon = closestPointOnPlane(plane, nearCenterCommon, scratchPosition);
|
|
94
|
-
const cartesianPos = worldToCartesian(viewport, posCommon, scratchPosition);
|
|
95
|
-
cullingVolume.planes[i++].fromPointNormal(cartesianPos, scratchVector.copy(nearCenterCartesian).subtract(cartesianPos));
|
|
96
|
-
}
|
|
97
116
|
}
|
|
98
|
-
function closestPointOnPlane(plane, refPoint) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
function closestPointOnPlane(plane, refPoint, out = new Vector3()) {
|
|
118
|
+
const distanceToRef = plane.normal.dot(refPoint);
|
|
119
|
+
out
|
|
120
|
+
.copy(plane.normal)
|
|
121
|
+
.scale(plane.distance - distanceToRef)
|
|
122
|
+
.add(refPoint);
|
|
123
|
+
return out;
|
|
103
124
|
}
|
|
104
|
-
function worldToCartesian(viewport, point) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return Ellipsoid.WGS84.cartographicToCartesian(cartographicPos, out);
|
|
125
|
+
function worldToCartesian(viewport, point, out = new Vector3()) {
|
|
126
|
+
const cartographicPos = viewport.unprojectPosition(point);
|
|
127
|
+
return Ellipsoid.WGS84.cartographicToCartesian(cartographicPos, out);
|
|
108
128
|
}
|
|
109
|
-
//# sourceMappingURL=frame-state.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Tile3D } from
|
|
2
|
-
import { FrameState } from
|
|
1
|
+
import { Tile3D } from "../tile-3d.js";
|
|
2
|
+
import { FrameState } from "./frame-state.js";
|
|
3
3
|
/**
|
|
4
4
|
* For the maxScreenThreshold error metric, maxError means that you should replace the node with it's children
|
|
5
5
|
as soon as the nodes bounding sphere has a screen radius larger than maxError pixels.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i3s-lod.d.ts","sourceRoot":"","sources":["../../../src/tileset/helpers/i3s-lod.ts"],"names":[],"mappings":"AAMA,OAAO,EAAC,MAAM,EAAC,
|
|
1
|
+
{"version":3,"file":"i3s-lod.d.ts","sourceRoot":"","sources":["../../../src/tileset/helpers/i3s-lod.ts"],"names":[],"mappings":"AAMA,OAAO,EAAC,MAAM,EAAC,sBAAmB;AAClC,OAAO,EAAC,UAAU,EAAC,yBAAsB;AAUzC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAczF;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CA6C/E"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
1
4
|
import { Matrix4, Vector3 } from '@math.gl/core';
|
|
2
5
|
import { Ellipsoid } from '@math.gl/geospatial';
|
|
3
6
|
const cameraPositionCartesian = new Vector3();
|
|
@@ -7,47 +10,73 @@ const extraVertexEnu = new Vector3();
|
|
|
7
10
|
const projectedOriginVector = new Vector3();
|
|
8
11
|
const enuToCartesianMatrix = new Matrix4();
|
|
9
12
|
const cartesianToEnuMatrix = new Matrix4();
|
|
13
|
+
/**
|
|
14
|
+
* For the maxScreenThreshold error metric, maxError means that you should replace the node with it's children
|
|
15
|
+
as soon as the nodes bounding sphere has a screen radius larger than maxError pixels.
|
|
16
|
+
In this sense a value of 0 means you should always load it's children,
|
|
17
|
+
or if it's a leaf node, you should always display it.
|
|
18
|
+
* @param tile
|
|
19
|
+
* @param frameState
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
10
22
|
export function getLodStatus(tile, frameState) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
if (tile.lodMetricValue === 0 || isNaN(tile.lodMetricValue)) {
|
|
24
|
+
return 'DIG';
|
|
25
|
+
}
|
|
26
|
+
const screenSize = 2 * getProjectedRadius(tile, frameState);
|
|
27
|
+
if (screenSize < 2) {
|
|
28
|
+
return 'OUT';
|
|
29
|
+
}
|
|
30
|
+
if (!tile.header.children || screenSize <= tile.lodMetricValue) {
|
|
31
|
+
return 'DRAW';
|
|
32
|
+
}
|
|
33
|
+
else if (tile.header.children) {
|
|
34
|
+
return 'DIG';
|
|
35
|
+
}
|
|
16
36
|
return 'OUT';
|
|
17
|
-
}
|
|
18
|
-
if (!tile.header.children || screenSize <= tile.lodMetricValue) {
|
|
19
|
-
return 'DRAW';
|
|
20
|
-
} else if (tile.header.children) {
|
|
21
|
-
return 'DIG';
|
|
22
|
-
}
|
|
23
|
-
return 'OUT';
|
|
24
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculate size of MBS radius projected on the screen plane
|
|
40
|
+
* @param tile
|
|
41
|
+
* @param frameState
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
// eslint-disable-next-line max-statements
|
|
25
45
|
export function getProjectedRadius(tile, frameState) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
const { topDownViewport: viewport } = frameState;
|
|
47
|
+
const mbsLat = tile.header.mbs[1];
|
|
48
|
+
const mbsLon = tile.header.mbs[0];
|
|
49
|
+
const mbsZ = tile.header.mbs[2];
|
|
50
|
+
const mbsR = tile.header.mbs[3];
|
|
51
|
+
const mbsCenterCartesian = [...tile.boundingVolume.center];
|
|
52
|
+
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
53
|
+
Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, cameraPositionCartesian);
|
|
54
|
+
// ---------------------------
|
|
55
|
+
// Calculate mbs border vertex
|
|
56
|
+
// ---------------------------
|
|
57
|
+
toEye.copy(cameraPositionCartesian).subtract(mbsCenterCartesian).normalize();
|
|
58
|
+
// Add extra vector to form plane
|
|
59
|
+
Ellipsoid.WGS84.eastNorthUpToFixedFrame(mbsCenterCartesian, enuToCartesianMatrix);
|
|
60
|
+
cartesianToEnuMatrix.copy(enuToCartesianMatrix).invert();
|
|
61
|
+
cameraPositionEnu.copy(cameraPositionCartesian).transform(cartesianToEnuMatrix);
|
|
62
|
+
// Mean Proportionals in Right Triangles - Altitude rule
|
|
63
|
+
// https://mathbitsnotebook.com/Geometry/RightTriangles/RTmeanRight.html
|
|
64
|
+
const projection = Math.sqrt(cameraPositionEnu[0] * cameraPositionEnu[0] + cameraPositionEnu[1] * cameraPositionEnu[1]);
|
|
65
|
+
const extraZ = (projection * projection) / cameraPositionEnu[2];
|
|
66
|
+
extraVertexEnu.copy([cameraPositionEnu[0], cameraPositionEnu[1], extraZ]);
|
|
67
|
+
const extraVertexCartesian = extraVertexEnu.transform(enuToCartesianMatrix);
|
|
68
|
+
const extraVectorCartesian = extraVertexCartesian.subtract(mbsCenterCartesian).normalize();
|
|
69
|
+
// We need radius vector orthogonal to toEye vector
|
|
70
|
+
const radiusVector = toEye.cross(extraVectorCartesian).normalize().scale(mbsR);
|
|
71
|
+
const sphereMbsBorderVertexCartesian = radiusVector.add(mbsCenterCartesian);
|
|
72
|
+
const sphereMbsBorderVertexCartographic = Ellipsoid.WGS84.cartesianToCartographic(sphereMbsBorderVertexCartesian);
|
|
73
|
+
// ---------------------------
|
|
74
|
+
// Project center vertex and border vertex and calculate projected radius of MBS
|
|
75
|
+
const projectedOrigin = viewport.project([mbsLon, mbsLat, mbsZ]);
|
|
76
|
+
const projectedMbsBorderVertex = viewport.project(sphereMbsBorderVertexCartographic);
|
|
77
|
+
const projectedRadius = projectedOriginVector
|
|
78
|
+
.copy(projectedOrigin)
|
|
79
|
+
.subtract(projectedMbsBorderVertex)
|
|
80
|
+
.magnitude();
|
|
81
|
+
return projectedRadius;
|
|
52
82
|
}
|
|
53
|
-
//# sourceMappingURL=i3s-lod.js.map
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
// This file is derived from the Cesium code base under Apache 2 license
|
|
5
|
+
// See LICENSE.md and https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md
|
|
6
|
+
// TODO - Dynamic screen space error provides an optimization when looking at
|
|
7
|
+
// tilesets from above
|
|
8
|
+
/* eslint-disable */
|
|
9
|
+
// @ts-nocheck
|
|
1
10
|
import { Matrix4, Vector3, clamp } from '@math.gl/core';
|
|
2
11
|
const scratchPositionNormal = new Vector3();
|
|
3
12
|
const scratchCartographic = new Vector3();
|
|
@@ -5,96 +14,99 @@ const scratchMatrix = new Matrix4();
|
|
|
5
14
|
const scratchCenter = new Vector3();
|
|
6
15
|
const scratchPosition = new Vector3();
|
|
7
16
|
const scratchDirection = new Vector3();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const tileBoundingVolume = root.contentBoundingVolume;
|
|
24
|
-
if (tileBoundingVolume instanceof TileBoundingRegion) {
|
|
25
|
-
up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
|
|
26
|
-
direction = camera.directionWC;
|
|
27
|
-
height = camera.positionCartographic.height;
|
|
28
|
-
minimumHeight = tileBoundingVolume.minimumHeight;
|
|
29
|
-
maximumHeight = tileBoundingVolume.maximumHeight;
|
|
30
|
-
} else {
|
|
31
|
-
const transformLocal = Matrix4.inverseTransformation(root.computedTransform, scratchMatrix);
|
|
32
|
-
const ellipsoid = mapProjection.ellipsoid;
|
|
33
|
-
const boundingVolume = tileBoundingVolume.boundingVolume;
|
|
34
|
-
const centerLocal = Matrix4.multiplyByPoint(transformLocal, boundingVolume.center, scratchCenter);
|
|
35
|
-
if (Cartesian3.magnitude(centerLocal) > ellipsoid.minimumRadius) {
|
|
36
|
-
const centerCartographic = Cartographic.fromCartesian(centerLocal, ellipsoid, scratchCartographic);
|
|
37
|
-
up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
|
|
38
|
-
direction = camera.directionWC;
|
|
39
|
-
height = camera.positionCartographic.height;
|
|
40
|
-
minimumHeight = 0.0;
|
|
41
|
-
maximumHeight = centerCartographic.height * 2.0;
|
|
42
|
-
} else {
|
|
43
|
-
const positionLocal = Matrix4.multiplyByPoint(transformLocal, camera.positionWC, scratchPosition);
|
|
44
|
-
up = Cartesian3.UNIT_Z;
|
|
45
|
-
direction = Matrix4.multiplyByPointAsVector(transformLocal, camera.directionWC, scratchDirection);
|
|
46
|
-
direction = Cartesian3.normalize(direction, direction);
|
|
47
|
-
height = positionLocal.z;
|
|
48
|
-
if (tileBoundingVolume instanceof TileOrientedBoundingBox) {
|
|
49
|
-
const boxHeight = root._header.boundingVolume.box[11];
|
|
50
|
-
minimumHeight = centerLocal.z - boxHeight;
|
|
51
|
-
maximumHeight = centerLocal.z + boxHeight;
|
|
52
|
-
} else if (tileBoundingVolume instanceof TileBoundingSphere) {
|
|
53
|
-
const radius = boundingVolume.radius;
|
|
54
|
-
minimumHeight = centerLocal.z - radius;
|
|
55
|
-
maximumHeight = centerLocal.z + radius;
|
|
56
|
-
}
|
|
17
|
+
// eslint-disable-next-line max-statements, complexity
|
|
18
|
+
export function calculateDynamicScreenSpaceError(root, { camera, mapProjection }, options = {}) {
|
|
19
|
+
const { dynamicScreenSpaceErrorHeightFalloff = 0.25, dynamicScreenSpaceErrorDensity = 0.00278 } = options;
|
|
20
|
+
let up;
|
|
21
|
+
let direction;
|
|
22
|
+
let height;
|
|
23
|
+
let minimumHeight;
|
|
24
|
+
let maximumHeight;
|
|
25
|
+
const tileBoundingVolume = root.contentBoundingVolume;
|
|
26
|
+
if (tileBoundingVolume instanceof TileBoundingRegion) {
|
|
27
|
+
up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
|
|
28
|
+
direction = camera.directionWC;
|
|
29
|
+
height = camera.positionCartographic.height;
|
|
30
|
+
minimumHeight = tileBoundingVolume.minimumHeight;
|
|
31
|
+
maximumHeight = tileBoundingVolume.maximumHeight;
|
|
57
32
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
33
|
+
else {
|
|
34
|
+
// Transform camera position and direction into the local coordinate system of the tileset
|
|
35
|
+
const transformLocal = Matrix4.inverseTransformation(root.computedTransform, scratchMatrix);
|
|
36
|
+
const ellipsoid = mapProjection.ellipsoid;
|
|
37
|
+
const boundingVolume = tileBoundingVolume.boundingVolume;
|
|
38
|
+
const centerLocal = Matrix4.multiplyByPoint(transformLocal, boundingVolume.center, scratchCenter);
|
|
39
|
+
if (Cartesian3.magnitude(centerLocal) > ellipsoid.minimumRadius) {
|
|
40
|
+
// The tileset is defined in WGS84. Approximate the minimum and maximum height.
|
|
41
|
+
const centerCartographic = Cartographic.fromCartesian(centerLocal, ellipsoid, scratchCartographic);
|
|
42
|
+
up = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
|
|
43
|
+
direction = camera.directionWC;
|
|
44
|
+
height = camera.positionCartographic.height;
|
|
45
|
+
minimumHeight = 0.0;
|
|
46
|
+
maximumHeight = centerCartographic.height * 2.0;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// The tileset is defined in local coordinates (z-up)
|
|
50
|
+
const positionLocal = Matrix4.multiplyByPoint(transformLocal, camera.positionWC, scratchPosition);
|
|
51
|
+
up = Cartesian3.UNIT_Z;
|
|
52
|
+
direction = Matrix4.multiplyByPointAsVector(transformLocal, camera.directionWC, scratchDirection);
|
|
53
|
+
direction = Cartesian3.normalize(direction, direction);
|
|
54
|
+
height = positionLocal.z;
|
|
55
|
+
if (tileBoundingVolume instanceof TileOrientedBoundingBox) {
|
|
56
|
+
// Assuming z-up, the last component stores the half-height of the box
|
|
57
|
+
const boxHeight = root._header.boundingVolume.box[11];
|
|
58
|
+
minimumHeight = centerLocal.z - boxHeight;
|
|
59
|
+
maximumHeight = centerLocal.z + boxHeight;
|
|
60
|
+
}
|
|
61
|
+
else if (tileBoundingVolume instanceof TileBoundingSphere) {
|
|
62
|
+
const radius = boundingVolume.radius;
|
|
63
|
+
minimumHeight = centerLocal.z - radius;
|
|
64
|
+
maximumHeight = centerLocal.z + radius;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// The range where the density starts to lessen. Start at the quarter height of the tileset.
|
|
69
|
+
const heightFalloff = dynamicScreenSpaceErrorHeightFalloff;
|
|
70
|
+
const heightClose = minimumHeight + (maximumHeight - minimumHeight) * heightFalloff;
|
|
71
|
+
const heightFar = maximumHeight;
|
|
72
|
+
const t = clamp((height - heightClose) / (heightFar - heightClose), 0.0, 1.0);
|
|
73
|
+
// Increase density as the camera tilts towards the horizon
|
|
74
|
+
const dot = Math.abs(Cartesian3.dot(direction, up));
|
|
75
|
+
let horizonFactor = 1.0 - dot;
|
|
76
|
+
// Weaken the horizon factor as the camera height increases, implying the camera is further away from the tileset.
|
|
77
|
+
// The goal is to increase density for the "street view", not when viewing the tileset from a distance.
|
|
78
|
+
horizonFactor = horizonFactor * (1.0 - t);
|
|
79
|
+
return dynamicScreenSpaceErrorDensity * horizonFactor;
|
|
67
80
|
}
|
|
68
81
|
export function fog(distanceToCamera, density) {
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
const scalar = distanceToCamera * density;
|
|
83
|
+
return 1.0 - Math.exp(-(scalar * scalar));
|
|
71
84
|
}
|
|
72
85
|
export function getDynamicScreenSpaceError(tileset, distanceToCamera) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
if (tileset.dynamicScreenSpaceError && tileset.dynamicScreenSpaceErrorComputedDensity) {
|
|
87
|
+
const density = tileset.dynamicScreenSpaceErrorComputedDensity;
|
|
88
|
+
const factor = tileset.dynamicScreenSpaceErrorFactor;
|
|
89
|
+
// TODO: Refined screen space error that minimizes tiles in non-first-person
|
|
90
|
+
const dynamicError = fog(distanceToCamera, density) * factor;
|
|
91
|
+
return dynamicError;
|
|
92
|
+
}
|
|
93
|
+
return 0;
|
|
80
94
|
}
|
|
81
95
|
export function getTiles3DScreenSpaceError(tile, frameState, useParentLodMetric) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
viewDistanceScale
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return error;
|
|
96
|
+
const tileset = tile.tileset;
|
|
97
|
+
const parentLodMetricValue = (tile.parent && tile.parent.lodMetricValue) || tile.lodMetricValue;
|
|
98
|
+
const lodMetricValue = useParentLodMetric ? parentLodMetricValue : tile.lodMetricValue;
|
|
99
|
+
// Leaf tiles do not have any error so save the computation
|
|
100
|
+
if (lodMetricValue === 0.0) {
|
|
101
|
+
return 0.0;
|
|
102
|
+
}
|
|
103
|
+
// TODO: Orthographic Frustum needs special treatment?
|
|
104
|
+
// this._getOrthograhicScreenSpaceError();
|
|
105
|
+
// Avoid divide by zero when viewer is inside the tile
|
|
106
|
+
const distance = Math.max(tile._distanceToCamera, 1e-7);
|
|
107
|
+
const { height, sseDenominator } = frameState;
|
|
108
|
+
const { viewDistanceScale } = tileset.options;
|
|
109
|
+
let error = (lodMetricValue * height * (viewDistanceScale || 1.0)) / (distance * sseDenominator);
|
|
110
|
+
error -= getDynamicScreenSpaceError(tileset, distance);
|
|
111
|
+
return error;
|
|
99
112
|
}
|
|
100
|
-
//# sourceMappingURL=tiles-3d-lod.js.map
|