@inweb/viewer-three 26.9.6 → 26.9.8
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/viewer-three.js +372 -126
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +357 -111
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/components/ResetComponent.d.ts +10 -0
- package/package.json +5 -5
- package/src/Viewer/commands/ResetView.ts +5 -1
- package/src/Viewer/commands/ZoomTo.ts +1 -1
- package/src/Viewer/components/ResetComponent.ts +64 -0
- package/src/Viewer/components/SelectionComponent.ts +4 -4
- package/src/Viewer/components/index.ts +2 -0
- package/src/Viewer/draggers/MeasureLineDragger.ts +175 -17
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +272 -105
package/dist/viewer-three.js
CHANGED
|
@@ -3509,11 +3509,11 @@
|
|
|
3509
3509
|
if ( this.isEmpty() ) {
|
|
3510
3510
|
return false;
|
|
3511
3511
|
}
|
|
3512
|
-
this.getCenter( _center );
|
|
3513
|
-
_extents.subVectors( this.max, _center );
|
|
3514
|
-
_v0$2.subVectors( triangle.a, _center );
|
|
3515
|
-
_v1$7.subVectors( triangle.b, _center );
|
|
3516
|
-
_v2$4.subVectors( triangle.c, _center );
|
|
3512
|
+
this.getCenter( _center$1 );
|
|
3513
|
+
_extents.subVectors( this.max, _center$1 );
|
|
3514
|
+
_v0$2.subVectors( triangle.a, _center$1 );
|
|
3515
|
+
_v1$7.subVectors( triangle.b, _center$1 );
|
|
3516
|
+
_v2$4.subVectors( triangle.c, _center$1 );
|
|
3517
3517
|
_f0.subVectors( _v1$7, _v0$2 );
|
|
3518
3518
|
_f1.subVectors( _v2$4, _v1$7 );
|
|
3519
3519
|
_f2.subVectors( _v0$2, _v2$4 );
|
|
@@ -3610,7 +3610,7 @@
|
|
|
3610
3610
|
const _f0 = new Vector3();
|
|
3611
3611
|
const _f1 = new Vector3();
|
|
3612
3612
|
const _f2 = new Vector3();
|
|
3613
|
-
const _center = new Vector3();
|
|
3613
|
+
const _center$1 = new Vector3();
|
|
3614
3614
|
const _extents = new Vector3();
|
|
3615
3615
|
const _triangleNormal = new Vector3();
|
|
3616
3616
|
const _testAxis = new Vector3();
|
|
@@ -8899,7 +8899,7 @@
|
|
|
8899
8899
|
const _skinWeight = new Vector4();
|
|
8900
8900
|
const _vector3 = new Vector3();
|
|
8901
8901
|
const _matrix4 = new Matrix4();
|
|
8902
|
-
const _vertex = new Vector3();
|
|
8902
|
+
const _vertex$1 = new Vector3();
|
|
8903
8903
|
const _sphere$5 = new Sphere();
|
|
8904
8904
|
const _inverseMatrix$2 = new Matrix4();
|
|
8905
8905
|
const _ray$2 = new Ray();
|
|
@@ -8922,8 +8922,8 @@
|
|
|
8922
8922
|
this.boundingBox.makeEmpty();
|
|
8923
8923
|
const positionAttribute = geometry.getAttribute( 'position' );
|
|
8924
8924
|
for ( let i = 0; i < positionAttribute.count; i ++ ) {
|
|
8925
|
-
this.getVertexPosition( i, _vertex );
|
|
8926
|
-
this.boundingBox.expandByPoint( _vertex );
|
|
8925
|
+
this.getVertexPosition( i, _vertex$1 );
|
|
8926
|
+
this.boundingBox.expandByPoint( _vertex$1 );
|
|
8927
8927
|
}
|
|
8928
8928
|
}
|
|
8929
8929
|
computeBoundingSphere() {
|
|
@@ -8934,8 +8934,8 @@
|
|
|
8934
8934
|
this.boundingSphere.makeEmpty();
|
|
8935
8935
|
const positionAttribute = geometry.getAttribute( 'position' );
|
|
8936
8936
|
for ( let i = 0; i < positionAttribute.count; i ++ ) {
|
|
8937
|
-
this.getVertexPosition( i, _vertex );
|
|
8938
|
-
this.boundingSphere.expandByPoint( _vertex );
|
|
8937
|
+
this.getVertexPosition( i, _vertex$1 );
|
|
8938
|
+
this.boundingSphere.expandByPoint( _vertex$1 );
|
|
8939
8939
|
}
|
|
8940
8940
|
}
|
|
8941
8941
|
copy( source, recursive ) {
|
|
@@ -10588,8 +10588,8 @@
|
|
|
10588
10588
|
object: object
|
|
10589
10589
|
};
|
|
10590
10590
|
}
|
|
10591
|
-
const _start$
|
|
10592
|
-
const _end$
|
|
10591
|
+
const _start$2 = new Vector3();
|
|
10592
|
+
const _end$2 = new Vector3();
|
|
10593
10593
|
class LineSegments extends Line$1 {
|
|
10594
10594
|
constructor( geometry, material ) {
|
|
10595
10595
|
super( geometry, material );
|
|
@@ -10602,10 +10602,10 @@
|
|
|
10602
10602
|
const positionAttribute = geometry.attributes.position;
|
|
10603
10603
|
const lineDistances = [];
|
|
10604
10604
|
for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
|
|
10605
|
-
_start$
|
|
10606
|
-
_end$
|
|
10605
|
+
_start$2.fromBufferAttribute( positionAttribute, i );
|
|
10606
|
+
_end$2.fromBufferAttribute( positionAttribute, i + 1 );
|
|
10607
10607
|
lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
|
|
10608
|
-
lineDistances[ i + 1 ] = lineDistances[ i ] + _start$
|
|
10608
|
+
lineDistances[ i + 1 ] = lineDistances[ i ] + _start$2.distanceTo( _end$2 );
|
|
10609
10609
|
}
|
|
10610
10610
|
geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
|
|
10611
10611
|
} else {
|
|
@@ -33831,6 +33831,8 @@ void main() {
|
|
|
33831
33831
|
}
|
|
33832
33832
|
|
|
33833
33833
|
const PRECISION = 0.01;
|
|
33834
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
33835
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
33834
33836
|
class MeasureLineDragger extends OrbitDragger {
|
|
33835
33837
|
constructor(viewer) {
|
|
33836
33838
|
super(viewer);
|
|
@@ -33845,7 +33847,10 @@ void main() {
|
|
|
33845
33847
|
this.onPointerMove = (event) => {
|
|
33846
33848
|
if (this.orbit.enabled && this.orbit.state !== -1)
|
|
33847
33849
|
return;
|
|
33848
|
-
|
|
33850
|
+
const snapPoint = this.snapper.getSnapPoint(event);
|
|
33851
|
+
if (snapPoint && this.line.endPoint && snapPoint.equals(this.line.endPoint))
|
|
33852
|
+
return;
|
|
33853
|
+
this.line.endPoint = snapPoint;
|
|
33849
33854
|
this.line.render();
|
|
33850
33855
|
if (this.line.startPoint)
|
|
33851
33856
|
this.changed = true;
|
|
@@ -33874,14 +33879,14 @@ void main() {
|
|
|
33874
33879
|
this.overlay.render();
|
|
33875
33880
|
};
|
|
33876
33881
|
this.updateSnapper = () => {
|
|
33877
|
-
this.snapper.update(this.viewer
|
|
33882
|
+
this.snapper.update(this.viewer);
|
|
33878
33883
|
};
|
|
33879
33884
|
this.overlay = new MeasureOverlay(viewer.camera, viewer.canvas);
|
|
33880
33885
|
this.overlay.attach();
|
|
33881
33886
|
this.line = new MeasureLine(this.overlay);
|
|
33882
33887
|
this.overlay.addLine(this.line);
|
|
33883
33888
|
this.snapper = new MeasureSnapper(viewer.camera, viewer.canvas);
|
|
33884
|
-
this.
|
|
33889
|
+
this.updateSnapper();
|
|
33885
33890
|
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown);
|
|
33886
33891
|
this.viewer.canvas.addEventListener("pointermove", this.onPointerMove);
|
|
33887
33892
|
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -33904,20 +33909,39 @@ void main() {
|
|
|
33904
33909
|
this.viewer.removeEventListener("isolate", this.updateSnapper);
|
|
33905
33910
|
this.viewer.removeEventListener("show", this.updateSnapper);
|
|
33906
33911
|
this.viewer.removeEventListener("showall", this.updateSnapper);
|
|
33912
|
+
this.snapper.dispose();
|
|
33907
33913
|
this.overlay.detach();
|
|
33908
33914
|
this.overlay.dispose();
|
|
33909
33915
|
super.dispose();
|
|
33910
33916
|
}
|
|
33911
33917
|
}
|
|
33918
|
+
const _vertex = new Vector3();
|
|
33919
|
+
const _start$1 = new Vector3();
|
|
33920
|
+
const _end$1 = new Vector3();
|
|
33921
|
+
const _line = new Line3();
|
|
33922
|
+
const _center = new Vector3();
|
|
33923
|
+
const _projection = new Vector3();
|
|
33912
33924
|
class MeasureSnapper {
|
|
33913
33925
|
constructor(camera, canvas) {
|
|
33914
|
-
this.objects = [];
|
|
33915
33926
|
this.camera = camera;
|
|
33916
33927
|
this.canvas = canvas;
|
|
33928
|
+
this.objects = [];
|
|
33917
33929
|
this.raycaster = new Raycaster();
|
|
33930
|
+
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
33931
|
+
this.edgesCache = new WeakMap();
|
|
33918
33932
|
}
|
|
33919
|
-
|
|
33920
|
-
|
|
33933
|
+
dispose() {
|
|
33934
|
+
this.objects = [];
|
|
33935
|
+
}
|
|
33936
|
+
isMobile() {
|
|
33937
|
+
if (typeof navigator === "undefined")
|
|
33938
|
+
return false;
|
|
33939
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
33940
|
+
}
|
|
33941
|
+
getMousePosition(event, target) {
|
|
33942
|
+
return target.set(event.clientX, event.clientY);
|
|
33943
|
+
}
|
|
33944
|
+
getPointerIntersects(mouse, objects) {
|
|
33921
33945
|
const rect = this.canvas.getBoundingClientRect();
|
|
33922
33946
|
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
33923
33947
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
@@ -33925,20 +33949,86 @@ void main() {
|
|
|
33925
33949
|
this.raycaster.setFromCamera(coords, this.camera);
|
|
33926
33950
|
this.raycaster.params = {
|
|
33927
33951
|
Mesh: {},
|
|
33928
|
-
Line: { threshold: 0.
|
|
33929
|
-
Line2: { threshold: 0.
|
|
33952
|
+
Line: { threshold: 0.05 },
|
|
33953
|
+
Line2: { threshold: 0.05 },
|
|
33930
33954
|
LOD: {},
|
|
33931
|
-
Points: { threshold: 0.
|
|
33955
|
+
Points: { threshold: 0.01 },
|
|
33932
33956
|
Sprite: {},
|
|
33933
33957
|
};
|
|
33934
|
-
|
|
33935
|
-
if (intersects.length === 0)
|
|
33936
|
-
return undefined;
|
|
33937
|
-
return intersects[0].point;
|
|
33958
|
+
return this.raycaster.intersectObjects(objects, false);
|
|
33938
33959
|
}
|
|
33939
|
-
|
|
33940
|
-
|
|
33941
|
-
|
|
33960
|
+
getDetectRadius(point) {
|
|
33961
|
+
const camera = this.camera;
|
|
33962
|
+
if (camera.isOrthographicCamera) {
|
|
33963
|
+
const worldHeight = camera.top - camera.bottom;
|
|
33964
|
+
const canvasHeight = this.canvas.height;
|
|
33965
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
33966
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
33967
|
+
}
|
|
33968
|
+
if (camera.isPerspectiveCamera) {
|
|
33969
|
+
const distance = camera.position.distanceTo(point);
|
|
33970
|
+
const worldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
33971
|
+
const canvasHeight = this.canvas.height;
|
|
33972
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
33973
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
33974
|
+
}
|
|
33975
|
+
return 0.1;
|
|
33976
|
+
}
|
|
33977
|
+
getSnapPoint(event) {
|
|
33978
|
+
const mouse = this.getMousePosition(event, new Vector2());
|
|
33979
|
+
const intersections = this.getPointerIntersects(mouse, this.objects);
|
|
33980
|
+
if (intersections.length === 0)
|
|
33981
|
+
return undefined;
|
|
33982
|
+
const object = intersections[0].object;
|
|
33983
|
+
const intersectionPoint = intersections[0].point;
|
|
33984
|
+
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
33985
|
+
let snapPoint;
|
|
33986
|
+
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
33987
|
+
const geometry = object.geometry;
|
|
33988
|
+
const positions = geometry.attributes.position.array;
|
|
33989
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
33990
|
+
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
33991
|
+
const distance = _vertex.distanceTo(localPoint);
|
|
33992
|
+
if (distance < snapDistance) {
|
|
33993
|
+
snapDistance = distance;
|
|
33994
|
+
snapPoint = _vertex.clone();
|
|
33995
|
+
}
|
|
33996
|
+
}
|
|
33997
|
+
if (snapPoint)
|
|
33998
|
+
return object.localToWorld(snapPoint);
|
|
33999
|
+
let edges = this.edgesCache.get(geometry);
|
|
34000
|
+
if (!edges) {
|
|
34001
|
+
edges = new EdgesGeometry(geometry);
|
|
34002
|
+
this.edgesCache.set(geometry, edges);
|
|
34003
|
+
}
|
|
34004
|
+
const edgePositions = edges.attributes.position.array;
|
|
34005
|
+
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
34006
|
+
_start$1.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
34007
|
+
_end$1.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
34008
|
+
_line.set(_start$1, _end$1);
|
|
34009
|
+
_line.getCenter(_center);
|
|
34010
|
+
const centerDistance = _center.distanceTo(localPoint);
|
|
34011
|
+
if (centerDistance < snapDistance) {
|
|
34012
|
+
snapDistance = centerDistance;
|
|
34013
|
+
snapPoint = _center.clone();
|
|
34014
|
+
continue;
|
|
34015
|
+
}
|
|
34016
|
+
_line.closestPointToPoint(localPoint, true, _projection);
|
|
34017
|
+
const lineDistance = _projection.distanceTo(localPoint);
|
|
34018
|
+
if (lineDistance < snapDistance) {
|
|
34019
|
+
snapDistance = lineDistance;
|
|
34020
|
+
snapPoint = _projection.clone();
|
|
34021
|
+
}
|
|
34022
|
+
}
|
|
34023
|
+
if (snapPoint)
|
|
34024
|
+
return object.localToWorld(snapPoint);
|
|
34025
|
+
return intersectionPoint.clone();
|
|
34026
|
+
}
|
|
34027
|
+
update(viewer) {
|
|
34028
|
+
this.objects.length = 0;
|
|
34029
|
+
viewer.models.forEach((model) => {
|
|
34030
|
+
model.getVisibleObjects().forEach((object) => this.objects.push(object));
|
|
34031
|
+
});
|
|
33942
34032
|
}
|
|
33943
34033
|
}
|
|
33944
34034
|
class MeasureOverlay {
|
|
@@ -33960,6 +34050,8 @@ void main() {
|
|
|
33960
34050
|
this.container.style.outline = "none";
|
|
33961
34051
|
this.container.style.pointerEvents = "none";
|
|
33962
34052
|
this.container.style.overflow = "hidden";
|
|
34053
|
+
if (!this.canvas.parentElement)
|
|
34054
|
+
return;
|
|
33963
34055
|
this.canvas.parentElement.appendChild(this.container);
|
|
33964
34056
|
}
|
|
33965
34057
|
dispose() {
|
|
@@ -33990,7 +34082,7 @@ void main() {
|
|
|
33990
34082
|
const _middlePoint = new Vector3();
|
|
33991
34083
|
class MeasureLine {
|
|
33992
34084
|
constructor(overlay) {
|
|
33993
|
-
this.id =
|
|
34085
|
+
this.id = MathUtils.generateUUID();
|
|
33994
34086
|
this.unit = "";
|
|
33995
34087
|
this.scale = 1.0;
|
|
33996
34088
|
this.size = 10.0;
|
|
@@ -34014,6 +34106,10 @@ void main() {
|
|
|
34014
34106
|
this.elementEndPoint.remove();
|
|
34015
34107
|
this.elementLine.remove();
|
|
34016
34108
|
this.elementLabel.remove();
|
|
34109
|
+
this.elementStartPoint = undefined;
|
|
34110
|
+
this.elementEndPoint = undefined;
|
|
34111
|
+
this.elementLine = undefined;
|
|
34112
|
+
this.elementLabel = undefined;
|
|
34017
34113
|
}
|
|
34018
34114
|
render() {
|
|
34019
34115
|
const projector = this.overlay.projector;
|
|
@@ -34670,7 +34766,7 @@ void main() {
|
|
|
34670
34766
|
if (camera.isPerspectiveCamera) {
|
|
34671
34767
|
const offset = new Vector3(0, 0, 1)
|
|
34672
34768
|
.applyQuaternion(camera.quaternion)
|
|
34673
|
-
.multiplyScalar(boxSize / Math.tan(MathUtils.
|
|
34769
|
+
.multiplyScalar(boxSize / Math.tan(MathUtils.degToRad(camera.fov * 0.5)));
|
|
34674
34770
|
camera.position.copy(offset).add(boxCenter);
|
|
34675
34771
|
camera.updateMatrixWorld();
|
|
34676
34772
|
}
|
|
@@ -34756,6 +34852,7 @@ void main() {
|
|
|
34756
34852
|
}
|
|
34757
34853
|
|
|
34758
34854
|
function resetView(viewer) {
|
|
34855
|
+
const reset = viewer.getComponent("ResetComponent");
|
|
34759
34856
|
viewer.executeCommand("setActiveDragger");
|
|
34760
34857
|
viewer.executeCommand("clearSlices");
|
|
34761
34858
|
viewer.executeCommand("clearOverlay");
|
|
@@ -34764,7 +34861,7 @@ void main() {
|
|
|
34764
34861
|
viewer.executeCommand("showAll");
|
|
34765
34862
|
viewer.executeCommand("explode", 0);
|
|
34766
34863
|
viewer.executeCommand("zoomToExtents", true);
|
|
34767
|
-
|
|
34864
|
+
reset.resetCameraPosition();
|
|
34768
34865
|
viewer.emit({ type: "resetview" });
|
|
34769
34866
|
}
|
|
34770
34867
|
|
|
@@ -35970,12 +36067,12 @@ void main() {
|
|
|
35970
36067
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
35971
36068
|
const coords = new Vector2(x, y);
|
|
35972
36069
|
this.raycaster.setFromCamera(coords, this.viewer.camera);
|
|
35973
|
-
this.raycaster.params =
|
|
36070
|
+
this.raycaster.params = {
|
|
35974
36071
|
Mesh: {},
|
|
35975
|
-
Line: { threshold: 0.
|
|
35976
|
-
Line2: { threshold: 0.
|
|
36072
|
+
Line: { threshold: 0.05 },
|
|
36073
|
+
Line2: { threshold: 0.05 },
|
|
35977
36074
|
LOD: {},
|
|
35978
|
-
Points: { threshold: 0.
|
|
36075
|
+
Points: { threshold: 0.01 },
|
|
35979
36076
|
Sprite: {},
|
|
35980
36077
|
};
|
|
35981
36078
|
return this.raycaster.intersectObjects(objects, false);
|
|
@@ -36141,6 +36238,31 @@ void main() {
|
|
|
36141
36238
|
}
|
|
36142
36239
|
}
|
|
36143
36240
|
|
|
36241
|
+
class ResetComponent {
|
|
36242
|
+
constructor(viewer) {
|
|
36243
|
+
this.savedCameraPosition = null;
|
|
36244
|
+
this.onDatabaseChunk = () => {
|
|
36245
|
+
this.savedCameraPosition = {
|
|
36246
|
+
position: this.viewer.camera.position.clone(),
|
|
36247
|
+
up: this.viewer.camera.up.clone(),
|
|
36248
|
+
direction: this.viewer.camera.getWorldDirection(new Vector3()),
|
|
36249
|
+
};
|
|
36250
|
+
};
|
|
36251
|
+
this.viewer = viewer;
|
|
36252
|
+
this.viewer.addEventListener("databasechunk", this.onDatabaseChunk);
|
|
36253
|
+
}
|
|
36254
|
+
dispose() {
|
|
36255
|
+
this.viewer.removeEventListener("databasechunk", this.onDatabaseChunk);
|
|
36256
|
+
}
|
|
36257
|
+
resetCameraPosition() {
|
|
36258
|
+
if (this.savedCameraPosition) {
|
|
36259
|
+
this.viewer.camera.position.copy(this.savedCameraPosition.position);
|
|
36260
|
+
this.viewer.camera.up.copy(this.savedCameraPosition.up);
|
|
36261
|
+
this.viewer.camera.lookAt(this.savedCameraPosition.position.clone().add(this.savedCameraPosition.direction));
|
|
36262
|
+
}
|
|
36263
|
+
}
|
|
36264
|
+
}
|
|
36265
|
+
|
|
36144
36266
|
const components = componentsRegistry("threejs");
|
|
36145
36267
|
components.registerComponent("ExtentsComponent", (viewer) => new ExtentsComponent(viewer));
|
|
36146
36268
|
components.registerComponent("CameraComponent", (viewer) => new CameraComponent(viewer));
|
|
@@ -36151,6 +36273,7 @@ void main() {
|
|
|
36151
36273
|
components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
|
|
36152
36274
|
components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
|
|
36153
36275
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
36276
|
+
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
36154
36277
|
|
|
36155
36278
|
function mergeGeometries( geometries, useGroups = false ) {
|
|
36156
36279
|
const isIndexed = geometries[ 0 ].index !== null;
|
|
@@ -39507,6 +39630,12 @@ void main() {
|
|
|
39507
39630
|
this.maxConcurrentChunks = 8;
|
|
39508
39631
|
this.activeChunkLoads = 0;
|
|
39509
39632
|
this.chunkQueue = [];
|
|
39633
|
+
this.objectIdToIndex = new Map();
|
|
39634
|
+
this.maxObjectId = 0;
|
|
39635
|
+
this.objectVisibility = new Float32Array();
|
|
39636
|
+
this.maxConcurrentChunks = 6;
|
|
39637
|
+
this.mergedObjectMap = new Map();
|
|
39638
|
+
this.mergedGeometryVisibility = new Map();
|
|
39510
39639
|
}
|
|
39511
39640
|
setVisibleEdges(visible) {
|
|
39512
39641
|
this.visibleEdges = visible;
|
|
@@ -40213,6 +40342,50 @@ void main() {
|
|
|
40213
40342
|
this.originalObjects.clear();
|
|
40214
40343
|
this.originalObjectsToSelection.clear();
|
|
40215
40344
|
}
|
|
40345
|
+
initializeObjectVisibility() {
|
|
40346
|
+
if (this.maxObjectId > 0) {
|
|
40347
|
+
this.objectVisibility = new Float32Array(this.maxObjectId);
|
|
40348
|
+
for (let i = 0; i < this.maxObjectId; i++) {
|
|
40349
|
+
this.objectVisibility[i] = 1.0;
|
|
40350
|
+
}
|
|
40351
|
+
console.log(`Initialized object visibility array: ${this.maxObjectId} objects`);
|
|
40352
|
+
}
|
|
40353
|
+
}
|
|
40354
|
+
createVisibilityMaterial(material) {
|
|
40355
|
+
material.onBeforeCompile = (shader) => {
|
|
40356
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
40357
|
+
"#include <common>",
|
|
40358
|
+
`
|
|
40359
|
+
#include <common>
|
|
40360
|
+
attribute float visibility;
|
|
40361
|
+
varying float vVisibility;
|
|
40362
|
+
`
|
|
40363
|
+
);
|
|
40364
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
40365
|
+
"#include <common>",
|
|
40366
|
+
`
|
|
40367
|
+
#include <common>
|
|
40368
|
+
varying float vVisibility;
|
|
40369
|
+
`
|
|
40370
|
+
);
|
|
40371
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
40372
|
+
"void main() {",
|
|
40373
|
+
`
|
|
40374
|
+
void main() {
|
|
40375
|
+
vVisibility = visibility;
|
|
40376
|
+
`
|
|
40377
|
+
);
|
|
40378
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
40379
|
+
"void main() {",
|
|
40380
|
+
`
|
|
40381
|
+
void main() {
|
|
40382
|
+
if (vVisibility < 0.5) discard;
|
|
40383
|
+
`
|
|
40384
|
+
);
|
|
40385
|
+
};
|
|
40386
|
+
material.needsUpdate = true;
|
|
40387
|
+
return material;
|
|
40388
|
+
}
|
|
40216
40389
|
clear() {
|
|
40217
40390
|
this.chunkQueue = [];
|
|
40218
40391
|
this.structures.forEach((structure) => {
|
|
@@ -40318,6 +40491,9 @@ void main() {
|
|
|
40318
40491
|
this.loadedGeometrySize = 0;
|
|
40319
40492
|
this.abortController = new AbortController();
|
|
40320
40493
|
this.updateMemoryIndicator();
|
|
40494
|
+
this.objectIdToIndex.clear();
|
|
40495
|
+
this.maxObjectId = 0;
|
|
40496
|
+
this.objectVisibility = new Float32Array();
|
|
40321
40497
|
}
|
|
40322
40498
|
setStructureTransform(structureId, matrix) {
|
|
40323
40499
|
const rootGroup = this.structureRoots.get(structureId);
|
|
@@ -40467,18 +40643,43 @@ void main() {
|
|
|
40467
40643
|
this.originalObjectsToSelection.add(obj);
|
|
40468
40644
|
}
|
|
40469
40645
|
});
|
|
40646
|
+
this.initializeObjectVisibility();
|
|
40647
|
+
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
40470
40648
|
this.dispatchEvent("update");
|
|
40471
40649
|
}
|
|
40472
40650
|
mergeMeshGroups(materialGroups, rootGroup) {
|
|
40473
40651
|
for (const group of materialGroups) {
|
|
40652
|
+
if (!group.material) {
|
|
40653
|
+
console.warn("Skipping mesh group with null material");
|
|
40654
|
+
continue;
|
|
40655
|
+
}
|
|
40474
40656
|
try {
|
|
40475
40657
|
const geometries = [];
|
|
40476
40658
|
const handles = new Set();
|
|
40477
40659
|
const optimizedObjects = [];
|
|
40660
|
+
const objectMapping = new Map();
|
|
40661
|
+
let currentVertexOffset = 0;
|
|
40478
40662
|
for (const mesh of group.objects) {
|
|
40479
40663
|
const geometry = mesh.geometry.clone();
|
|
40480
40664
|
mesh.updateWorldMatrix(true, false);
|
|
40481
40665
|
geometry.applyMatrix4(mesh.matrixWorld);
|
|
40666
|
+
const handle = mesh.userData.handle;
|
|
40667
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
40668
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
40669
|
+
}
|
|
40670
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
40671
|
+
const vertexCount = geometry.attributes.position.count;
|
|
40672
|
+
const objectIds = new Float32Array(vertexCount);
|
|
40673
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
40674
|
+
objectIds[i] = objectId;
|
|
40675
|
+
}
|
|
40676
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
40677
|
+
objectMapping.set(mesh, {
|
|
40678
|
+
geometry,
|
|
40679
|
+
startVertexIndex: currentVertexOffset,
|
|
40680
|
+
vertexCount: geometry.attributes.position.count,
|
|
40681
|
+
});
|
|
40682
|
+
currentVertexOffset += geometry.attributes.position.count;
|
|
40482
40683
|
geometries.push(geometry);
|
|
40483
40684
|
optimizedObjects.push(mesh);
|
|
40484
40685
|
handles.add(mesh.userData.handle);
|
|
@@ -40486,13 +40687,26 @@ void main() {
|
|
|
40486
40687
|
const mergedObjects = [];
|
|
40487
40688
|
if (geometries.length > 0) {
|
|
40488
40689
|
const mergedGeometry = mergeGeometries(geometries);
|
|
40690
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
40691
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
40692
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
40693
|
+
visibilityArray[i] = 1.0;
|
|
40694
|
+
}
|
|
40695
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40489
40696
|
if (this.useVAO) {
|
|
40490
40697
|
this.createVAO(mergedGeometry);
|
|
40491
40698
|
}
|
|
40492
|
-
const
|
|
40699
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40700
|
+
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
40493
40701
|
rootGroup.add(mergedMesh);
|
|
40494
40702
|
this.mergedMesh.add(mergedMesh);
|
|
40495
40703
|
this.optimizedOriginalMap.set(mergedMesh, optimizedObjects);
|
|
40704
|
+
this.mergedObjectMap.set(mergedMesh.uuid, {
|
|
40705
|
+
objectMapping,
|
|
40706
|
+
visibilityArray,
|
|
40707
|
+
totalVertices,
|
|
40708
|
+
});
|
|
40709
|
+
this.mergedGeometryVisibility.set(mergedMesh, visibilityArray);
|
|
40496
40710
|
mergedObjects.push(mergedMesh);
|
|
40497
40711
|
geometries.forEach((geometry) => {
|
|
40498
40712
|
geometry.dispose();
|
|
@@ -40518,8 +40732,14 @@ void main() {
|
|
|
40518
40732
|
mergeLineGroups(materialGroups, rootGroup) {
|
|
40519
40733
|
for (const group of materialGroups) {
|
|
40520
40734
|
if (group.objects.length === 0) continue;
|
|
40735
|
+
if (!group.material) {
|
|
40736
|
+
console.warn("Skipping line group with null material");
|
|
40737
|
+
continue;
|
|
40738
|
+
}
|
|
40521
40739
|
const handles = new Set();
|
|
40522
40740
|
let totalVertices = 0;
|
|
40741
|
+
const objectMapping = new Map();
|
|
40742
|
+
let currentVertexOffset = 0;
|
|
40523
40743
|
group.objects.map((line) => {
|
|
40524
40744
|
handles.add(line.userData.handle);
|
|
40525
40745
|
totalVertices += line.geometry.attributes.position.count;
|
|
@@ -40532,6 +40752,15 @@ void main() {
|
|
|
40532
40752
|
const geometry = line.geometry;
|
|
40533
40753
|
const positionAttr = geometry.attributes.position;
|
|
40534
40754
|
const vertexCount = positionAttr.count;
|
|
40755
|
+
const handle = line.userData.handle;
|
|
40756
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
40757
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
40758
|
+
}
|
|
40759
|
+
objectMapping.set(line, {
|
|
40760
|
+
startVertexIndex: currentVertexOffset,
|
|
40761
|
+
vertexCount,
|
|
40762
|
+
});
|
|
40763
|
+
currentVertexOffset += vertexCount;
|
|
40535
40764
|
line.updateWorldMatrix(true, false);
|
|
40536
40765
|
const matrix = line.matrixWorld;
|
|
40537
40766
|
const vector = new Vector3();
|
|
@@ -40552,7 +40781,24 @@ void main() {
|
|
|
40552
40781
|
geometry.setIndex(indices);
|
|
40553
40782
|
geometry.computeBoundingSphere();
|
|
40554
40783
|
geometry.computeBoundingBox();
|
|
40555
|
-
const
|
|
40784
|
+
const objectIds = new Float32Array(totalVertices);
|
|
40785
|
+
let vertexIndex = 0;
|
|
40786
|
+
group.objects.forEach((line) => {
|
|
40787
|
+
const vertexCount = line.geometry.attributes.position.count;
|
|
40788
|
+
const handle = line.userData.handle;
|
|
40789
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
40790
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
40791
|
+
objectIds[vertexIndex++] = objectId;
|
|
40792
|
+
}
|
|
40793
|
+
});
|
|
40794
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
40795
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
40796
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
40797
|
+
visibilityArray[i] = 1.0;
|
|
40798
|
+
}
|
|
40799
|
+
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40800
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40801
|
+
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
40556
40802
|
const mergedObjects = [mergedLine];
|
|
40557
40803
|
if (this.useVAO) {
|
|
40558
40804
|
this.createVAO(mergedLine);
|
|
@@ -40560,6 +40806,12 @@ void main() {
|
|
|
40560
40806
|
rootGroup.add(mergedLine);
|
|
40561
40807
|
this.mergedLines.add(mergedLine);
|
|
40562
40808
|
this.optimizedOriginalMap.set(mergedLine, group.objects);
|
|
40809
|
+
this.mergedObjectMap.set(mergedLine.uuid, {
|
|
40810
|
+
objectMapping,
|
|
40811
|
+
visibilityArray,
|
|
40812
|
+
totalVertices,
|
|
40813
|
+
});
|
|
40814
|
+
this.mergedGeometryVisibility.set(mergedLine, visibilityArray);
|
|
40563
40815
|
handles.forEach((handle) => {
|
|
40564
40816
|
if (this.handleToOptimizedObjects.has(handle)) {
|
|
40565
40817
|
const existingObjects = this.handleToOptimizedObjects.get(handle);
|
|
@@ -40573,14 +40825,37 @@ void main() {
|
|
|
40573
40825
|
}
|
|
40574
40826
|
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
40575
40827
|
for (const group of materialGroups) {
|
|
40828
|
+
if (!group.material) {
|
|
40829
|
+
console.warn("Skipping line segment group with null material");
|
|
40830
|
+
continue;
|
|
40831
|
+
}
|
|
40576
40832
|
try {
|
|
40577
40833
|
const geometries = [];
|
|
40578
40834
|
const optimizedObjects = [];
|
|
40579
40835
|
const handles = new Set();
|
|
40836
|
+
const objectMapping = new Map();
|
|
40837
|
+
let currentVertexOffset = 0;
|
|
40580
40838
|
for (const line of group.objects) {
|
|
40581
40839
|
const geometry = line.geometry.clone();
|
|
40582
40840
|
line.updateWorldMatrix(true, false);
|
|
40583
40841
|
geometry.applyMatrix4(line.matrixWorld);
|
|
40842
|
+
const handle = line.userData.handle;
|
|
40843
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
40844
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
40845
|
+
}
|
|
40846
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
40847
|
+
const vertexCount = geometry.attributes.position.count;
|
|
40848
|
+
const objectIds = new Float32Array(vertexCount);
|
|
40849
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
40850
|
+
objectIds[i] = objectId;
|
|
40851
|
+
}
|
|
40852
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
40853
|
+
objectMapping.set(line, {
|
|
40854
|
+
geometry,
|
|
40855
|
+
startVertexIndex: currentVertexOffset,
|
|
40856
|
+
vertexCount: geometry.attributes.position.count,
|
|
40857
|
+
});
|
|
40858
|
+
currentVertexOffset += geometry.attributes.position.count;
|
|
40584
40859
|
geometries.push(geometry);
|
|
40585
40860
|
optimizedObjects.push(line);
|
|
40586
40861
|
handles.add(line.userData.handle);
|
|
@@ -40588,13 +40863,26 @@ void main() {
|
|
|
40588
40863
|
const mergedObjects = [];
|
|
40589
40864
|
if (geometries.length > 0) {
|
|
40590
40865
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
40591
|
-
const
|
|
40866
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
40867
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
40868
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
40869
|
+
visibilityArray[i] = 1.0;
|
|
40870
|
+
}
|
|
40871
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40872
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40873
|
+
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
40592
40874
|
if (this.useVAO) {
|
|
40593
40875
|
this.createVAO(mergedLine);
|
|
40594
40876
|
}
|
|
40595
40877
|
rootGroup.add(mergedLine);
|
|
40596
40878
|
this.mergedLineSegments.add(mergedLine);
|
|
40597
40879
|
this.optimizedOriginalMap.set(mergedLine, optimizedObjects);
|
|
40880
|
+
this.mergedObjectMap.set(mergedLine.uuid, {
|
|
40881
|
+
objectMapping,
|
|
40882
|
+
visibilityArray,
|
|
40883
|
+
totalVertices,
|
|
40884
|
+
});
|
|
40885
|
+
this.mergedGeometryVisibility.set(mergedLine, visibilityArray);
|
|
40598
40886
|
mergedObjects.push(mergedLine);
|
|
40599
40887
|
geometries.forEach((geometry) => {
|
|
40600
40888
|
geometry.dispose();
|
|
@@ -40619,6 +40907,10 @@ void main() {
|
|
|
40619
40907
|
}
|
|
40620
40908
|
mergePointsGroups(materialGroups, rootGroup) {
|
|
40621
40909
|
for (const group of materialGroups) {
|
|
40910
|
+
if (!group.material) {
|
|
40911
|
+
console.warn("Skipping points group with null material");
|
|
40912
|
+
continue;
|
|
40913
|
+
}
|
|
40622
40914
|
try {
|
|
40623
40915
|
const geometries = [];
|
|
40624
40916
|
const optimizedObjects = [];
|
|
@@ -40801,97 +41093,51 @@ void main() {
|
|
|
40801
41093
|
});
|
|
40802
41094
|
this.syncHiddenObjects();
|
|
40803
41095
|
}
|
|
40804
|
-
|
|
40805
|
-
if (
|
|
40806
|
-
|
|
40807
|
-
|
|
40808
|
-
|
|
40809
|
-
|
|
40810
|
-
|
|
40811
|
-
|
|
40812
|
-
for (
|
|
40813
|
-
|
|
40814
|
-
|
|
40815
|
-
|
|
41096
|
+
_updateVisibilityAttribute(mergedObject) {
|
|
41097
|
+
if (
|
|
41098
|
+
mergedObject.geometry &&
|
|
41099
|
+
mergedObject.geometry.attributes.visibility &&
|
|
41100
|
+
mergedObject.geometry.attributes.objectId
|
|
41101
|
+
) {
|
|
41102
|
+
const visibilityArray = mergedObject.geometry.attributes.visibility.array;
|
|
41103
|
+
const objectIdArray = mergedObject.geometry.attributes.objectId.array;
|
|
41104
|
+
for (let i = 0; i < visibilityArray.length; i++) {
|
|
41105
|
+
const objectId = objectIdArray[i];
|
|
41106
|
+
if (objectId < this.objectVisibility.length) {
|
|
41107
|
+
visibilityArray[i] = this.objectVisibility[objectId];
|
|
41108
|
+
}
|
|
40816
41109
|
}
|
|
40817
|
-
|
|
41110
|
+
mergedObject.geometry.attributes.visibility.needsUpdate = true;
|
|
40818
41111
|
}
|
|
40819
|
-
|
|
41112
|
+
}
|
|
41113
|
+
syncHiddenObjects() {
|
|
41114
|
+
if (this.mergedObjectMap.size === 0) {
|
|
41115
|
+
console.log("No merged objects to sync");
|
|
40820
41116
|
return;
|
|
40821
41117
|
}
|
|
40822
|
-
this.
|
|
40823
|
-
|
|
40824
|
-
|
|
40825
|
-
objects.forEach((x) => this.oldOptimizeObjects.add(x));
|
|
41118
|
+
if (this.objectVisibility.length > 0) {
|
|
41119
|
+
for (let i = 0; i < this.objectVisibility.length; i++) {
|
|
41120
|
+
this.objectVisibility[i] = 1.0;
|
|
40826
41121
|
}
|
|
40827
|
-
|
|
40828
|
-
|
|
40829
|
-
|
|
40830
|
-
|
|
40831
|
-
const updateListToOptimize = [];
|
|
40832
|
-
originObjects.forEach((obj) => {
|
|
40833
|
-
if (!this.hiddenHandles.has(obj.userData.handle)) {
|
|
40834
|
-
updateListToOptimize.push(obj);
|
|
41122
|
+
this.hiddenHandles.forEach((handle) => {
|
|
41123
|
+
const index = this.objectIdToIndex.get(handle);
|
|
41124
|
+
if (index !== undefined && index < this.objectVisibility.length) {
|
|
41125
|
+
this.objectVisibility[index] = 0.0;
|
|
40835
41126
|
}
|
|
40836
41127
|
});
|
|
40837
|
-
|
|
40838
|
-
|
|
40839
|
-
|
|
40840
|
-
|
|
40841
|
-
|
|
40842
|
-
|
|
40843
|
-
|
|
40844
|
-
|
|
40845
|
-
|
|
40846
|
-
|
|
40847
|
-
|
|
40848
|
-
|
|
40849
|
-
|
|
40850
|
-
mergedObject.visible = true;
|
|
40851
|
-
optimizedObject.parent.add(mergedObject);
|
|
40852
|
-
this.newOptimizedObjects.add(mergedObject);
|
|
40853
|
-
geometries.forEach((geometry) => {
|
|
40854
|
-
geometry.dispose();
|
|
40855
|
-
});
|
|
40856
|
-
} else if (firstObject instanceof Line$1) {
|
|
40857
|
-
let totalVertices = 0;
|
|
40858
|
-
updateListToOptimize.map((line) => {
|
|
40859
|
-
totalVertices += line.geometry.attributes.position.count;
|
|
40860
|
-
});
|
|
40861
|
-
const positions = new Float32Array(totalVertices * 3);
|
|
40862
|
-
let posOffset = 0;
|
|
40863
|
-
const indices = [];
|
|
40864
|
-
let vertexOffset = 0;
|
|
40865
|
-
updateListToOptimize.forEach((line) => {
|
|
40866
|
-
const geometry = line.geometry;
|
|
40867
|
-
const positionAttr = geometry.attributes.position;
|
|
40868
|
-
const vertexCount = positionAttr.count;
|
|
40869
|
-
line.updateWorldMatrix(true, false);
|
|
40870
|
-
const matrix = line.matrixWorld;
|
|
40871
|
-
const vector = new Vector3();
|
|
40872
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
40873
|
-
vector.fromBufferAttribute(positionAttr, i);
|
|
40874
|
-
vector.applyMatrix4(matrix);
|
|
40875
|
-
positions[posOffset++] = vector.x;
|
|
40876
|
-
positions[posOffset++] = vector.y;
|
|
40877
|
-
positions[posOffset++] = vector.z;
|
|
40878
|
-
}
|
|
40879
|
-
for (let i = 0; i < vertexCount - 1; i++) {
|
|
40880
|
-
indices.push(vertexOffset + i, vertexOffset + i + 1);
|
|
40881
|
-
}
|
|
40882
|
-
vertexOffset += vertexCount;
|
|
40883
|
-
});
|
|
40884
|
-
const geometry = new BufferGeometry();
|
|
40885
|
-
geometry.setAttribute("position", new BufferAttribute(positions, 3));
|
|
40886
|
-
geometry.setIndex(indices);
|
|
40887
|
-
geometry.computeBoundingSphere();
|
|
40888
|
-
geometry.computeBoundingBox();
|
|
40889
|
-
const mergedLine = new LineSegments(geometry, optimizedObject.material);
|
|
40890
|
-
mergedLine.visible = true;
|
|
40891
|
-
optimizedObject.parent.add(mergedLine);
|
|
40892
|
-
this.newOptimizedObjects.add(mergedLine);
|
|
40893
|
-
}
|
|
40894
|
-
});
|
|
41128
|
+
}
|
|
41129
|
+
for (const mesh of this.mergedMesh) {
|
|
41130
|
+
this._updateVisibilityAttribute(mesh);
|
|
41131
|
+
}
|
|
41132
|
+
for (const line of this.mergedLines) {
|
|
41133
|
+
this._updateVisibilityAttribute(line);
|
|
41134
|
+
}
|
|
41135
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
41136
|
+
this._updateVisibilityAttribute(lineSegment);
|
|
41137
|
+
}
|
|
41138
|
+
for (const point of this.mergedPoints) {
|
|
41139
|
+
this._updateVisibilityAttribute(point);
|
|
41140
|
+
}
|
|
40895
41141
|
}
|
|
40896
41142
|
getStructureGeometryExtent(structureId) {
|
|
40897
41143
|
const extent = new Box3();
|