@inweb/viewer-three 27.4.6 → 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 +1765 -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 +1302 -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 +75 -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 { buffer } = await this.getBufferView(bufferView.byteOffset || 0, bufferView.byteLength, 5121);
38632
- const blob = new Blob([buffer], { 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);
@@ -39017,6 +40220,7 @@ void main() {
39017
40220
  return result;
39018
40221
  }
39019
40222
 
40223
+ const DRACO_EXTENSION_NAME = "KHR_draco_mesh_compression";
39020
40224
  const STRUCTURE_ID_SEPARATOR = ":";
39021
40225
  class DynamicGltfLoader {
39022
40226
  constructor(camera, scene, renderer) {
@@ -39091,6 +40295,189 @@ void main() {
39091
40295
  this.transformData = null;
39092
40296
  this.identityTransformData = null;
39093
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);
39094
40481
  }
39095
40482
  createDummyTexture() {
39096
40483
  const data = new Float32Array(16);
@@ -39162,7 +40549,7 @@ void main() {
39162
40549
  if (!this.transformTexture) return;
39163
40550
  this.transformTexture.needsUpdate = true;
39164
40551
  }
39165
- setVisibleEdges(visible) {
40552
+ setVisibleEdges(visible = true) {
39166
40553
  this.visibleEdges = visible;
39167
40554
  }
39168
40555
  getAvailableMemory() {
@@ -39416,78 +40803,51 @@ void main() {
39416
40803
  node.loading = true;
39417
40804
  const meshDef = node.structure.getJson().meshes[node.meshIndex];
39418
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
+ }
39419
40816
  const bufferRequests = [];
39420
40817
  const primitiveReqMap = new Map();
40818
+ const dracoPrimitives = new Map();
39421
40819
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39422
40820
  const primitive = meshDef.primitives[primIdx];
39423
40821
  const reqs = [];
39424
- if (primitive.attributes.POSITION !== undefined) {
39425
- const accessorIndex = primitive.attributes.POSITION;
39426
- const accessor = node.structure.json.accessors[accessorIndex];
39427
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39428
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39429
- const components = node.structure.getNumComponents(accessor.type);
39430
- const count = accessor.count;
39431
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39432
- 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 = {
39433
40828
  offset: byteOffset,
39434
40829
  length: byteLength,
39435
- componentType: accessor.componentType,
39436
- accessorIndex,
39437
- type: "position",
40830
+ componentType: 5121,
40831
+ type: "draco",
39438
40832
  primIdx,
39439
- });
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));
39440
40842
  }
39441
40843
  if (primitive.attributes.NORMAL !== undefined) {
39442
- const accessorIndex = primitive.attributes.NORMAL;
39443
- const accessor = node.structure.json.accessors[accessorIndex];
39444
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39445
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39446
- const components = node.structure.getNumComponents(accessor.type);
39447
- const count = accessor.count;
39448
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39449
- reqs.push({
39450
- offset: byteOffset,
39451
- length: byteLength,
39452
- componentType: accessor.componentType,
39453
- accessorIndex,
39454
- type: "normal",
39455
- primIdx,
39456
- });
40844
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.NORMAL, "normal", primIdx));
39457
40845
  }
39458
40846
  if (primitive.attributes.TEXCOORD_0 !== undefined) {
39459
- const accessorIndex = primitive.attributes.TEXCOORD_0;
39460
- const accessor = node.structure.json.accessors[accessorIndex];
39461
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39462
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39463
- const components = node.structure.getNumComponents(accessor.type);
39464
- const count = accessor.count;
39465
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39466
- reqs.push({
39467
- offset: byteOffset,
39468
- length: byteLength,
39469
- componentType: accessor.componentType,
39470
- accessorIndex,
39471
- type: "uv",
39472
- primIdx,
39473
- });
40847
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.TEXCOORD_0, "uv", primIdx));
39474
40848
  }
39475
40849
  if (primitive.indices !== undefined) {
39476
- const accessorIndex = primitive.indices;
39477
- const accessor = node.structure.json.accessors[accessorIndex];
39478
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39479
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39480
- const components = node.structure.getNumComponents(accessor.type);
39481
- const count = accessor.count;
39482
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39483
- reqs.push({
39484
- offset: byteOffset,
39485
- length: byteLength,
39486
- componentType: accessor.componentType,
39487
- accessorIndex,
39488
- type: "index",
39489
- primIdx,
39490
- });
40850
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.indices, "index", primIdx));
39491
40851
  }
