@inweb/viewer-three 27.4.7 → 27.5.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 (64) hide show
  1. package/dist/extensions/components/AxesHelperComponent.js +3 -0
  2. package/dist/extensions/components/AxesHelperComponent.js.map +1 -1
  3. package/dist/extensions/components/AxesHelperComponent.min.js +1 -1
  4. package/dist/extensions/components/AxesHelperComponent.module.js +3 -0
  5. package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
  6. package/dist/extensions/components/ExtentsHelperComponent.js +6 -2
  7. package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -1
  8. package/dist/extensions/components/ExtentsHelperComponent.min.js +1 -1
  9. package/dist/extensions/components/ExtentsHelperComponent.module.js +6 -2
  10. package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -1
  11. package/dist/extensions/components/GridHelperComponent.js +1 -0
  12. package/dist/extensions/components/GridHelperComponent.js.map +1 -1
  13. package/dist/extensions/components/GridHelperComponent.min.js +1 -1
  14. package/dist/extensions/components/GridHelperComponent.module.js +1 -0
  15. package/dist/extensions/components/GridHelperComponent.module.js.map +1 -1
  16. package/dist/extensions/components/LightHelperComponent.js +1 -0
  17. package/dist/extensions/components/LightHelperComponent.js.map +1 -1
  18. package/dist/extensions/components/LightHelperComponent.min.js +1 -1
  19. package/dist/extensions/components/LightHelperComponent.module.js +1 -0
  20. package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
  21. package/dist/viewer-three.js +1766 -438
  22. package/dist/viewer-three.js.map +1 -1
  23. package/dist/viewer-three.min.js +4 -4
  24. package/dist/viewer-three.module.js +1303 -403
  25. package/dist/viewer-three.module.js.map +1 -1
  26. package/extensions/components/AxesHelperComponent.ts +3 -0
  27. package/extensions/components/ExtentsHelperComponent.ts +5 -2
  28. package/extensions/components/GridHelperComponent.ts +1 -0
  29. package/extensions/components/LightHelperComponent.ts +1 -0
  30. package/lib/Viewer/Viewer.d.ts +5 -7
  31. package/lib/Viewer/components/CameraComponent.d.ts +1 -1
  32. package/lib/Viewer/components/ClippingPlaneComponent.d.ts +8 -0
  33. package/lib/Viewer/components/HighlighterComponent.d.ts +2 -2
  34. package/lib/Viewer/components/InfoComponent.d.ts +1 -1
  35. package/lib/Viewer/components/SectionsComponent.d.ts +15 -0
  36. package/lib/Viewer/components/WCSHelperComponent.d.ts +2 -2
  37. package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +6 -6
  38. package/lib/Viewer/draggers/OrbitDragger.d.ts +1 -1
  39. package/lib/Viewer/measurement/Snapper.d.ts +3 -3
  40. package/package.json +5 -5
  41. package/src/Viewer/Viewer.ts +50 -37
  42. package/src/Viewer/commands/index.ts +1 -1
  43. package/src/Viewer/components/BackgroundComponent.ts +1 -0
  44. package/src/Viewer/components/CameraComponent.ts +5 -6
  45. package/src/Viewer/{scenes/Helpers.ts → components/ClippingPlaneComponent.ts} +22 -12
  46. package/src/Viewer/components/HighlighterComponent.ts +9 -5
  47. package/src/Viewer/components/InfoComponent.ts +4 -4
  48. package/src/Viewer/components/SectionsComponent.ts +119 -0
  49. package/src/Viewer/components/SelectionComponent.ts +1 -1
  50. package/src/Viewer/components/WCSHelperComponent.ts +8 -6
  51. package/src/Viewer/components/index.ts +4 -0
  52. package/src/Viewer/draggers/CuttingPlaneDragger.ts +57 -34
  53. package/src/Viewer/draggers/MeasureLineDragger.ts +1 -1
  54. package/src/Viewer/draggers/OrbitDragger.ts +3 -3
  55. package/src/Viewer/helpers/SectionsHelper.js +1065 -0
  56. package/src/Viewer/helpers/WCSHelper.ts +24 -0
  57. package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +417 -92
  58. package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +76 -9
  59. package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +3 -2
  60. package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +4 -2
  61. package/src/Viewer/measurement/Snapper.ts +4 -5
  62. package/src/Viewer/models/ModelImpl.ts +27 -3
  63. package/lib/Viewer/scenes/Helpers.d.ts +0 -7
  64. package/src/Viewer/postprocessing/SSAARenderPass.js +0 -245
@@ -235,6 +235,15 @@
235
235
  enablePartialMode: false,
236
236
  memoryLimit: 3294967296,
237
237
  cuttingPlaneFillColor: { red: 0xff, green: 0x98, blue: 0x00 },
238
+ enableSectionFill: true,
239
+ sectionFillColor: { r: 0xff, g: 0x98, b: 0x00 },
240
+ sectionUseObjectColor: false,
241
+ enableSectionHatch: true,
242
+ sectionHatchColor: { r: 0, g: 0, b: 0 },
243
+ sectionHatchScale: 8,
244
+ enableSectionOutline: true,
245
+ sectionOutlineColor: { r: 0, g: 0, b: 0 },
246
+ sectionOutlineWidth: 2,
238
247
  edgesColor: { r: 0xff, g: 0x98, b: 0x00 },
239
248
  facesColor: { r: 0xff, g: 0x98, b: 0x00 },
240
249
  edgesVisibility: true,
@@ -309,9 +318,17 @@
309
318
  return this._data;
310
319
  }
311
320
  set data(value) {
312
- const enablePartialMode = value.enableStreamingMode ? value.enablePartialMode : false;
313
- const sceneGraph = enablePartialMode ? false : value.sceneGraph;
314
- this._data = { ...Options.defaults(), ...this._data, ...value, enablePartialMode, sceneGraph };
321
+ this._data = { ...Options.defaults(), ...this._data, ...value };
322
+ if (this._data.enablePartialMode) {
323
+ this._data.enableStreamingMode = true;
324
+ this._data.sceneGraph = false;
325
+ }
326
+ if (!value.sectionFillColor && value.cuttingPlaneFillColor)
327
+ this._data.sectionFillColor = {
328
+ r: value.cuttingPlaneFillColor.red,
329
+ g: value.cuttingPlaneFillColor.green,
330
+ b: value.cuttingPlaneFillColor.blue,
331
+ };
315
332
  this.change();
316
333
  }
317
334
  get showWCS() {
@@ -398,10 +415,83 @@
398
415
  this.change();
399
416
  }
400
417
  get cuttingPlaneFillColor() {
401
- return this._data.cuttingPlaneFillColor;
418
+ console.warn("Options.cuttingPlaneFillColor has been deprecated since 27.5 and will be removed in a future release, use sectionFillColor instead");
419
+ return {
420
+ red: this._data.sectionFillColor.r,
421
+ green: this._data.sectionFillColor.g,
422
+ blue: this._data.sectionFillColor.b,
423
+ };
402
424
  }
403
425
  set cuttingPlaneFillColor(value) {
404
- this._data.cuttingPlaneFillColor = value;
426
+ console.warn("Options.cuttingPlaneFillColor has been deprecated since 27.5 and will be removed in a future release, use sectionFillColor instead");
427
+ this._data.sectionFillColor = {
428
+ r: value.red,
429
+ g: value.green,
430
+ b: value.blue,
431
+ };
432
+ this.change();
433
+ }
434
+ get enableSectionFill() {
435
+ return this._data.enableSectionFill;
436
+ }
437
+ set enableSectionFill(value) {
438
+ this._data.enableSectionFill = value;
439
+ this.change();
440
+ }
441
+ get sectionFillColor() {
442
+ return this._data.sectionFillColor;
443
+ }
444
+ set sectionFillColor(value) {
445
+ this._data.sectionFillColor = value;
446
+ this.change();
447
+ }
448
+ get sectionUseObjectColor() {
449
+ return this._data.sectionUseObjectColor;
450
+ }
451
+ set sectionUseObjectColor(value) {
452
+ this._data.sectionUseObjectColor = value;
453
+ this.change();
454
+ }
455
+ get enableSectionHatch() {
456
+ return this._data.enableSectionHatch;
457
+ }
458
+ set enableSectionHatch(value) {
459
+ this._data.enableSectionHatch = value;
460
+ this.change();
461
+ }
462
+ get sectionHatchColor() {
463
+ return this._data.sectionHatchColor;
464
+ }
465
+ set sectionHatchColor(value) {
466
+ this._data.sectionHatchColor = value;
467
+ this.change();
468
+ }
469
+ get sectionHatchScale() {
470
+ return this._data.sectionHatchScale;
471
+ }
472
+ set sectionHatchScale(value) {
473
+ this._data.sectionHatchScale = value;
474
+ this.change();
475
+ }
476
+ get enableSectionOutline() {
477
+ return this._data.enableSectionOutline;
478
+ }
479
+ set enableSectionOutline(value) {
480
+ this._data.enableSectionOutline = value;
481
+ this.change();
482
+ }
483
+ get sectionOutlineColor() {
484
+ return this._data.sectionOutlineColor;
485
+ }
486
+ set sectionOutlineColor(value) {
487
+ this._data.sectionOutlineColor = value;
488
+ this.change();
489
+ }
490
+ get sectionOutlineWidth() {
491
+ return this._data.sectionOutlineWidth;
492
+ }
493
+ set sectionOutlineWidth(value) {
494
+ this._data.sectionOutlineWidth = value;
405
495
  this.change();
406
496
  }
407
497
  get edgesColor() {
@@ -9820,7 +9910,7 @@
9820
9910
  const _whiteColor = new Color( 1, 1, 1 );
9821
9911
  const _frustum = new Frustum();
9822
9912
  const _frustumArray = new FrustumArray();
9823
- const _box$1 = new Box3();
9913
+ const _box$1$1 = new Box3();
9824
9914
  const _sphere$2 = new Sphere();
9825
9915
  const _vector$5 = new Vector3();
9826
9916
  const _forward$1 = new Vector3();
@@ -9983,8 +10073,8 @@
9983
10073
  if ( instanceInfo[ i ].active === false ) continue;
9984
10074
  const geometryId = instanceInfo[ i ].geometryIndex;
9985
10075
  this.getMatrixAt( i, _matrix$1 );
9986
- this.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 );
9987
- boundingBox.union( _box$1 );
10076
+ this.getBoundingBoxAt( geometryId, _box$1$1 ).applyMatrix4( _matrix$1 );
10077
+ boundingBox.union( _box$1$1 );
9988
10078
  }
9989
10079
  }
9990
10080
  computeBoundingSphere() {
@@ -10244,8 +10334,8 @@
10244
10334
  const geometryInfo = this._geometryInfo[ geometryId ];
10245
10335
  if ( geometryInfo.boundingSphere === null ) {
10246
10336
  const sphere = new Sphere();
10247
- this.getBoundingBoxAt( geometryId, _box$1 );
10248
- _box$1.getCenter( sphere.center );
10337
+ this.getBoundingBoxAt( geometryId, _box$1$1 );
10338
+ _box$1$1.getCenter( sphere.center );
10249
10339
  const index = geometry.index;
10250
10340
  const position = geometry.attributes.position;
10251
10341
  let maxRadiusSq = 0;
@@ -10713,8 +10803,8 @@
10713
10803
  object: object
10714
10804
  };
10715
10805
  }
10716
- const _start$2 = new Vector3();
10717
- const _end$2 = new Vector3();
10806
+ const _start$3 = new Vector3();
10807
+ const _end$3 = new Vector3();
10718
10808
  class LineSegments extends Line$1 {
10719
10809
  constructor( geometry, material ) {
10720
10810
  super( geometry, material );
@@ -10727,10 +10817,10 @@
10727
10817
  const positionAttribute = geometry.attributes.position;
10728
10818
  const lineDistances = [];
10729
10819
  for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
10730
- _start$2.fromBufferAttribute( positionAttribute, i );
10731
- _end$2.fromBufferAttribute( positionAttribute, i + 1 );
10820
+ _start$3.fromBufferAttribute( positionAttribute, i );
10821
+ _end$3.fromBufferAttribute( positionAttribute, i + 1 );
10732
10822
  lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
10733
- lineDistances[ i + 1 ] = lineDistances[ i ] + _start$2.distanceTo( _end$2 );
10823
+ lineDistances[ i + 1 ] = lineDistances[ i ] + _start$3.distanceTo( _end$3 );
10734
10824
  }
10735
10825
  geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
10736
10826
  } else {
@@ -10771,8 +10861,8 @@
10771
10861
  }
10772
10862
  }
10773
10863
  const _inverseMatrix = new Matrix4();
10774
- const _ray = new Ray();
10775
- const _sphere = new Sphere();
10864
+ const _ray$4 = new Ray();
10865
+ const _sphere$7 = new Sphere();
10776
10866
  const _position$2 = new Vector3();
10777
10867
  class Points extends Object3D {
10778
10868
  constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
@@ -10797,12 +10887,12 @@
10797
10887
  const threshold = raycaster.params.Points.threshold;
10798
10888
  const drawRange = geometry.drawRange;
10799
10889
  if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
10800
- _sphere.copy( geometry.boundingSphere );
10801
- _sphere.applyMatrix4( matrixWorld );
10802
- _sphere.radius += threshold;
10803
- if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
10890
+ _sphere$7.copy( geometry.boundingSphere );
10891
+ _sphere$7.applyMatrix4( matrixWorld );
10892
+ _sphere$7.radius += threshold;
10893
+ if ( raycaster.ray.intersectsSphere( _sphere$7 ) === false ) return;
10804
10894
  _inverseMatrix.copy( matrixWorld ).invert();
10805
- _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
10895
+ _ray$4.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
10806
10896
  const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
10807
10897
  const localThresholdSq = localThreshold * localThreshold;
10808
10898
  const index = geometry.index;
@@ -10844,10 +10934,10 @@
10844
10934
  }
10845
10935
  }
10846
10936
  function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
