@inweb/viewer-three 26.9.7 → 26.9.9

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.
@@ -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$1 = new Vector3();
10592
- const _end$1 = new Vector3();
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$1.fromBufferAttribute( positionAttribute, i );
10606
- _end$1.fromBufferAttribute( positionAttribute, i + 1 );
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$1.distanceTo( _end$1 );
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
- this.line.endPoint = this.snapper.getSnapPoint(event);
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.scene);
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.snapper.update(viewer.scene);
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
- getSnapPoint(event) {
33920
- const mouse = new Vector2(event.clientX, event.clientY);
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.25 },
33929
- Line2: { threshold: 0.25 },
33952
+ Line: { threshold: 0.05 },
33953
+ Line2: { threshold: 0.05 },
33930
33954
  LOD: {},
33931
- Points: { threshold: 0.1 },
33955
+ Points: { threshold: 0.01 },
33932
33956
  Sprite: {},
33933
33957
  };
33934
- const intersects = this.raycaster.intersectObjects(this.objects, false);
33935
- if (intersects.length === 0)
33936
- return undefined;
33937
- return intersects[0].point;
33958
+ return this.raycaster.intersectObjects(objects, false);
33938
33959
  }
33939
- update(scene) {
33940
- this.objects = [];
33941
- scene.traverseVisible((child) => this.objects.push(child));
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 = Date.now();
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.DEG2RAD * camera.fov * 0.5));
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
  }