39492
40852
  primitiveReqMap.set(primIdx, reqs);
39493
40853
  bufferRequests.push(...reqs);
@@ -39513,29 +40873,31 @@ void main() {
39513
40873
  }
39514
40874
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39515
40875
  const primitive = meshDef.primitives[primIdx];
39516
- const geometry = new BufferGeometry();
39517
40876
  const reqs = primitiveReqMap.get(primIdx);
39518
- if (primitive.attributes.POSITION !== undefined) {
39519
- const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
39520
- const accessor = node.structure.json.accessors[primitive.attributes.POSITION];
39521
- const components = node.structure.getNumComponents(accessor.type);
39522
- geometry.setAttribute("position", new BufferAttribute(req.data, components));
39523
- }
39524
- if (primitive.attributes.NORMAL !== undefined) {
39525
- const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
39526
- const accessor = node.structure.json.accessors[primitive.attributes.NORMAL];
39527
- const components = node.structure.getNumComponents(accessor.type);
39528
- geometry.setAttribute("normal", new BufferAttribute(req.data, components));
39529
- }
39530
- if (primitive.attributes.TEXCOORD_0 !== undefined) {
39531
- const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
39532
- const accessor = node.structure.json.accessors[primitive.attributes.TEXCOORD_0];
39533
- const components = node.structure.getNumComponents(accessor.type);
39534
- geometry.setAttribute("uv", new BufferAttribute(req.data, components));
39535
- }
39536
- if (primitive.indices !== undefined) {
39537
- const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
39538
- 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
+ }
39539
40901
  }
39540
40902
  let material;
39541
40903
  if (primitive.material !== undefined) {
@@ -39774,20 +41136,43 @@ void main() {
39774
41136
  const nodeMatrix = new Matrix4();
39775
41137
  const uniqueNodeId = `${structure.id}_${nodeId}`;
39776
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
+ }
39777
41147
  const geometryExtents = new Box3();
39778
41148
  for (const primitive of meshDef.primitives) {
41149
+ if (!primitive.attributes) continue;
39779
41150
  const positionAccessor = structure.json.accessors[primitive.attributes.POSITION];
39780
41151
  if (positionAccessor && positionAccessor.min && positionAccessor.max) {
39781
- const primitiveBox = new Box3(
39782
- new Vector3().fromArray(positionAccessor.min),
39783
- new Vector3().fromArray(positionAccessor.max)
39784
- );
39785
- 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));
39786
41170
  }
39787
41171
  }
39788
41172
  let isEdge = false;
39789
- if (meshDef.primitives[0].material !== undefined) {
39790
- 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];
39791
41176
  if (material?.name === "edges") {
39792
41177
  isEdge = true;
39793
41178
  }
