t3d-3dtiles 0.1.0

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.
Files changed (83) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +41 -0
  3. package/build/t3d.3dtiles.js +5418 -0
  4. package/build/t3d.3dtiles.min.js +2 -0
  5. package/build/t3d.3dtiles.module.js +6183 -0
  6. package/examples/jsm/CesiumIon.js +30 -0
  7. package/examples/jsm/Tiles3DDebugger.js +219 -0
  8. package/examples/jsm/Tiles3DUtils.js +32 -0
  9. package/examples/jsm/helpers/LineSegmentHelper.js +74 -0
  10. package/examples/jsm/helpers/OBBHelper.js +48 -0
  11. package/examples/jsm/helpers/Tiles3DHelper.js +135 -0
  12. package/examples/jsm/math/Intersects.js +100 -0
  13. package/examples/jsm/math/LineSegment.js +234 -0
  14. package/package.json +57 -0
  15. package/src/Tiles3D.js +402 -0
  16. package/src/libs/ImageBitmapLoader.js +56 -0
  17. package/src/libs/glTF/Constants.js +85 -0
  18. package/src/libs/glTF/GLTFLoader.js +169 -0
  19. package/src/libs/glTF/GLTFResource.js +28 -0
  20. package/src/libs/glTF/GLTFUtils.js +131 -0
  21. package/src/libs/glTF/extensions/EXT_meshopt_compression.js +35 -0
  22. package/src/libs/glTF/extensions/KHR_draco_mesh_compression.js +54 -0
  23. package/src/libs/glTF/extensions/KHR_lights_punctual.js +53 -0
  24. package/src/libs/glTF/extensions/KHR_materials_clearcoat.js +42 -0
  25. package/src/libs/glTF/extensions/KHR_materials_pbrSpecularGlossiness.js +53 -0
  26. package/src/libs/glTF/extensions/KHR_materials_unlit.js +13 -0
  27. package/src/libs/glTF/extensions/KHR_texture_basisu.js +14 -0
  28. package/src/libs/glTF/extensions/KHR_texture_transform.js +31 -0
  29. package/src/libs/glTF/parsers/AccessorParser.js +99 -0
  30. package/src/libs/glTF/parsers/AnimationParser.js +118 -0
  31. package/src/libs/glTF/parsers/BufferParser.js +35 -0
  32. package/src/libs/glTF/parsers/BufferViewParser.js +27 -0
  33. package/src/libs/glTF/parsers/ImageParser.js +97 -0
  34. package/src/libs/glTF/parsers/IndexParser.js +22 -0
  35. package/src/libs/glTF/parsers/MaterialParser.js +146 -0
  36. package/src/libs/glTF/parsers/NodeParser.js +145 -0
  37. package/src/libs/glTF/parsers/PrimitiveParser.js +289 -0
  38. package/src/libs/glTF/parsers/ReferenceParser.js +67 -0
  39. package/src/libs/glTF/parsers/SceneParser.js +41 -0
  40. package/src/libs/glTF/parsers/SkinParser.js +53 -0
  41. package/src/libs/glTF/parsers/TextureParser.js +71 -0
  42. package/src/libs/glTF/parsers/Validator.js +16 -0
  43. package/src/loaders/B3DMLoader.js +49 -0
  44. package/src/loaders/CMPTLoader.js +48 -0
  45. package/src/loaders/I3DMLoader.js +49 -0
  46. package/src/loaders/PNTSLoader.js +20 -0
  47. package/src/loaders/TileGLTFLoader.js +17 -0
  48. package/src/loaders/parsers/HeaderParser.js +104 -0
  49. package/src/loaders/parsers/LoadParser.js +22 -0
  50. package/src/loaders/parsers/TableParser.js +66 -0
  51. package/src/loaders/parsers/b3dm/B3DMParser.js +18 -0
  52. package/src/loaders/parsers/b3dm/B3DMRootParser.js +22 -0
  53. package/src/loaders/parsers/b3dm/MaterialParser.js +156 -0
  54. package/src/loaders/parsers/cmpt/CMPTParser.js +37 -0
  55. package/src/loaders/parsers/cmpt/CMPTRootParser.js +44 -0
  56. package/src/loaders/parsers/gltf/IndexParser.js +24 -0
  57. package/src/loaders/parsers/i3dm/I3DMParser.js +28 -0
  58. package/src/loaders/parsers/i3dm/I3DMRootParser.js +123 -0
  59. package/src/loaders/parsers/i3dm/MaterialParser.js +152 -0
  60. package/src/loaders/parsers/i3dm/PrimitiveParser.js +291 -0
  61. package/src/loaders/parsers/pnts/PNTSRootParser.js +69 -0
  62. package/src/main.js +14 -0
  63. package/src/materials/InstancedBasicMaterial.js +32 -0
  64. package/src/materials/InstancedPBRMaterial.js +32 -0
  65. package/src/materials/InstancedShaderChunks.js +23 -0
  66. package/src/math/Ellipsoid.js +41 -0
  67. package/src/math/EllipsoidRegion.js +160 -0
  68. package/src/math/FastFrustum.js +49 -0
  69. package/src/math/GeoUtils.js +31 -0
  70. package/src/math/OBB.js +395 -0
  71. package/src/math/TileBoundingVolume.js +172 -0
  72. package/src/math/TileOBB.js +103 -0
  73. package/src/utils/BatchTable.js +14 -0
  74. package/src/utils/CameraList.js +131 -0
  75. package/src/utils/FeatureTable.js +107 -0
  76. package/src/utils/IntersectionUtils.js +136 -0
  77. package/src/utils/LRUCache.js +159 -0
  78. package/src/utils/ModelLoader.js +150 -0
  79. package/src/utils/PriorityQueue.js +102 -0
  80. package/src/utils/RequestState.js +17 -0
  81. package/src/utils/TilesLoader.js +386 -0
  82. package/src/utils/TilesScheduler.js +375 -0
  83. package/src/utils/Utils.js +43 -0
