easy-three-utils 0.0.1
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/package.json +12 -0
- package/src/common/index.ts +24 -0
- package/src/common/useLine2.ts +87 -0
- package/src/common/useLoader.ts +184 -0
- package/src/common/useLocationCalculator.ts +145 -0
- package/src/common/useMark.ts +42 -0
- package/src/common/useTween.ts +86 -0
- package/src/core/basic/camera.ts +28 -0
- package/src/core/basic/clock.ts +11 -0
- package/src/core/basic/control.ts +32 -0
- package/src/core/basic/index.ts +35 -0
- package/src/core/basic/labelRenderer.ts +26 -0
- package/src/core/basic/light.ts +63 -0
- package/src/core/basic/renderer.ts +37 -0
- package/src/core/basic/scene.ts +11 -0
- package/src/core/basic/stats.ts +16 -0
- package/src/core/event.ts +74 -0
- package/src/core/index.ts +11 -0
- package/src/core/main.ts +389 -0
- package/src/draco/README.md +32 -0
- package/src/draco/draco_decoder.js +34 -0
- package/src/draco/draco_decoder.wasm +0 -0
- package/src/draco/draco_encoder.js +33 -0
- package/src/draco/draco_wasm_wrapper.js +117 -0
- package/src/draco/gltf/draco_decoder.js +33 -0
- package/src/draco/gltf/draco_decoder.wasm +0 -0
- package/src/draco/gltf/draco_encoder.js +33 -0
- package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/src/tileRenderer/base/Tile.d.ts +50 -0
- package/src/tileRenderer/base/TileBase.d.ts +76 -0
- package/src/tileRenderer/base/TileInternal.d.ts +36 -0
- package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
- package/src/tileRenderer/base/TilesRendererBase.js +847 -0
- package/src/tileRenderer/base/Tileset.d.ts +66 -0
- package/src/tileRenderer/base/constants.d.ts +6 -0
- package/src/tileRenderer/base/constants.js +16 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
- package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
- package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
- package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
- package/src/tileRenderer/base/traverseFunctions.js +468 -0
- package/src/tileRenderer/gltf.js +144 -0
- package/src/tileRenderer/index.d.ts +41 -0
- package/src/tileRenderer/index.js +44 -0
- package/src/tileRenderer/plugins/README.md +578 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
- package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
- package/src/tileRenderer/plugins/index.d.ts +17 -0
- package/src/tileRenderer/plugins/index.js +17 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
- package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
- package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
- package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
- package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
- package/src/tileRenderer/r3f/README.md +238 -0
- package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
- package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
- package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
- package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
- package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
- package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
- package/src/tileRenderer/r3f/index.jsx +6 -0
- package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
- package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
- package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
- package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
- package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
- package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
- package/src/tileRenderer/three/TilesGroup.js +91 -0
- package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
- package/src/tileRenderer/three/TilesRenderer.js +1049 -0
- package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
- package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
- package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
- package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
- package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
- package/src/tileRenderer/three/controls/utils.js +113 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
- package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
- package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
- package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
- package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
- package/src/tileRenderer/three/math/GeoConstants.js +5 -0
- package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
- package/src/tileRenderer/three/math/GeoUtils.js +106 -0
- package/src/tileRenderer/three/math/OBB.js +179 -0
- package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
- package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
- package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
- package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
- package/src/tileRenderer/three/raycastTraverse.js +178 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
- package/src/tileRenderer/three/utilities.js +54 -0
- package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
- package/src/tileRenderer/utilities/BatchTable.js +82 -0
- package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
- package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
- package/src/tileRenderer/utilities/FeatureTable.js +159 -0
- package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
- package/src/tileRenderer/utilities/LRUCache.js +385 -0
- package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
- package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
- package/src/tileRenderer/utilities/arrayToString.js +7 -0
- package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
- package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
- package/src/tileRenderer/utilities/urlExtension.js +34 -0
- package/tsconfig.json +42 -0
- package/tsconfig.node.json +11 -0
- package/typings/three.d.ts +27 -0
|
@@ -0,0 +1,876 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structure almost identical to Cesium, also the comments and the names are kept
|
|
3
|
+
* https://github.com/CesiumGS/cesium/blob/0a69f67b393ba194eefb7254600811c4b712ddc0/packages/engine/Source/Scene/Implicit3DTileContent.js
|
|
4
|
+
*/
|
|
5
|
+
import { LoaderBase } from '../../base/loaders/LoaderBase.js';
|
|
6
|
+
import { readMagicBytes } from '../../utilities/readMagicBytes.js';
|
|
7
|
+
import { arrayToString } from '../../utilities/arrayToString.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function isOctreeSubdivision( tile ) {
|
|
12
|
+
|
|
13
|
+
return tile.__implicitRoot.implicitTiling.subdivisionScheme === 'OCTREE';
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getBoundsDivider( tile ) {
|
|
18
|
+
|
|
19
|
+
return isOctreeSubdivision( tile ) ? 8 : 4;
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
function getSubtreeCoordinates( tile, parentTile ) {
|
|
25
|
+
|
|
26
|
+
if ( ! parentTile ) {
|
|
27
|
+
|
|
28
|
+
return [ 0, 0, 0 ];
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const x = 2 * parentTile.__x + ( tile.__subtreeIdx % 2 );
|
|
33
|
+
const y = 2 * parentTile.__y + ( Math.floor( tile.__subtreeIdx / 2 ) % 2 );
|
|
34
|
+
const z = isOctreeSubdivision( tile ) ?
|
|
35
|
+
2 * parentTile.__z + ( Math.floor( tile.__subtreeIdx / 4 ) % 2 ) : 0;
|
|
36
|
+
|
|
37
|
+
return [ x, y, z ];
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class SubtreeTile {
|
|
42
|
+
|
|
43
|
+
constructor( parentTile, childMortonIndex ) {
|
|
44
|
+
|
|
45
|
+
this.parent = parentTile;
|
|
46
|
+
this.children = [];
|
|
47
|
+
this.__level = parentTile.__level + 1;
|
|
48
|
+
this.__implicitRoot = parentTile.__implicitRoot;
|
|
49
|
+
|
|
50
|
+
// Index inside the tree
|
|
51
|
+
this.__subtreeIdx = childMortonIndex;
|
|
52
|
+
[ this.__x, this.__y, this.__z ] = getSubtreeCoordinates( this, parentTile );
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static copy( tile ) {
|
|
57
|
+
|
|
58
|
+
const copyTile = {};
|
|
59
|
+
copyTile.children = [];
|
|
60
|
+
copyTile.__level = tile.__level;
|
|
61
|
+
copyTile.__implicitRoot = tile.__implicitRoot;
|
|
62
|
+
|
|
63
|
+
// Index inside the tree
|
|
64
|
+
copyTile.__subtreeIdx = tile.__subtreeIdx;
|
|
65
|
+
[ copyTile.__x, copyTile.__y, copyTile.__z ] = [ tile.__x, tile.__y, tile.__z ];
|
|
66
|
+
|
|
67
|
+
copyTile.boundingVolume = tile.boundingVolume;
|
|
68
|
+
copyTile.geometricError = tile.geometricError;
|
|
69
|
+
return copyTile;
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class SUBTREELoader extends LoaderBase {
|
|
76
|
+
|
|
77
|
+
constructor( tile ) {
|
|
78
|
+
|
|
79
|
+
super();
|
|
80
|
+
this.tile = tile;
|
|
81
|
+
this.rootTile = tile.__implicitRoot; // The implicit root tile
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A helper object for storing the two parts of the subtree binary
|
|
87
|
+
*
|
|
88
|
+
* @typedef {object} Subtree
|
|
89
|
+
* @property {number} version
|
|
90
|
+
* @property {JSON} subtreeJson
|
|
91
|
+
* @property {ArrayBuffer} subtreeByte
|
|
92
|
+
* @private
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @param buffer
|
|
98
|
+
* @return {Subtree}
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
parseBuffer( buffer ) {
|
|
102
|
+
|
|
103
|
+
const dataView = new DataView( buffer );
|
|
104
|
+
let offset = 0;
|
|
105
|
+
|
|
106
|
+
// 16-byte header
|
|
107
|
+
|
|
108
|
+
// 4 bytes
|
|
109
|
+
const magic = readMagicBytes( dataView );
|
|
110
|
+
console.assert( magic === 'subt', 'SUBTREELoader: The magic bytes equal "subt".' );
|
|
111
|
+
offset += 4;
|
|
112
|
+
|
|
113
|
+
// 4 bytes
|
|
114
|
+
const version = dataView.getUint32( offset, true );
|
|
115
|
+
console.assert( version === 1, 'SUBTREELoader: The version listed in the header is "1".' );
|
|
116
|
+
offset += 4;
|
|
117
|
+
|
|
118
|
+
// From Cesium
|
|
119
|
+
// Read the bottom 32 bits of the 64-bit byte length.
|
|
120
|
+
// This is ok for now because:
|
|
121
|
+
// 1) not all browsers have native 64-bit operations
|
|
122
|
+
// 2) the data is well under 4GB
|
|
123
|
+
|
|
124
|
+
// 8 bytes
|
|
125
|
+
const jsonLength = dataView.getUint32( offset, true );
|
|
126
|
+
offset += 8;
|
|
127
|
+
|
|
128
|
+
// 8 bytes
|
|
129
|
+
const byteLength = dataView.getUint32( offset, true );
|
|
130
|
+
offset += 8;
|
|
131
|
+
|
|
132
|
+
const subtreeJson = JSON.parse( arrayToString( new Uint8Array( buffer, offset, jsonLength ) ) );
|
|
133
|
+
offset += jsonLength;
|
|
134
|
+
|
|
135
|
+
const subtreeByte = buffer.slice( offset, offset + byteLength );
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
version,
|
|
139
|
+
subtreeJson,
|
|
140
|
+
subtreeByte
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
parse( buffer ) {
|
|
147
|
+
|
|
148
|
+
// todo here : handle json
|
|
149
|
+
const subtree = this.parseBuffer( buffer );
|
|
150
|
+
const subtreeJson = subtree.subtreeJson;
|
|
151
|
+
|
|
152
|
+
// TODO Handle metadata
|
|
153
|
+
/*
|
|
154
|
+
const subtreeMetadata = subtreeJson.subtreeMetadata;
|
|
155
|
+
subtree._metadata = subtreeMetadata;
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
Tile availability indicates which tiles exist within the subtree
|
|
161
|
+
|
|
162
|
+
Content availability indicates which tiles have associated content resources
|
|
163
|
+
|
|
164
|
+
Child subtree availability indicates what subtrees are reachable from this subtree
|
|
165
|
+
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// After identifying how availability is stored, put the results in this new array for consistent processing later
|
|
170
|
+
subtreeJson.contentAvailabilityHeaders = [].concat( subtreeJson.contentAvailability );
|
|
171
|
+
|
|
172
|
+
const bufferHeaders = this.preprocessBuffers( subtreeJson.buffers );
|
|
173
|
+
const bufferViewHeaders = this.preprocessBufferViews(
|
|
174
|
+
subtreeJson.bufferViews,
|
|
175
|
+
bufferHeaders
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// Buffers and buffer views are inactive until explicitly marked active.
|
|
179
|
+
// This way we can avoid fetching buffers that will not be used.
|
|
180
|
+
this.markActiveBufferViews( subtreeJson, bufferViewHeaders );
|
|
181
|
+
|
|
182
|
+
const buffersU8 = this.requestActiveBuffers(
|
|
183
|
+
bufferHeaders,
|
|
184
|
+
subtree.subtreeByte
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const bufferViewsU8 = this.parseActiveBufferViews( bufferViewHeaders, buffersU8 );
|
|
188
|
+
this.parseAvailability( subtree, subtreeJson, bufferViewsU8 );
|
|
189
|
+
this.expandSubtree( this.tile, subtree );
|
|
190
|
+
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Determine which buffer views need to be loaded into memory. This includes:
|
|
196
|
+
*
|
|
197
|
+
* <ul>
|
|
198
|
+
* <li>The tile availability bitstream (if a bitstream is defined)</li>
|
|
199
|
+
* <li>The content availability bitstream(s) (if a bitstream is defined)</li>
|
|
200
|
+
* <li>The child subtree availability bitstream (if a bitstream is defined)</li>
|
|
201
|
+
* </ul>
|
|
202
|
+
*
|
|
203
|
+
* <p>
|
|
204
|
+
* This function modifies the buffer view headers' isActive flags in place.
|
|
205
|
+
* </p>
|
|
206
|
+
*
|
|
207
|
+
* @param {JSON} subtreeJson The JSON chunk from the subtree
|
|
208
|
+
* @param {BufferViewHeader[]} bufferViewHeaders The preprocessed buffer view headers
|
|
209
|
+
* @private
|
|
210
|
+
*/
|
|
211
|
+
markActiveBufferViews( subtreeJson, bufferViewHeaders ) {
|
|
212
|
+
|
|
213
|
+
let header;
|
|
214
|
+
const tileAvailabilityHeader = subtreeJson.tileAvailability;
|
|
215
|
+
|
|
216
|
+
// Check for bitstream first, which is part of the current schema.
|
|
217
|
+
// bufferView is the name of the bitstream from an older schema.
|
|
218
|
+
if ( ! isNaN( tileAvailabilityHeader.bitstream ) ) {
|
|
219
|
+
|
|
220
|
+
header = bufferViewHeaders[ tileAvailabilityHeader.bitstream ];
|
|
221
|
+
|
|
222
|
+
} else if ( ! isNaN( tileAvailabilityHeader.bufferView ) ) {
|
|
223
|
+
|
|
224
|
+
header = bufferViewHeaders[ tileAvailabilityHeader.bufferView ];
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if ( header ) {
|
|
229
|
+
|
|
230
|
+
header.isActive = true;
|
|
231
|
+
header.bufferHeader.isActive = true;
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const contentAvailabilityHeaders = subtreeJson.contentAvailabilityHeaders;
|
|
236
|
+
for ( let i = 0; i < contentAvailabilityHeaders.length; i ++ ) {
|
|
237
|
+
|
|
238
|
+
header = undefined;
|
|
239
|
+
if ( ! isNaN( contentAvailabilityHeaders[ i ].bitstream ) ) {
|
|
240
|
+
|
|
241
|
+
header = bufferViewHeaders[ contentAvailabilityHeaders[ i ].bitstream ];
|
|
242
|
+
|
|
243
|
+
} else if ( ! isNaN( contentAvailabilityHeaders[ i ].bufferView ) ) {
|
|
244
|
+
|
|
245
|
+
header = bufferViewHeaders[ contentAvailabilityHeaders[ i ].bufferView ];
|
|
246
|
+
|
|
247
|
+
}
|
|
248
|
+
if ( header ) {
|
|
249
|
+
|
|
250
|
+
header.isActive = true;
|
|
251
|
+
header.bufferHeader.isActive = true;
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
header = undefined;
|
|
257
|
+
const childSubtreeAvailabilityHeader = subtreeJson.childSubtreeAvailability;
|
|
258
|
+
if ( ! isNaN( childSubtreeAvailabilityHeader.bitstream ) ) {
|
|
259
|
+
|
|
260
|
+
header = bufferViewHeaders[ childSubtreeAvailabilityHeader.bitstream ];
|
|
261
|
+
|
|
262
|
+
} else if ( ! isNaN( childSubtreeAvailabilityHeader.bufferView ) ) {
|
|
263
|
+
|
|
264
|
+
header = bufferViewHeaders[ childSubtreeAvailabilityHeader.bufferView ];
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
if ( header ) {
|
|
268
|
+
|
|
269
|
+
header.isActive = true;
|
|
270
|
+
header.bufferHeader.isActive = true;
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Go through the list of buffers and gather all the active ones into
|
|
279
|
+
* a dictionary.
|
|
280
|
+
* <p>
|
|
281
|
+
* The results are put into a dictionary object. The keys are indices of
|
|
282
|
+
* buffers, and the values are Uint8Arrays of the contents. Only buffers
|
|
283
|
+
* marked with the isActive flag are fetched.
|
|
284
|
+
* </p>
|
|
285
|
+
* <p>
|
|
286
|
+
* The internal buffer (the subtree's binary chunk) is also stored in this
|
|
287
|
+
* dictionary if it is marked active.
|
|
288
|
+
* </p>
|
|
289
|
+
* @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers
|
|
290
|
+
* @param {ArrayBuffer} internalBuffer The binary chunk of the subtree file
|
|
291
|
+
* @returns {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
294
|
+
requestActiveBuffers( bufferHeaders, internalBuffer ) {
|
|
295
|
+
|
|
296
|
+
const bufferResults = [];
|
|
297
|
+
for ( let i = 0; i < bufferHeaders.length; i ++ ) {
|
|
298
|
+
|
|
299
|
+
const bufferHeader = bufferHeaders[ i ];
|
|
300
|
+
if ( bufferHeader.isActive ) {
|
|
301
|
+
|
|
302
|
+
bufferResults.push( internalBuffer );
|
|
303
|
+
|
|
304
|
+
} else {
|
|
305
|
+
|
|
306
|
+
bufferResults.push( undefined );
|
|
307
|
+
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const buffersU8 = {};
|
|
313
|
+
for ( let i = 0; i < bufferResults.length; i ++ ) {
|
|
314
|
+
|
|
315
|
+
const result = bufferResults[ i ];
|
|
316
|
+
if ( result ) {
|
|
317
|
+
|
|
318
|
+
buffersU8[ i ] = result;
|
|
319
|
+
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
}
|
|
323
|
+
return buffersU8;
|
|
324
|
+
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Go through the list of buffer views, and if they are marked as active,
|
|
329
|
+
* extract a subarray from one of the active buffers.
|
|
330
|
+
*
|
|
331
|
+
* @param {BufferViewHeader[]} bufferViewHeaders
|
|
332
|
+
* @param {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
|
|
333
|
+
* @returns {object} A dictionary of buffer view index to a Uint8Array of its contents.
|
|
334
|
+
* @private
|
|
335
|
+
*/
|
|
336
|
+
parseActiveBufferViews( bufferViewHeaders, buffersU8 ) {
|
|
337
|
+
|
|
338
|
+
const bufferViewsU8 = {};
|
|
339
|
+
for ( let i = 0; i < bufferViewHeaders.length; i ++ ) {
|
|
340
|
+
|
|
341
|
+
const bufferViewHeader = bufferViewHeaders[ i ];
|
|
342
|
+
if ( ! bufferViewHeader.isActive ) {
|
|
343
|
+
|
|
344
|
+
continue;
|
|
345
|
+
|
|
346
|
+
}
|
|
347
|
+
const start = bufferViewHeader.byteOffset;
|
|
348
|
+
const end = start + bufferViewHeader.byteLength;
|
|
349
|
+
const buffer = buffersU8[ bufferViewHeader.buffer ];
|
|
350
|
+
bufferViewsU8[ i ] = buffer.slice( start, end );
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
return bufferViewsU8;
|
|
354
|
+
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* A buffer header is the JSON header from the subtree JSON chunk plus
|
|
359
|
+
* a couple extra boolean flags for easy reference.
|
|
360
|
+
*
|
|
361
|
+
* Buffers are assumed inactive until explicitly marked active. This is used
|
|
362
|
+
* to avoid fetching unneeded buffers.
|
|
363
|
+
*
|
|
364
|
+
* @typedef {object} BufferHeader
|
|
365
|
+
* @property {boolean} isActive Whether this buffer is currently used.
|
|
366
|
+
* @property {string} [uri] The URI of the buffer (external buffers only)
|
|
367
|
+
* @property {number} byteLength The byte length of the buffer, including any padding contained within.
|
|
368
|
+
* @private
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Iterate over the list of buffers from the subtree JSON and add the isActive field for easier parsing later.
|
|
373
|
+
* This modifies the objects in place.
|
|
374
|
+
* @param {Object[]} [bufferHeaders=[]] The JSON from subtreeJson.buffers.
|
|
375
|
+
* @returns {BufferHeader[]} The same array of headers with additional fields.
|
|
376
|
+
* @private
|
|
377
|
+
*/
|
|
378
|
+
preprocessBuffers( bufferHeaders = [] ) {
|
|
379
|
+
|
|
380
|
+
for ( let i = 0; i < bufferHeaders.length; i ++ ) {
|
|
381
|
+
|
|
382
|
+
const bufferHeader = bufferHeaders[ i ];
|
|
383
|
+
bufferHeader.isActive = false;
|
|
384
|
+
|
|
385
|
+
}
|
|
386
|
+
return bufferHeaders;
|
|
387
|
+
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A buffer header is the JSON header from the subtree JSON chunk plus
|
|
393
|
+
* the isActive flag and a reference to the header for the underlying buffer
|
|
394
|
+
*
|
|
395
|
+
* @typedef {object} BufferViewHeader
|
|
396
|
+
* @property {BufferHeader} bufferHeader A reference to the header for the underlying buffer
|
|
397
|
+
* @property {boolean} isActive Whether this bufferView is currently used.
|
|
398
|
+
* @property {number} buffer The index of the underlying buffer.
|
|
399
|
+
* @property {number} byteOffset The start byte of the bufferView within the buffer.
|
|
400
|
+
* @property {number} byteLength The length of the bufferView. No padding is included in this length.
|
|
401
|
+
* @private
|
|
402
|
+
*/
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Iterate the list of buffer views from the subtree JSON and add the
|
|
406
|
+
* isActive flag. Also save a reference to the bufferHeader
|
|
407
|
+
*
|
|
408
|
+
* @param {Object[]} [bufferViewHeaders=[]] The JSON from subtree.bufferViews
|
|
409
|
+
* @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers
|
|
410
|
+
* @returns {BufferViewHeader[]} The same array of bufferView headers with additional fields
|
|
411
|
+
* @private
|
|
412
|
+
*/
|
|
413
|
+
preprocessBufferViews( bufferViewHeaders = [], bufferHeaders ) {
|
|
414
|
+
|
|
415
|
+
for ( let i = 0; i < bufferViewHeaders.length; i ++ ) {
|
|
416
|
+
|
|
417
|
+
const bufferViewHeader = bufferViewHeaders[ i ];
|
|
418
|
+
bufferViewHeader.bufferHeader = bufferHeaders[ bufferViewHeader.buffer ];
|
|
419
|
+
bufferViewHeader.isActive = false;
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
return bufferViewHeaders;
|
|
423
|
+
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Parse the three availability bitstreams and store them in the subtree
|
|
429
|
+
*
|
|
430
|
+
* @param {Subtree} subtree The subtree to modify
|
|
431
|
+
* @param {Object} subtreeJson The subtree JSON
|
|
432
|
+
* @param {Object} bufferViewsU8 A dictionary of buffer view index to a Uint8Array of its contents.
|
|
433
|
+
* @private
|
|
434
|
+
*/
|
|
435
|
+
parseAvailability(
|
|
436
|
+
subtree,
|
|
437
|
+
subtreeJson,
|
|
438
|
+
bufferViewsU8
|
|
439
|
+
) {
|
|
440
|
+
|
|
441
|
+
const branchingFactor = getBoundsDivider( this.rootTile );
|
|
442
|
+
const subtreeLevels = this.rootTile.implicitTiling.subtreeLevels;
|
|
443
|
+
const tileAvailabilityBits =
|
|
444
|
+
( Math.pow( branchingFactor, subtreeLevels ) - 1 ) / ( branchingFactor - 1 );
|
|
445
|
+
const childSubtreeBits = Math.pow( branchingFactor, subtreeLevels );
|
|
446
|
+
|
|
447
|
+
subtree._tileAvailability = this.parseAvailabilityBitstream(
|
|
448
|
+
subtreeJson.tileAvailability,
|
|
449
|
+
bufferViewsU8,
|
|
450
|
+
tileAvailabilityBits
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
subtree._contentAvailabilityBitstreams = [];
|
|
454
|
+
for ( let i = 0; i < subtreeJson.contentAvailabilityHeaders.length; i ++ ) {
|
|
455
|
+
|
|
456
|
+
const bitstream = this.parseAvailabilityBitstream(
|
|
457
|
+
subtreeJson.contentAvailabilityHeaders[ i ],
|
|
458
|
+
bufferViewsU8,
|
|
459
|
+
// content availability has the same length as tile availability.
|
|
460
|
+
tileAvailabilityBits
|
|
461
|
+
);
|
|
462
|
+
subtree._contentAvailabilityBitstreams.push( bitstream );
|
|
463
|
+
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
subtree._childSubtreeAvailability = this.parseAvailabilityBitstream(
|
|
467
|
+
subtreeJson.childSubtreeAvailability,
|
|
468
|
+
bufferViewsU8,
|
|
469
|
+
childSubtreeBits
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* A helper object for storing the two parts of the subtree binary
|
|
476
|
+
*
|
|
477
|
+
* @typedef {object} ParsedBitstream
|
|
478
|
+
* @property {Boolean} constant
|
|
479
|
+
* @property {ArrayBuffer} bitstream
|
|
480
|
+
* @property {number} lengthBits The length of the availability bitstream in bits
|
|
481
|
+
* @private
|
|
482
|
+
*/
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Given the JSON describing an availability bitstream, turn it into an
|
|
487
|
+
* in-memory representation using an object. This handles bitstreams from a bufferView.
|
|
488
|
+
*
|
|
489
|
+
* @param {Object} availabilityJson A JSON object representing the availability
|
|
490
|
+
* @param {Object} bufferViewsU8 A dictionary of bufferView index to its Uint8Array contents.
|
|
491
|
+
* @param {number} lengthBits The length of the availability bitstream in bits
|
|
492
|
+
* @returns {ParsedBitstream}
|
|
493
|
+
* @private
|
|
494
|
+
*/
|
|
495
|
+
parseAvailabilityBitstream(
|
|
496
|
+
availabilityJson,
|
|
497
|
+
bufferViewsU8,
|
|
498
|
+
lengthBits,
|
|
499
|
+
) {
|
|
500
|
+
|
|
501
|
+
if ( ! isNaN( availabilityJson.constant ) ) {
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
constant: Boolean( availabilityJson.constant ),
|
|
505
|
+
lengthBits: lengthBits,
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
}
|
|
509
|
+
let bufferView;
|
|
510
|
+
// Check for bitstream first, which is part of the current schema.
|
|
511
|
+
// bufferView is the name of the bitstream from an older schema.
|
|
512
|
+
|
|
513
|
+
if ( ! isNaN( availabilityJson.bitstream ) ) {
|
|
514
|
+
|
|
515
|
+
bufferView = bufferViewsU8[ availabilityJson.bitstream ];
|
|
516
|
+
|
|
517
|
+
} else if ( ! isNaN( availabilityJson.bufferView ) ) {
|
|
518
|
+
|
|
519
|
+
bufferView = bufferViewsU8[ availabilityJson.bufferView ];
|
|
520
|
+
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
bitstream: bufferView,
|
|
524
|
+
lengthBits: lengthBits
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Expand a single subtree tile. This transcodes the subtree into
|
|
532
|
+
* a tree of {@link SubtreeTile}. The root of this tree is stored in
|
|
533
|
+
* the placeholder tile's children array. This method also creates
|
|
534
|
+
* tiles for the child subtrees to be lazily expanded as needed.
|
|
535
|
+
*
|
|
536
|
+
* @param {Object | SubtreeTile} subtreeRoot The first node of the subtree
|
|
537
|
+
* @param {Subtree} subtree The parsed subtree
|
|
538
|
+
* @private
|
|
539
|
+
*/
|
|
540
|
+
expandSubtree( subtreeRoot, subtree ) {
|
|
541
|
+
|
|
542
|
+
// TODO If multiple contents were supported then this tile could contain both renderable and un renderable content.
|
|
543
|
+
const contentTile = SubtreeTile.copy( subtreeRoot );
|
|
544
|
+
|
|
545
|
+
// If the subtree root tile has content, then create a placeholder child with cloned parameters
|
|
546
|
+
// Todo Multiple contents not handled, keep the first content found
|
|
547
|
+
for ( let i = 0; subtree && i < subtree._contentAvailabilityBitstreams.length; i ++ ) {
|
|
548
|
+
|
|
549
|
+
if ( subtree && this.getBit( subtree._contentAvailabilityBitstreams[ i ], 0 ) ) {
|
|
550
|
+
|
|
551
|
+
// Create a child holding the content uri, this child is similar to its parent and doesn't have any children
|
|
552
|
+
contentTile.content = { uri: this.parseImplicitURI( subtreeRoot, this.rootTile.content.uri ) };
|
|
553
|
+
break;
|
|
554
|
+
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
subtreeRoot.children.push( contentTile );
|
|
560
|
+
|
|
561
|
+
// Creating each leaf inside the current subtree
|
|
562
|
+
const bottomRow = this.transcodeSubtreeTiles(
|
|
563
|
+
contentTile,
|
|
564
|
+
subtree
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
// For each child subtree, create a tile containing the uri of the next subtree to fetch
|
|
568
|
+
const childSubtrees = this.listChildSubtrees( subtree, bottomRow );
|
|
569
|
+
for ( let i = 0; i < childSubtrees.length; i ++ ) {
|
|
570
|
+
|
|
571
|
+
const subtreeLocator = childSubtrees[ i ];
|
|
572
|
+
const leafTile = subtreeLocator.tile;
|
|
573
|
+
const subtreeTile = this.deriveChildTile(
|
|
574
|
+
null,
|
|
575
|
+
leafTile,
|
|
576
|
+
null,
|
|
577
|
+
subtreeLocator.childMortonIndex
|
|
578
|
+
);
|
|
579
|
+
// Assign subtree uri as content
|
|
580
|
+
subtreeTile.content = { uri: this.parseImplicitURI( subtreeTile, this.rootTile.implicitTiling.subtrees.uri ) };
|
|
581
|
+
leafTile.children.push( subtreeTile );
|
|
582
|
+
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Transcode the implicitly defined tiles within this subtree and generate
|
|
589
|
+
* explicit {@link SubtreeTile} objects. This function only transcode tiles,
|
|
590
|
+
* child subtrees are handled separately.
|
|
591
|
+
*
|
|
592
|
+
* @param {Object | SubtreeTile} subtreeRoot The root of the current subtree
|
|
593
|
+
* @param {Subtree} subtree The subtree to get availability information
|
|
594
|
+
* @returns {Array} The bottom row of transcoded tiles. This is helpful for processing child subtrees
|
|
595
|
+
* @private
|
|
596
|
+
*/
|
|
597
|
+
transcodeSubtreeTiles( subtreeRoot, subtree ) {
|
|
598
|
+
|
|
599
|
+
// Sliding window over the levels of the tree.
|
|
600
|
+
// Each row is branchingFactor * length of previous row
|
|
601
|
+
// Tiles within a row are ordered by Morton index.
|
|
602
|
+
let parentRow = [ subtreeRoot ];
|
|
603
|
+
let currentRow = [];
|
|
604
|
+
|
|
605
|
+
for ( let level = 1; level < this.rootTile.implicitTiling.subtreeLevels; level ++ ) {
|
|
606
|
+
|
|
607
|
+
const branchingFactor = getBoundsDivider( this.rootTile );
|
|
608
|
+
const levelOffset = ( Math.pow( branchingFactor, level ) - 1 ) / ( branchingFactor - 1 );
|
|
609
|
+
const numberOfChildren = branchingFactor * parentRow.length;
|
|
610
|
+
for (
|
|
611
|
+
let childMortonIndex = 0;
|
|
612
|
+
childMortonIndex < numberOfChildren;
|
|
613
|
+
childMortonIndex ++
|
|
614
|
+
) {
|
|
615
|
+
|
|
616
|
+
const childBitIndex = levelOffset + childMortonIndex;
|
|
617
|
+
const parentMortonIndex = childMortonIndex >> Math.log2( branchingFactor );
|
|
618
|
+
const parentTile = parentRow[ parentMortonIndex ];
|
|
619
|
+
|
|
620
|
+
// Check if tile is available
|
|
621
|
+
if ( ! this.getBit( subtree._tileAvailability, childBitIndex ) ) {
|
|
622
|
+
|
|
623
|
+
currentRow.push( undefined );
|
|
624
|
+
continue;
|
|
625
|
+
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Create a tile and add it as a child
|
|
629
|
+
const childTile = this.deriveChildTile(
|
|
630
|
+
subtree,
|
|
631
|
+
parentTile,
|
|
632
|
+
childBitIndex,
|
|
633
|
+
childMortonIndex
|
|
634
|
+
);
|
|
635
|
+
parentTile.children.push( childTile );
|
|
636
|
+
currentRow.push( childTile );
|
|
637
|
+
|
|
638
|
+
}
|
|
639
|
+
parentRow = currentRow;
|
|
640
|
+
currentRow = [];
|
|
641
|
+
|
|
642
|
+
}
|
|
643
|
+
return parentRow;
|
|
644
|
+
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Given a parent tile and information about which child to create, derive
|
|
649
|
+
* the properties of the child tile implicitly.
|
|
650
|
+
* <p>
|
|
651
|
+
* This creates a real tile for rendering.
|
|
652
|
+
* </p>
|
|
653
|
+
*
|
|
654
|
+
* @param {Subtree} subtree The subtree the child tile belongs to
|
|
655
|
+
* @param {Object | SubtreeTile} parentTile The parent of the new child tile
|
|
656
|
+
* @param {number} childBitIndex The index of the child tile within the tile's availability information.
|
|
657
|
+
* @param {number} childMortonIndex The morton index of the child tile relative to its parent
|
|
658
|
+
* @returns {SubtreeTile} The new child tile.
|
|
659
|
+
* @private
|
|
660
|
+
*/
|
|
661
|
+
deriveChildTile(
|
|
662
|
+
subtree,
|
|
663
|
+
parentTile,
|
|
664
|
+
childBitIndex,
|
|
665
|
+
childMortonIndex
|
|
666
|
+
) {
|
|
667
|
+
|
|
668
|
+
const subtreeTile = new SubtreeTile( parentTile, childMortonIndex );
|
|
669
|
+
subtreeTile.boundingVolume = this.getTileBoundingVolume( subtreeTile );
|
|
670
|
+
subtreeTile.geometricError = this.getGeometricError( subtreeTile );
|
|
671
|
+
|
|
672
|
+
// Todo Multiple contents not handled, keep the first found content
|
|
673
|
+
for ( let i = 0; subtree && i < subtree._contentAvailabilityBitstreams.length; i ++ ) {
|
|
674
|
+
|
|
675
|
+
if ( subtree && this.getBit( subtree._contentAvailabilityBitstreams[ i ], childBitIndex ) ) {
|
|
676
|
+
|
|
677
|
+
subtreeTile.content = { uri: this.parseImplicitURI( subtreeTile, this.rootTile.content.uri ) };
|
|
678
|
+
break;
|
|
679
|
+
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
}
|
|
683
|
+
return subtreeTile;
|
|
684
|
+
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Get a bit from the bitstream as a Boolean. If the bitstream
|
|
690
|
+
* is a constant, the constant value is returned instead.
|
|
691
|
+
*
|
|
692
|
+
* @param {ParsedBitstream} object
|
|
693
|
+
* @param {number} index The integer index of the bit.
|
|
694
|
+
* @returns {boolean} The value of the bit
|
|
695
|
+
* @private
|
|
696
|
+
*/
|
|
697
|
+
getBit( object, index ) {
|
|
698
|
+
|
|
699
|
+
if ( index < 0 || index >= object.lengthBits ) {
|
|
700
|
+
|
|
701
|
+
throw new Error( 'Bit index out of bounds.' );
|
|
702
|
+
|
|
703
|
+
}
|
|
704
|
+
if ( object.constant !== undefined ) {
|
|
705
|
+
|
|
706
|
+
return object.constant;
|
|
707
|
+
|
|
708
|
+
}
|
|
709
|
+
// byteIndex is floor(index / 8)
|
|
710
|
+
const byteIndex = index >> 3;
|
|
711
|
+
const bitIndex = index % 8;
|
|
712
|
+
return ( ( new Uint8Array( object.bitstream )[ byteIndex ] >> bitIndex ) & 1 ) === 1;
|
|
713
|
+
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* //TODO Adapt for Sphere
|
|
718
|
+
* To maintain numerical stability during this subdivision process,
|
|
719
|
+
* the actual bounding volumes should not be computed progressively by subdividing a non-root tile volume.
|
|
720
|
+
* Instead, the exact bounding volumes are computed directly for a given level.
|
|
721
|
+
* @param {Object | SubtreeTile} tile
|
|
722
|
+
* @return {Object} object containing the bounding volume
|
|
723
|
+
*/
|
|
724
|
+
getTileBoundingVolume( tile ) {
|
|
725
|
+
|
|
726
|
+
const boundingVolume = {};
|
|
727
|
+
if ( this.rootTile.boundingVolume.region ) {
|
|
728
|
+
|
|
729
|
+
const region = [ ...this.rootTile.boundingVolume.region ];
|
|
730
|
+
const minX = region[ 0 ];
|
|
731
|
+
const maxX = region[ 2 ];
|
|
732
|
+
const minY = region[ 1 ];
|
|
733
|
+
const maxY = region[ 3 ];
|
|
734
|
+
const sizeX = ( maxX - minX ) / Math.pow( 2, tile.__level );
|
|
735
|
+
const sizeY = ( maxY - minY ) / Math.pow( 2, tile.__level );
|
|
736
|
+
region[ 0 ] = minX + sizeX * tile.__x; //west
|
|
737
|
+
region[ 2 ] = minX + sizeX * ( tile.__x + 1 ); //east
|
|
738
|
+
region[ 1 ] = minY + sizeY * tile.__y; //south
|
|
739
|
+
region[ 3 ] = minY + sizeY * ( tile.__y + 1 ); //north
|
|
740
|
+
|
|
741
|
+
for ( let k = 0; k < 4; k ++ ) {
|
|
742
|
+
|
|
743
|
+
const coord = region[ k ];
|
|
744
|
+
if ( coord < - Math.PI ) {
|
|
745
|
+
|
|
746
|
+
region[ k ] += 2 * Math.PI;
|
|
747
|
+
|
|
748
|
+
} else if ( coord > Math.PI ) {
|
|
749
|
+
|
|
750
|
+
region[ k ] -= 2 * Math.PI;
|
|
751
|
+
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
//Also divide the height in the case of octree.
|
|
757
|
+
if ( isOctreeSubdivision( tile ) ) {
|
|
758
|
+
|
|
759
|
+
const minZ = region[ 4 ];
|
|
760
|
+
const maxZ = region[ 5 ];
|
|
761
|
+
|
|
762
|
+
const sizeZ = ( maxZ - minZ ) / Math.pow( 2, tile.__level );
|
|
763
|
+
|
|
764
|
+
region[ 4 ] = minZ + sizeZ * tile.__z; //minimum height
|
|
765
|
+
region[ 5 ] = minZ + sizeZ * ( tile.__z + 1 ); // maximum height
|
|
766
|
+
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
boundingVolume.region = region;
|
|
770
|
+
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if ( this.rootTile.boundingVolume.box ) {
|
|
774
|
+
|
|
775
|
+
// 0-2: center of the box
|
|
776
|
+
// 3-5: x axis direction and half length
|
|
777
|
+
// 6-8: y axis direction and half length
|
|
778
|
+
// 9-11: z axis direction and half length
|
|
779
|
+
|
|
780
|
+
const box = [ ...this.rootTile.boundingVolume.box ];
|
|
781
|
+
const cellSteps = 2 ** tile.__level - 1;
|
|
782
|
+
const scale = Math.pow( 2, - tile.__level );
|
|
783
|
+
const axisNumber = isOctreeSubdivision( tile ) ? 3 : 2;
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
for ( let i = 0; i < axisNumber; i ++ ) {
|
|
787
|
+
|
|
788
|
+
// scale the bounds axes
|
|
789
|
+
box[ 3 + i * 3 + 0 ] *= scale;
|
|
790
|
+
box[ 3 + i * 3 + 1 ] *= scale;
|
|
791
|
+
box[ 3 + i * 3 + 2 ] *= scale;
|
|
792
|
+
|
|
793
|
+
// axis vector
|
|
794
|
+
const x = box[ 3 + i * 3 + 0 ];
|
|
795
|
+
const y = box[ 3 + i * 3 + 1 ];
|
|
796
|
+
const z = box[ 3 + i * 3 + 2 ];
|
|
797
|
+
|
|
798
|
+
// adjust the center by the x, y and z axes
|
|
799
|
+
const axisOffset = i === 0 ? tile.__x : ( i === 1 ? tile.__y : tile.__z );
|
|
800
|
+
box[ 0 ] += 2 * x * ( - 0.5 * cellSteps + axisOffset );
|
|
801
|
+
box[ 1 ] += 2 * y * ( - 0.5 * cellSteps + axisOffset );
|
|
802
|
+
box[ 2 ] += 2 * z * ( - 0.5 * cellSteps + axisOffset );
|
|
803
|
+
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
boundingVolume.box = box;
|
|
807
|
+
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return boundingVolume;
|
|
811
|
+
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Each child’s geometricError is half of its parent’s geometricError
|
|
816
|
+
* @param {Object | SubtreeTile} tile
|
|
817
|
+
* @return {number}
|
|
818
|
+
*/
|
|
819
|
+
getGeometricError( tile ) {
|
|
820
|
+
|
|
821
|
+
return this.rootTile.geometricError / Math.pow( 2, tile.__level );
|
|
822
|
+
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Determine what child subtrees exist and return a list of information
|
|
828
|
+
*
|
|
829
|
+
* @param {Object} subtree The subtree for looking up availability
|
|
830
|
+
* @param {Array} bottomRow The bottom row of tiles in a transcoded subtree
|
|
831
|
+
* @returns {[]} A list of identifiers for the child subtrees.
|
|
832
|
+
* @private
|
|
833
|
+
*/
|
|
834
|
+
listChildSubtrees( subtree, bottomRow ) {
|
|
835
|
+
|
|
836
|
+
const results = [];
|
|
837
|
+
const branchingFactor = getBoundsDivider( this.rootTile );
|
|
838
|
+
for ( let i = 0; i < bottomRow.length; i ++ ) {
|
|
839
|
+
|
|
840
|
+
const leafTile = bottomRow[ i ];
|
|
841
|
+
if ( leafTile === undefined ) {
|
|
842
|
+
|
|
843
|
+
continue;
|
|
844
|
+
|
|
845
|
+
}
|
|
846
|
+
for ( let j = 0; j < branchingFactor; j ++ ) {
|
|
847
|
+
|
|
848
|
+
const index = i * branchingFactor + j;
|
|
849
|
+
if ( this.getBit( subtree._childSubtreeAvailability, index ) ) {
|
|
850
|
+
|
|
851
|
+
results.push( {
|
|
852
|
+
tile: leafTile,
|
|
853
|
+
childMortonIndex: index
|
|
854
|
+
} );
|
|
855
|
+
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
}
|
|
861
|
+
return results;
|
|
862
|
+
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
parseImplicitURI( tile, uri ) {
|
|
867
|
+
|
|
868
|
+
uri = uri.replace( '{level}', tile.__level );
|
|
869
|
+
uri = uri.replace( '{x}', tile.__x );
|
|
870
|
+
uri = uri.replace( '{y}', tile.__y );
|
|
871
|
+
uri = uri.replace( '{z}', tile.__z );
|
|
872
|
+
return uri;
|
|
873
|
+
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
}
|