@@ -40100,6 +41485,10 @@ void main() {
40100
41485
  vec3 objectNormal = vec3( normal );
40101
41486
  mat3 bm = mat3( batchingMatrix );
40102
41487
  objectNormal = bm * objectNormal;
41488
+ #ifdef USE_TANGENT
41489
+ vec3 objectTangent = vec3( tangent.xyz );
41490
+ objectTangent = bm * objectTangent;
41491
+ #endif
40103
41492
  `
40104
41493
  );
40105
41494
  }
@@ -41272,7 +42661,7 @@ void main() {
41272
42661
  }
41273
42662
  return extent;
41274
42663
  }
41275
- setMaxConcurrentChunks(maxChunks) {
42664
+ setMaxConcurrentChunks(maxChunks = 6) {
41276
42665
  if (maxChunks < 1) {
41277
42666
  console.warn("Max concurrent chunks must be at least 1");
41278
42667
  return;
@@ -42711,8 +44100,10 @@ void main() {
42711
44100
  this.manager = new GLTFLoadingManager(file, params);
42712
44101
  const scene = new Group$1();
42713
44102
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42714
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
42715
- 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);
42716
44107
  const modelImpl = new DynamicModelImpl(scene);
42717
44108
  modelImpl.id = params.modelId || this.extractFileName(file);
42718
44109
  modelImpl.gltfLoader = this.gltfLoader;
@@ -42799,8 +44190,10 @@ void main() {
42799
44190
  async load(model, format, params = {}) {
42800
44191
  const scene = new Group$1();
42801
44192
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42802
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
44193
+ this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
42803
44194
  this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
44195
+ this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
44196
+ this.gltfLoader.setDracoLoader(params.dracoLoader);
42804
44197
  const modelImpl = new DynamicModelImpl(scene);
42805
44198
  modelImpl.id = model.file.id;
42806
44199
  modelImpl.gltfLoader = this.gltfLoader;
@@ -44016,186 +45409,133 @@ void main() {
44016
45409
  }
44017
45410
 
44018
45411
  class SSAARenderPass extends Pass {
44019
- constructor(scenes, camera, clearColor = 0x000000, clearAlpha = 0) {
44020
- super();
44021
- this.scenes = Array.isArray(scenes) ? scenes : [scenes];
44022
- this.camera = camera;
44023
- this.sampleLevel = 2;
44024
- this.unbiased = true;
44025
- this.stencilBuffer = false;
44026
- this.clearColor = clearColor;
44027
- this.clearAlpha = clearAlpha;
44028
- this._sampleRenderTarget = null;
44029
- this._oldClearColor = new Color();
44030
- this._copyUniforms = UniformsUtils.clone(CopyShader.uniforms);
44031
- this._copyMaterial = new ShaderMaterial({
44032
- uniforms: this._copyUniforms,
44033
- vertexShader: CopyShader.vertexShader,
44034
- fragmentShader: CopyShader.fragmentShader,
44035
- transparent: true,
44036
- depthTest: false,
44037
- depthWrite: false,
44038
- premultipliedAlpha: true,
44039
- blending: AdditiveBlending,
44040
- });
44041
- this._fsQuad = new FullScreenQuad(this._copyMaterial);
44042
- }
44043
- dispose() {
44044
- if (this._sampleRenderTarget) {
44045
- this._sampleRenderTarget.dispose();
44046
- this._sampleRenderTarget = null;
44047
- }
44048
- this._copyMaterial.dispose();
44049
- this._fsQuad.dispose();
44050
- }
44051
- setSize(width, height) {
44052
- if (this._sampleRenderTarget) this._sampleRenderTarget.setSize(width, height);
44053
- }
44054
- render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
44055
- if (!this._sampleRenderTarget) {
44056
- this._sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, {
44057
- type: HalfFloatType,
44058
- stencilBuffer: this.stencilBuffer,
44059
- });
44060
- this._sampleRenderTarget.texture.name = "SSAAMultiRenderPass.sample";
44061
- }
44062
- const jitterOffsets = _JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))];
44063
- const autoClear = renderer.autoClear;
44064
- renderer.autoClear = false;
44065
- renderer.getClearColor(this._oldClearColor);
44066
- const oldClearAlpha = renderer.getClearAlpha();
44067
- const baseSampleWeight = 1.0 / jitterOffsets.length;
44068
- const roundingRange = 1 / 32;
44069
- this._copyUniforms["tDiffuse"].value = this._sampleRenderTarget.texture;
44070
- const viewOffset = {
44071
- fullWidth: readBuffer.width,
44072
- fullHeight: readBuffer.height,
44073
- offsetX: 0,
44074
- offsetY: 0,
44075
- width: readBuffer.width,
44076
- height: readBuffer.height,
44077
- };
44078
- const originalViewOffset = Object.assign({}, this.camera.view);
44079
- if (originalViewOffset.enabled) Object.assign(viewOffset, originalViewOffset);
44080
- for (let i = 0; i < jitterOffsets.length; i++) {
44081
- const jitterOffset = jitterOffsets[i];
44082
- if (this.camera.setViewOffset) {
44083
- this.camera.setViewOffset(
44084
- viewOffset.fullWidth,
44085
- viewOffset.fullHeight,
44086
- viewOffset.offsetX + jitterOffset[0] * 0.0625,
44087
- viewOffset.offsetY + jitterOffset[1] * 0.0625,
44088
- viewOffset.width,
44089
- viewOffset.height
44090
- );
44091
- }
44092
- let sampleWeight = baseSampleWeight;
44093
- if (this.unbiased) {
44094
- const uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length;
44095
- sampleWeight += roundingRange * uniformCenteredDistribution;
44096
- }
44097
- this._copyUniforms["opacity"].value = sampleWeight;
44098
- renderer.setClearColor(this.clearColor, this.clearAlpha);
44099
- renderer.setRenderTarget(this._sampleRenderTarget);
44100
- renderer.clear();
44101
- this.scenes.forEach((scene) => renderer.render(scene, this.camera));
44102
- renderer.setRenderTarget(this.renderToScreen ? null : writeBuffer);
44103
- if (i === 0) {
44104
- renderer.setClearColor(0x000000, 0.0);
44105
- renderer.clear();
44106
- }
44107
- this._fsQuad.render(renderer);
44108
- }
44109
- if (this.camera.setViewOffset && originalViewOffset.enabled) {
44110
- this.camera.setViewOffset(
44111
- originalViewOffset.fullWidth,
44112
- originalViewOffset.fullHeight,
44113
- originalViewOffset.offsetX,
44114
- originalViewOffset.offsetY,
44115
- originalViewOffset.width,
44116
- originalViewOffset.height
44117
- );
44118
- } else if (this.camera.clearViewOffset) {
44119
- this.camera.clearViewOffset();
44120
- }
44121
- renderer.autoClear = autoClear;
44122
- renderer.setClearColor(this._oldClearColor, oldClearAlpha);
44123
- }
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
+ }
44124
45508
  }
44125
45509
  const _JitterVectors = [
44126
- [[0, 0]],
44127
- [
44128
- [4, 4],
44129
- [-4, -4],
44130
- ],
44131
- [
44132
- [-2, -6],
44133
- [6, -2],
44134
- [-6, 2],
44135
- [2, 6],
44136
- ],
44137
- [
44138
- [1, -3],
44139
- [-1, 3],
44140
- [5, 1],
44141
- [-3, -5],
44142
- [-5, 5],
44143
- [-7, -1],
44144
- [3, 7],
44145
- [7, -7],
44146
- ],
44147
- [
44148
- [1, 1],
44149
- [-1, -3],
44150
- [-3, 2],
44151
- [4, -1],
44152
- [-5, -2],
44153
- [2, 5],
44154
- [5, 3],
44155
- [3, -5],
44156
- [-2, 6],
44157
- [0, -7],
44158
- [-4, -6],
44159
- [-6, 4],
44160
- [-8, 0],
44161
- [7, -4],
44162
- [6, 7],
44163
- [-7, -8],
44164
- ],
44165
- [
44166
- [-4, -7],
44167
- [-7, -5],
44168
- [-3, -5],
44169
- [-5, -4],
44170
- [-1, -4],
44171
- [-2, -2],
44172
- [-6, -1],
44173
- [-4, 0],
44174
- [-7, 1],
44175
- [-1, 2],
44176
- [-6, 3],
44177
- [-3, 3],
44178
- [-7, 6],
44179
- [-3, 6],
44180
- [-5, 7],
44181
- [-1, 7],
44182
- [5, -7],
44183
- [1, -6],
44184
- [6, -5],
44185
- [4, -4],
44186
- [2, -3],
44187
- [7, -2],
44188
- [1, -1],
44189
- [4, -1],
44190
- [2, 1],
44191
- [6, 2],
44192
- [0, 4],
44193
- [4, 4],
44194
- [2, 5],
44195
- [7, 5],
44196
- [5, 6],
44197
- [3, 7],
44198
- ],
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
+ ]
44199
45539
  ];
44200
45540
 
44201
45541
  const OutputShader = {
@@ -57969,24 +59309,6 @@ js: import "konva/skia-backend";
57969
59309
  }
57970
59310
  }
57971
59311
 
57972
- class Helpers extends Scene {
57973
- constructor() {
57974
- super(...arguments);
57975
- this.oldAutoClear = false;
57976
- this.oldClippingPlanes = [];
57977
- }
57978
- onBeforeRender(renderer) {
57979
- this.oldAutoClear = renderer.autoClear;
57980
- this.oldClippingPlanes = renderer.clippingPlanes;
57981
- renderer.autoClear = false;
57982
- renderer.clippingPlanes = [];
57983
- }
57984
- onAfterRender(renderer) {
57985
- renderer.clippingPlanes = this.oldClippingPlanes;
57986
- renderer.autoClear = this.oldAutoClear;
57987
- }
57988
- }
57989
-
57990
59312
  class Viewer extends EventEmitter2 {
57991
59313
  constructor(client) {
57992
59314
  super();
@@ -58000,9 +59322,9 @@ js: import "konva/skia-backend";
58000
59322
  this.selected = [];
58001
59323
  this.extents = new Box3();
58002
59324
  this.target = new Vector3(0, 0, 0);
59325
+ this.clippingPlanes = [];
58003
59326
  this._activeDragger = null;
58004
59327
  this._components = [];
58005
- this._updateDelay = 1000;
58006
59328
  this._renderNeeded = false;
58007
59329
  this._renderTime = 0;
58008
59330
  this.render = this.render.bind(this);
@@ -58021,7 +59343,9 @@ js: import "konva/skia-backend";
58021
59343
  initialize(canvas, onProgress) {
58022
59344
  this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
58023
59345
  this.scene = new Scene();
58024
- this.helpers = new Helpers();
59346
+ this.helpers = new Group$1();
59347
+ this.helpers.name = "Helpers";
59348
+ this.scene.add(this.helpers);
58025
59349
  const pixelRatio = window.devicePixelRatio;
58026
59350
  const rect = canvas.parentElement.getBoundingClientRect();
58027
59351
  const width = rect.width || 1;
@@ -58043,17 +59367,17 @@ js: import "konva/skia-backend";
58043
59367
  this.renderer.setPixelRatio(pixelRatio);
58044
59368
  this.renderer.setSize(width, height);
58045
59369
  this.renderer.outputColorSpace = LinearSRGBColorSpace;
59370
+ this.renderer.localClippingEnabled = true;
58046
59371
  this.renderPass = new RenderPass(this.scene, this.camera);
58047
- this.helpersPass = new RenderPass(this.helpers, this.camera);
58048
- this.helpersPass.clear = false;
58049
59372
  this.fxaaPass = new FXAAPass();
58050
59373
  this.smaaPass = new SMAAPass();
58051
- this.ssaaRenderPass = new SSAARenderPass([this.scene, this.helpers], this.camera);
59374
+ this.ssaaRenderPass = new SSAARenderPass(this.scene, this.camera);
58052
59375
  this.ssaaRenderPass.unbiased = true;
58053
59376
  this.outputPass = new OutputPass();
58054
- 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);
58055
59380
  this.composer.addPass(this.renderPass);
58056
- this.composer.addPass(this.helpersPass);
58057
59381
  this.composer.addPass(this.smaaPass);
58058
59382
  this.composer.addPass(this.fxaaPass);
58059
59383
  this.composer.addPass(this.ssaaRenderPass);
@@ -58084,8 +59408,11 @@ js: import "konva/skia-backend";
58084
59408
  this.removeAllListeners();
58085
59409
  this.setActiveDragger();
58086
59410
  this._components.forEach((component) => component.dispose());
58087
- this._components = [];
58088
- this._markup.dispose();
59411
+ this._components.length = 0;
59412
+ if (this._markup) {
59413
+ this._markup.dispose();
59414
+ this._markup = undefined;
59415
+ }
58089
59416
  if (this.canvas) {
58090
59417
  this.canvasEvents.forEach((x) => this.canvas.removeEventListener(x, this.canvaseventlistener));
58091
59418
  this.canvas = undefined;
@@ -58094,8 +59421,6 @@ js: import "konva/skia-backend";
58094
59421
  this.composer.dispose();
58095
59422
  if (this.renderPass)
58096
59423
  this.renderPass.dispose();
58097
- if (this.helpersPass)
58098
- this.helpersPass.dispose();
58099
59424
  if (this.fxaaPass)
58100
59425
  this.fxaaPass.dispose();
58101
59426
  if (this.smaaPass)
@@ -58111,7 +59436,6 @@ js: import "konva/skia-backend";
58111
59436
  this.camera = undefined;
58112
59437
  this.renderer = undefined;
58113
59438
  this.renderPass = undefined;
58114
- this.helpersPass = undefined;
58115
59439
  this.fxaaPass = undefined;
58116
59440
  this.smaaPass = undefined;
58117
59441
  this.ssaaRenderPass = undefined;
@@ -58143,11 +59467,12 @@ js: import "konva/skia-backend";
58143
59467
  }
58144
59468
  update(force = false) {
58145
59469
  const time = performance.now();
58146
- force = force || time - this._renderTime >= this._updateDelay;
59470
+ if (typeof force === "number" && time - this._renderTime >= force)
59471
+ force = true;
58147
59472
  this._renderNeeded = true;
58148
59473
  if (force)
58149
59474
  this.render(time);
58150
- this.emitEvent({ type: "update", force });
59475
+ this.emitEvent({ type: "update", force: !!force });
58151
59476
  }
58152
59477
  render(time, force = false) {
58153
59478
  if (!this.renderer)
@@ -58161,13 +59486,7 @@ js: import "konva/skia-backend";
58161
59486
  this._renderNeeded = false;
58162
59487
  this.renderer.info.autoReset = false;
58163
59488
  this.renderer.info.reset();
58164
- if (this.options.antialiasing === true || this.options.antialiasing === "msaa") {
58165
- this.renderer.render(this.scene, this.camera);
58166
- this.renderer.render(this.helpers, this.camera);
58167
- }
58168
- else {
58169
- this.composer.render(deltaTime);
58170
- }
59489
+ this.composer.render(deltaTime);
58171
59490
  this.emitEvent({ type: "render", time, deltaTime });
58172
59491
  }
58173
59492
  loadReferences(model) {
@@ -58227,11 +59546,12 @@ js: import "konva/skia-backend";
58227
59546
  this.clearOverlay();
58228
59547
  this.clearSelected();
58229
59548
  this.loaders.forEach((loader) => loader.dispose());
58230
- this.loaders = [];
59549
+ this.loaders.length = 0;
58231
59550
  this.models.forEach((model) => model.dispose());
58232
- this.models = [];
58233
- this.scene.clear();
59551
+ this.models.length = 0;
58234
59552
  this.helpers.clear();
59553
+ this.scene.clear();
59554
+ this.scene.add(this.helpers);
58235
59555
  this.extents.makeEmpty();
58236
59556
  this.syncOptions();
58237
59557
  this.syncOverlay();
@@ -58248,8 +59568,15 @@ js: import "konva/skia-backend";
58248
59568
  this.fxaaPass.enabled = options.antialiasing === "fxaa";
58249
59569
  this.smaaPass.enabled = options.antialiasing === "smaa";
58250
59570
  this.ssaaRenderPass.enabled = options.antialiasing === "ssaa";
58251
- this.renderPass.enabled = !this.ssaaRenderPass.enabled;
58252
- 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
+ }
58253
59580
  this.update();
58254
59581
  }
58255
59582
  syncOverlay() {
@@ -58268,7 +59595,8 @@ js: import "konva/skia-backend";
58268
59595
  clearSlices() {
58269
59596
  if (!this.renderer)
58270
59597
  return;
58271
- this.renderer.clippingPlanes = [];
59598
+ this.clippingPlanes.length = 0;
59599
+ this.emitEvent({ type: "changecuttingplanes" });
58272
59600
  this.emitEvent({ type: "clearslices" });
58273
59601
  this.update();
58274
59602
  }
@@ -58364,7 +59692,6 @@ js: import "konva/skia-backend";
58364
59692
  camera.updateMatrixWorld();
58365
59693
  this.camera = camera;
58366
59694
  this.renderPass.camera = camera;
58367
- this.helpersPass.camera = camera;
58368
59695
  this.ssaaRenderPass.camera = camera;
58369
59696
  this.options.cameraMode = "orthographic";
58370
59697
  this.emitEvent({ type: "changecameramode", mode: "orthographic" });
@@ -58387,7 +59714,6 @@ js: import "konva/skia-backend";
58387
59714
  camera.updateMatrixWorld();
58388
59715
  this.camera = camera;
58389
59716
  this.renderPass.camera = camera;
58390
- this.helpersPass.camera = camera;
58391
59717
  this.ssaaRenderPass.camera = camera;
58392
59718
  this.options.cameraMode = "perspective";
58393
59719
  this.emitEvent({ type: "changecameramode", mode: "perspective" });
@@ -58398,8 +59724,9 @@ js: import "konva/skia-backend";
58398
59724
  clipping_planes.forEach((clipping_plane) => {
58399
59725
  const plane = new Plane();
58400
59726
  plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
58401
- this.renderer.clippingPlanes.push(plane);
59727
+ this.clippingPlanes.push(plane);
58402
59728
  });
59729
+ this.emitEvent({ type: "changecuttingplanes" });
58403
59730
  }
58404
59731
  };
58405
59732
  const setSelection = (selection) => {
@@ -58454,7 +59781,7 @@ js: import "konva/skia-backend";
58454
59781
  };
58455
59782
  const getClippingPlanes = () => {
58456
59783
  const clipping_planes = [];
58457
- this.renderer.clippingPlanes.forEach((plane) => {
59784
+ this.clippingPlanes.forEach((plane) => {
58458
59785
  const clipping_plane = {
58459
59786
  location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3())),
58460
59787
  direction: getPoint3dFromVector3(plane.normal),