@@ -0,0 +1,234 @@
1
+ import { Vector3, Matrix4, Triangle, Ray } from 't3d';
2
+
3
+ export class LineSegment {
4
+
5
+ constructor(startPoint = new Vector3(), endPoint = new Vector3()) {
6
+ this.startPoint = startPoint;
7
+ this.endPoint = endPoint;
8
+ }
9
+
10
+ setPoints(startPoint, endPoint) {
11
+ this.startPoint.copy(startPoint);
12
+ this.endPoint.copy(endPoint);
13
+ return this;
14
+ }
15
+
16
+ copy(lineSegment) {
17
+ this.startPoint.copy(lineSegment.startPoint);
18
+ this.endPoint.copy(lineSegment.endPoint);
19
+ return this;
20
+ }
21
+
22
+ applyMatrix4(m) {
23
+ this.startPoint.applyMatrix4(m);
24
+ this.endPoint.applyMatrix4(m);
25
+ return this;
26
+ }
27
+
28
+ getLength() {
29
+ return this.startPoint.distanceTo(this.endPoint);
30
+ }
31
+
32
+ getLengthSquared() {
33
+ return this.startPoint.distanceToSquared(this.endPoint);
34
+ }
35
+
36
+ getCenter(target) {
37
+ return target.addVectors(this.startPoint, this.endPoint).multiplyScalar(0.5);
38
+ }
39
+
40
+ getOBB(radius, target) {
41
+ const center = this.getCenter(_vec3_1);
42
+ const halfSize = _vec3_2.set(radius, radius, this.getLength() * 0.5 + radius); // expand box size by radius
43
+
44
+ const rotationMatrix4 = _mat4_1.identity().lookAtRH(this.startPoint, this.endPoint, _up);
45
+
46
+ target.box.min.subVectors(center, halfSize);
47
+ target.box.max.addVectors(center, halfSize);
48
+ target.rotation.setFromMatrix4(rotationMatrix4);
49
+
50
+ return target;
51
+ }
52
+
53
+ closestLineToLineSegment(lineSegment, target) {
54
+ const lineVec = _lineVec1.subVectors(this.endPoint, this.startPoint);
55
+ const lineVec2 = _lineVec2.subVectors(lineSegment.endPoint, lineSegment.startPoint);
56
+ const r = _lineVec3.subVectors(this.startPoint, lineSegment.startPoint);
57
+ const a = lineVec.getLengthSquared();
58
+ const invA = 1.0 / a;
59
+ const e = lineVec2.getLengthSquared();
60
+ const f = lineVec2.dot(r);
61
+ const EPSILON = 1E-5;
62
+ let s, t;
63
+
64
+ if (a <= EPSILON && e <= EPSILON) {
65
+ // Both segments degenerate into points
66
+ target.startPoint.copy(this.startPoint);
67
+ target.endPoint.copy(lineSegment.startPoint);
68
+ return target;
69
+ }
70
+
71
+ if (a <= EPSILON) {
72
+ // First segment degenerates into a point
73
+ s = 0.0;
74
+ t = f / e;
75
+ t = Math.min(Math.max(t, 0.0), 1.0);
76
+ } else {
77
+ const c = lineVec.dot(r);
78
+ if (e <= EPSILON) {
79
+ // Second segment degenerates into a point
80
+ t = 0.0;
81
+ s = Math.min(Math.max(-c * invA, 0.0), 1.0);
82
+ } else {
83
+ // The general nondegenerate case starts here
84
+ const b = lineVec.dot(lineVec2);
85
+ const denom = a * e - b * b;
86
+ // If segments not parallel, compute closest point on L1 to L2 and clamp to segment S1. Else pick arbitrary s (here 0)
87
+ if (denom !== 0.0) { s = Math.min(Math.max((b * f - c * e) / denom, 0.0), 1.0) } else { s = 0.0 }
88
+ // Compute point on L2 closest to S1(s) using
89
+ // t = Dot((P1 + D1 * s) - P2, D2) / Dot(D2, D2) = (b * s + f) / e
90
+ t = (b * s + f) / e;
91
+ // If t in [0,1] done. Else clamp t, recompute s for the new value of t using s = Dot((P2 + D2 * t) - P1, D1) / Dot(D1, D1) = (t * b - c) / a and clamp s to [0, 1]
92
+ if (t < 0.0) {
93
+ t = 0.0;
94
+ s = Math.min(Math.max(-c * invA, 0.0), 1.0);
95
+ } else if (t > 1.0) {
96
+ t = 1.0;
97
+ s = Math.min(Math.max((b - c) * invA, 0.0), 1.0);
98
+ }
99
+ }
100
+ }
101
+
102
+ target.startPoint.addVectors(this.startPoint, lineVec.multiplyScalar(s));
103
+ target.endPoint.addVectors(lineSegment.startPoint, lineVec2.multiplyScalar(t));
104
+ return target;
105
+ }
106
+
107
+ intersectTriangle(triangle, target) {
108
+ const lineVec = _lineVec0.subVectors(this.endPoint, this.startPoint).normalize();
109
+ const ray = _ray.set(this.startPoint, lineVec);
110
+ const backfaceCulling = false;
111
+
112
+ const intersect = ray.intersectTriangle(triangle.a, triangle.b, triangle.c, backfaceCulling, target);
113
+ if (intersect === null) return null;
114
+
115
+ const distance = this.startPoint.distanceTo(target);
116
+ const t = distance / this.getLength();
117
+ if (t >= 0.0 && t <= 1.0) {
118
+ return true;
119
+ }
120
+ return false;
121
+ }
122
+
123
+ closestLineToTriangle(triangle, target) {
124
+ let min = Infinity, d;
125
+
126
+ const intersectWithTriangle = this.intersectTriangle(triangle, _vec3_1);
127
+ if (intersectWithTriangle) {
128
+ target.startPoint.copy(_vec3_1);
129
+ target.endPoint.copy(_vec3_1);
130
+ return target;
131
+ } else {
132
+ const isPointAintri = Triangle.containsPoint(this.startPoint, triangle.a, triangle.b, triangle.c);
133
+ const isPointBintri = Triangle.containsPoint(this.endPoint, triangle.a, triangle.b, triangle.c);
134
+
135
+ // segment endpoint A and plane of triangle (when A projects inside V0V1V2)
136
+ let computed = false;
137
+ let a = NaN, b = NaN, c = NaN, nd = NaN;
138
+ if (isPointAintri) {
139
+ const lineVec1 = _lineVec1.subVectors(triangle.b, triangle.a);
140
+ const lineVec2 = _lineVec2.subVectors(triangle.c, triangle.a);
141
+ a = lineVec1.y * lineVec2.z - lineVec1.z * lineVec2.y;
142
+ b = lineVec1.z * lineVec2.x - lineVec1.x * lineVec2.z;
143
+ c = lineVec1.x * lineVec2.y - lineVec1.y * lineVec2.x;
144
+ const lineVec3 = _lineVec3.set(a, b, c);
145
+ computed = true;
146
+ nd = -lineVec3.normalize().dot(triangle.a);
147
+
148
+ d = lineVec3.dot(this.startPoint) + nd;
149
+ const l = d;
150
+ d *= d;
151
+ if (d < min) {
152
+ min = d;
153
+ target.startPoint.copy(this.startPoint);
154
+ target.endPoint.subVectors(this.startPoint, lineVec3.multiplyScalar(l));
155
+ }
156
+ }
157
+
158
+ // segment endpoint B and plane of triangle (when B projects inside V0V1V2)
159
+ if (isPointBintri) {
160
+ const lineVec3 = _lineVec3;
161
+ if (!computed) {
162
+ const lineVec1 = _lineVec1.subVectors(triangle.b, triangle.a);
163
+ const lineVec2 = _lineVec2.subVectors(triangle.c, triangle.a);
164
+ a = lineVec1.y * lineVec2.z - lineVec1.z * lineVec2.y;
165
+ b = lineVec1.z * lineVec2.x - lineVec1.x * lineVec2.z;
166
+ c = lineVec1.x * lineVec2.y - lineVec1.y * lineVec2.x;
167
+ lineVec3.set(a, b, c);
168
+ computed = true;
169
+ nd = -lineVec3.normalize().dot(triangle.a);
170
+ }
171
+ d = lineVec3.dot(this.endPoint) + nd;
172
+ const l = d;
173
+ d *= d;
174
+ if (d < min) {
175
+ min = d;
176
+ target.startPoint.copy(this.endPoint);
177
+ target.endPoint.subVectors(this.endPoint, lineVec3.multiplyScalar(l));
178
+ }
179
+ }
180
+
181
+ if (isPointBintri && isPointAintri) {
182
+ return target;
183
+ }
184
+
185
+ // AB -> V0V1
186
+ _lineSegmentEdge.setPoints(triangle.a, triangle.b);
187
+ this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
188
+ min = _tampTarget.getLength();
189
+ target.startPoint.copy(_tampTarget.startPoint);
190
+ target.endPoint.copy(_tampTarget.endPoint);
191
+
192
+ // AB -> V1V2
193
+ _lineSegmentEdge.setPoints(triangle.b, triangle.c);
194
+ this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
195
+ d = _tampTarget.getLength();
196
+ if (d < min) {
197
+ min = d;
198
+ target.startPoint.copy(_tampTarget.startPoint);
199
+ target.endPoint.copy(_tampTarget.endPoint);
200
+ }
201
+
202
+ // AB -> V2V0
203
+ _lineSegmentEdge.setPoints(triangle.c, triangle.a);
204
+ this.closestLineToLineSegment(_lineSegmentEdge, _tampTarget);
205
+ d = _tampTarget.getLength();
206
+ if (d < min) {
207
+ min = d;
208
+ target.startPoint.copy(_tampTarget.startPoint);
209
+ target.endPoint.copy(_tampTarget.endPoint);
210
+ }
211
+
212
+ return target;
213
+ }
214
+ }
215
+
216
+ }
217
+
218
+ const _vec3_1 = new Vector3();
219
+ const _vec3_2 = new Vector3();
220
+ const _mat4_1 = new Matrix4();
221
+
222
+ const _up = new Vector3(0, 1, 0);
223
+
224
+ const _ray = new Ray();
225
+
226
+ const _lineVec0 = new Vector3();
227
+
228
+ const _lineVec1 = new Vector3();
229
+ const _lineVec2 = new Vector3();
230
+ const _lineVec3 = new Vector3();
231
+
232
+ const _lineSegmentEdge = new LineSegment();
233
+
234
+ const _tampTarget = new LineSegment();
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "t3d-3dtiles",
3
+ "version": "0.1.0",
4
+ "description": "An extension for 3D Tiles based on t3d.js",
5
+ "type": "module",
6
+ "main": "./build/t3d.3dtiles.js",
7
+ "module": "./build/t3d.3dtiles.module.js",
8
+ "exports": {
9
+ ".": "./build/t3d.3dtiles.module.js",
10
+ "./src/*": "./src/*",
11
+ "./addons/*": "./examples/jsm/*"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/uinosoft/t3d-3dtiles"
16
+ },
17
+ "files": [
18
+ "build",
19
+ "examples/jsm",
20
+ "LICENSE",
21
+ "package.json",
22
+ "README.md",
23
+ "src"
24
+ ],
25
+ "keywords": [
26
+ "3dtiles",
27
+ "t3d",
28
+ "javascript",
29
+ "3d",
30
+ "webgl",
31
+ "webgl2",
32
+ "canvas",
33
+ "html5"
34
+ ],
35
+ "author": "uino",
36
+ "license": "BSD-3-Clause",
37
+ "devDependencies": {
38
+ "@babel/core": "^7.18.10",
39
+ "@babel/preset-env": "^7.18.10",
40
+ "@rollup/plugin-babel": "^6.0.3",
41
+ "@rollup/plugin-terser": "^0.4.0",
42
+ "eslint": "^8.57.0",
43
+ "eslint-plugin-html": "^8.1.1",
44
+ "eslint-plugin-import": "^2.29.0",
45
+ "rollup": "^4.18.0"
46
+ },
47
+ "peerDependencies": {
48
+ "t3d": "^0.2.7"
49
+ },
50
+ "scripts": {
51
+ "dev": "rollup -w -c",
52
+ "build": "rollup -c",
53
+ "lint": "eslint src",
54
+ "lint-fix": "eslint src --fix",
55
+ "lint-examples": "eslint examples --ext .html"
56
+ }
57
+ }
package/src/Tiles3D.js ADDED
@@ -0,0 +1,402 @@
1
+ import { EventDispatcher, LoadingManager, Matrix4, Object3D } from 't3d';
2
+ import { traverseSet } from './utils/Utils.js';
3
+ import { raycastTraverse, raycastTraverseFirstHit, distanceSort } from './utils/IntersectionUtils.js';
4
+ import RequestState from './utils/RequestState.js';
5
+ import { CameraList } from './utils/CameraList.js';
6
+ import { TilesLoader } from './utils/TilesLoader.js';
7
+ import { ModelLoader } from './utils/ModelLoader.js';
8
+ import { schedulingTiles } from './utils/TilesScheduler.js';
9
+
10
+ export class Tiles3D extends Object3D {
11
+
12
+ constructor(url, manager = new LoadingManager()) {
13
+ super();
14
+
15
+ // options
16
+
17
+ this.fetchOptions = {};
18
+ this.errorTarget = 6.0;
19
+ this.errorThreshold = Infinity;
20
+ this.loadSiblings = true;
21
+ this.displayActiveTiles = false;
22
+ this.maxDepth = Infinity;
23
+ this.stopAtEmptyTiles = true;
24
+
25
+ this.preprocessURL = null;
26
+ manager.setURLModifier(url => {
27
+ if (this.preprocessURL) {
28
+ return this.preprocessURL(url);
29
+ } else {
30
+ return url;
31
+ }
32
+ });
33
+ this.manager = manager;
34
+
35
+ // stats
36
+
37
+ this.stats = {
38
+ parsing: 0,
39
+ downloading: 0,
40
+ failed: 0,
41
+ inFrustum: 0,
42
+ used: 0,
43
+ active: 0,
44
+ visible: 0
45
+ };
46
+
47
+ this.frameCount = 0;
48
+
49
+ this.activeTiles = new Set();
50
+ this.visibleTiles = new Set();
51
+
52
+ // internals
53
+
54
+ this._rootURL = url;
55
+ this._rootTileSet = null;
56
+
57
+ this._autoDisableRendererCulling = true;
58
+
59
+ this.$cameras = new CameraList();
60
+ this.$tilesLoader = new TilesLoader();
61
+ this.$modelLoader = new ModelLoader(manager);
62
+ this.$events = new EventDispatcher();
63
+ }
64
+
65
+ get rootURL() {
66
+ return this._rootURL;
67
+ }
68
+
69
+ get rootTileSet() {
70
+ const rootTileSet = this._rootTileSet;
71
+
72
+ if (!rootTileSet) {
73
+ const url = this._rootURL;
74
+ this._rootTileSet = this.$tilesLoader.fetchTileSet(this.preprocessURL ? this.preprocessURL(url) : url, null, this.fetchOptions)
75
+ .then(json => {
76
+ this._rootTileSet = json;
77
+ })
78
+ .then(json => {
79
+ // Push this onto the end of the event stack to ensure this runs
80
+ // after the base renderer has placed the provided json where it
81
+ // needs to be placed and is ready for an update.
82
+ Promise.resolve().then(() => {
83
+ // TODO dispatch event only if this is the root tileset for now, we can
84
+ // dispatch this event for all tilesets in the future
85
+ _TileSetLoadedEvent.json = json;
86
+ _TileSetLoadedEvent.url = url;
87
+ this.$events.dispatchEvent(_TileSetLoadedEvent);
88
+ });
89
+ })
90
+ .catch(err => {
91
+ console.error(err);
92
+ this._rootTileSet = err;
93
+ });
94
+ return null;
95
+ } else if (rootTileSet instanceof Promise || rootTileSet instanceof Error) {
96
+ return null;
97
+ }
98
+
99
+ return rootTileSet;
100
+ }
101
+
102
+ get root() {
103
+ const rootTileSet = this.rootTileSet;
104
+ return rootTileSet ? rootTileSet.root : null;
105
+ }
106
+
107
+ get autoDisableRendererCulling() {
108
+ return this._autoDisableRendererCulling;
109
+ }
110
+
111
+ set autoDisableRendererCulling(value) {
112
+ if (this._autoDisableRendererCulling !== value) {
113
+ super._autoDisableRendererCulling = value;
114
+ this.traverse(tile => {
115
+ const scene = tile.cached.scene;
116
+ if (scene) {
117
+ scene.traverse(c => {
118
+ c.frustumCulled = c[INITIAL_FRUSTUM_CULLED] && !value;
119
+ });
120
+ }
121
+ });
122
+ }
123
+ }
124
+
125
+ setDRACOLoader(dracoLoader) {
126
+ this.$modelLoader.setDRACOLoader(dracoLoader);
127
+ }
128
+
129
+ setKTX2Loader(ktx2Loader) {
130
+ this.$modelLoader.setKTX2Loader(ktx2Loader);
131
+ }
132
+
133
+ addEventListener(type, listener, thisObject) {
134
+ this.$events.addEventListener(type, listener, thisObject);
135
+ }
136
+
137
+ removeEventListener(type, listener, thisObject) {
138
+ this.$events.removeEventListener(type, listener, thisObject);
139
+ }
140
+
141
+ update() {
142
+ const rootTile = this.root;
143
+ if (!rootTile) return;
144
+
145
+ const { stats } = this;
146
+ stats.inFrustum = 0;
147
+ stats.used = 0;
148
+ stats.active = 0;
149
+ stats.visible = 0;
150
+
151
+ this.frameCount++;
152
+
153
+ this.$cameras.updateInfos(this.worldMatrix);
154
+
155
+ schedulingTiles(rootTile, this);
156
+ }
157
+
158
+ addCamera(camera) {
159
+ return this.$cameras.add(camera);
160
+ }
161
+
162
+ removeCamera(camera) {
163
+ return this.$cameras.remove(camera);
164
+ }
165
+
166
+ resize(width, height) {
167
+ this.$cameras.setResolution(width, height);
168
+ }
169
+
170
+ raycast(ray, intersects) {
171
+ if (!this.root) {
172
+ return null;
173
+ }
174
+
175
+ raycastTraverse(this.root, this, ray, intersects);
176
+
177
+ intersects.sort(distanceSort);
178
+ }
179
+
180
+ raycastFirst(ray) {
181
+ if (!this.root) {
182
+ return null;
183
+ }
184
+
185
+ return raycastTraverseFirstHit(this.root, this, ray);
186
+ }
187
+
188
+ getBoundingBox(box) {
189
+ if (!this.root) {
190
+ return false;
191
+ }
192
+
193
+ const boundingVolume = this.root.cached.boundingVolume;
194
+
195
+ if (boundingVolume) {
196
+ boundingVolume.getBoundingBox(box);
197
+ return true;
198
+ } else {
199
+ return false;
200
+ }
201
+ }
202
+
203
+ getOrientedBoundingBox(targetBox, targetMatrix) {
204
+ if (!this.root) {
205
+ return false;
206
+ }
207
+
208
+ const boundingVolume = this.root.cached.boundingVolume;
209
+
210
+ if (boundingVolume) {
211
+ boundingVolume.getOrientedBoundingBox(targetBox, targetMatrix);
212
+ return true;
213
+ } else {
214
+ return false;
215
+ }
216
+ }
217
+
218
+ getBoundingSphere(sphere) {
219
+ if (!this.root) {
220
+ return false;
221
+ }
222
+
223
+ const boundingVolume = this.root.cached.boundingVolume;
224
+
225
+ if (boundingVolume) {
226
+ boundingVolume.getBoundingSphere(sphere);
227
+ return true;
228
+ } else {
229
+ return false;
230
+ }
231
+ }
232
+
233
+ traverse(beforecb, aftercb) {
234
+ const rootTile = this.root;
235
+ if (!rootTile) return;
236
+ traverseSet(rootTile, beforecb, aftercb);
237
+ }
238
+
239
+ resetFailedTiles() {
240
+ const stats = this.stats;
241
+ if (stats.failed === 0) {
242
+ return;
243
+ }
244
+
245
+ this.traverse(tile => {
246
+ if (tile.__loadingState === RequestState.FAILED) {
247
+ tile.__loadingState = RequestState.UNLOADED;
248
+ }
249
+ });
250
+
251
+ stats.failed = 0;
252
+ }
253
+
254
+ dispose() {
255
+ const lruCache = this.$tilesLoader.lruCache;
256
+ this.traverse(tile => {
257
+ lruCache.remove(tile);
258
+ });
259
+
260
+ this.stats = {
261
+ parsing: 0,
262
+ downloading: 0,
263
+ failed: 0,
264
+ inFrustum: 0,
265
+ used: 0,
266
+ active: 0,
267
+ visible: 0
268
+ };
269
+ this.frameCount = 0;
270
+ }
271
+
272
+ // override Object3D methods
273
+ updateMatrix(force) {
274
+ if (this.matrixAutoUpdate || this.matrixNeedsUpdate) {
275
+ this.matrix.transform(this.position, this.scale, this.quaternion);
276
+
277
+ this.matrixNeedsUpdate = false;
278
+ this.worldMatrixNeedsUpdate = true;
279
+ }
280
+
281
+ if (this.worldMatrixNeedsUpdate || force) {
282
+ if (this.parent === null) {
283
+ tempMat.copy(this.matrix);
284
+ } else {
285
+ tempMat.multiplyMatrices(this.parent.worldMatrix, this.matrix);
286
+ }
287
+ this.worldMatrixNeedsUpdate = false;
288
+
289
+ if (!matrixEquals(tempMat, this.worldMatrix)) {
290
+ this.worldMatrix.copy(tempMat);
291
+
292
+ // update children
293
+ // the children will not have to change unless the parent group has updated
294
+ const children = this.children;
295
+ for (let i = 0, l = children.length; i < l; i++) {
296
+ children[i].updateMatrix();
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ $parseTile(buffer, tile, extension) {
303
+ return this.$modelLoader.loadTileContent(buffer, tile, extension, this)
304
+ .then(scene => {
305
+ scene.traverse(c => {
306
+ c[INITIAL_FRUSTUM_CULLED] = c.frustumCulled; // store initial value
307
+ c.frustumCulled = c.frustumCulled && !this._autoDisableRendererCulling;
308
+ });
309
+
310
+ _TileLoadedEvent.scene = scene;
311
+ _TileLoadedEvent.tile = tile;
312
+ this.$events.dispatchEvent(_TileLoadedEvent);
313
+ });
314
+ }
315
+
316
+ $setTileVisible(tile, visible) {
317
+ const scene = tile.cached.scene;
318
+ if (!scene) {
319
+ return;
320
+ }
321
+ const visibleTiles = this.visibleTiles;
322
+ if (visible) {
323
+ this.add(scene);
324
+ visibleTiles.add(tile);
325
+ scene.updateMatrix(true); // TODO: remove this?
326
+ } else {
327
+ this.remove(scene);
328
+ visibleTiles.delete(tile);
329
+ }
330
+
331
+ _TileVisibilityChangedEvent.scene = scene;
332
+ _TileVisibilityChangedEvent.tile = tile;
333
+ _TileVisibilityChangedEvent.visible = visible;
334
+ this.$events.dispatchEvent(_TileVisibilityChangedEvent);
335
+ }
336
+
337
+ $setTileActive(tile, active) {
338
+ const activeTiles = this.activeTiles;
339
+ if (active) {
340
+ activeTiles.add(tile);
341
+ } else {
342
+ activeTiles.delete(tile);
343
+ }
344
+ }
345
+
346
+ $disposeTile(tile) {
347
+ // This could get called before the tile has finished downloading
348
+ const cached = tile.cached;
349
+ if (cached.scene) {
350
+ const materials = cached.materials;
351
+ const geometry = cached.geometry;
352
+ const textures = cached.textures;
353
+
354
+ for (let i = 0, l = geometry.length; i < l; i++) {
355
+ geometry[i].dispose();
356
+ }
357
+
358
+ for (let i = 0, l = materials.length; i < l; i++) {
359
+ materials[i].dispose();
360
+ }
361
+
362
+ for (let i = 0, l = textures.length; i < l; i++) {
363
+ const texture = textures[i];
364
+ texture.dispose();
365
+ }
366
+
367
+ _TileDisposedEvent.scene = cached.scene;
368
+ _TileDisposedEvent.tile = tile;
369
+ this.$events.dispatchEvent(_TileDisposedEvent);
370
+
371
+ cached.scene = null;
372
+ cached.materials = null;
373
+ cached.textures = null;
374
+ cached.geometry = null;
375
+ }
376
+
377
+ tile._loadIndex++;
378
+ }
379
+
380
+ }
381
+
382
+ const INITIAL_FRUSTUM_CULLED = Symbol('INITIAL_FRUSTUM_CULLED');
383
+
384
+ const _TileSetLoadedEvent = { type: 'TileSetLoaded', json: null, url: null };
385
+ const _TileLoadedEvent = { type: 'TileLoaded', scene: null, tile: null };
386
+ const _TileDisposedEvent = { type: 'TileDisposed', scene: null, tile: null };
387
+ const _TileVisibilityChangedEvent = { type: 'TileVisibilityChanged', scene: null, tile: null, visible: false };
388
+
389
+ const tempMat = new Matrix4();
390
+
391
+ const matrixEquals = (matrixA, matrixB, epsilon = Number.EPSILON) => {
392
+ const te = matrixA.elements;
393
+ const me = matrixB.elements;
394
+
395
+ for (let i = 0; i < 16; i++) {
396
+ if (Math.abs(te[i] - me[i]) > epsilon) {
397
+ return false;
398
+ }
399
+ }
400
+
401
+ return true;
402
+ };