@@ -35971,12 +36067,12 @@ void main() {
35971
36067
  const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
35972
36068
  const coords = new Vector2(x, y);
35973
36069
  this.raycaster.setFromCamera(coords, this.viewer.camera);
35974
- this.raycaster.params = this.raycaster.params = {
36070
+ this.raycaster.params = {
35975
36071
  Mesh: {},
35976
- Line: { threshold: 0.25 },
35977
- Line2: { threshold: 0.25 },
36072
+ Line: { threshold: 0.05 },
36073
+ Line2: { threshold: 0.05 },
35978
36074
  LOD: {},
35979
- Points: { threshold: 0.1 },
36075
+ Points: { threshold: 0.01 },
35980
36076
  Sprite: {},
35981
36077
  };
35982
36078
  return this.raycaster.intersectObjects(objects, false);
@@ -39534,6 +39630,12 @@ void main() {
39534
39630
  this.maxConcurrentChunks = 8;
39535
39631
  this.activeChunkLoads = 0;
39536
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();
39537
39639
  }
39538
39640
  setVisibleEdges(visible) {
39539
39641
  this.visibleEdges = visible;
@@ -40240,6 +40342,50 @@ void main() {
40240
40342
  this.originalObjects.clear();
40241
40343
  this.originalObjectsToSelection.clear();
40242
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
+ }
40243
40389
  clear() {
40244
40390
  this.chunkQueue = [];
40245
40391
  this.structures.forEach((structure) => {
@@ -40345,6 +40491,9 @@ void main() {
40345
40491
  this.loadedGeometrySize = 0;
40346
40492
  this.abortController = new AbortController();
40347
40493
  this.updateMemoryIndicator();
40494
+ this.objectIdToIndex.clear();
40495
+ this.maxObjectId = 0;
40496
+ this.objectVisibility = new Float32Array();
40348
40497
  }
40349
40498
  setStructureTransform(structureId, matrix) {
40350
40499
  const rootGroup = this.structureRoots.get(structureId);
@@ -40494,18 +40643,43 @@ void main() {
40494
40643
  this.originalObjectsToSelection.add(obj);
40495
40644
  }
40496
40645
  });
40646
+ this.initializeObjectVisibility();
40647
+ console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
40497
40648
  this.dispatchEvent("update");
40498
40649
  }
40499
40650
  mergeMeshGroups(materialGroups, rootGroup) {
40500
40651
  for (const group of materialGroups) {
40652
+ if (!group.material) {
40653
+ console.warn("Skipping mesh group with null material");
40654
+ continue;
40655
+ }
40501
40656
  try {
40502
40657
  const geometries = [];
40503
40658
  const handles = new Set();
40504
40659
  const optimizedObjects = [];
40660
+ const objectMapping = new Map();
40661
+ let currentVertexOffset = 0;
40505
40662
  for (const mesh of group.objects) {
40506
40663
  const geometry = mesh.geometry.clone();
40507
40664
  mesh.updateWorldMatrix(true, false);
40508
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;
40509
40683
  geometries.push(geometry);
40510
40684
  optimizedObjects.push(mesh);
40511
40685
  handles.add(mesh.userData.handle);
@@ -40513,13 +40687,26 @@ void main() {
40513
40687
  const mergedObjects = [];
40514
40688
  if (geometries.length > 0) {
40515
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));
40516
40696
  if (this.useVAO) {
40517
40697
  this.createVAO(mergedGeometry);
40518
40698
  }
40519
- const mergedMesh = new Mesh(mergedGeometry, group.material);
40699
+ const visibilityMaterial = this.createVisibilityMaterial(group.material);
40700
+ const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
40520
40701
  rootGroup.add(mergedMesh);
40521
40702
  this.mergedMesh.add(mergedMesh);
40522
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);
40523
40710
  mergedObjects.push(mergedMesh);
40524
40711
  geometries.forEach((geometry) => {
40525
40712
  geometry.dispose();
@@ -40545,8 +40732,14 @@ void main() {
40545
40732
  mergeLineGroups(materialGroups, rootGroup) {
40546
40733
  for (const group of materialGroups) {
40547
40734
  if (group.objects.length === 0) continue;
40735
+ if (!group.material) {
40736
+ console.warn("Skipping line group with null material");
40737
+ continue;
40738
+ }
40548
40739
  const handles = new Set();
40549
40740
  let totalVertices = 0;
40741
+ const objectMapping = new Map();
40742
+ let currentVertexOffset = 0;
40550
40743
  group.objects.map((line) => {
40551
40744
  handles.add(line.userData.handle);
40552
40745
  totalVertices += line.geometry.attributes.position.count;
@@ -40559,6 +40752,15 @@ void main() {
40559
40752
  const geometry = line.geometry;
40560
40753
  const positionAttr = geometry.attributes.position;
40561
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;
40562
40764
  line.updateWorldMatrix(true, false);
40563
40765
  const matrix = line.matrixWorld;
40564
40766
  const vector = new Vector3();
@@ -40579,7 +40781,24 @@ void main() {
40579
40781
  geometry.setIndex(indices);
40580
40782
  geometry.computeBoundingSphere();
40581
40783
  geometry.computeBoundingBox();
40582
- const mergedLine = new LineSegments(geometry, group.material);
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);
40583
40802
  const mergedObjects = [mergedLine];
40584
40803
  if (this.useVAO) {
40585
40804
  this.createVAO(mergedLine);
@@ -40587,6 +40806,12 @@ void main() {
40587
40806
  rootGroup.add(mergedLine);
40588
40807
  this.mergedLines.add(mergedLine);
40589
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);
40590
40815
  handles.forEach((handle) => {
40591
40816
  if (this.handleToOptimizedObjects.has(handle)) {
40592
40817
  const existingObjects = this.handleToOptimizedObjects.get(handle);
@@ -40600,14 +40825,37 @@ void main() {
40600
40825
  }
40601
40826
  mergeLineSegmentGroups(materialGroups, rootGroup) {
40602
40827
  for (const group of materialGroups) {
40828
+ if (!group.material) {
40829
+ console.warn("Skipping line segment group with null material");
40830
+ continue;
40831
+ }
40603
40832
  try {
40604
40833
  const geometries = [];
40605
40834
  const optimizedObjects = [];
40606
40835
  const handles = new Set();
40836
+ const objectMapping = new Map();
40837
+ let currentVertexOffset = 0;
40607
40838
  for (const line of group.objects) {
40608
40839
  const geometry = line.geometry.clone();
40609
40840
  line.updateWorldMatrix(true, false);
40610
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;
40611
40859
  geometries.push(geometry);
40612
40860
  optimizedObjects.push(line);
40613
40861
  handles.add(line.userData.handle);
@@ -40615,13 +40863,26 @@ void main() {
40615
40863
  const mergedObjects = [];
40616
40864
  if (geometries.length > 0) {
40617
40865
  const mergedGeometry = mergeGeometries(geometries, false);
40618
- const mergedLine = new LineSegments(mergedGeometry, group.material);
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);
40619
40874
  if (this.useVAO) {
40620
40875
  this.createVAO(mergedLine);
40621
40876
  }
40622
40877
  rootGroup.add(mergedLine);
40623
40878
  this.mergedLineSegments.add(mergedLine);
40624
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);
40625
40886
  mergedObjects.push(mergedLine);
40626
40887
  geometries.forEach((geometry) => {
40627
40888
  geometry.dispose();
@@ -40646,6 +40907,10 @@ void main() {
40646
40907
  }
40647
40908
  mergePointsGroups(materialGroups, rootGroup) {
40648
40909
  for (const group of materialGroups) {
40910
+ if (!group.material) {
40911
+ console.warn("Skipping points group with null material");
40912
+ continue;
40913
+ }
40649
40914
  try {
40650
40915
  const geometries = [];
40651
40916
  const optimizedObjects = [];
@@ -40828,97 +41093,51 @@ void main() {
40828
41093
  });
40829
41094
  this.syncHiddenObjects();
40830
41095
  }
40831
- syncHiddenObjects() {
40832
- if (this.oldOptimizeObjects.size !== 0) {
40833
- for (const obj of this.oldOptimizeObjects) {
40834
- obj.visible = true;
40835
- }
40836
- this.oldOptimizeObjects.clear();
40837
- }
40838
- if (this.newOptimizedObjects.size !== 0) {
40839
- for (const obj of this.newOptimizedObjects) {
40840
- obj.visible = false;
40841
- obj.geometry.dispose();
40842
- obj.parent.remove(obj);
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
+ }
40843
41109
  }
40844
- this.newOptimizedObjects.clear();
41110
+ mergedObject.geometry.attributes.visibility.needsUpdate = true;
40845
41111
  }
40846
- if (this.hiddenHandles.size === 0) {
41112
+ }
41113
+ syncHiddenObjects() {
41114
+ if (this.mergedObjectMap.size === 0) {
41115
+ console.log("No merged objects to sync");
40847
41116
  return;
40848
41117
  }
40849
- this.hiddenHandles.forEach((handle) => {
40850
- const objects = this.handleToOptimizedObjects.get(handle);
40851
- if (objects) {
40852
- 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;
40853
41121
  }
40854
- });
40855
- this.oldOptimizeObjects.forEach((optimizedObject) => {
40856
- optimizedObject.visible = false;
40857
- const originObjects = this.optimizedOriginalMap.get(optimizedObject);
40858
- const updateListToOptimize = [];
40859
- originObjects.forEach((obj) => {
40860
- if (!this.hiddenHandles.has(obj.userData.handle)) {
40861
- 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;
40862
41126
  }
40863
41127
  });
40864
- const firstObject = updateListToOptimize[0];
40865
- if (firstObject instanceof Mesh || firstObject instanceof LineSegments) {
40866
- const geometries = updateListToOptimize.map((obj) => {
40867
- const geometry = obj.geometry.clone();
40868
- obj.updateWorldMatrix(true, false);
40869
- geometry.applyMatrix4(obj.matrixWorld);
40870
- return geometry;
40871
- });
40872
- const newMergedGeometry = mergeGeometries(geometries);
40873
- const mergedObject =
40874
- firstObject instanceof Mesh
40875
- ? new Mesh(newMergedGeometry, optimizedObject.material)
40876
- : new LineSegments(newMergedGeometry, optimizedObject.material);
40877
- mergedObject.visible = true;
40878
- optimizedObject.parent.add(mergedObject);
40879
- this.newOptimizedObjects.add(mergedObject);
40880
- geometries.forEach((geometry) => {
40881
- geometry.dispose();
40882
- });
40883
- } else if (firstObject instanceof Line$1) {
40884
- let totalVertices = 0;
40885
- updateListToOptimize.map((line) => {
40886
- totalVertices += line.geometry.attributes.position.count;
40887
- });
40888
- const positions = new Float32Array(totalVertices * 3);
40889
- let posOffset = 0;
40890
- const indices = [];
40891
- let vertexOffset = 0;
40892
- updateListToOptimize.forEach((line) => {
40893
- const geometry = line.geometry;
40894
- const positionAttr = geometry.attributes.position;
40895
- const vertexCount = positionAttr.count;
40896
- line.updateWorldMatrix(true, false);
40897
- const matrix = line.matrixWorld;
40898
- const vector = new Vector3();
40899
- for (let i = 0; i < vertexCount; i++) {
40900
- vector.fromBufferAttribute(positionAttr, i);
40901
- vector.applyMatrix4(matrix);
40902
- positions[posOffset++] = vector.x;
40903
- positions[posOffset++] = vector.y;
40904
- positions[posOffset++] = vector.z;
40905
- }
40906
- for (let i = 0; i < vertexCount - 1; i++) {
40907
- indices.push(vertexOffset + i, vertexOffset + i + 1);
40908
- }
40909
- vertexOffset += vertexCount;
40910
- });
40911
- const geometry = new BufferGeometry();
40912
- geometry.setAttribute("position", new BufferAttribute(positions, 3));
40913
- geometry.setIndex(indices);
40914
- geometry.computeBoundingSphere();
40915
- geometry.computeBoundingBox();
40916
- const mergedLine = new LineSegments(geometry, optimizedObject.material);
40917
- mergedLine.visible = true;
40918
- optimizedObject.parent.add(mergedLine);
40919
- this.newOptimizedObjects.add(mergedLine);
40920
- }
40921
- });
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
+ }
40922
41141
  }
40923
41142
  getStructureGeometryExtent(structureId) {
40924
41143
  const extent = new Box3();
@@ -55343,6 +55562,9 @@ void main() {
55343
55562
  draggable: true,
55344
55563
  });
55345
55564
  this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({ x: params.position.x, y: params.position.y }));
55565
+ if (params.position2) {
55566
+ this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({ x: params.position2.x, y: params.position2.y }));
55567
+ }
55346
55568
  this._ref.on("transform", (e) => {
55347
55569
  const attrs = e.target.attrs;
55348
55570
  if (attrs.rotation !== this._ref.rotation())