10847
- const rayPointDistanceSq = _ray.distanceSqToPoint( point );
10937
+ const rayPointDistanceSq = _ray$4.distanceSqToPoint( point );
10848
10938
  if ( rayPointDistanceSq < localThresholdSq ) {
10849
10939
  const intersectPoint = new Vector3();
10850
- _ray.closestPointToPoint( point, intersectPoint );
10940
+ _ray$4.closestPointToPoint( point, intersectPoint );
10851
10941
  intersectPoint.applyMatrix4( matrixWorld );
10852
10942
  const distance = raycaster.ray.origin.distanceTo( intersectPoint );
10853
10943
  if ( distance < raycaster.near || distance > raycaster.far ) return;
@@ -34348,15 +34438,15 @@ void main() {
34348
34438
  const DESKTOP_SNAP_DISTANCE = 10;
34349
34439
  const MOBILE_SNAP_DISTANCE = 50;
34350
34440
  const _vertex = new Vector3();
34351
- const _start$1 = new Vector3();
34352
- const _end$1 = new Vector3();
34353
- const _line = new Line3();
34441
+ const _start$2 = new Vector3();
34442
+ const _end$2 = new Vector3();
34443
+ const _line$1 = new Line3();
34354
34444
  const _center = new Vector3();
34355
34445
  const _projection = new Vector3();
34356
34446
  class Snapper {
34357
- constructor(camera, renderer, canvas) {
34447
+ constructor(camera, clippingPlanes, canvas) {
34358
34448
  this.camera = camera;
34359
- this.renderer = renderer;
34449
+ this.clippingPlanes = clippingPlanes;
34360
34450
  this.canvas = canvas;
34361
34451
  this.threshold = 0.0001;
34362
34452
  this.raycaster = new Raycaster();
@@ -34387,7 +34477,7 @@ void main() {
34387
34477
  };
34388
34478
  let intersects = this.raycaster.intersectObjects(objects, recursive);
34389
34479
  if (clip) {
34390
- const clippingPlanes = this.renderer.clippingPlanes || [];
34480
+ const clippingPlanes = this.clippingPlanes;
34391
34481
  clippingPlanes.forEach((plane) => {
34392
34482
  intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
34393
34483
  });
@@ -34439,17 +34529,17 @@ void main() {
34439
34529
  }
34440
34530
  const edgePositions = edges.attributes.position.array;
34441
34531
  for (let i = 0; i < edgePositions.length; i += 6) {
34442
- _start$1.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
34443
- _end$1.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
34444
- _line.set(_start$1, _end$1);
34445
- _line.getCenter(_center);
34532
+ _start$2.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
34533
+ _end$2.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
34534
+ _line$1.set(_start$2, _end$2);
34535
+ _line$1.getCenter(_center);
34446
34536
  const centerDistance = _center.distanceTo(localPoint);
34447
34537
  if (centerDistance < snapDistance) {
34448
34538
  snapDistance = centerDistance;
34449
34539
  snapPoint = _center.clone();
34450
34540
  continue;
34451
34541
  }
34452
- _line.closestPointToPoint(localPoint, true, _projection);
34542
+ _line$1.closestPointToPoint(localPoint, true, _projection);
34453
34543
  const lineDistance = _projection.distanceTo(localPoint);
34454
34544
  if (lineDistance < snapDistance) {
34455
34545
  snapDistance = lineDistance;
@@ -34474,7 +34564,7 @@ void main() {
34474
34564
  this.orbit.object = this.viewer.camera;
34475
34565
  this.orbit.update();
34476
34566
  };
34477
- this.optionsChange = ({ data: options }) => {
34567
+ this.updateZoomSpeed = ({ data: options }) => {
34478
34568
  this.orbit.zoomSpeed = Math.abs(this.orbit.zoomSpeed) * (options.reverseZoomWheel ? -1 : 1);
34479
34569
  };
34480
34570
  this.controlsStart = () => {
@@ -34533,7 +34623,7 @@ void main() {
34533
34623
  this.viewer.addEventListener("zoom", this.updateControls);
34534
34624
  this.viewer.addEventListener("drawviewpoint", this.updateControls);
34535
34625
  this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
34536
- this.viewer.addEventListener("optionschange", this.optionsChange);
34626
+ this.viewer.addEventListener("optionschange", this.updateZoomSpeed);
34537
34627
  this.viewer.addEventListener("contextmenu", this.stopContextMenu);
34538
34628
  this.updateControls();
34539
34629
  this.updateControlsCamera();
@@ -34545,7 +34635,7 @@ void main() {
34545
34635
  this.viewer.removeEventListener("zoom", this.updateControls);
34546
34636
  this.viewer.removeEventListener("drawviewpoint", this.updateControls);
34547
34637
  this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
34548
- this.viewer.removeEventListener("optionschange", this.optionsChange);
34638
+ this.viewer.removeEventListener("optionschange", this.updateZoomSpeed);
34549
34639
  this.viewer.removeEventListener("contextmenu", this.stopContextMenu);
34550
34640
  this.orbit.removeEventListener("start", this.controlsStart);
34551
34641
  this.orbit.removeEventListener("change", this.controlsChange);
@@ -34557,13 +34647,17 @@ void main() {
34557
34647
  constructor(viewer) {
34558
34648
  super(viewer);
34559
34649
  this.helpers = [];
34560
- this.activeHelper = null;
34650
+ this.activeHelper = undefined;
34651
+ this.transformUpdate = () => {
34652
+ this.viewer.update();
34653
+ };
34561
34654
  this.transformChange = () => {
34562
34655
  if (!this.activeHelper)
34563
34656
  return;
34564
34657
  const plane = this.activeHelper.plane;
34565
34658
  plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
34566
34659
  plane.constant = -this.activeHelper.position.dot(plane.normal);
34660
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34567
34661
  this.viewer.update();
34568
34662
  this.changed = true;
34569
34663
  };
@@ -34575,25 +34669,29 @@ void main() {
34575
34669
  this.orbit.enabled = !event.value;
34576
34670
  this.translate.enabled = !event.value;
34577
34671
  };
34578
- this.updatePlaneSize = () => {
34672
+ this.syncHelpers = () => {
34579
34673
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
34580
- this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
34674
+ const extentsCenter = this.viewer.extents.getCenter(new Vector3());
34675
+ this.helpers.forEach((planeHelper) => {
34676
+ planeHelper.size = extentsSize;
34677
+ planeHelper.position.copy(planeHelper.plane.projectPoint(extentsCenter, new Vector3()));
34678
+ });
34581
34679
  this.viewer.update();
34582
34680
  };
34583
- this.updateTransformCamera = () => {
34584
- this.translate.camera = this.viewer.camera;
34585
- this.rotate.camera = this.viewer.camera;
34586
- this.snapper.camera = this.viewer.camera;
34587
- };
34588
34681
  this.clearHelpers = () => {
34589
34682
  this.setActiveHelper();
34590
34683
  this.helpers.forEach((helper) => {
34591
34684
  helper.removeFromParent();
34592
34685
  helper.dispose();
34593
34686
  });
34594
- this.helpers = [];
34687
+ this.helpers.length = 0;
34595
34688
  this.viewer.update();
34596
34689
  };
34690
+ this.updateTransformCamera = () => {
34691
+ this.translate.camera = this.viewer.camera;
34692
+ this.rotate.camera = this.viewer.camera;
34693
+ this.snapper.camera = this.viewer.camera;
34694
+ };
34597
34695
  this.onKeyDown = (event) => {
34598
34696
  if (event.key === "Shift")
34599
34697
  this.rotate.setRotationSnap(Math.PI / 4);
@@ -34637,12 +34735,9 @@ void main() {
34637
34735
  this.transformChange();
34638
34736
  event.stopPropagation();
34639
34737
  };
34640
- if (!viewer.renderer.clippingPlanes)
34641
- viewer.renderer.clippingPlanes = [];
34642
- this.clippingPlanes = viewer.renderer.clippingPlanes;
34643
- this.clippingPlanes.forEach((plane) => this.addHelper(plane));
34738
+ viewer.clippingPlanes.forEach((plane) => this.addHelper(plane));
34644
34739
  const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
34645
- this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
34740
+ this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
34646
34741
  this.snapper.threshold = extentsSize / 10000;
34647
34742
  this.downPosition = new Vector2();
34648
34743
  this.position0 = new Vector3();
@@ -34653,7 +34748,8 @@ void main() {
34653
34748
  this.translate.showX = false;
34654
34749
  this.translate.showY = false;
34655
34750
  this.translate.showZ = true;
34656
- this.translate.addEventListener("change", this.transformChange);
34751
+ this.translate.addEventListener("change", this.transformUpdate);
34752
+ this.translate.addEventListener("objectChange", this.transformChange);
34657
34753
  this.translate.addEventListener("dragging-changed", this.translateDrag);
34658
34754
  this.viewer.helpers.add(this.translate.getHelper());
34659
34755
  this.rotate = new TransformControls(viewer.camera, viewer.canvas);
@@ -34662,15 +34758,18 @@ void main() {
34662
34758
  this.rotate.showX = true;
34663
34759
  this.rotate.showY = true;
34664
34760
  this.rotate.showZ = false;
34665
- this.rotate.addEventListener("change", this.transformChange);
34761
+ this.rotate.addEventListener("change", this.transformUpdate);
34762
+ this.rotate.addEventListener("objectChange", this.transformChange);
34666
34763
  this.rotate.addEventListener("dragging-changed", this.rotateDrag);
34667
34764
  this.viewer.helpers.add(this.rotate.getHelper());
34668
34765
  this.setActiveHelper(this.helpers[this.helpers.length - 1]);
34669
- this.viewer.addEventListener("explode", this.updatePlaneSize);
34670
- this.viewer.addEventListener("show", this.updatePlaneSize);
34671
- this.viewer.addEventListener("showall", this.updatePlaneSize);
34672
- this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
34766
+ this.viewer.addEventListener("explode", this.syncHelpers);
34767
+ this.viewer.addEventListener("hide", this.syncHelpers);
34768
+ this.viewer.addEventListener("isolate", this.syncHelpers);
34769
+ this.viewer.addEventListener("show", this.syncHelpers);
34770
+ this.viewer.addEventListener("showall", this.syncHelpers);
34673
34771
  this.viewer.addEventListener("clearslices", this.clearHelpers);
34772
+ this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
34674
34773
  this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
34675
34774
  this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
34676
34775
  this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
@@ -34680,23 +34779,27 @@ void main() {
34680
34779
  this.viewer.update();
34681
34780
  }
34682
34781
  dispose() {
34683
- this.viewer.removeEventListener("explode", this.updatePlaneSize);
34684
- this.viewer.removeEventListener("show", this.updatePlaneSize);
34685
- this.viewer.removeEventListener("showall", this.updatePlaneSize);
34686
- this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
34782
+ this.viewer.removeEventListener("explode", this.syncHelpers);
34783
+ this.viewer.removeEventListener("hide", this.syncHelpers);
34784
+ this.viewer.removeEventListener("isolate", this.syncHelpers);
34785
+ this.viewer.removeEventListener("show", this.syncHelpers);
34786
+ this.viewer.removeEventListener("showall", this.syncHelpers);
34687
34787
  this.viewer.removeEventListener("clearslices", this.clearHelpers);
34788
+ this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
34688
34789
  this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
34689
34790
  this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
34690
34791
  this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
34691
34792
  this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
34692
34793
  window.removeEventListener("keydown", this.onKeyDown);
34693
34794
  window.removeEventListener("keyup", this.onKeyUp);
34694
- this.translate.removeEventListener("change", this.transformChange);
34795
+ this.translate.removeEventListener("change", this.transformUpdate);
34796
+ this.translate.removeEventListener("objectChange", this.transformChange);
34695
34797
  this.translate.removeEventListener("dragging-changed", this.translateDrag);
34696
34798
  this.translate.getHelper().removeFromParent();
34697
34799
  this.translate.detach();
34698
34800
  this.translate.dispose();
34699
- this.rotate.removeEventListener("change", this.transformChange);
34801
+ this.rotate.removeEventListener("change", this.transformUpdate);
34802
+ this.rotate.removeEventListener("objectChange", this.transformChange);
34700
34803
  this.rotate.removeEventListener("dragging-changed", this.rotateDrag);
34701
34804
  this.rotate.getHelper().removeFromParent();
34702
34805
  this.rotate.detach();
@@ -34705,8 +34808,8 @@ void main() {
34705
34808
  helper.removeFromParent();
34706
34809
  helper.dispose();
34707
34810
  });
34708
- this.helpers = [];
34709
- this.activeHelper = null;
34811
+ this.helpers.length = 0;
34812
+ this.activeHelper = undefined;
34710
34813
  super.dispose();
34711
34814
  }
34712
34815
  addHelper(plane) {
@@ -34758,9 +34861,10 @@ void main() {
34758
34861
  const extentsCenter = this.viewer.extents.getCenter(new Vector3());
34759
34862
  const constant = -extentsCenter.dot(normal);
34760
34863
  const plane = new Plane(normal, constant);
34761
- this.clippingPlanes.push(plane);
34864
+ this.viewer.clippingPlanes.push(plane);
34762
34865
  const helper = this.addHelper(plane);
34763
34866
  this.setActiveHelper(helper);
34867
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34764
34868
  }
34765
34869
  addPlaneX() {
34766
34870
  this.addPlane(new Vector3(-1, 0, 0));
@@ -34775,13 +34879,14 @@ void main() {
34775
34879
  if (!this.activeHelper)
34776
34880
  return;
34777
34881
  const helper = this.activeHelper;
34778
- const index = this.clippingPlanes.indexOf(helper.plane);
34882
+ const index = this.viewer.clippingPlanes.indexOf(helper.plane);
34779
34883
  if (index !== -1)
34780
- this.clippingPlanes.splice(index, 1);
34884
+ this.viewer.clippingPlanes.splice(index, 1);
34781
34885
  this.helpers = this.helpers.filter((x) => x !== helper);
34782
34886
  helper.removeFromParent();
34783
34887
  helper.dispose();
34784
34888
  this.setActiveHelper(this.helpers[this.helpers.length - 1]);
34889
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34785
34890
  }
34786
34891
  }
34787
34892
 
@@ -34975,7 +35080,7 @@ void main() {
34975
35080
  this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
34976
35081
  this.overlay.addLine(this.line);
34977
35082
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
34978
- this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
35083
+ this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
34979
35084
  this.snapper.threshold = extentsSize / 10000;
34980
35085
  this.objects = [];
34981
35086
  this.updateObjects();
@@ -36254,8 +36359,8 @@ void main() {
36254
36359
  commands.registerCommand("right", (viewer) => setDefaultViewPosition(viewer, "right"));
36255
36360
  commands.registerCommand("front", (viewer) => setDefaultViewPosition(viewer, "front"));
36256
36361
  commands.registerCommand("back", (viewer) => setDefaultViewPosition(viewer, "back"));
36257
- commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
36258
36362
  commands.registerCommand("se", (viewer) => setDefaultViewPosition(viewer, "se"));
36363
+ commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
36259
36364
  commands.registerCommand("ne", (viewer) => setDefaultViewPosition(viewer, "ne"));
36260
36365
  commands.registerCommand("nw", (viewer) => setDefaultViewPosition(viewer, "nw"));
36261
36366
  commands.registerCommandAlias("clearMarkup", "clearOverlay");
@@ -36278,6 +36383,7 @@ void main() {
36278
36383
  this.syncOptions = () => {
36279
36384
  this.backgroundColor.setHex(0xffffff);
36280
36385
  this.viewer.renderer.setClearColor(this.backgroundColor);
36386
+ this.viewer.update();
36281
36387
  };
36282
36388
  this.viewer = viewer;
36283
36389
  this.backgroundColor = new Color(0xffffff);
@@ -36293,7 +36399,7 @@ void main() {
36293
36399
 
36294
36400
  class CameraComponent {
36295
36401
  constructor(viewer) {
36296
- this.optionsChange = () => {
36402
+ this.syncOptions = () => {
36297
36403
  this.switchCameraMode(this.viewer.options.cameraMode);
36298
36404
  };
36299
36405
  this.geometryEnd = () => {
@@ -36324,13 +36430,13 @@ void main() {
36324
36430
  };
36325
36431
  this.viewer = viewer;
36326
36432
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
36327
- this.viewer.addEventListener("optionschange", this.optionsChange);
36328
- this.viewer.addEventListener("initialize", this.optionsChange);
36433
+ this.viewer.addEventListener("optionschange", this.syncOptions);
36434
+ this.viewer.addEventListener("initialize", this.syncOptions);
36329
36435
  }
36330
36436
  dispose() {
36331
36437
  this.viewer.removeEventListener("databasechunk", this.geometryEnd);
36332
- this.viewer.removeEventListener("optionschange", this.optionsChange);
36333
- this.viewer.removeEventListener("initialize", this.optionsChange);
36438
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
36439
+ this.viewer.removeEventListener("initialize", this.syncOptions);
36334
36440
  }
36335
36441
  getCameraMode(camera) {
36336
36442
  return camera.isOrthographicCamera ? "orthographic" : "perspective";
@@ -36353,7 +36459,6 @@ void main() {
36353
36459
  camera.updateProjectionMatrix();
36354
36460
  this.viewer.camera = camera;
36355
36461
  this.viewer.renderPass.camera = camera;
36356
- this.viewer.helpersPass.camera = camera;
36357
36462
  this.viewer.ssaaRenderPass.camera = camera;
36358
36463
  this.viewer.update();
36359
36464
  }
@@ -36497,7 +36602,7 @@ void main() {
36497
36602
  console.log("WebGL Renderer:", this.viewer.info.system.webglRenderer);
36498
36603
  console.log("WebGL Vendor:", this.viewer.info.system.webglVendor);
36499
36604
  this.resize();
36500
- this.optionsChange({ data: this.viewer.options });
36605
+ this.syncOptions({ data: this.viewer.options });
36501
36606
  };
36502
36607
  this.clear = () => {
36503
36608
  this.viewer.info.performance.timeToFirstRender = 0;
@@ -36521,7 +36626,7 @@ void main() {
36521
36626
  this.viewer.info.memory.totalEstimatedGpuBytes = 0;
36522
36627
  this.viewer.info.memory.usedJSHeapSize = 0;
36523
36628
  };
36524
- this.optionsChange = ({ data: options }) => {
36629
+ this.syncOptions = ({ data: options }) => {
36525
36630
  if (options.antialiasing === false)
36526
36631
  this.viewer.info.render.antialiasing = "";
36527
36632
  else if (options.antialiasing === true)
@@ -36596,7 +36701,7 @@ void main() {
36596
36701
  this.frames = 0;
36597
36702
  this.viewer.addEventListener("initialize", this.initialize);
36598
36703
  this.viewer.addEventListener("clear", this.clear);
36599
- this.viewer.addEventListener("optionschange", this.optionsChange);
36704
+ this.viewer.addEventListener("optionschange", this.syncOptions);
36600
36705
  this.viewer.addEventListener("geometrystart", this.geometryStart);
36601
36706
  this.viewer.addEventListener("databasechunk", this.databaseChunk);
36602
36707
  this.viewer.addEventListener("geometryend", this.geometryEnd);
@@ -36607,7 +36712,7 @@ void main() {
36607
36712
  dispose() {
36608
36713
  this.viewer.removeEventListener("initialize", this.initialize);
36609
36714
  this.viewer.removeEventListener("clear", this.clear);
36610
- this.viewer.removeEventListener("optionschange", this.optionsChange);
36715
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
36611
36716
  this.viewer.removeEventListener("geometrystart", this.geometryStart);
36612
36717
  this.viewer.removeEventListener("databasechunk", this.databaseChunk);
36613
36718
  this.viewer.removeEventListener("geometryend", this.geometryEnd);
@@ -36674,7 +36779,7 @@ void main() {
36674
36779
  }
36675
36780
  }
36676
36781
 
36677
- const _box = new Box3();
36782
+ const _box$1 = new Box3();
36678
36783
  const _vector = new Vector3();
36679
36784
  class LineSegmentsGeometry extends InstancedBufferGeometry {
36680
36785
  constructor() {
@@ -36756,8 +36861,8 @@ void main() {
36756
36861
  const end = this.attributes.instanceEnd;
36757
36862
  if ( start !== undefined && end !== undefined ) {
36758
36863
  this.boundingBox.setFromBufferAttribute( start );
36759
- _box.setFromBufferAttribute( end );
36760
- this.boundingBox.union( _box );
36864
+ _box$1.setFromBufferAttribute( end );
36865
+ this.boundingBox.union( _box$1 );
36761
36866
  }
36762
36867
  }
36763
36868
  computeBoundingSphere() {
@@ -37279,9 +37384,9 @@ void main() {
37279
37384
  }
37280
37385
  }
37281
37386
 
37282
- const _start = new Vector3();
37283
- const _end = new Vector3();
37284
- const _viewport = new Vector4();
37387
+ const _start$1 = new Vector3();
37388
+ const _end$1 = new Vector3();
37389
+ const _viewport$1 = new Vector4();
37285
37390
  class Wireframe extends Mesh {
37286
37391
  constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
37287
37392
  super( geometry, material );
@@ -37294,10 +37399,10 @@ void main() {
37294
37399
  const instanceEnd = geometry.attributes.instanceEnd;
37295
37400
  const lineDistances = new Float32Array( 2 * instanceStart.count );
37296
37401
  for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
37297
- _start.fromBufferAttribute( instanceStart, i );
37298
- _end.fromBufferAttribute( instanceEnd, i );
37402
+ _start$1.fromBufferAttribute( instanceStart, i );
37403
+ _end$1.fromBufferAttribute( instanceEnd, i );
37299
37404
  lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
37300
- lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
37405
+ lineDistances[ j + 1 ] = lineDistances[ j ] + _start$1.distanceTo( _end$1 );
37301
37406
  }
37302
37407
  const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 );
37303
37408
  geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) );
@@ -37307,8 +37412,8 @@ void main() {
37307
37412
  onBeforeRender( renderer ) {
37308
37413
  const uniforms = this.material.uniforms;
37309
37414
  if ( uniforms && uniforms.resolution ) {
37310
- renderer.getViewport( _viewport );
37311
- this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
37415
+ renderer.getViewport( _viewport$1 );
37416
+ this.material.uniforms.resolution.value.set( _viewport$1.z, _viewport$1.w );
37312
37417
  }
37313
37418
  }
37314
37419
  }
@@ -37384,28 +37489,38 @@ void main() {
37384
37489
  polygonOffset: true,
37385
37490
  polygonOffsetFactor: 1,
37386
37491
  polygonOffsetUnits: 1,
37492
+ clippingPlanes: this.viewer.clippingPlanes,
37387
37493
  });
37388
37494
  this.edgesMaterial = new LineMaterial({
37389
37495
  linewidth: 1.5,
37390
37496
  resolution: new Vector2(window.innerWidth, window.innerHeight),
37497
+ clippingPlanes: this.viewer.clippingPlanes,
37391
37498
  });
37392
37499
  this.lineMaterial = new LineBasicMaterial({
37393
37500
  transparent: true,
37394
37501
  depthTest: true,
37395
37502
  depthWrite: true,
37503
+ clippingPlanes: this.viewer.clippingPlanes,
37396
37504
  });
37397
37505
  this.lineGlowMaterial = new LineMaterial({
37398
37506
  linewidth: 1.5,
37399
37507
  transparent: true,
37400
37508
  opacity: 0.8,
37401
37509
  resolution: new Vector2(window.innerWidth, window.innerHeight),
37510
+ clippingPlanes: this.viewer.clippingPlanes,
37402
37511
  });
37403
37512
  this.syncHighlightColors();
37404
37513
  };
37405
- this.optionsChange = () => {
37514
+ this.syncOptions = () => {
37406
37515
  this.syncHighlightColors();
37407
37516
  this.viewer.update();
37408
37517
  };
37518
+ this.viewerResize = (event) => {
37519
+ var _a, _b, _c;
37520
+ (_a = this.renderTarget) === null || _a === void 0 ? void 0 : _a.setSize(event.width, event.height);
37521
+ (_b = this.edgesMaterial) === null || _b === void 0 ? void 0 : _b.resolution.set(event.width, event.height);
37522
+ (_c = this.lineGlowMaterial) === null || _c === void 0 ? void 0 : _c.resolution.set(event.width, event.height);
37523
+ };
37409
37524
  this.viewer = viewer;
37410
37525
  const gl2 = viewer.canvas.getContext("webgl2");
37411
37526
  if (gl2) {
@@ -37418,13 +37533,13 @@ void main() {
37418
37533
  });
37419
37534
  }
37420
37535
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
37421
- this.viewer.addEventListener("optionschange", this.optionsChange);
37536
+ this.viewer.addEventListener("optionschange", this.syncOptions);
37422
37537
  this.viewer.addEventListener("resize", this.viewerResize);
37423
37538
  this.geometryEnd();
37424
37539
  }
37425
37540
  dispose() {
37426
37541
  this.viewer.removeEventListener("databasechunk", this.geometryEnd);
37427
- this.viewer.removeEventListener("optionschange", this.optionsChange);
37542
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
37428
37543
  this.viewer.removeEventListener("resize", this.viewerResize);
37429
37544
  }
37430
37545
  highlight(objects) {
@@ -37503,12 +37618,6 @@ void main() {
37503
37618
  wireframe.visible = edgesVisibility;
37504
37619
  });
37505
37620
  }
37506
- viewerResize(event) {
37507
- var _a, _b, _c;
37508
- (_a = this.renderTarget) === null || _a === void 0 ? void 0 : _a.setSize(event.width, event.height);
37509
- (_b = this.edgesMaterial) === null || _b === void 0 ? void 0 : _b.resolution.set(event.width, event.height);
37510
- (_c = this.lineGlowMaterial) === null || _c === void 0 ? void 0 : _c.resolution.set(event.width, event.height);
37511
- }
37512
37621
  }
37513
37622
 
37514
37623
  class SelectionComponent {
@@ -37525,7 +37634,7 @@ void main() {
37525
37634
  if (upPosition.distanceTo(this.downPosition) !== 0)
37526
37635
  return;
37527
37636
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
37528
- const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
37637
+ const snapper = new Snapper(this.viewer.camera, this.viewer.clippingPlanes, this.viewer.canvas);
37529
37638
  snapper.threshold = extentsSize / 10000;
37530
37639
  let intersections = [];
37531
37640
  this.viewer.models.forEach((model) => {
@@ -37622,9 +37731,1032 @@ void main() {
37622
37731
  }
37623
37732
  }
37624
37733
 
37734
+ class ClippingPlaneComponent {
37735
+ constructor(viewer) {
37736
+ this.applyClippingPlanes = () => {
37737
+ this.viewer.models.forEach((model) => {
37738
+ model.scene.traverse((object) => {
37739
+ if (object.material) {
37740
+ const materials = Array.isArray(object.material) ? object.material : [object.material];
37741
+ materials.forEach((material) => (material.clippingPlanes = this.viewer.clippingPlanes));
37742
+ }
37743
+ });
37744
+ });
37745
+ };
37746
+ this.viewer = viewer;
37747
+ this.viewer.addEventListener("geometryend", this.applyClippingPlanes);
37748
+ this.viewer.addEventListener("changecuttingplanes", this.applyClippingPlanes);
37749
+ }
37750
+ dispose() {
37751
+ this.viewer.removeEventListener("geometryend", this.applyClippingPlanes);
37752
+ this.viewer.removeEventListener("changecuttingplanes", this.applyClippingPlanes);
37753
+ }
37754
+ }
37755
+
37756
+ const _viewport = new Vector4();
37757
+ const _start = new Vector3();
37758
+ const _end = new Vector3();
37759
+ const _start4 = new Vector4();
37760
+ const _end4 = new Vector4();
37761
+ const _ssOrigin = new Vector4();
37762
+ const _ssOrigin3 = new Vector3();
37763
+ const _mvMatrix = new Matrix4();
37764
+ const _line = new Line3();
37765
+ const _closestPoint = new Vector3();
37766
+ const _box = new Box3();
37767
+ const _sphere = new Sphere();
37768
+ const _clipToWorldVector = new Vector4();
37769
+ let _ray, _lineWidth;
37770
+ function getWorldSpaceHalfWidth( camera, distance, resolution ) {
37771
+ _clipToWorldVector.set( 0, 0, - distance, 1.0 ).applyMatrix4( camera.projectionMatrix );
37772
+ _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
37773
+ _clipToWorldVector.x = _lineWidth / resolution.width;
37774
+ _clipToWorldVector.y = _lineWidth / resolution.height;
37775
+ _clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
37776
+ _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
37777
+ return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) );
37778
+ }
37779
+ function raycastWorldUnits( lineSegments, intersects ) {
37780
+ const matrixWorld = lineSegments.matrixWorld;
37781
+ const geometry = lineSegments.geometry;
37782
+ const instanceStart = geometry.attributes.instanceStart;
37783
+ const instanceEnd = geometry.attributes.instanceEnd;
37784
+ const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
37785
+ for ( let i = 0, l = segmentCount; i < l; i ++ ) {
37786
+ _line.start.fromBufferAttribute( instanceStart, i );
37787
+ _line.end.fromBufferAttribute( instanceEnd, i );
37788
+ _line.applyMatrix4( matrixWorld );
37789
+ const pointOnLine = new Vector3();
37790
+ const point = new Vector3();
37791
+ _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
37792
+ const isInside = point.distanceTo( pointOnLine ) < _lineWidth * 0.5;
37793
+ if ( isInside ) {
37794
+ intersects.push( {
37795
+ point,
37796
+ pointOnLine,
37797
+ distance: _ray.origin.distanceTo( point ),
37798
+ object: lineSegments,
37799
+ face: null,
37800
+ faceIndex: i,
37801
+ uv: null,
37802
+ uv1: null,
37803
+ } );
37804
+ }
37805
+ }
37806
+ }
37807
+ function raycastScreenSpace( lineSegments, camera, intersects ) {
37808
+ const projectionMatrix = camera.projectionMatrix;
37809
+ const material = lineSegments.material;
37810
+ const resolution = material.resolution;
37811
+ const matrixWorld = lineSegments.matrixWorld;
37812
+ const geometry = lineSegments.geometry;
37813
+ const instanceStart = geometry.attributes.instanceStart;
37814
+ const instanceEnd = geometry.attributes.instanceEnd;
37815
+ const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
37816
+ const near = - camera.near;
37817
+ _ray.at( 1, _ssOrigin );
37818
+ _ssOrigin.w = 1;
37819
+ _ssOrigin.applyMatrix4( camera.matrixWorldInverse );
37820
+ _ssOrigin.applyMatrix4( projectionMatrix );
37821
+ _ssOrigin.multiplyScalar( 1 / _ssOrigin.w );
37822
+ _ssOrigin.x *= resolution.x / 2;
37823
+ _ssOrigin.y *= resolution.y / 2;
37824
+ _ssOrigin.z = 0;
37825
+ _ssOrigin3.copy( _ssOrigin );
37826
+ _mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
37827
+ for ( let i = 0, l = segmentCount; i < l; i ++ ) {
37828
+ _start4.fromBufferAttribute( instanceStart, i );
37829
+ _end4.fromBufferAttribute( instanceEnd, i );
37830
+ _start4.w = 1;
37831
+ _end4.w = 1;
37832
+ _start4.applyMatrix4( _mvMatrix );
37833
+ _end4.applyMatrix4( _mvMatrix );
37834
+ const isBehindCameraNear = _start4.z > near && _end4.z > near;
37835
+ if ( isBehindCameraNear ) {
37836
+ continue;
37837
+ }
37838
+ if ( _start4.z > near ) {
37839
+ const deltaDist = _start4.z - _end4.z;
37840
+ const t = ( _start4.z - near ) / deltaDist;
37841
+ _start4.lerp( _end4, t );
37842
+ } else if ( _end4.z > near ) {
37843
+ const deltaDist = _end4.z - _start4.z;
37844
+ const t = ( _end4.z - near ) / deltaDist;
37845
+ _end4.lerp( _start4, t );
37846
+ }
37847
+ _start4.applyMatrix4( projectionMatrix );
37848
+ _end4.applyMatrix4( projectionMatrix );
37849
+ _start4.multiplyScalar( 1 / _start4.w );
37850
+ _end4.multiplyScalar( 1 / _end4.w );
37851
+ _start4.x *= resolution.x / 2;
37852
+ _start4.y *= resolution.y / 2;
37853
+ _end4.x *= resolution.x / 2;
37854
+ _end4.y *= resolution.y / 2;
37855
+ _line.start.copy( _start4 );
37856
+ _line.start.z = 0;
37857
+ _line.end.copy( _end4 );
37858
+ _line.end.z = 0;
37859
+ const param = _line.closestPointToPointParameter( _ssOrigin3, true );
37860
+ _line.at( param, _closestPoint );
37861
+ const zPos = MathUtils.lerp( _start4.z, _end4.z, param );
37862
+ const isInClipSpace = zPos >= -1 && zPos <= 1;
37863
+ const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;
37864
+ if ( isInClipSpace && isInside ) {
37865
+ _line.start.fromBufferAttribute( instanceStart, i );
37866
+ _line.end.fromBufferAttribute( instanceEnd, i );
37867
+ _line.start.applyMatrix4( matrixWorld );
37868
+ _line.end.applyMatrix4( matrixWorld );
37869
+ const pointOnLine = new Vector3();
37870
+ const point = new Vector3();
37871
+ _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
37872
+ intersects.push( {
37873
+ point: point,
37874
+ pointOnLine: pointOnLine,
37875
+ distance: _ray.origin.distanceTo( point ),
37876
+ object: lineSegments,
37877
+ face: null,
37878
+ faceIndex: i,
37879
+ uv: null,
37880
+ uv1: null,
37881
+ } );
37882
+ }
37883
+ }
37884
+ }
37885
+ class LineSegments2 extends Mesh {
37886
+ constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
37887
+ super( geometry, material );
37888
+ this.isLineSegments2 = true;
37889
+ this.type = 'LineSegments2';
37890
+ }
37891
+ computeLineDistances() {
37892
+ const geometry = this.geometry;
37893
+ const instanceStart = geometry.attributes.instanceStart;
37894
+ const instanceEnd = geometry.attributes.instanceEnd;
37895
+ const lineDistances = new Float32Array( 2 * instanceStart.count );
37896
+ for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
37897
+ _start.fromBufferAttribute( instanceStart, i );
37898
+ _end.fromBufferAttribute( instanceEnd, i );
37899
+ lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
37900
+ lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
37901
+ }
37902
+ const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 );
37903
+ geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) );
37904
+ geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) );
37905
+ return this;
37906
+ }
37907
+ raycast( raycaster, intersects ) {
37908
+ const worldUnits = this.material.worldUnits;
37909
+ const camera = raycaster.camera;
37910
+ if ( camera === null && ! worldUnits ) {
37911
+ console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.' );
37912
+ }
37913
+ const threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0;
37914
+ _ray = raycaster.ray;
37915
+ const matrixWorld = this.matrixWorld;
37916
+ const geometry = this.geometry;
37917
+ const material = this.material;
37918
+ _lineWidth = material.linewidth + threshold;
37919
+ if ( geometry.boundingSphere === null ) {
37920
+ geometry.computeBoundingSphere();
37921
+ }
37922
+ _sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
37923
+ let sphereMargin;
37924
+ if ( worldUnits ) {
37925
+ sphereMargin = _lineWidth * 0.5;
37926
+ } else {
37927
+ const distanceToSphere = Math.max( camera.near, _sphere.distanceToPoint( _ray.origin ) );
37928
+ sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, material.resolution );
37929
+ }
37930
+ _sphere.radius += sphereMargin;
37931
+ if ( _ray.intersectsSphere( _sphere ) === false ) {
37932
+ return;
37933
+ }
37934
+ if ( geometry.boundingBox === null ) {
37935
+ geometry.computeBoundingBox();
37936
+ }
37937
+ _box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
37938
+ let boxMargin;
37939
+ if ( worldUnits ) {
37940
+ boxMargin = _lineWidth * 0.5;
37941
+ } else {
37942
+ const distanceToBox = Math.max( camera.near, _box.distanceToPoint( _ray.origin ) );
37943
+ boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, material.resolution );
37944
+ }
37945
+ _box.expandByScalar( boxMargin );
37946
+ if ( _ray.intersectsBox( _box ) === false ) {
37947
+ return;
37948
+ }
37949
+ if ( worldUnits ) {
37950
+ raycastWorldUnits( this, intersects );
37951
+ } else {
37952
+ raycastScreenSpace( this, camera, intersects );
37953
+ }
37954
+ }
37955
+ onBeforeRender( renderer ) {
37956
+ const uniforms = this.material.uniforms;
37957
+ if ( uniforms && uniforms.resolution ) {
37958
+ renderer.getViewport( _viewport );
37959
+ this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
37960
+ }
37961
+ }
37962
+ }
37963
+
37964
+ class PointHashGrid {
37965
+ constructor(tolerance = 1e-5) {
37966
+ this.tolerance = tolerance;
37967
+ this.points = [];
37968
+ this.grid = new Map();
37969
+ }
37970
+ _hash(hx, hy, hz) {
37971
+ return `${hx},${hy},${hz}`;
37972
+ }
37973
+ add(v) {
37974
+ const hx = Math.round(v.x / this.tolerance);
37975
+ const hy = Math.round(v.y / this.tolerance);
37976
+ const hz = Math.round(v.z / this.tolerance);
37977
+ for (let i = -1; i <= 1; i++) {
37978
+ for (let j = -1; j <= 1; j++) {
37979
+ for (let k = -1; k <= 1; k++) {
37980
+ const hash = this._hash(hx + i, hy + j, hz + k);
37981
+ const cell = this.grid.get(hash);
37982
+ if (cell) {
37983
+ for (const id of cell) {
37984
+ if (this.points[id].distanceTo(v) <= this.tolerance) return id;
37985
+ }
37986
+ }
37987
+ }
37988
+ }
37989
+ }
37990
+ const id = this.points.length;
37991
+ this.points.push(v.clone());
37992
+ const centerHash = this._hash(hx, hy, hz);
37993
+ if (!this.grid.has(centerHash)) this.grid.set(centerHash, []);
37994
+ this.grid.get(centerHash).push(id);
37995
+ return id;
37996
+ }
37997
+ }
37998
+ class SectionsHelper extends Object3D {
37999
+ constructor() {
38000
+ super();
38001
+ this.type = "SectionsHelper";
38002
+ this.flags = {
38003
+ fillEnabled: true,
38004
+ fillColor: "#fffde7",
38005
+ hatchEnabled: true,
38006
+ hatchColor: "#000000",
38007
+ hatchScale: 8.0,
38008
+ outlineEnabled: true,
38009
+ outlineColor: "#000000",
38010
+ outlineWidth: 2,
38011
+ boundaryOnly: true,
38012
+ showDebugSeams: false,
38013
+ showDebugPoints: false,
38014
+ showDebugSegments: false,
38015
+ showDebugGaps: false,
38016
+ showDebugInfo: false,
38017
+ useObjFillColor: false,
38018
+ useObjOutlineColor: false,
38019
+ };
38020
+ this._caps = [];
38021
+ this._outlines = [];
38022
+ this._debugPoints = [];
38023
+ this._debugSegments = [];
38024
+ this._debugGaps = [];
38025
+ this._vA = new Vector3();
38026
+ this._vB = new Vector3();
38027
+ this._vC = new Vector3();
38028
+ this._worldBox = new Box3();
38029
+ }
38030
+ dispose() {
38031
+ const disposeMesh = (item) => {
38032
+ if (item.geometry) item.geometry.dispose();
38033
+ if (item.material) item.material.dispose();
38034
+ this.remove(item);
38035
+ };
38036
+ this._caps.forEach(disposeMesh);
38037
+ this._outlines.forEach(disposeMesh);
38038
+ this._debugPoints.forEach(disposeMesh);
38039
+ this._debugSegments.forEach(disposeMesh);
38040
+ this._debugGaps.forEach(disposeMesh);
38041
+ this._caps.length = 0;
38042
+ this._outlines.length = 0;
38043
+ this._debugPoints.length = 0;
38044
+ this._debugSegments.length = 0;
38045
+ this._debugGaps.length = 0;
38046
+ }
38047
+ setSize(width, height) {
38048
+ this._outlines.forEach((o) => {
38049
+ if (o.material.resolution) o.material.resolution.set(width, height);
38050
+ });
38051
+ this._debugSegments.forEach((s) => {
38052
+ if (s.material.resolution) s.material.resolution.set(width, height);
38053
+ });
38054
+ }
38055
+ _ensureHelpersCount(count) {
38056
+ const hatchVertexShader = `
38057
+ #include <common>
38058
+ #include <logdepthbuf_pars_vertex>
38059
+ #include <clipping_planes_pars_vertex>
38060
+
38061
+ attribute float aHatchDir;
38062
+ attribute vec3 aFillColor;
38063
+
38064
+ varying vec3 vWP;
38065
+ varying float vHatchDir;
38066
+ varying vec3 vFillColor;
38067
+
38068
+ void main() {
38069
+ vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
38070
+ #include <clipping_planes_vertex>
38071
+
38072
+ vWP = (modelMatrix * vec4(position, 1.0)).xyz;
38073
+ vHatchDir = aHatchDir;
38074
+ vFillColor = aFillColor;
38075
+
38076
+ gl_Position = projectionMatrix * mvPosition;
38077
+ #include <logdepthbuf_vertex>
38078
+ }
38079
+ `;
38080
+ const hatchFragmentShader = `
38081
+ #include <common>
38082
+ #include <logdepthbuf_pars_fragment>
38083
+ #include <clipping_planes_pars_fragment>
38084
+
38085
+ uniform vec3 lineColor;
38086
+ uniform float uHatchScale;
38087
+ uniform float uHatchEnabled;
38088
+
38089
+ varying vec3 vWP;
38090
+ varying float vHatchDir;
38091
+ varying vec3 vFillColor;
38092
+
38093
+ void main() {
38094
+ #include <clipping_planes_fragment>
38095
+ #include <logdepthbuf_fragment>
38096
+
38097
+ float v1 = mod(gl_FragCoord.x + gl_FragCoord.y, uHatchScale);
38098
+ float v2 = mod(gl_FragCoord.x - gl_FragCoord.y, uHatchScale);
38099
+ float v = mix(v1, v2, vHatchDir);
38100
+
38101
+ float hatchMask = step(v, 1.5) * uHatchEnabled;
38102
+ gl_FragColor = vec4(mix(vFillColor, lineColor, hatchMask), 1.0);
38103
+ }
38104
+ `;
38105
+ while (this._caps.length < count) {
38106
+ const capMat = new ShaderMaterial({
38107
+ uniforms: {
38108
+ lineColor: { value: new Color() },
38109
+ uHatchScale: { value: 10.0 },
38110
+ uHatchEnabled: { value: 1.0 },
38111
+ },
38112
+ vertexShader: hatchVertexShader,
38113
+ fragmentShader: hatchFragmentShader,
38114
+ side: DoubleSide,
38115
+ clipping: true,
38116
+ depthTest: true,
38117
+ depthWrite: false,
38118
+ });
38119
+ const capMesh = new Mesh(new BufferGeometry(), capMat);
38120
+ capMesh.renderOrder = 5;
38121
+ this.add(capMesh);
38122
+ this._caps.push(capMesh);
38123
+ const lineMat = new LineMaterial({
38124
+ color: 0xffffff,
38125
+ linewidth: 2,
38126
+ resolution: new Vector2(window.innerWidth, window.innerHeight),
38127
+ depthTest: true,
38128
+ clipping: true,
38129
+ vertexColors: true,
38130
+ });
38131
+ const lineObj = new LineSegments2(new LineSegmentsGeometry(), lineMat);
38132
+ lineObj.renderOrder = 100;
38133
+ this.add(lineObj);
38134
+ this._outlines.push(lineObj);
38135
+ const ptsMat = new PointsMaterial({
38136
+ color: 0x00aaff,
38137
+ size: 6,
38138
+ sizeAttenuation: false,
38139
+ depthTest: false,
38140
+ transparent: true,
38141
+ depthWrite: false,
38142
+ });
38143
+ const pointsObj = new Points(new BufferGeometry(), ptsMat);
38144
+ pointsObj.renderOrder = 200;
38145
+ this.add(pointsObj);
38146
+ this._debugPoints.push(pointsObj);
38147
+ const debugSegMat = new LineMaterial({
38148
+ color: 0x00ff00,
38149
+ linewidth: 4,
38150
+ resolution: new Vector2(window.innerWidth, window.innerHeight),
38151
+ depthTest: false,
38152
+ transparent: true,
38153
+ depthWrite: false,
38154
+ clipping: true,
38155
+ });
38156
+ const debugSegObj = new LineSegments2(new LineSegmentsGeometry(), debugSegMat);
38157
+ debugSegObj.renderOrder = 150;
38158
+ this.add(debugSegObj);
38159
+ this._debugSegments.push(debugSegObj);
38160
+ const gapPtsMat = new PointsMaterial({
38161
+ size: 6,
38162
+ sizeAttenuation: false,
38163
+ depthTest: false,
38164
+ transparent: true,
38165
+ depthWrite: false,
38166
+ vertexColors: true,
38167
+ });
38168
+ const gapsObj = new Points(new BufferGeometry(), gapPtsMat);
38169
+ gapsObj.renderOrder = 250;
38170
+ this.add(gapsObj);
38171
+ this._debugGaps.push(gapsObj);
38172
+ }
38173
+ for (let i = count; i < this._caps.length; i++) {
38174
+ this._caps[i].visible = false;
38175
+ this._outlines[i].visible = false;
38176
+ this._debugPoints[i].visible = false;
38177
+ this._debugSegments[i].visible = false;
38178
+ this._debugGaps[i].visible = false;
38179
+ }
38180
+ }
38181
+ update(objects, extents, planes) {
38182
+ const t0 = performance.now();
38183
+ this._ensureHelpersCount(planes.length);
38184
+ if (planes.length === 0) return;
38185
+ const sphere = extents.getBoundingSphere(new Sphere());
38186
+ const globalRadius = Math.max(sphere.radius, 1e-3);
38187
+ const clippingBias = globalRadius * 1e-4;
38188
+ const biasedPlanes = planes.map((p) => {
38189
+ const bp = p.clone();
38190
+ bp.constant += clippingBias;
38191
+ return bp;
38192
+ });
38193
+ const targetMeshes = [];
38194
+ objects.forEach((obj) => {
38195
+ if (obj.isMesh && obj.material) {
38196
+ const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
38197
+ if (mats.some((m) => m.clippingPlanes)) targetMeshes.push(obj);
38198
+ }
38199
+ });
38200
+ planes.forEach((plane, pIdx) => {
38201
+ const capMesh = this._caps[pIdx];
38202
+ const outlineMesh = this._outlines[pIdx];
38203
+ const debugPtsMesh = this._debugPoints[pIdx];
38204
+ const debugSegsMesh = this._debugSegments[pIdx];
38205
+ const debugGapsMesh = this._debugGaps[pIdx];
38206
+ const hatchColor = new Color(this.flags.hatchColor);
38207
+ hatchColor.convertLinearToSRGB();
38208
+ capMesh.material.uniforms.lineColor.value.set(hatchColor);
38209
+ capMesh.material.uniforms.uHatchScale.value = this.flags.hatchScale;
38210
+ capMesh.material.uniforms.uHatchEnabled.value = this.flags.hatchEnabled ? 1.0 : 0.0;
38211
+ outlineMesh.material.linewidth = this.flags.outlineWidth;
38212
+ const otherBiasedPlanes = biasedPlanes.filter((_, i) => i !== pIdx);
38213
+ capMesh.material.clippingPlanes = otherBiasedPlanes;
38214
+ outlineMesh.material.clippingPlanes = otherBiasedPlanes;
38215
+ debugSegsMesh.material.clippingPlanes = otherBiasedPlanes;
38216
+ const n = plane.normal;
38217
+ const planeOrigin = n.clone().multiplyScalar(-plane.constant);
38218
+ const up = new Vector3(0, 1, 0);
38219
+ if (Math.abs(n.dot(up)) > 0.999) up.set(1, 0, 0);
38220
+ const uAxis = new Vector3().crossVectors(up, n).normalize();
38221
+ const vAxis = new Vector3().crossVectors(n, uAxis).normalize();
38222
+ const positions = [];
38223
+ const indices = [];
38224
+ const hatchDirs = [];
38225
+ const fillColors = [];
38226
+ const combinedOutlinePoints = [];
38227
+ const combinedOutlineColors = [];
38228
+ const rawPts = [];
38229
+ const rawSegs = [];
38230
+ const rawGaps = [];
38231
+ const rawGapColors = [];
38232
+ targetMeshes.forEach((mesh, meshIndex) => {
38233
+ if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();
38234
+ if (!mesh.geometry.boundingSphere) mesh.geometry.computeBoundingSphere();
38235
+ this._worldBox.copy(mesh.geometry.boundingBox).applyMatrix4(mesh.matrixWorld);
38236
+ if (!plane.intersectsBox(this._worldBox)) return;
38237
+ const localScale = new Vector3().setFromMatrixScale(mesh.matrixWorld);
38238
+ const maxScale = Math.max(localScale.x, localScale.y, localScale.z);
38239
+ const localRadius = Math.max(mesh.geometry.boundingSphere.radius * maxScale, 1e-3);
38240
+ const localHashTolerance = Math.max(localRadius * 1e-4, 1e-6);
38241
+ const localEps = Math.max(localRadius * 1e-5, 1e-7);
38242
+ const baseColor = new Color(0xffffff);
38243
+ const om = mesh.userData.originalMaterial;
38244
+ const mm = om ?? (Array.isArray(mesh.material) ? mesh.material[0] : mesh.material);
38245
+ if (mm.color) baseColor.copy(mm.color);
38246
+ const objFillColor = baseColor.clone().lerp(new Color(0x000000), 0.2);
38247
+ const objOutlineColor = baseColor.clone().lerp(new Color(0x000000), 0.85);
38248
+ const hue = ((meshIndex * 137.5) % 360) / 360;
38249
+ const meshGapColor = new Color().setHSL(hue, 1.0, 0.5);
38250
+ const currentHatchDir = meshIndex % 2 === 0 ? 0.0 : 1.0;
38251
+ const fillColor = this.flags.useObjFillColor ? objFillColor : new Color(this.flags.fillColor);
38252
+ const outlineColor = this.flags.useObjOutlineColor ? objOutlineColor : new Color(this.flags.outlineColor);
38253
+ meshGapColor.convertLinearToSRGB();
38254
+ fillColor.convertLinearToSRGB();
38255
+ outlineColor.convertLinearToSRGB();
38256
+ const localEdgeStats = new Map();
38257
+ const localPointGrid = new PointHashGrid(localHashTolerance);
38258
+ this._calculateMeshSegmentsUndirected(mesh, plane, localEdgeStats, localPointGrid, localEps);
38259
+ if (localEdgeStats.size > 0) {
38260
+ const boundaryEdges = [];
38261
+ for (const [key, stat] of localEdgeStats.entries()) {
38262
+ const isBoundary = stat.count % 2 !== 0;
38263
+ const ids = key.split("-");
38264
+ const id0 = Number(ids[0]);
38265
+ const id1 = Number(ids[1]);
38266
+ const p1 = localPointGrid.points[id0];
38267
+ const p2 = localPointGrid.points[id1];
38268
+ if (this.flags.showDebugSeams || (this.flags.boundaryOnly ? isBoundary : true)) {
38269
+ combinedOutlinePoints.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
38270
+ combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
38271
+ combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
38272
+ }
38273
+ if (isBoundary) boundaryEdges.push([id0, id1]);
38274
+ if (this.flags.showDebugSegments) rawSegs.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
38275
+ }
38276
+ if (this.flags.showDebugPoints) {
38277
+ for (const p of localPointGrid.points) rawPts.push(p.x, p.y, p.z);
38278
+ }
38279
+ if (this.flags.fillEnabled && boundaryEdges.length >= 3) {
38280
+ const currentAdj = new Map();
38281
+ for (const edge of boundaryEdges) {
38282
+ const a = edge[0];
38283
+ const b = edge[1];
38284
+ if (!currentAdj.has(a)) currentAdj.set(a, []);
38285
+ if (!currentAdj.has(b)) currentAdj.set(b, []);
38286
+ currentAdj.get(a).push(b);
38287
+ currentAdj.get(b).push(a);
38288
+ }
38289
+ const degree1 = [];
38290
+ for (const [node, neighbors] of currentAdj.entries()) {
38291
+ if (neighbors.length === 1) degree1.push(node);
38292
+ }
38293
+ const stitchTol = Math.max(localRadius * 0.05, 1e-4);
38294
+ for (let i = 0; i < degree1.length; i++) {
38295
+ const n1 = degree1[i];
38296
+ if (currentAdj.get(n1).length !== 1) continue;
38297
+ const p1 = localPointGrid.points[n1];
38298
+ let bestEdgeIdx = -1;
38299
+ let bestProj = null;
38300
+ let bestT = 0;
38301
+ let minDist = stitchTol;
38302
+ const edgeCount = boundaryEdges.length;
38303
+ for (let eIdx = 0; eIdx < edgeCount; eIdx++) {
38304
+ const edge = boundaryEdges[eIdx];
38305
+ const eA = edge[0];
38306
+ const eB = edge[1];
38307
+ if (eA === n1 || eB === n1) continue;
38308
+ const pA = localPointGrid.points[eA];
38309
+ const pB = localPointGrid.points[eB];
38310
+ const lineVec = new Vector3().subVectors(pB, pA);
38311
+ const lineLenSq = lineVec.lengthSq();
38312
+ let proj;
38313
+ let t;
38314
+ if (lineLenSq < 1e-12) {
38315
+ proj = pA.clone();
38316
+ t = 0;
38317
+ } else {
38318
+ const ptVec = new Vector3().subVectors(p1, pA);
38319
+ t = ptVec.dot(lineVec) / lineLenSq;
38320
+ t = Math.max(0, Math.min(1, t));
38321
+ proj = new Vector3().copy(pA).addScaledVector(lineVec, t);
38322
+ }
38323
+ const dist = p1.distanceTo(proj);
38324
+ if (dist < minDist) {
38325
+ minDist = dist;
38326
+ bestEdgeIdx = eIdx;
38327
+ bestProj = proj;
38328
+ bestT = t;
38329
+ }
38330
+ }
38331
+ if (bestEdgeIdx !== -1) {
38332
+ const edge = boundaryEdges[bestEdgeIdx];
38333
+ const eA = edge[0];
38334
+ const eB = edge[1];
38335
+ if (bestT < 0.001) {
38336
+ boundaryEdges.push([n1, eA]);
38337
+ currentAdj.get(n1).push(eA);
38338
+ currentAdj.get(eA).push(n1);
38339
+ p1.copy(localPointGrid.points[eA]);
38340
+ } else if (bestT > 0.999) {
38341
+ boundaryEdges.push([n1, eB]);
38342
+ currentAdj.get(n1).push(eB);
38343
+ currentAdj.get(eB).push(n1);
38344
+ p1.copy(localPointGrid.points[eB]);
38345
+ } else {
38346
+ const newNodeId = localPointGrid.add(bestProj);
38347
+ edge[1] = newNodeId;
38348
+ boundaryEdges.push([newNodeId, eB]);
38349
+ boundaryEdges.push([n1, newNodeId]);
38350
+ const neighborsA = currentAdj.get(eA);
38351
+ neighborsA[neighborsA.indexOf(eB)] = newNodeId;
38352
+ const neighborsB = currentAdj.get(eB);
38353
+ neighborsB[neighborsB.indexOf(eA)] = newNodeId;
38354
+ if (!currentAdj.has(newNodeId)) currentAdj.set(newNodeId, []);
38355
+ currentAdj.get(newNodeId).push(eA, eB, n1);
38356
+ currentAdj.get(n1).push(newNodeId);
38357
+ p1.copy(bestProj);
38358
+ }
38359
+ }
38360
+ }
38361
+ if (this.flags.showDebugGaps) {
38362
+ for (const [node, neighbors] of currentAdj.entries()) {
38363
+ if (neighbors.length !== 2) {
38364
+ const p = localPointGrid.points[node];
38365
+ rawGaps.push(p.x, p.y, p.z);
38366
+ rawGapColors.push(meshGapColor.r, meshGapColor.g, meshGapColor.b);
38367
+ }
38368
+ }
38369
+ }
38370
+ const loops = this._assembleLoopsUndirected(boundaryEdges, localPointGrid, uAxis, vAxis);
38371
+ if (loops.length > 0) {
38372
+ this._triangulateTreeOptimized(
38373
+ loops,
38374
+ planeOrigin,
38375
+ uAxis,
38376
+ vAxis,
38377
+ positions,
38378
+ indices,
38379
+ localRadius,
38380
+ fillColor,
38381
+ currentHatchDir,
38382
+ hatchDirs,
38383
+ fillColors
38384
+ );
38385
+ }
38386
+ }
38387
+ }
38388
+ });
38389
+ if (indices.length > 0) {
38390
+ capMesh.geometry.dispose();
38391
+ capMesh.geometry = new BufferGeometry();
38392
+ capMesh.geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
38393
+ capMesh.geometry.setAttribute("aHatchDir", new Float32BufferAttribute(hatchDirs, 1));
38394
+ capMesh.geometry.setAttribute("aFillColor", new Float32BufferAttribute(fillColors, 3));
38395
+ capMesh.geometry.setIndex(indices);
38396
+ capMesh.geometry.computeVertexNormals();
38397
+ capMesh.visible = this.flags.fillEnabled;
38398
+ } else {
38399
+ capMesh.visible = false;
38400
+ }
38401
+ if (outlineMesh.geometry) outlineMesh.geometry.dispose();
38402
+ outlineMesh.geometry = new LineSegmentsGeometry();
38403
+ if (this.flags.outlineEnabled && combinedOutlinePoints.length >= 6) {
38404
+ outlineMesh.geometry.setPositions(new Float32Array(combinedOutlinePoints));
38405
+ outlineMesh.geometry.setColors(new Float32Array(combinedOutlineColors));
38406
+ outlineMesh.visible = true;
38407
+ } else {
38408
+ outlineMesh.visible = false;
38409
+ }
38410
+ if (this.flags.showDebugPoints && rawPts.length > 0) {
38411
+ debugPtsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawPts, 3));
38412
+ debugPtsMesh.visible = true;
38413
+ } else {
38414
+ debugPtsMesh.visible = false;
38415
+ }
38416
+ if (debugSegsMesh.geometry) debugSegsMesh.geometry.dispose();
38417
+ debugSegsMesh.geometry = new LineSegmentsGeometry();
38418
+ if (this.flags.showDebugSegments && rawSegs.length >= 6) {
38419
+ debugSegsMesh.geometry.setPositions(new Float32Array(rawSegs));
38420
+ debugSegsMesh.visible = true;
38421
+ } else {
38422
+ debugSegsMesh.visible = false;
38423
+ }
38424
+ if (debugGapsMesh.geometry) debugGapsMesh.geometry.dispose();
38425
+ debugGapsMesh.geometry = new BufferGeometry();
38426
+ if (this.flags.showDebugGaps && rawGaps.length > 0) {
38427
+ debugGapsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawGaps, 3));
38428
+ debugGapsMesh.geometry.setAttribute("color", new Float32BufferAttribute(rawGapColors, 3));
38429
+ debugGapsMesh.visible = true;
38430
+ } else {
38431
+ debugGapsMesh.visible = false;
38432
+ }
38433
+ });
38434
+ if (this.flags.showDebugInfo) {
38435
+ console.log(`[SectionsHelper] v7.00 Updated in ${(performance.now() - t0).toFixed(2)} ms`);
38436
+ }
38437
+ }
38438
+ _assembleLoopsUndirected(edges, pointGrid, uAxis, vAxis) {
38439
+ const adj = new Map();
38440
+ for (const edge of edges) {
38441
+ const a = edge[0];
38442
+ const b = edge[1];
38443
+ if (!adj.has(a)) adj.set(a, []);
38444
+ if (!adj.has(b)) adj.set(b, []);
38445
+ adj.get(a).push(b);
38446
+ adj.get(b).push(a);
38447
+ }
38448
+ const loops = [];
38449
+ while (adj.size > 0) {
38450
+ let startNode = -1;
38451
+ for (const key of adj.keys()) {
38452
+ if (adj.get(key).length > 0) {
38453
+ startNode = key;
38454
+ break;
38455
+ }
38456
+ }
38457
+ if (startNode === -1) break;
38458
+ let current = startNode;
38459
+ let prev = -1;
38460
+ const path = [];
38461
+ const pathIndices = new Map();
38462
+ while (true) {
38463
+ path.push(current);
38464
+ pathIndices.set(current, path.length - 1);
38465
+ const neighbors = adj.get(current);
38466
+ if (!neighbors || neighbors.length === 0) break;
38467
+ let nextIdx = 0;
38468
+ if (neighbors.length > 1 && prev !== -1) {
38469
+ const pPrev = pointGrid.points[prev];
38470
+ const pCurr = pointGrid.points[current];
38471
+ const vIn = new Vector3().subVectors(pCurr, pPrev);
38472
+ const in2d = new Vector2(vIn.dot(uAxis), vIn.dot(vAxis));
38473
+ if (in2d.lengthSq() > 1e-10) {
38474
+ in2d.normalize();
38475
+ let minAngle = Infinity;
38476
+ for (let i = 0; i < neighbors.length; i++) {
38477
+ const pNext = pointGrid.points[neighbors[i]];
38478
+ const vOut = new Vector3().subVectors(pNext, pCurr);
38479
+ const out2d = new Vector2(vOut.dot(uAxis), vOut.dot(vAxis));
38480
+ if (out2d.lengthSq() > 1e-10) {
38481
+ out2d.normalize();
38482
+ const angle = Math.atan2(in2d.cross(out2d), in2d.dot(out2d));
38483
+ if (angle < minAngle) {
38484
+ minAngle = angle;
38485
+ nextIdx = i;
38486
+ }
38487
+ }
38488
+ }
38489
+ }
38490
+ }
38491
+ const next = neighbors[nextIdx];
38492
+ neighbors.splice(nextIdx, 1);
38493
+ const nextNeighbors = adj.get(next);
38494
+ if (nextNeighbors) {
38495
+ const revIdx = nextNeighbors.indexOf(current);
38496
+ if (revIdx !== -1) nextNeighbors.splice(revIdx, 1);
38497
+ }
38498
+ prev = current;
38499
+ current = next;
38500
+ if (pathIndices.has(current)) {
38501
+ const loopStartIdx = pathIndices.get(current);
38502
+ const loopNodes = path.slice(loopStartIdx);
38503
+ if (loopNodes.length >= 3) loops.push(loopNodes.map((id) => pointGrid.points[id]));
38504
+ for (let i = loopStartIdx; i < path.length; i++) pathIndices.delete(path[i]);
38505
+ path.length = loopStartIdx;
38506
+ prev = path.length > 1 ? path[path.length - 2] : -1;
38507
+ }
38508
+ }
38509
+ for (const key of adj.keys()) {
38510
+ if (adj.get(key).length === 0) adj.delete(key);
38511
+ }
38512
+ }
38513
+ return loops;
38514
+ }
38515
+ _triangulateTreeOptimized(
38516
+ loops,
38517
+ planeOrigin,
38518
+ uAxis,
38519
+ vAxis,
38520
+ positionsBuffer,
38521
+ indicesBuffer,
38522
+ localRadius,
38523
+ fillColor,
38524
+ hatchDir,
38525
+ hatchDirsBuffer,
38526
+ fillColorsBuffer
38527
+ ) {
38528
+ const shapesData = [];
38529
+ const minArea = localRadius * 1e-5 * (localRadius * 1e-5);
38530
+ loops.forEach((loop) => {
38531
+ const pts2d = loop.map((p) => {
38532
+ const pv = p.clone().sub(planeOrigin);
38533
+ return new Vector2(pv.dot(uAxis), pv.dot(vAxis));
38534
+ });
38535
+ const cleaned = [];
38536
+ for (let k = 0; k < pts2d.length; k++) {
38537
+ const prev = k === 0 ? pts2d[pts2d.length - 1] : pts2d[k - 1];
38538
+ if (pts2d[k].distanceTo(prev) > 1e-5) cleaned.push(pts2d[k]);
38539
+ }
38540
+ if (cleaned.length < 3) return;
38541
+ const area = ShapeUtils.area(cleaned);
38542
+ if (Math.abs(area) > minArea) {
38543
+ shapesData.push({ pts2d: cleaned, absArea: Math.abs(area), depth: 0, parent: -1, holes: [] });
38544
+ }
38545
+ });
38546
+ shapesData.sort((a, b) => b.absArea - a.absArea);
38547
+ for (let i = 0; i < shapesData.length; i++) {
38548
+ for (let j = i - 1; j >= 0; j--) {
38549
+ if (shapesData[i].absArea > shapesData[j].absArea * 0.98) continue;
38550
+ if (this._isLoopInside(shapesData[i].pts2d, shapesData[j].pts2d, localRadius)) {
38551
+ shapesData[i].parent = j;
38552
+ shapesData[i].depth = shapesData[j].depth + 1;
38553
+ break;
38554
+ }
38555
+ }
38556
+ }
38557
+ for (let i = 0; i < shapesData.length; i++) {
38558
+ const shape = shapesData[i];
38559
+ if (shape.depth % 2 === 1 && shape.parent !== -1) {
38560
+ shapesData[shape.parent].holes.push(shape.pts2d);
38561
+ }
38562
+ }
38563
+ for (let i = 0; i < shapesData.length; i++) {
38564
+ const shapeData = shapesData[i];
38565
+ if (shapeData.depth % 2 !== 0) continue;
38566
+ if (ShapeUtils.area(shapeData.pts2d) < 0) {
38567
+ shapeData.pts2d.reverse();
38568
+ }
38569
+ shapeData.holes.forEach((h) => {
38570
+ if (ShapeUtils.area(h) > 0) h.reverse();
38571
+ });
38572
+ const allPoints = [...shapeData.pts2d];
38573
+ shapeData.holes.forEach((h) => allPoints.push(...h));
38574
+ const faces = ShapeUtils.triangulateShape(shapeData.pts2d, shapeData.holes);
38575
+ const vertexOffset = positionsBuffer.length / 3;
38576
+ for (const pt of allPoints) {
38577
+ const p3d = planeOrigin.clone().addScaledVector(uAxis, pt.x).addScaledVector(vAxis, pt.y);
38578
+ positionsBuffer.push(p3d.x, p3d.y, p3d.z);
38579
+ hatchDirsBuffer.push(hatchDir);
38580
+ fillColorsBuffer.push(fillColor.r, fillColor.g, fillColor.b);
38581
+ }
38582
+ for (let f = 0; f < faces.length; f++) {
38583
+ indicesBuffer.push(vertexOffset + faces[f][0], vertexOffset + faces[f][1], vertexOffset + faces[f][2]);
38584
+ }
38585
+ }
38586
+ }
38587
+ _isPointInPoly(pt, poly) {
38588
+ let inside = false;
38589
+ const py = pt.y + 1.119e-7;
38590
+ const px = pt.x;
38591
+ for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
38592
+ if (
38593
+ poly[i].y > py !== poly[j].y > py &&
38594
+ px < ((poly[j].x - poly[i].x) * (py - poly[i].y)) / (poly[j].y - poly[i].y) + poly[i].x
38595
+ ) {
38596
+ inside = !inside;
38597
+ }
38598
+ }
38599
+ return inside;
38600
+ }
38601
+ _isLoopInside(child, parent, localRadius) {
38602
+ let minX1 = Infinity;
38603
+ let maxX1 = -Infinity;
38604
+ let minY1 = Infinity;
38605
+ let maxY1 = -Infinity;
38606
+ for (const p of child) {
38607
+ if (p.x < minX1) minX1 = p.x;
38608
+ if (p.x > maxX1) maxX1 = p.x;
38609
+ if (p.y < minY1) minY1 = p.y;
38610
+ if (p.y > maxY1) maxY1 = p.y;
38611
+ }
38612
+ let minX2 = Infinity;
38613
+ let maxX2 = -Infinity;
38614
+ let minY2 = Infinity;
38615
+ let maxY2 = -Infinity;
38616
+ for (const p of parent) {
38617
+ if (p.x < minX2) minX2 = p.x;
38618
+ if (p.x > maxX2) maxX2 = p.x;
38619
+ if (p.y < minY2) minY2 = p.y;
38620
+ if (p.y > maxY2) maxY2 = p.y;
38621
+ }
38622
+ const margin = Math.max(localRadius * 1e-4, 1e-5);
38623
+ if (minX1 < minX2 - margin || maxX1 > maxX2 + margin || minY1 < minY2 - margin || maxY1 > maxY2 + margin) {
38624
+ return false;
38625
+ }
38626
+ let insideCount = 0;
38627
+ for (let i = 0; i < child.length; i++) {
38628
+ if (this._isPointInPoly(child[i], parent)) {
38629
+ insideCount++;
38630
+ }
38631
+ }
38632
+ return insideCount >= child.length * 0.85;
38633
+ }
38634
+ _calculateMeshSegmentsUndirected(mesh, plane, edgeStats, grid, eps) {
38635
+ const geom = mesh.geometry;
38636
+ const pos = geom.attributes.position;
38637
+ const index = geom.index;
38638
+ const world = mesh.matrixWorld;
38639
+ const count = index ? index.count : pos.count;
38640
+ for (let i = 0; i < count; i += 3) {
38641
+ const i1 = index ? index.getX(i) : i;
38642
+ const i2 = index ? index.getX(i + 1) : i + 1;
38643
+ const i3 = index ? index.getX(i + 2) : i + 2;
38644
+ const v1 = this._vA.fromBufferAttribute(pos, i1).applyMatrix4(world);
38645
+ const v2 = this._vB.fromBufferAttribute(pos, i2).applyMatrix4(world);
38646
+ const v3 = this._vC.fromBufferAttribute(pos, i3).applyMatrix4(world);
38647
+ let d1 = plane.distanceToPoint(v1);
38648
+ let d2 = plane.distanceToPoint(v2);
38649
+ let d3 = plane.distanceToPoint(v3);
38650
+ if (Math.abs(d1) <= eps) d1 = eps;
38651
+ if (Math.abs(d2) <= eps) d2 = eps;
38652
+ if (Math.abs(d3) <= eps) d3 = eps;
38653
+ const s1 = d1 > 0 ? 1 : -1;
38654
+ const s2 = d2 > 0 ? 1 : -1;
38655
+ const s3 = d3 > 0 ? 1 : -1;
38656
+ if (s1 === s2 && s2 === s3) continue;
38657
+ const intersections = [];
38658
+ if (s1 !== s2) {
38659
+ intersections.push(new Vector3().lerpVectors(v1, v2, Math.abs(d1) / (Math.abs(d1) + Math.abs(d2))));
38660
+ }
38661
+ if (s2 !== s3) {
38662
+ intersections.push(new Vector3().lerpVectors(v2, v3, Math.abs(d2) / (Math.abs(d2) + Math.abs(d3))));
38663
+ }
38664
+ if (s3 !== s1) {
38665
+ intersections.push(new Vector3().lerpVectors(v3, v1, Math.abs(d3) / (Math.abs(d3) + Math.abs(d1))));
38666
+ }
38667
+ if (intersections.length >= 2) {
38668
+ const id1 = grid.add(intersections[0]);
38669
+ const id2 = grid.add(intersections[1]);
38670
+ if (id1 !== id2) {
38671
+ const key = id1 < id2 ? `${id1}-${id2}` : `${id2}-${id1}`;
38672
+ const stat = edgeStats.get(key) || { count: 0 };
38673
+ stat.count++;
38674
+ edgeStats.set(key, stat);
38675
+ }
38676
+ }
38677
+ }
38678
+ }
38679
+ }
38680
+
38681
+ class SectionsComponent {
38682
+ constructor(viewer) {
38683
+ this.updateTimerId = 0;
38684
+ this.updateDelay = 250;
38685
+ this.syncOptions = () => {
38686
+ function rgbToHex(c) {
38687
+ const hex = (v = 0) => v.toString(16).padStart(2, "0");
38688
+ return "#" + hex(c.r) + hex(c.g) + hex(c.b);
38689
+ }
38690
+ const options = this.viewer.options;
38691
+ const flags = this.sectionsHelper.flags;
38692
+ flags.fillEnabled = options.enableSectionFill;
38693
+ flags.fillColor = rgbToHex(options.sectionFillColor);
38694
+ flags.useObjFillColor = options.sectionUseObjectColor;
38695
+ flags.hatchEnabled = options.enableSectionHatch;
38696
+ flags.hatchColor = rgbToHex(options.sectionHatchColor);
38697
+ flags.hatchScale = options.sectionHatchScale;
38698
+ flags.outlineEnabled = options.enableSectionOutline;
38699
+ flags.outlineColor = rgbToHex(options.sectionOutlineColor);
38700
+ flags.outlineWidth = options.sectionOutlineWidth;
38701
+ this.syncSections();
38702
+ };
38703
+ this.syncHelper = () => {
38704
+ this.sectionsHelper.removeFromParent();
38705
+ this.viewer.helpers.add(this.sectionsHelper);
38706
+ };
38707
+ this.syncSections = () => {
38708
+ this.sectionsHelper.visible = false;
38709
+ clearTimeout(this.updateTimerId);
38710
+ this.updateTimerId = window.setTimeout(this.updateSections, this.updateDelay);
38711
+ };
38712
+ this.viewerResize = (event) => {
38713
+ this.sectionsHelper.setSize(event.width, event.height);
38714
+ };
38715
+ this.updateSections = () => {
38716
+ const objects = [];
38717
+ this.viewer.models.forEach((model) => objects.push(model.getVisibleObjects()));
38718
+ const objects2 = objects.flat();
38719
+ this.sectionsHelper.update(objects2, this.viewer.extents, this.viewer.clippingPlanes);
38720
+ this.sectionsHelper.visible = true;
38721
+ this.viewer.update();
38722
+ };
38723
+ this.sectionsHelper = new SectionsHelper();
38724
+ this.viewer = viewer;
38725
+ this.viewer.addEventListener("initialize", this.syncHelper);
38726
+ this.viewer.addEventListener("databasechunk", this.syncHelper);
38727
+ this.viewer.addEventListener("drawviewpoint", this.syncHelper);
38728
+ this.viewer.addEventListener("changecuttingplanes", this.syncSections);
38729
+ this.viewer.addEventListener("explode", this.syncSections);
38730
+ this.viewer.addEventListener("hide", this.syncSections);
38731
+ this.viewer.addEventListener("isolate", this.syncSections);
38732
+ this.viewer.addEventListener("show", this.syncSections);
38733
+ this.viewer.addEventListener("showall", this.syncSections);
38734
+ this.viewer.addEventListener("resize", this.viewerResize);
38735
+ this.viewer.addEventListener("optionschange", this.syncOptions);
38736
+ this.syncOptions();
38737
+ }
38738
+ dispose() {
38739
+ clearTimeout(this.updateTimerId);
38740
+ this.sectionsHelper.removeFromParent();
38741
+ this.sectionsHelper.dispose();
38742
+ this.viewer.removeEventListener("initialize", this.syncHelper);
38743
+ this.viewer.removeEventListener("databasechunk", this.syncHelper);
38744
+ this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
38745
+ this.viewer.removeEventListener("changecuttingplanes", this.syncSections);
38746
+ this.viewer.removeEventListener("explode", this.syncSections);
38747
+ this.viewer.removeEventListener("hide", this.syncSections);
38748
+ this.viewer.removeEventListener("isolate", this.syncSections);
38749
+ this.viewer.removeEventListener("show", this.syncSections);
38750
+ this.viewer.removeEventListener("showall", this.syncSections);
38751
+ this.viewer.removeEventListener("resize", this.viewerResize);
38752
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
38753
+ }
38754
+ }
38755
+
37625
38756
  class WCSHelper extends Object3D {
37626
38757
  constructor(camera) {
37627
38758
  super();
38759
+ this.type = "WCSHelper";
37628
38760
  this.camera = camera;
37629
38761
  this.size = 160;
37630
38762
  this.orthoCamera = new OrthographicCamera(-2, 2, 2, -2, 0, 4);
@@ -37712,7 +38844,7 @@ void main() {
37712
38844
 
37713
38845
  class WCSHelperComponent {
37714
38846
  constructor(viewer) {
37715
- this.geometryEnd = () => {
38847
+ this.syncHelper = () => {
37716
38848
  this.wcsHelper.dispose();
37717
38849
  this.wcsHelper = new WCSHelper(this.viewer.camera);
37718
38850
  };
@@ -37726,14 +38858,14 @@ void main() {
37726
38858
  };
37727
38859
  this.wcsHelper = new WCSHelper(viewer.camera);
37728
38860
  this.viewer = viewer;
37729
- this.viewer.addEventListener("databasechunk", this.geometryEnd);
37730
- this.viewer.addEventListener("drawviewpoint", this.geometryEnd);
38861
+ this.viewer.addEventListener("databasechunk", this.syncHelper);
38862
+ this.viewer.addEventListener("drawviewpoint", this.syncHelper);
37731
38863
  this.viewer.addEventListener("render", this.viewerRender);
37732
38864
  this.viewer.addEventListener("changecameramode", this.updateHelperCamera);
37733
38865
  }
37734
38866
  dispose() {
37735
- this.viewer.removeEventListener("databasechunk", this.geometryEnd);
37736
- this.viewer.removeEventListener("drawviewpoint", this.geometryEnd);
38867
+ this.viewer.removeEventListener("databasechunk", this.syncHelper);
38868
+ this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
37737
38869
  this.viewer.removeEventListener("render", this.viewerRender);
37738
38870
  this.viewer.removeEventListener("changecameramode", this.updateHelperCamera);
37739
38871
  this.wcsHelper.dispose();
@@ -37779,11 +38911,14 @@ void main() {
37779
38911
  components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
37780
38912
  components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
37781
38913
  components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
38914
+ components.registerComponent("ClippingPlaneComponent", (viewer) => new ClippingPlaneComponent(viewer));
38915
+ components.registerComponent("SectionsComponent", (viewer) => new SectionsComponent(viewer));
37782
38916
  components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
37783
38917
  components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
37784
38918
 
37785
38919
  class ModelImpl {
37786
38920
  constructor(scene) {
38921
+ this.id = "";
37787
38922
  this.scene = scene;
37788
38923
  this.handleToObjects = new Map();
37789
38924
  this.originalObjects = new Set();
@@ -37959,7 +39094,25 @@ void main() {
37959
39094
  return info;
37960
39095
  }
37961
39096
  getExtents(target) {
37962
- this.scene.traverseVisible((object) => target.expandByObject(object));
39097
+ const _box = new Box3();
39098
+ function expandByObject(object, target) {
39099
+ if (!object.geometry)
39100
+ return;
39101
+ object.updateWorldMatrix(false, false);
39102
+ if (object.boundingBox !== undefined) {
39103
+ if (object.boundingBox === null)
39104
+ object.computeBoundingBox();
39105
+ _box.copy(object.boundingBox);
39106
+ }
39107
+ else {
39108
+ if (object.geometry.boundingBox === null)
39109
+ object.geometry.computeBoundingBox();
39110
+ _box.copy(object.geometry.boundingBox);
39111
+ }
39112
+ _box.applyMatrix4(object.matrixWorld);
39113
+ target.union(_box);
39114
+ }
39115
+ this.scene.traverseVisible((object) => expandByObject(object, target));
37963
39116
  return target;
37964
39117
  }
37965
39118
  getObjects() {
@@ -37967,8 +39120,8 @@ void main() {
37967
39120
  }
37968
39121
  getVisibleObjects() {
37969
39122
  const objects = [];
37970
- this.scene.traverseVisible((object) => objects.push(object));
37971
- return objects.filter((object) => object.userData.handle);
39123
+ this.scene.traverseVisible((object) => object.userData.handle && objects.push(object));
39124
+ return objects;
37972
39125
  }
37973
39126
  getObjectsByHandles(handles) {
37974
39127
  if (!Array.isArray(handles))
@@ -38322,6 +39475,7 @@ void main() {
38322
39475
  this._nextObjectId = 1;
38323
39476
  this.loadingAborted = false;
38324
39477
  this.criticalError = null;
39478
+ this.embeddedBinaryChunk = null;
38325
39479
  }
38326
39480
  async initialize(loader) {
38327
39481
  const json = await this.loadController.loadJson();
@@ -38330,28 +39484,72 @@ void main() {
38330
39484
  }
38331
39485
  this.json = json;
38332
39486
  this.loader = loader;
38333
- this.uri = this.json.buffers[0].uri || "";
39487
+ const bufferUri = this.json.buffers?.[0]?.uri || "";
39488
+ if (bufferUri.startsWith("data:")) {
39489
+ this.embeddedBinaryChunk = await this._decodeDataUri(bufferUri);
39490
+ this.uri = "";
39491
+ } else {
39492
+ this.uri = bufferUri;
39493
+ }
39494
+ }
39495
+ async _decodeDataUri(dataUri) {
39496
+ try {
39497
+ const response = await fetch(dataUri);
39498
+ return await response.arrayBuffer();
39499
+ } catch (e) {
39500
+ throw new Error(`DynamicLoader: Failed to decode embedded data URI: ${e.message}`);
39501
+ }
38334
39502
  }
38335
39503
  clear() {
38336
- this.json = null;
38337
- this.loadController = null;
38338
- this.pendingRequests = [];
38339
39504
  if (this.batchTimeout) {
38340
39505
  clearTimeout(this.batchTimeout);
38341
39506
  this.batchTimeout = null;
38342
39507
  }
38343
- this.disposeMaterials();
38344
- this.textureCache.clear();
38345
- this.materials.clear();
39508
+ this._rejectPendingRequests();
39509
+ if (this.disposeMaterials) {
39510
+ try {
39511
+ this.disposeMaterials();
39512
+ } catch (e) {
39513
+ console.warn("DynamicLoader: error during disposeMaterials in clear():", e);
39514
+ }
39515
+ }
39516
+ if (this.textureCache) this.textureCache.clear();
39517
+ if (this.materials) this.materials.clear();
39518
+ this.embeddedBinaryChunk = null;
39519
+ this.json = null;
39520
+ this.loadController = null;
39521
+ this.uri = "";
38346
39522
  this.activeChunkLoads = 0;
38347
39523
  this.chunkQueue = [];
38348
39524
  this.loadingAborted = false;
38349
39525
  this.criticalError = null;
38350
39526
  }
39527
+ _rejectPendingRequests() {
39528
+ const pending = this.pendingRequests;
39529
+ this.pendingRequests = [];
39530
+ if (!pending || pending.length === 0) return;
39531
+ const cancelError = new Error("DynamicLoader: Structure cleared while requests pending");
39532
+ for (let i = 0; i < pending.length; i++) {
39533
+ const item = pending[i];
39534
+ if (item && typeof item._reject === "function") {
39535
+ try {
39536
+ item._reject(cancelError);
39537
+ } catch {
39538
+ }
39539
+ }
39540
+ }
39541
+ }
38351
39542
  getJson() {
38352
39543
  return this.json;
38353
39544
  }
38354
39545
  scheduleRequest(request) {
39546
+ if (this.embeddedBinaryChunk && !this.uri) {
39547
+ return Promise.resolve({
39548
+ buffer: this.embeddedBinaryChunk,
39549
+ relOffset: request.offset,
39550
+ length: request.length,
39551
+ });
39552
+ }
38355
39553
  return new Promise((resolve, reject) => {
38356
39554
  if (this.loadingAborted) {
38357
39555
  reject(
@@ -38628,8 +39826,13 @@ void main() {
38628
39826
  return await this.textureLoader.loadAsync(fullUrl);
38629
39827
  } else if (image.bufferView !== undefined) {
38630
39828
  const bufferView = this.json.bufferViews[image.bufferView];
38631
- const array = await this.getBufferView(bufferView.byteOffset || 0, bufferView.byteLength, 5121);
38632
- const blob = new Blob([array], { type: image.mimeType });
39829
+ const { buffer, relOffset } = await this.getBufferView(
39830
+ bufferView.byteOffset || 0,
39831
+ bufferView.byteLength,
39832
+ 5121
39833
+ );
39834
+ const imageBytes = new Uint8Array(buffer, relOffset, bufferView.byteLength);
39835
+ const blob = new Blob([imageBytes], { type: image.mimeType });
38633
39836
  const url = URL.createObjectURL(blob);
38634
39837
  const texture = await this.textureLoader.loadAsync(url);
38635
39838
  URL.revokeObjectURL(url);
@@ -38659,6 +39862,7 @@ void main() {
38659
39862
  })
38660
39863
  );
38661
39864
  }
39865
+ await this.flushBufferRequests();
38662
39866
  await Promise.all(texturePromises);
38663
39867
  }
38664
39868
  loadMaterials() {
@@ -39016,6 +40220,7 @@ void main() {
39016
40220
  return result;
39017
40221
  }
39018
40222
 
40223
+ const DRACO_EXTENSION_NAME = "KHR_draco_mesh_compression";
39019
40224
  const STRUCTURE_ID_SEPARATOR = ":";
39020
40225
  class DynamicGltfLoader {
39021
40226
  constructor(camera, scene, renderer) {
@@ -39090,6 +40295,189 @@ void main() {
39090
40295
  this.transformData = null;
39091
40296
  this.identityTransformData = null;
39092
40297
  this.visibilityMaterials = new Set();
40298
+ this._dracoLoader = null;
40299
+ }
40300
+ setDracoLoader(loader = null) {
40301
+ this._dracoLoader = loader || null;
40302
+ }
40303
+ async _decodeDracoPrimitive(structure, primitive, dracoBufferData) {
40304
+ const dracoExt = primitive.extensions[DRACO_EXTENSION_NAME];
40305
+ const loader = this._dracoLoader;
40306
+ const attributeIDs = {};
40307
+ const attributeTypes = {};
40308
+ const gltfNameToThreeName = new Map();
40309
+ const threeNameToAccessor = new Map();
40310
+ for (const [gltfAttrName, dracoUniqueId] of Object.entries(dracoExt.attributes)) {
40311
+ const threeName = this._gltfAttributeNameToThreeName(gltfAttrName);
40312
+ attributeIDs[threeName] = dracoUniqueId;
40313
+ gltfNameToThreeName.set(gltfAttrName, threeName);
40314
+ const accessorIdx = primitive.attributes[gltfAttrName];
40315
+ if (accessorIdx !== undefined) {
40316
+ const accessor = structure.json.accessors[accessorIdx];
40317
+ attributeTypes[threeName] = this._gltfComponentTypeToTypedArrayName(accessor.componentType);
40318
+ threeNameToAccessor.set(threeName, accessor);
40319
+ }
40320
+ }
40321
+ const geometry = await loader.decodeGeometry(dracoBufferData, {
40322
+ attributeIDs,
40323
+ attributeTypes,
40324
+ useUniqueIDs: true,
40325
+ });
40326
+ for (const [threeName, accessor] of threeNameToAccessor) {
40327
+ const attribute = geometry.getAttribute(threeName);
40328
+ if (!attribute) continue;
40329
+ if (accessor.normalized === true) {
40330
+ attribute.normalized = true;
40331
+ }
40332
+ if (accessor.min) attribute.min = accessor.min;
40333
+ if (accessor.max) attribute.max = accessor.max;
40334
+ }
40335
+ for (const [threeName, accessor] of threeNameToAccessor) {
40336
+ const attribute = geometry.getAttribute(threeName);
40337
+ if (!attribute || !attribute.normalized) continue;
40338
+ const denom = this._normalizedDenominator(accessor.componentType);
40339
+ if (denom <= 0) continue;
40340
+ const src = attribute.array;
40341
+ const inv = 1 / denom;
40342
+ const isSigned = accessor.componentType === 5120 || accessor.componentType === 5122;
40343
+ const out = new Float32Array(src.length);
40344
+ for (let i = 0; i < src.length; i++) {
40345
+ let v = src[i] * inv;
40346
+ if (isSigned && v < -1) v = -1;
40347
+ out[i] = v;
40348
+ }
40349
+ const newAttr = new BufferAttribute(out, attribute.itemSize, false);
40350
+ if (accessor.min) newAttr.min = accessor.min;
40351
+ if (accessor.max) newAttr.max = accessor.max;
40352
+ geometry.setAttribute(threeName, newAttr);
40353
+ }
40354
+ return geometry;
40355
+ }
40356
+ _gltfComponentTypeToTypedArrayName(componentType) {
40357
+ switch (componentType) {
40358
+ case 5120:
40359
+ return "Int8Array";
40360
+ case 5121:
40361
+ return "Uint8Array";
40362
+ case 5122:
40363
+ return "Int16Array";
40364
+ case 5123:
40365
+ return "Uint16Array";
40366
+ case 5125:
40367
+ return "Uint32Array";
40368
+ case 5126:
40369
+ return "Float32Array";
40370
+ default:
40371
+ return "Float32Array";
40372
+ }
40373
+ }
40374
+ _normalizedDenominator(componentType) {
40375
+ switch (componentType) {
40376
+ case 5120:
40377
+ return 127;
40378
+ case 5121:
40379
+ return 255;
40380
+ case 5122:
40381
+ return 32767;
40382
+ case 5123:
40383
+ return 65535;
40384
+ default:
40385
+ return 0;
40386
+ }
40387
+ }
40388
+ _gltfAttributeNameToThreeName(name) {
40389
+ switch (name) {
40390
+ case "POSITION":
40391
+ return "position";
40392
+ case "NORMAL":
40393
+ return "normal";
40394
+ case "TANGENT":
40395
+ return "tangent";
40396
+ case "TEXCOORD_0":
40397
+ return "uv";
40398
+ case "TEXCOORD_1":
40399
+ return "uv2";
40400
+ case "COLOR_0":
40401
+ return "color";
40402
+ case "JOINTS_0":
40403
+ return "skinIndex";
40404
+ case "WEIGHTS_0":
40405
+ return "skinWeight";
40406
+ default:
40407
+ return name.toLowerCase();
40408
+ }
40409
+ }
40410
+ _buildAccessorRequest(structure, accessorIndex, type, primIdx) {
40411
+ const accessor = structure.json.accessors[accessorIndex];
40412
+ const bufferView = structure.json.bufferViews[accessor.bufferView];
40413
+ const components = structure.getNumComponents(accessor.type);
40414
+ const componentSize = structure.getComponentSize(accessor.componentType);
40415
+ const itemBytes = components * componentSize;
40416
+ const accessorByteOffset = accessor.byteOffset || 0;
40417
+ const bvByteOffset = bufferView.byteOffset || 0;
40418
+ const byteStride = bufferView.byteStride || 0;
40419
+ const interleaved = byteStride !== 0 && byteStride !== itemBytes;
40420
+ const offset = bvByteOffset + accessorByteOffset;
40421
+ let length;
40422
+ if (interleaved) {
40423
+ length = (accessor.count - 1) * byteStride + itemBytes;
40424
+ } else {
40425
+ length = accessor.count * itemBytes;
40426
+ }
40427
+ return {
40428
+ offset,
40429
+ length,
40430
+ componentType: accessor.componentType,
40431
+ accessorIndex,
40432
+ type,
40433
+ primIdx,
40434
+ _accessor: accessor,
40435
+ _components: components,
40436
+ _componentSize: componentSize,
40437
+ _itemBytes: itemBytes,
40438
+ _byteStride: byteStride,
40439
+ _interleaved: interleaved,
40440
+ };
40441
+ }
40442
+ _createGeometryAttribute(req) {
40443
+ const accessor = req._accessor;
40444
+ const components = req._components;
40445
+ const count = accessor.count;
40446
+ const stride = req._interleaved ? req._byteStride / req._componentSize : components;
40447
+ const normalized = accessor.normalized === true;
40448
+ const componentType = req.componentType;
40449
+ const src = req.data;
40450
+ if (!req._interleaved && !normalized) {
40451
+ return new BufferAttribute(src, components, false);
40452
+ }
40453
+ if (normalized) {
40454
+ const denom = this._normalizedDenominator(componentType);
40455
+ if (denom > 0) {
40456
+ const out = new Float32Array(count * components);
40457
+ const inv = 1 / denom;
40458
+ const isSignedNormalized = componentType === 5120 || componentType === 5122;
40459
+ for (let i = 0; i < count; i++) {
40460
+ const srcBase = i * stride;
40461
+ const dstBase = i * components;
40462
+ for (let c = 0; c < components; c++) {
40463
+ let v = src[srcBase + c] * inv;
40464
+ if (isSignedNormalized && v < -1) v = -1;
40465
+ out[dstBase + c] = v;
40466
+ }
40467
+ }
40468
+ return new BufferAttribute(out, components, false);
40469
+ }
40470
+ }
40471
+ const TypedArrayCtor = src.constructor;
40472
+ const out = new TypedArrayCtor(count * components);
40473
+ for (let i = 0; i < count; i++) {
40474
+ const srcBase = i * stride;
40475
+ const dstBase = i * components;
40476
+ for (let c = 0; c < components; c++) {
40477
+ out[dstBase + c] = src[srcBase + c];
40478
+ }
40479
+ }
40480
+ return new BufferAttribute(out, components, false);
39093
40481
  }
39094
40482
  createDummyTexture() {
39095
40483
  const data = new Float32Array(16);
@@ -39161,7 +40549,7 @@ void main() {
39161
40549
  if (!this.transformTexture) return;
39162
40550
  this.transformTexture.needsUpdate = true;
39163
40551
  }
39164
- setVisibleEdges(visible) {
40552
+ setVisibleEdges(visible = true) {
39165
40553
  this.visibleEdges = visible;
39166
40554
  }
39167
40555
  getAvailableMemory() {
@@ -39415,78 +40803,51 @@ void main() {
39415
40803
  node.loading = true;
39416
40804
  const meshDef = node.structure.getJson().meshes[node.meshIndex];
39417
40805
  try {
40806
+ if (
40807
+ !this._dracoLoader &&
40808
+ meshDef.primitives &&
40809
+ meshDef.primitives.some((p) => p.extensions && p.extensions[DRACO_EXTENSION_NAME])
40810
+ ) {
40811
+ throw new Error(
40812
+ "primitive uses KHR_draco_mesh_compression but no DRACOLoader is configured. " +
40813
+ "Inject one via dynamicLoader.setDracoLoader(new DRACOLoader()) before opening the file."
40814
+ );
40815
+ }
39418
40816
  const bufferRequests = [];
39419
40817
  const primitiveReqMap = new Map();
40818
+ const dracoPrimitives = new Map();
39420
40819
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39421
40820
  const primitive = meshDef.primitives[primIdx];
39422
40821
  const reqs = [];
39423
- if (primitive.attributes.POSITION !== undefined) {
39424
- const accessorIndex = primitive.attributes.POSITION;
39425
- const accessor = node.structure.json.accessors[accessorIndex];
39426
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39427
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39428
- const components = node.structure.getNumComponents(accessor.type);
39429
- const count = accessor.count;
39430
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39431
- reqs.push({
40822
+ const dracoExt = primitive.extensions && primitive.extensions[DRACO_EXTENSION_NAME];
40823
+ if (dracoExt) {
40824
+ const bufferView = node.structure.json.bufferViews[dracoExt.bufferView];
40825
+ const byteOffset = bufferView.byteOffset || 0;
40826
+ const byteLength = bufferView.byteLength;
40827
+ const dracoReq = {
39432
40828
  offset: byteOffset,
39433
40829
  length: byteLength,
39434
- componentType: accessor.componentType,
39435
- accessorIndex,
39436
- type: "position",
40830
+ componentType: 5121,
40831
+ type: "draco",
39437
40832
  primIdx,
39438
- });
40833
+ };
40834
+ reqs.push(dracoReq);
40835
+ dracoPrimitives.set(primIdx, { req: dracoReq, primitive });
40836
+ primitiveReqMap.set(primIdx, reqs);
40837
+ bufferRequests.push(...reqs);
40838
+ continue;
40839
+ }
40840
+ if (primitive.attributes.POSITION !== undefined) {
40841
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.POSITION, "position", primIdx));
39439
40842
  }
39440
40843
  if (primitive.attributes.NORMAL !== undefined) {
39441
- const accessorIndex = primitive.attributes.NORMAL;
39442
- const accessor = node.structure.json.accessors[accessorIndex];
39443
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39444
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39445
- const components = node.structure.getNumComponents(accessor.type);
39446
- const count = accessor.count;
39447
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39448
- reqs.push({
39449
- offset: byteOffset,
39450
- length: byteLength,
39451
- componentType: accessor.componentType,
39452
- accessorIndex,
39453
- type: "normal",
39454
- primIdx,
39455
- });
40844
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.NORMAL, "normal", primIdx));
39456
40845
  }
39457
40846
  if (primitive.attributes.TEXCOORD_0 !== undefined) {
39458
- const accessorIndex = primitive.attributes.TEXCOORD_0;
39459
- const accessor = node.structure.json.accessors[accessorIndex];
39460
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39461
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39462
- const components = node.structure.getNumComponents(accessor.type);
39463
- const count = accessor.count;
39464
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39465
- reqs.push({
39466
- offset: byteOffset,
39467
- length: byteLength,
39468
- componentType: accessor.componentType,
39469
- accessorIndex,
39470
- type: "uv",
39471
- primIdx,
39472
- });
40847
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.TEXCOORD_0, "uv", primIdx));
39473
40848
  }
39474
40849
  if (primitive.indices !== undefined) {
39475
- const accessorIndex = primitive.indices;
39476
- const accessor = node.structure.json.accessors[accessorIndex];
39477
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39478
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39479
- const components = node.structure.getNumComponents(accessor.type);
39480
- const count = accessor.count;
39481
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39482
- reqs.push({
39483
- offset: byteOffset,
39484
- length: byteLength,
39485
- componentType: accessor.componentType,
39486
- accessorIndex,
39487
- type: "index",
39488
- primIdx,
39489
- });
40850
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.indices, "index", primIdx));
39490
40851
  }
39491
40852
  primitiveReqMap.set(primIdx, reqs);
39492
40853
  bufferRequests.push(...reqs);
@@ -39512,29 +40873,31 @@ void main() {
39512
40873
  }
39513
40874
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39514
40875
  const primitive = meshDef.primitives[primIdx];
39515
- const geometry = new BufferGeometry();
39516
40876
  const reqs = primitiveReqMap.get(primIdx);
39517
- if (primitive.attributes.POSITION !== undefined) {
39518
- const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
39519
- const accessor = node.structure.json.accessors[primitive.attributes.POSITION];
39520
- const components = node.structure.getNumComponents(accessor.type);
39521
- geometry.setAttribute("position", new BufferAttribute(req.data, components));
39522
- }
39523
- if (primitive.attributes.NORMAL !== undefined) {
39524
- const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
39525
- const accessor = node.structure.json.accessors[primitive.attributes.NORMAL];
39526
- const components = node.structure.getNumComponents(accessor.type);
39527
- geometry.setAttribute("normal", new BufferAttribute(req.data, components));
39528
- }
39529
- if (primitive.attributes.TEXCOORD_0 !== undefined) {
39530
- const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
39531
- const accessor = node.structure.json.accessors[primitive.attributes.TEXCOORD_0];
39532
- const components = node.structure.getNumComponents(accessor.type);
39533
- geometry.setAttribute("uv", new BufferAttribute(req.data, components));
39534
- }
39535
- if (primitive.indices !== undefined) {
39536
- const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
39537
- geometry.setIndex(new BufferAttribute(req.data, 1));
40877
+ let geometry;
40878
+ if (dracoPrimitives.has(primIdx)) {
40879
+ const dracoReq = reqs.find((r) => r.type === "draco");
40880
+ const dracoBytes = new Uint8Array(dracoReq.data.buffer, dracoReq.data.byteOffset, dracoReq.data.byteLength);
40881
+ const dracoBuffer = dracoBytes.slice().buffer;
40882
+ geometry = await this._decodeDracoPrimitive(node.structure, primitive, dracoBuffer);
40883
+ } else {
40884
+ geometry = new BufferGeometry();
40885
+ if (primitive.attributes.POSITION !== undefined) {
40886
+ const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
40887
+ geometry.setAttribute("position", this._createGeometryAttribute(req));
40888
+ }
40889
+ if (primitive.attributes.NORMAL !== undefined) {
40890
+ const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
40891
+ geometry.setAttribute("normal", this._createGeometryAttribute(req));
40892
+ }
40893
+ if (primitive.attributes.TEXCOORD_0 !== undefined) {
40894
+ const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
40895
+ geometry.setAttribute("uv", this._createGeometryAttribute(req));
40896
+ }
40897
+ if (primitive.indices !== undefined) {
40898
+ const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
40899
+ geometry.setIndex(this._createGeometryAttribute(req));
40900
+ }
39538
40901
  }
39539
40902
  let material;
39540
40903
  if (primitive.material !== undefined) {
@@ -39773,20 +41136,43 @@ void main() {
39773
41136
  const nodeMatrix = new Matrix4();
39774
41137
  const uniqueNodeId = `${structure.id}_${nodeId}`;
39775
41138
  const meshDef = structure.json.meshes[nodeDef.mesh];
41139
+ if (!meshDef || !meshDef.primitives || meshDef.primitives.length === 0) {
41140
+ if (nodeDef.children) {
41141
+ for (const childId of nodeDef.children) {
41142
+ await this.processNodeHierarchy(structure, childId, nodeGroup || parentGroup);
41143
+ }
41144
+ }
41145
+ return nodeGroup;
41146
+ }
39776
41147
  const geometryExtents = new Box3();
39777
41148
  for (const primitive of meshDef.primitives) {
41149
+ if (!primitive.attributes) continue;
39778
41150
  const positionAccessor = structure.json.accessors[primitive.attributes.POSITION];
39779
41151
  if (positionAccessor && positionAccessor.min && positionAccessor.max) {
39780
- const primitiveBox = new Box3(
39781
- new Vector3().fromArray(positionAccessor.min),
39782
- new Vector3().fromArray(positionAccessor.max)
39783
- );
39784
- geometryExtents.union(primitiveBox);
41152
+ const minVec = new Vector3().fromArray(positionAccessor.min);
41153
+ const maxVec = new Vector3().fromArray(positionAccessor.max);
41154
+ if (positionAccessor.normalized === true) {
41155
+ const denom = this._normalizedDenominator(positionAccessor.componentType);
41156
+ if (denom > 0) {
41157
+ minVec.divideScalar(denom);
41158
+ maxVec.divideScalar(denom);
41159
+ if (positionAccessor.componentType === 5120 || positionAccessor.componentType === 5122) {
41160
+ minVec.x = Math.max(minVec.x, -1);
41161
+ minVec.y = Math.max(minVec.y, -1);
41162
+ minVec.z = Math.max(minVec.z, -1);
41163
+ maxVec.x = Math.max(maxVec.x, -1);
41164
+ maxVec.y = Math.max(maxVec.y, -1);
41165
+ maxVec.z = Math.max(maxVec.z, -1);
41166
+ }
41167
+ }
41168
+ }
41169
+ geometryExtents.union(new Box3(minVec, maxVec));
39785
41170
  }
39786
41171
  }
39787
41172
  let isEdge = false;
39788
- if (meshDef.primitives[0].material !== undefined) {
39789
- const material = structure.json.materials[meshDef.primitives[0].material];
41173
+ const firstPrimitive = meshDef.primitives[0];
41174
+ if (firstPrimitive && firstPrimitive.material !== undefined) {
41175
+ const material = structure.json.materials[firstPrimitive.material];
39790
41176
  if (material?.name === "edges") {
39791
41177
  isEdge = true;
39792
41178
  }
@@ -40099,6 +41485,10 @@ void main() {
40099
41485
  vec3 objectNormal = vec3( normal );
40100
41486
  mat3 bm = mat3( batchingMatrix );
40101
41487
  objectNormal = bm * objectNormal;
41488
+ #ifdef USE_TANGENT
41489
+ vec3 objectTangent = vec3( tangent.xyz );
41490
+ objectTangent = bm * objectTangent;
41491
+ #endif
40102
41492
  `
40103
41493
  );
40104
41494
  }
@@ -41271,7 +42661,7 @@ void main() {
41271
42661
  }
41272
42662
  return extent;
41273
42663
  }
41274
- setMaxConcurrentChunks(maxChunks) {
42664
+ setMaxConcurrentChunks(maxChunks = 6) {
41275
42665
  if (maxChunks < 1) {
41276
42666
  console.warn("Max concurrent chunks must be at least 1");
41277
42667
  return;
@@ -42710,8 +44100,10 @@ void main() {
42710
44100
  this.manager = new GLTFLoadingManager(file, params);
42711
44101
  const scene = new Group$1();
42712
44102
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42713
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
42714
- this.gltfLoader.visibleEdges = this.viewer.options.edgeModel;
44103
+ this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
44104
+ this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
44105
+ this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
44106
+ this.gltfLoader.setDracoLoader(params.dracoLoader);
42715
44107
  const modelImpl = new DynamicModelImpl(scene);
42716
44108
  modelImpl.id = params.modelId || this.extractFileName(file);
42717
44109
  modelImpl.gltfLoader = this.gltfLoader;
@@ -42798,8 +44190,10 @@ void main() {
42798
44190
  async load(model, format, params = {}) {
42799
44191
  const scene = new Group$1();
42800
44192
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42801
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
44193
+ this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
42802
44194
  this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
44195
+ this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
44196
+ this.gltfLoader.setDracoLoader(params.dracoLoader);
42803
44197
  const modelImpl = new DynamicModelImpl(scene);
42804
44198
  modelImpl.id = model.file.id;
42805
44199
  modelImpl.gltfLoader = this.gltfLoader;
@@ -44015,186 +45409,133 @@ void main() {
44015
45409
  }
44016
45410
 
44017
45411
  class SSAARenderPass extends Pass {
44018
- constructor(scenes, camera, clearColor = 0x000000, clearAlpha = 0) {
44019
- super();
44020
- this.scenes = Array.isArray(scenes) ? scenes : [scenes];
44021
- this.camera = camera;
44022
- this.sampleLevel = 2;
44023
- this.unbiased = true;
44024
- this.stencilBuffer = false;
44025
- this.clearColor = clearColor;
44026
- this.clearAlpha = clearAlpha;
44027
- this._sampleRenderTarget = null;
44028
- this._oldClearColor = new Color();
44029
- this._copyUniforms = UniformsUtils.clone(CopyShader.uniforms);
44030
- this._copyMaterial = new ShaderMaterial({
44031
- uniforms: this._copyUniforms,
44032
- vertexShader: CopyShader.vertexShader,
44033
- fragmentShader: CopyShader.fragmentShader,
44034
- transparent: true,
44035
- depthTest: false,
44036
- depthWrite: false,
44037
- premultipliedAlpha: true,
44038
- blending: AdditiveBlending,
44039
- });
44040
- this._fsQuad = new FullScreenQuad(this._copyMaterial);
44041
- }
44042
- dispose() {
44043
- if (this._sampleRenderTarget) {
44044
- this._sampleRenderTarget.dispose();
44045
- this._sampleRenderTarget = null;
44046
- }
44047
- this._copyMaterial.dispose();
44048
- this._fsQuad.dispose();
44049
- }
44050
- setSize(width, height) {
44051
- if (this._sampleRenderTarget) this._sampleRenderTarget.setSize(width, height);
44052
- }
44053
- render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
44054
- if (!this._sampleRenderTarget) {
44055
- this._sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, {
44056
- type: HalfFloatType,
44057
- stencilBuffer: this.stencilBuffer,
44058
- });
44059
- this._sampleRenderTarget.texture.name = "SSAAMultiRenderPass.sample";
44060
- }
44061
- const jitterOffsets = _JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))];
44062
- const autoClear = renderer.autoClear;
44063
- renderer.autoClear = false;
44064
- renderer.getClearColor(this._oldClearColor);
44065
- const oldClearAlpha = renderer.getClearAlpha();
44066
- const baseSampleWeight = 1.0 / jitterOffsets.length;
44067
- const roundingRange = 1 / 32;
44068
- this._copyUniforms["tDiffuse"].value = this._sampleRenderTarget.texture;
44069
- const viewOffset = {
44070
- fullWidth: readBuffer.width,
44071
- fullHeight: readBuffer.height,
44072
- offsetX: 0,
44073
- offsetY: 0,
44074
- width: readBuffer.width,
44075
- height: readBuffer.height,
44076
- };
44077
- const originalViewOffset = Object.assign({}, this.camera.view);
44078
- if (originalViewOffset.enabled) Object.assign(viewOffset, originalViewOffset);
44079
- for (let i = 0; i < jitterOffsets.length; i++) {
44080
- const jitterOffset = jitterOffsets[i];
44081
- if (this.camera.setViewOffset) {
44082
- this.camera.setViewOffset(
44083
- viewOffset.fullWidth,
44084
- viewOffset.fullHeight,
44085
- viewOffset.offsetX + jitterOffset[0] * 0.0625,
44086
- viewOffset.offsetY + jitterOffset[1] * 0.0625,
44087
- viewOffset.width,
44088
- viewOffset.height
44089
- );
44090
- }
44091
- let sampleWeight = baseSampleWeight;
44092
- if (this.unbiased) {
44093
- const uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length;
44094
- sampleWeight += roundingRange * uniformCenteredDistribution;
44095
- }
44096
- this._copyUniforms["opacity"].value = sampleWeight;
44097
- renderer.setClearColor(this.clearColor, this.clearAlpha);
44098
- renderer.setRenderTarget(this._sampleRenderTarget);
44099
- renderer.clear();
44100
- this.scenes.forEach((scene) => renderer.render(scene, this.camera));
44101
- renderer.setRenderTarget(this.renderToScreen ? null : writeBuffer);
44102
- if (i === 0) {
44103
- renderer.setClearColor(0x000000, 0.0);
44104
- renderer.clear();
44105
- }
44106
- this._fsQuad.render(renderer);
44107
- }
44108
- if (this.camera.setViewOffset && originalViewOffset.enabled) {
44109
- this.camera.setViewOffset(
44110
- originalViewOffset.fullWidth,
44111
- originalViewOffset.fullHeight,
44112
- originalViewOffset.offsetX,
44113
- originalViewOffset.offsetY,
44114
- originalViewOffset.width,
44115
- originalViewOffset.height
44116
- );
44117
- } else if (this.camera.clearViewOffset) {
44118
- this.camera.clearViewOffset();
44119
- }
44120
- renderer.autoClear = autoClear;
44121
- renderer.setClearColor(this._oldClearColor, oldClearAlpha);
44122
- }
45412
+ constructor( scene, camera, clearColor = 0x000000, clearAlpha = 0 ) {
45413
+ super();
45414
+ this.scene = scene;
45415
+ this.camera = camera;
45416
+ this.sampleLevel = 4;
45417
+ this.unbiased = true;
45418
+ this.stencilBuffer = false;
45419
+ this.clearColor = clearColor;
45420
+ this.clearAlpha = clearAlpha;
45421
+ this._sampleRenderTarget = null;
45422
+ this._oldClearColor = new Color();
45423
+ this._copyUniforms = UniformsUtils.clone( CopyShader.uniforms );
45424
+ this._copyMaterial = new ShaderMaterial( {
45425
+ uniforms: this._copyUniforms,
45426
+ vertexShader: CopyShader.vertexShader,
45427
+ fragmentShader: CopyShader.fragmentShader,
45428
+ transparent: true,
45429
+ depthTest: false,
45430
+ depthWrite: false,
45431
+ premultipliedAlpha: true,
45432
+ blending: AdditiveBlending
45433
+ } );
45434
+ this._fsQuad = new FullScreenQuad( this._copyMaterial );
45435
+ }
45436
+ dispose() {
45437
+ if ( this._sampleRenderTarget ) {
45438
+ this._sampleRenderTarget.dispose();
45439
+ this._sampleRenderTarget = null;
45440
+ }
45441
+ this._copyMaterial.dispose();
45442
+ this._fsQuad.dispose();
45443
+ }
45444
+ setSize( width, height ) {
45445
+ if ( this._sampleRenderTarget ) this._sampleRenderTarget.setSize( width, height );
45446
+ }
45447
+ render( renderer, writeBuffer, readBuffer ) {
45448
+ if ( ! this._sampleRenderTarget ) {
45449
+ this._sampleRenderTarget = new WebGLRenderTarget( readBuffer.width, readBuffer.height, { type: HalfFloatType, stencilBuffer: this.stencilBuffer } );
45450
+ this._sampleRenderTarget.texture.name = 'SSAARenderPass.sample';
45451
+ }
45452
+ const jitterOffsets = _JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ];
45453
+ const autoClear = renderer.autoClear;
45454
+ renderer.autoClear = false;
45455
+ renderer.getClearColor( this._oldClearColor );
45456
+ const oldClearAlpha = renderer.getClearAlpha();
45457
+ const baseSampleWeight = 1.0 / jitterOffsets.length;
45458
+ const roundingRange = 1 / 32;
45459
+ this._copyUniforms[ 'tDiffuse' ].value = this._sampleRenderTarget.texture;
45460
+ const viewOffset = {
45461
+ fullWidth: readBuffer.width,
45462
+ fullHeight: readBuffer.height,
45463
+ offsetX: 0,
45464
+ offsetY: 0,
45465
+ width: readBuffer.width,
45466
+ height: readBuffer.height
45467
+ };
45468
+ const originalViewOffset = Object.assign( {}, this.camera.view );
45469
+ if ( originalViewOffset.enabled ) Object.assign( viewOffset, originalViewOffset );
45470
+ for ( let i = 0; i < jitterOffsets.length; i ++ ) {
45471
+ const jitterOffset = jitterOffsets[ i ];
45472
+ if ( this.camera.setViewOffset ) {
45473
+ this.camera.setViewOffset(
45474
+ viewOffset.fullWidth, viewOffset.fullHeight,
45475
+ viewOffset.offsetX + jitterOffset[ 0 ] * 0.0625, viewOffset.offsetY + jitterOffset[ 1 ] * 0.0625,
45476
+ viewOffset.width, viewOffset.height
45477
+ );
45478
+ }
45479
+ let sampleWeight = baseSampleWeight;
45480
+ if ( this.unbiased ) {
45481
+ const uniformCenteredDistribution = ( -0.5 + ( i + 0.5 ) / jitterOffsets.length );
45482
+ sampleWeight += roundingRange * uniformCenteredDistribution;
45483
+ }
45484
+ this._copyUniforms[ 'opacity' ].value = sampleWeight;
45485
+ renderer.setClearColor( this.clearColor, this.clearAlpha );
45486
+ renderer.setRenderTarget( this._sampleRenderTarget );
45487
+ renderer.clear();
45488
+ renderer.render( this.scene, this.camera );
45489
+ renderer.setRenderTarget( this.renderToScreen ? null : writeBuffer );
45490
+ if ( i === 0 ) {
45491
+ renderer.setClearColor( 0x000000, 0.0 );
45492
+ renderer.clear();
45493
+ }
45494
+ this._fsQuad.render( renderer );
45495
+ }
45496
+ if ( this.camera.setViewOffset && originalViewOffset.enabled ) {
45497
+ this.camera.setViewOffset(
45498
+ originalViewOffset.fullWidth, originalViewOffset.fullHeight,
45499
+ originalViewOffset.offsetX, originalViewOffset.offsetY,
45500
+ originalViewOffset.width, originalViewOffset.height
45501
+ );
45502
+ } else if ( this.camera.clearViewOffset ) {
45503
+ this.camera.clearViewOffset();
45504
+ }
45505
+ renderer.autoClear = autoClear;
45506
+ renderer.setClearColor( this._oldClearColor, oldClearAlpha );
45507
+ }
44123
45508
  }
44124
45509
  const _JitterVectors = [
44125
- [[0, 0]],
44126
- [
44127
- [4, 4],
44128
- [-4, -4],
44129
- ],
44130
- [
44131
- [-2, -6],
44132
- [6, -2],
44133
- [-6, 2],
44134
- [2, 6],
44135
- ],
44136
- [
44137
- [1, -3],
44138
- [-1, 3],
44139
- [5, 1],
44140
- [-3, -5],
44141
- [-5, 5],
44142
- [-7, -1],
44143
- [3, 7],
44144
- [7, -7],
44145
- ],
44146
- [
44147
- [1, 1],
44148
- [-1, -3],
44149
- [-3, 2],
44150
- [4, -1],
44151
- [-5, -2],
44152
- [2, 5],
44153
- [5, 3],
44154
- [3, -5],
44155
- [-2, 6],
44156
- [0, -7],
44157
- [-4, -6],
44158
- [-6, 4],
44159
- [-8, 0],
44160
- [7, -4],
44161
- [6, 7],
44162
- [-7, -8],
44163
- ],
44164
- [
44165
- [-4, -7],
44166
- [-7, -5],
44167
- [-3, -5],
44168
- [-5, -4],
44169
- [-1, -4],
44170
- [-2, -2],
44171
- [-6, -1],
44172
- [-4, 0],
44173
- [-7, 1],
44174
- [-1, 2],
44175
- [-6, 3],
44176
- [-3, 3],
44177
- [-7, 6],
44178
- [-3, 6],
44179
- [-5, 7],
44180
- [-1, 7],
44181
- [5, -7],
44182
- [1, -6],
44183
- [6, -5],
44184
- [4, -4],
44185
- [2, -3],
44186
- [7, -2],
44187
- [1, -1],
44188
- [4, -1],
44189
- [2, 1],
44190
- [6, 2],
44191
- [0, 4],
44192
- [4, 4],
44193
- [2, 5],
44194
- [7, 5],
44195
- [5, 6],
44196
- [3, 7],
44197
- ],
45510
+ [
45511
+ [ 0, 0 ]
45512
+ ],
45513
+ [
45514
+ [ 4, 4 ], [ -4, -4 ]
45515
+ ],
45516
+ [
45517
+ [ -2, -6 ], [ 6, -2 ], [ -6, 2 ], [ 2, 6 ]
45518
+ ],
45519
+ [
45520
+ [ 1, -3 ], [ -1, 3 ], [ 5, 1 ], [ -3, -5 ],
45521
+ [ -5, 5 ], [ -7, -1 ], [ 3, 7 ], [ 7, -7 ]
45522
+ ],
45523
+ [
45524
+ [ 1, 1 ], [ -1, -3 ], [ -3, 2 ], [ 4, -1 ],
45525
+ [ -5, -2 ], [ 2, 5 ], [ 5, 3 ], [ 3, -5 ],
45526
+ [ -2, 6 ], [ 0, -7 ], [ -4, -6 ], [ -6, 4 ],
45527
+ [ -8, 0 ], [ 7, -4 ], [ 6, 7 ], [ -7, -8 ]
45528
+ ],
45529
+ [
45530
+ [ -4, -7 ], [ -7, -5 ], [ -3, -5 ], [ -5, -4 ],
45531
+ [ -1, -4 ], [ -2, -2 ], [ -6, -1 ], [ -4, 0 ],
45532
+ [ -7, 1 ], [ -1, 2 ], [ -6, 3 ], [ -3, 3 ],
45533
+ [ -7, 6 ], [ -3, 6 ], [ -5, 7 ], [ -1, 7 ],
45534
+ [ 5, -7 ], [ 1, -6 ], [ 6, -5 ], [ 4, -4 ],
45535
+ [ 2, -3 ], [ 7, -2 ], [ 1, -1 ], [ 4, -1 ],
45536
+ [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ],
45537
+ [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]
45538
+ ]
44198
45539
  ];
44199
45540
 
44200
45541
  const OutputShader = {
@@ -57968,24 +59309,6 @@ js: import "konva/skia-backend";
57968
59309
  }
57969
59310
  }
57970
59311
 
57971
- class Helpers extends Scene {
57972
- constructor() {
57973
- super(...arguments);
57974
- this.oldAutoClear = false;
57975
- this.oldClippingPlanes = [];
57976
- }
57977
- onBeforeRender(renderer) {
57978
- this.oldAutoClear = renderer.autoClear;
57979
- this.oldClippingPlanes = renderer.clippingPlanes;
57980
- renderer.autoClear = false;
57981
- renderer.clippingPlanes = [];
57982
- }
57983
- onAfterRender(renderer) {
57984
- renderer.clippingPlanes = this.oldClippingPlanes;
57985
- renderer.autoClear = this.oldAutoClear;
57986
- }
57987
- }
57988
-
57989
59312
  class Viewer extends EventEmitter2 {
57990
59313
  constructor(client) {
57991
59314
  super();
@@ -57999,9 +59322,9 @@ js: import "konva/skia-backend";
57999
59322
  this.selected = [];
58000
59323
  this.extents = new Box3();
58001
59324
  this.target = new Vector3(0, 0, 0);
59325
+ this.clippingPlanes = [];
58002
59326
  this._activeDragger = null;
58003
59327
  this._components = [];
58004
- this._updateDelay = 1000;
58005
59328
  this._renderNeeded = false;
58006
59329
  this._renderTime = 0;
58007
59330
  this.render = this.render.bind(this);
@@ -58020,7 +59343,9 @@ js: import "konva/skia-backend";
58020
59343
  initialize(canvas, onProgress) {
58021
59344
  this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
58022
59345
  this.scene = new Scene();
58023
- this.helpers = new Helpers();
59346
+ this.helpers = new Group$1();
59347
+ this.helpers.name = "Helpers";
59348
+ this.scene.add(this.helpers);
58024
59349
  const pixelRatio = window.devicePixelRatio;
58025
59350
  const rect = canvas.parentElement.getBoundingClientRect();
58026
59351
  const width = rect.width || 1;
@@ -58042,17 +59367,17 @@ js: import "konva/skia-backend";
58042
59367
  this.renderer.setPixelRatio(pixelRatio);
58043
59368
  this.renderer.setSize(width, height);
58044
59369
  this.renderer.outputColorSpace = LinearSRGBColorSpace;
59370
+ this.renderer.localClippingEnabled = true;
58045
59371
  this.renderPass = new RenderPass(this.scene, this.camera);
58046
- this.helpersPass = new RenderPass(this.helpers, this.camera);
58047
- this.helpersPass.clear = false;
58048
59372
  this.fxaaPass = new FXAAPass();
58049
59373
  this.smaaPass = new SMAAPass();
58050
- this.ssaaRenderPass = new SSAARenderPass([this.scene, this.helpers], this.camera);
59374
+ this.ssaaRenderPass = new SSAARenderPass(this.scene, this.camera);
58051
59375
  this.ssaaRenderPass.unbiased = true;
58052
59376
  this.outputPass = new OutputPass();
58053
- this.composer = new EffectComposer(this.renderer);
59377
+ const renderTarget = new WebGLRenderTarget(1, 1, { samples: 4 });
59378
+ renderTarget.texture.name = "EffectComposer.rt1";
59379
+ this.composer = new EffectComposer(this.renderer, renderTarget);
58054
59380
  this.composer.addPass(this.renderPass);
58055
- this.composer.addPass(this.helpersPass);
58056
59381
  this.composer.addPass(this.smaaPass);
58057
59382
  this.composer.addPass(this.fxaaPass);
58058
59383
  this.composer.addPass(this.ssaaRenderPass);
@@ -58083,8 +59408,11 @@ js: import "konva/skia-backend";
58083
59408
  this.removeAllListeners();
58084
59409
  this.setActiveDragger();
58085
59410
  this._components.forEach((component) => component.dispose());
58086
- this._components = [];
58087
- this._markup.dispose();
59411
+ this._components.length = 0;
59412
+ if (this._markup) {
59413
+ this._markup.dispose();
59414
+ this._markup = undefined;
59415
+ }
58088
59416
  if (this.canvas) {
58089
59417
  this.canvasEvents.forEach((x) => this.canvas.removeEventListener(x, this.canvaseventlistener));
58090
59418
  this.canvas = undefined;
@@ -58093,8 +59421,6 @@ js: import "konva/skia-backend";
58093
59421
  this.composer.dispose();
58094
59422
  if (this.renderPass)
58095
59423
  this.renderPass.dispose();
58096
- if (this.helpersPass)
58097
- this.helpersPass.dispose();
58098
59424
  if (this.fxaaPass)
58099
59425
  this.fxaaPass.dispose();
58100
59426
  if (this.smaaPass)
@@ -58110,7 +59436,6 @@ js: import "konva/skia-backend";
58110
59436
  this.camera = undefined;
58111
59437
  this.renderer = undefined;
58112
59438
  this.renderPass = undefined;
58113
- this.helpersPass = undefined;
58114
59439
  this.fxaaPass = undefined;
58115
59440
  this.smaaPass = undefined;
58116
59441
  this.ssaaRenderPass = undefined;
@@ -58142,11 +59467,12 @@ js: import "konva/skia-backend";
58142
59467
  }
58143
59468
  update(force = false) {
58144
59469
  const time = performance.now();
58145
- force = force || time - this._renderTime >= this._updateDelay;
59470
+ if (typeof force === "number" && time - this._renderTime >= force)
59471
+ force = true;
58146
59472
  this._renderNeeded = true;
58147
59473
  if (force)
58148
59474
  this.render(time);
58149
- this.emitEvent({ type: "update", force });
59475
+ this.emitEvent({ type: "update", force: !!force });
58150
59476
  }
58151
59477
  render(time, force = false) {
58152
59478
  if (!this.renderer)
@@ -58160,13 +59486,7 @@ js: import "konva/skia-backend";
58160
59486
  this._renderNeeded = false;
58161
59487
  this.renderer.info.autoReset = false;
58162
59488
  this.renderer.info.reset();
58163
- if (this.options.antialiasing === true || this.options.antialiasing === "msaa") {
58164
- this.renderer.render(this.scene, this.camera);
58165
- this.renderer.render(this.helpers, this.camera);
58166
- }
58167
- else {
58168
- this.composer.render(deltaTime);
58169
- }
59489
+ this.composer.render(deltaTime);
58170
59490
  this.emitEvent({ type: "render", time, deltaTime });
58171
59491
  }
58172
59492
  loadReferences(model) {
@@ -58226,11 +59546,12 @@ js: import "konva/skia-backend";
58226
59546
  this.clearOverlay();
58227
59547
  this.clearSelected();
58228
59548
  this.loaders.forEach((loader) => loader.dispose());
58229
- this.loaders = [];
59549
+ this.loaders.length = 0;
58230
59550
  this.models.forEach((model) => model.dispose());
58231
- this.models = [];
58232
- this.scene.clear();
59551
+ this.models.length = 0;
58233
59552
  this.helpers.clear();
59553
+ this.scene.clear();
59554
+ this.scene.add(this.helpers);
58234
59555
  this.extents.makeEmpty();
58235
59556
  this.syncOptions();
58236
59557
  this.syncOverlay();
@@ -58247,8 +59568,15 @@ js: import "konva/skia-backend";
58247
59568
  this.fxaaPass.enabled = options.antialiasing === "fxaa";
58248
59569
  this.smaaPass.enabled = options.antialiasing === "smaa";
58249
59570
  this.ssaaRenderPass.enabled = options.antialiasing === "ssaa";
58250
- this.renderPass.enabled = !this.ssaaRenderPass.enabled;
58251
- this.helpersPass.enabled = !this.ssaaRenderPass.enabled;
59571
+ this.renderPass.enabled = options.antialiasing !== "ssaa";
59572
+ const samples = options.antialiasing === true || options.antialiasing === "msaa" ? 4 : 0;
59573
+ if (this.composer.renderTarget1.samples !== samples) {
59574
+ const size = this.renderer.getSize(new Vector2());
59575
+ const newRenderTarget = new WebGLRenderTarget(1, 1, { samples });
59576
+ newRenderTarget.texture.name = "EffectComposer.rt1";
59577
+ this.composer.reset(newRenderTarget);
59578
+ this.composer.setSize(size.x, size.y);
59579
+ }
58252
59580
  this.update();
58253
59581
  }
58254
59582
  syncOverlay() {
@@ -58267,7 +59595,8 @@ js: import "konva/skia-backend";
58267
59595
  clearSlices() {
58268
59596
  if (!this.renderer)
58269
59597
  return;
58270
- this.renderer.clippingPlanes = [];
59598
+ this.clippingPlanes.length = 0;
59599
+ this.emitEvent({ type: "changecuttingplanes" });
58271
59600
  this.emitEvent({ type: "clearslices" });
58272
59601
  this.update();
58273
59602
  }
@@ -58363,7 +59692,6 @@ js: import "konva/skia-backend";
58363
59692
  camera.updateMatrixWorld();
58364
59693
  this.camera = camera;
58365
59694
  this.renderPass.camera = camera;
58366
- this.helpersPass.camera = camera;
58367
59695
  this.ssaaRenderPass.camera = camera;
58368
59696
  this.options.cameraMode = "orthographic";
58369
59697
  this.emitEvent({ type: "changecameramode", mode: "orthographic" });
@@ -58386,7 +59714,6 @@ js: import "konva/skia-backend";
58386
59714
  camera.updateMatrixWorld();
58387
59715
  this.camera = camera;
58388
59716
  this.renderPass.camera = camera;
58389
- this.helpersPass.camera = camera;
58390
59717
  this.ssaaRenderPass.camera = camera;
58391
59718
  this.options.cameraMode = "perspective";
58392
59719
  this.emitEvent({ type: "changecameramode", mode: "perspective" });
@@ -58397,8 +59724,9 @@ js: import "konva/skia-backend";
58397
59724
  clipping_planes.forEach((clipping_plane) => {
58398
59725
  const plane = new Plane();
58399
59726
  plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
58400
- this.renderer.clippingPlanes.push(plane);
59727
+ this.clippingPlanes.push(plane);
58401
59728
  });
59729
+ this.emitEvent({ type: "changecuttingplanes" });
58402
59730
  }
58403
59731
  };
58404
59732
  const setSelection = (selection) => {
@@ -58453,7 +59781,7 @@ js: import "konva/skia-backend";
58453
59781
  };
58454
59782
  const getClippingPlanes = () => {
58455
59783
  const clipping_planes = [];
58456
- this.renderer.clippingPlanes.forEach((plane) => {
59784
+ this.clippingPlanes.forEach((plane) => {
58457
59785
  const clipping_plane = {
58458
59786
  location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3())),
58459
59787
  direction: getPoint3dFromVector3(plane.normal),