@inweb/viewer-three 27.4.7 → 27.6.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 (94) 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 +2 -1
  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 +2 -1
  20. package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
  21. package/dist/extensions/components/StatsPanelComponent.js +0 -1
  22. package/dist/extensions/components/StatsPanelComponent.js.map +1 -1
  23. package/dist/extensions/components/StatsPanelComponent.min.js +1 -1
  24. package/dist/extensions/components/StatsPanelComponent.module.js +0 -1
  25. package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -1
  26. package/dist/extensions/loaders/GLTFCloudLoader.js +7 -2
  27. package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -1
  28. package/dist/extensions/loaders/GLTFCloudLoader.min.js +1 -1
  29. package/dist/extensions/loaders/GLTFCloudLoader.module.js +7 -2
  30. package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -1
  31. package/dist/extensions/loaders/GLTFFileLoader.js +2 -1
  32. package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
  33. package/dist/extensions/loaders/GLTFFileLoader.min.js +1 -1
  34. package/dist/extensions/loaders/GLTFFileLoader.module.js +2 -1
  35. package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
  36. package/dist/extensions/loaders/IFCXLoader.js +10 -5
  37. package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
  38. package/dist/extensions/loaders/IFCXLoader.min.js +1 -1
  39. package/dist/extensions/loaders/IFCXLoader.module.js +10 -5
  40. package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
  41. package/dist/viewer-three.js +1901 -569
  42. package/dist/viewer-three.js.map +1 -1
  43. package/dist/viewer-three.min.js +4 -4
  44. package/dist/viewer-three.module.js +1366 -451
  45. package/dist/viewer-three.module.js.map +1 -1
  46. package/extensions/components/AxesHelperComponent.ts +3 -0
  47. package/extensions/components/ExtentsHelperComponent.ts +5 -2
  48. package/extensions/components/GridHelperComponent.ts +1 -0
  49. package/extensions/components/LightHelperComponent.ts +2 -1
  50. package/extensions/components/StatsPanelComponent.ts +0 -1
  51. package/extensions/loaders/GLTFCloudLoader.ts +8 -2
  52. package/extensions/loaders/GLTFFileLoader.ts +3 -2
  53. package/extensions/loaders/IFCX/IFCXFileLoader.ts +11 -5
  54. package/lib/Viewer/Viewer.d.ts +6 -8
  55. package/lib/Viewer/components/CameraComponent.d.ts +1 -1
  56. package/lib/Viewer/components/ClippingPlaneComponent.d.ts +8 -0
  57. package/lib/Viewer/components/HighlighterComponent.d.ts +2 -2
  58. package/lib/Viewer/components/InfoComponent.d.ts +1 -1
  59. package/lib/Viewer/components/SectionsComponent.d.ts +15 -0
  60. package/lib/Viewer/components/WCSHelperComponent.d.ts +2 -2
  61. package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +6 -6
  62. package/lib/Viewer/draggers/OrbitDragger.d.ts +1 -1
  63. package/lib/Viewer/measurement/Snapper.d.ts +4 -4
  64. package/package.json +5 -5
  65. package/src/Viewer/Viewer.ts +59 -48
  66. package/src/Viewer/commands/GetSelected2.ts +1 -1
  67. package/src/Viewer/commands/SetSelected.ts +1 -1
  68. package/src/Viewer/commands/index.ts +1 -1
  69. package/src/Viewer/components/BackgroundComponent.ts +2 -1
  70. package/src/Viewer/components/CameraComponent.ts +6 -7
  71. package/src/Viewer/components/CanvasRemoveComponent.ts +0 -1
  72. package/src/Viewer/{scenes/Helpers.ts → components/ClippingPlaneComponent.ts} +22 -12
  73. package/src/Viewer/components/HighlighterComponent.ts +9 -5
  74. package/src/Viewer/components/HighlighterUtils.ts +2 -2
  75. package/src/Viewer/components/InfoComponent.ts +4 -4
  76. package/src/Viewer/components/SectionsComponent.ts +119 -0
  77. package/src/Viewer/components/SelectionComponent.ts +5 -3
  78. package/src/Viewer/components/WCSHelperComponent.ts +8 -6
  79. package/src/Viewer/components/index.ts +4 -0
  80. package/src/Viewer/draggers/CuttingPlaneDragger.ts +57 -34
  81. package/src/Viewer/draggers/MeasureLineDragger.ts +1 -1
  82. package/src/Viewer/draggers/OrbitDragger.ts +3 -3
  83. package/src/Viewer/helpers/SectionsHelper.js +1061 -0
  84. package/src/Viewer/helpers/WCSHelper.ts +31 -5
  85. package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +417 -92
  86. package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +19 -14
  87. package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +76 -9
  88. package/src/Viewer/loaders/GLTFBinaryParser.ts +2 -2
  89. package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +3 -2
  90. package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +6 -4
  91. package/src/Viewer/measurement/Snapper.ts +6 -7
  92. package/src/Viewer/models/ModelImpl.ts +65 -28
  93. package/lib/Viewer/scenes/Helpers.d.ts +0 -7
  94. package/src/Viewer/postprocessing/SSAARenderPass.js +0 -245
@@ -159,8 +159,7 @@
159
159
  this.abortController = new AbortController();
160
160
  }
161
161
  dispose() {
162
- this.abortController.abort();
163
- this.abortController = undefined;
162
+ this.cancel();
164
163
  }
165
164
  isSupport(file, format) {
166
165
  return false;
@@ -179,10 +178,10 @@
179
178
  extractFileName(file) {
180
179
  const regex = /[^/\\?#:]+(?=\?|#|$)/;
181
180
  if (typeof file === "string")
182
- return (file.match(regex) || [])[0];
181
+ return (file.match(regex) || [])[0] || "";
183
182
  else if (file instanceof globalThis.File)
184
- return (file.name.match(regex) || [])[0];
185
- return undefined;
183
+ return (file.name.match(regex) || [])[0] || "";
184
+ return "";
186
185
  }
187
186
  };
188
187
  class Loaders {
@@ -235,6 +234,15 @@
235
234
  enablePartialMode: false,
236
235
  memoryLimit: 3294967296,
237
236
  cuttingPlaneFillColor: { red: 0xff, green: 0x98, blue: 0x00 },
237
+ enableSectionFill: true,
238
+ sectionFillColor: { r: 0xff, g: 0x98, b: 0x00 },
239
+ sectionUseObjectColor: false,
240
+ enableSectionHatch: true,
241
+ sectionHatchColor: { r: 0, g: 0, b: 0 },
242
+ sectionHatchScale: 8,
243
+ enableSectionOutline: true,
244
+ sectionOutlineColor: { r: 0, g: 0, b: 0 },
245
+ sectionOutlineWidth: 2,
238
246
  edgesColor: { r: 0xff, g: 0x98, b: 0x00 },
239
247
  facesColor: { r: 0xff, g: 0x98, b: 0x00 },
240
248
  edgesVisibility: true,
@@ -293,230 +301,301 @@
293
301
  }
294
302
  }
295
303
  resetToDefaults(fields) {
304
+ const defaults = Options.defaults();
296
305
  if (fields !== undefined) {
297
- const defaults = Options.defaults();
298
- const resetData = fields.reduce((acc, field) => {
299
- acc[field] = defaults[field];
300
- return acc;
301
- }, {});
302
- this.data = { ...this.data, ...resetData };
306
+ const resetData = {};
307
+ for (const field of fields) {
308
+ if (field in defaults)
309
+ resetData[field] = defaults[field];
310
+ }
311
+ this.data = resetData;
303
312
  }
304
313
  else {
305
- this.data = { ...this.data, ...Options.defaults() };
314
+ this.data = defaults;
315
+ }
316
+ }
317
+ setProperty(key, value = Options.defaults()[key]) {
318
+ if (this._data[key] !== value) {
319
+ this._data[key] = value;
320
+ this.change();
306
321
  }
307
322
  }
308
323
  get data() {
309
324
  return this._data;
310
325
  }
311
326
  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 };
327
+ const defaults = Options.defaults();
328
+ const merged = { ...defaults, ...this._data, ...value };
329
+ for (const key of Object.keys(defaults)) {
330
+ if (merged[key] === undefined)
331
+ merged[key] = defaults[key];
332
+ }
333
+ this._data = merged;
334
+ if (this._data.enablePartialMode) {
335
+ this._data.enableStreamingMode = true;
336
+ this._data.sceneGraph = false;
337
+ }
338
+ if (!value.sectionFillColor && value.cuttingPlaneFillColor)
339
+ this._data.sectionFillColor = {
340
+ r: value.cuttingPlaneFillColor.red,
341
+ g: value.cuttingPlaneFillColor.green,
342
+ b: value.cuttingPlaneFillColor.blue,
343
+ };
315
344
  this.change();
316
345
  }
317
346
  get showWCS() {
318
347
  return this._data.showWCS;
319
348
  }
320
349
  set showWCS(value) {
321
- this._data.showWCS = value;
322
- this.change();
350
+ this.setProperty("showWCS", value);
323
351
  }
324
352
  get cameraAnimation() {
325
353
  return this._data.cameraAnimation;
326
354
  }
327
355
  set cameraAnimation(value) {
328
- this._data.cameraAnimation = value;
329
- this.change();
356
+ this.setProperty("cameraAnimation", value);
330
357
  }
331
358
  get antialiasing() {
332
359
  return this._data.antialiasing;
333
360
  }
334
361
  set antialiasing(value) {
335
- this._data.antialiasing = value;
336
- this.change();
362
+ this.setProperty("antialiasing", value);
337
363
  }
338
364
  get groundShadow() {
339
365
  return this._data.groundShadow;
340
366
  }
341
367
  set groundShadow(value) {
342
- this._data.groundShadow = value;
343
- this.change();
368
+ this.setProperty("groundShadow", value);
344
369
  }
345
370
  get shadows() {
346
371
  return this._data.shadows;
347
372
  }
348
373
  set shadows(value) {
349
- this._data.shadows = value;
350
- this.change();
374
+ this.setProperty("shadows", value);
351
375
  }
352
376
  get cameraAxisXSpeed() {
353
377
  return this._data.cameraAxisXSpeed;
354
378
  }
355
379
  set cameraAxisXSpeed(value) {
356
- this._data.cameraAxisXSpeed = value;
357
- this.change();
380
+ this.setProperty("cameraAxisXSpeed", value);
358
381
  }
359
382
  get cameraAxisYSpeed() {
360
383
  return this._data.cameraAxisYSpeed;
361
384
  }
362
385
  set cameraAxisYSpeed(value) {
363
- this.cameraAxisYSpeed = value;
364
- this.change();
386
+ this.setProperty("cameraAxisYSpeed", value);
365
387
  }
366
388
  get ambientOcclusion() {
367
389
  return this._data.ambientOcclusion;
368
390
  }
369
391
  set ambientOcclusion(value) {
370
- this._data.ambientOcclusion = value;
371
- this.change();
392
+ this.setProperty("ambientOcclusion", value);
372
393
  }
373
394
  get enableStreamingMode() {
374
395
  return this._data.enableStreamingMode;
375
396
  }
376
397
  set enableStreamingMode(value) {
377
- this._data.enableStreamingMode = value;
378
- if (!value)
379
- this._data.enablePartialMode = false;
380
- this.change();
398
+ this.setProperty("enableStreamingMode", value);
399
+ if (!value) {
400
+ this.setProperty("enablePartialMode", false);
401
+ }
381
402
  }
382
403
  get enablePartialMode() {
383
404
  return this._data.enablePartialMode;
384
405
  }
385
406
  set enablePartialMode(value) {
386
- this._data.enablePartialMode = value;
407
+ this.setProperty("enablePartialMode", value);
387
408
  if (value) {
388
- this._data.enableStreamingMode = true;
389
- this._data.sceneGraph = false;
409
+ this.setProperty("enableStreamingMode", true);
410
+ this.setProperty("sceneGraph", false);
390
411
  }
391
- this.change();
392
412
  }
393
413
  get memoryLimit() {
394
414
  return this._data.memoryLimit;
395
415
  }
396
416
  set memoryLimit(value) {
397
- this._data.memoryLimit = value;
398
- this.change();
417
+ this.setProperty("memoryLimit", value);
399
418
  }
400
419
  get cuttingPlaneFillColor() {
401
- return this._data.cuttingPlaneFillColor;
420
+ console.warn("Options.cuttingPlaneFillColor has been deprecated since 27.5 and will be removed in a future release, use sectionFillColor instead");
421
+ return {
422
+ red: this._data.sectionFillColor.r,
423
+ green: this._data.sectionFillColor.g,
424
+ blue: this._data.sectionFillColor.b,
425
+ };
402
426
  }
403
427
  set cuttingPlaneFillColor(value) {
404
- this._data.cuttingPlaneFillColor = value;
405
- this.change();
428
+ console.warn("Options.cuttingPlaneFillColor has been deprecated since 27.5 and will be removed in a future release, use sectionFillColor instead");
429
+ this.setProperty("sectionFillColor", {
430
+ r: value.red,
431
+ g: value.green,
432
+ b: value.blue,
433
+ });
434
+ }
435
+ get enableSectionFill() {
436
+ return this._data.enableSectionFill;
437
+ }
438
+ set enableSectionFill(value) {
439
+ this.setProperty("enableSectionFill", value);
440
+ }
441
+ get sectionFillColor() {
442
+ return this._data.sectionFillColor;
443
+ }
444
+ set sectionFillColor(value) {
445
+ this.setProperty("sectionFillColor", value);
446
+ }
447
+ get sectionUseObjectColor() {
448
+ return this._data.sectionUseObjectColor;
449
+ }
450
+ set sectionUseObjectColor(value) {
451
+ this.setProperty("sectionUseObjectColor", value);
452
+ }
453
+ get enableSectionHatch() {
454
+ return this._data.enableSectionHatch;
455
+ }
456
+ set enableSectionHatch(value) {
457
+ this.setProperty("enableSectionHatch", value);
458
+ }
459
+ get sectionHatchColor() {
460
+ return this._data.sectionHatchColor;
461
+ }
462
+ set sectionHatchColor(value) {
463
+ this.setProperty("sectionHatchColor", value);
464
+ }
465
+ get sectionHatchScale() {
466
+ return this._data.sectionHatchScale;
467
+ }
468
+ set sectionHatchScale(value) {
469
+ this.setProperty("sectionHatchScale", value);
470
+ }
471
+ get enableSectionOutline() {
472
+ return this._data.enableSectionOutline;
473
+ }
474
+ set enableSectionOutline(value) {
475
+ this.setProperty("enableSectionOutline", value);
476
+ }
477
+ get sectionOutlineColor() {
478
+ return this._data.sectionOutlineColor;
479
+ }
480
+ set sectionOutlineColor(value) {
481
+ this.setProperty("sectionOutlineColor", value);
482
+ }
483
+ get sectionOutlineWidth() {
484
+ return this._data.sectionOutlineWidth;
485
+ }
486
+ set sectionOutlineWidth(value) {
487
+ this.setProperty("sectionOutlineWidth", value);
406
488
  }
407
489
  get edgesColor() {
408
490
  return this._data.edgesColor;
409
491
  }
410
492
  set edgesColor(value) {
411
- this._data.edgesColor = value;
412
- this.change();
493
+ this.setProperty("edgesColor", value);
413
494
  }
414
495
  get facesColor() {
415
496
  return this._data.facesColor;
416
497
  }
417
498
  set facesColor(value) {
418
- this._data.facesColor = value;
419
- this.change();
499
+ this.setProperty("facesColor", value);
420
500
  }
421
501
  get edgesVisibility() {
422
502
  return this._data.edgesVisibility;
423
503
  }
424
504
  set edgesVisibility(value) {
425
- this._data.edgesVisibility = value;
426
- this.change();
505
+ this.setProperty("edgesVisibility", value);
427
506
  }
428
507
  get edgesOverlap() {
429
508
  return this._data.edgesOverlap;
430
509
  }
431
510
  set edgesOverlap(value) {
432
- this._data.edgesOverlap = value;
433
- this.change();
511
+ this.setProperty("edgesOverlap", value);
434
512
  }
435
513
  get facesOverlap() {
436
514
  return this._data.facesOverlap;
437
515
  }
438
516
  set facesOverlap(value) {
439
- this._data.facesOverlap = value;
440
- this.change();
517
+ this.setProperty("facesOverlap", value);
441
518
  }
442
519
  get facesTransparancy() {
443
520
  return this._data.facesTransparancy;
444
521
  }
445
522
  set facesTransparancy(value) {
446
- this._data.facesTransparancy = value;
447
- this.change();
523
+ this.setProperty("facesTransparancy", value);
448
524
  }
449
525
  get enableCustomHighlight() {
450
526
  return this._data.enableCustomHighlight;
451
527
  }
452
528
  set enableCustomHighlight(value) {
453
- this._data.enableCustomHighlight = value;
454
- this.change();
529
+ this.setProperty("enableCustomHighlight", value);
455
530
  }
456
531
  get sceneGraph() {
457
532
  return this._data.sceneGraph;
458
533
  }
459
534
  set sceneGraph(value) {
460
- this._data.sceneGraph = value;
461
- if (value)
462
- this._data.enablePartialMode = false;
463
- this.change();
535
+ this.setProperty("sceneGraph", value);
536
+ if (value) {
537
+ this.setProperty("enablePartialMode", false);
538
+ }
464
539
  }
465
540
  get edgeModel() {
466
541
  return Boolean(this._data.edgeModel);
467
542
  }
468
543
  set edgeModel(value) {
469
- this._data.edgeModel = Boolean(value);
470
- this.change();
544
+ this.setProperty("edgeModel", value);
471
545
  }
472
546
  get reverseZoomWheel() {
473
547
  return this._data.reverseZoomWheel;
474
548
  }
475
549
  set reverseZoomWheel(value) {
476
- this._data.reverseZoomWheel = !!value;
477
- this.change();
550
+ this.setProperty("reverseZoomWheel", value);
478
551
  }
479
552
  get enableZoomWheel() {
480
553
  return this._data.enableZoomWheel;
481
554
  }
482
555
  set enableZoomWheel(value) {
483
- this._data.enableZoomWheel = !!value;
484
- this.change();
556
+ this.setProperty("enableZoomWheel", value);
485
557
  }
486
558
  get enableGestures() {
487
559
  return this._data.enableGestures;
488
560
  }
489
561
  set enableGestures(value) {
490
- this._data.enableGestures = !!value;
491
- this.change();
562
+ this.setProperty("enableGestures", value);
492
563
  }
493
564
  get geometryType() {
494
565
  return this._data.geometryType;
495
566
  }
496
567
  set geometryType(value) {
497
- this._data.geometryType = value;
498
- this.change();
568
+ this.setProperty("geometryType", value);
499
569
  }
500
570
  get rulerUnit() {
501
571
  return this._data.rulerUnit;
502
572
  }
503
573
  set rulerUnit(value) {
504
- this._data.rulerUnit = value;
505
- this.change();
574
+ this.setProperty("rulerUnit", value);
506
575
  }
507
576
  get rulerPrecision() {
508
577
  return this._data.rulerPrecision;
509
578
  }
510
579
  set rulerPrecision(value) {
511
- this._data.rulerPrecision = value;
512
- this.change();
580
+ this.setProperty("rulerPrecision", value);
513
581
  }
514
582
  get cameraMode() {
515
583
  return this._data.cameraMode || "perspective";
516
584
  }
517
585
  set cameraMode(value) {
518
- this._data.cameraMode = value;
519
- this.change();
586
+ this.setProperty("cameraMode", value);
587
+ }
588
+ get snapshotMimeType() {
589
+ return this._data.snapshotMimeType;
590
+ }
591
+ set snapshotMimeType(value) {
592
+ this.setProperty("snapshotMimeType", value);
593
+ }
594
+ get snapshotQuality() {
595
+ return this._data.snapshotQuality;
596
+ }
597
+ set snapshotQuality(value) {
598
+ this.setProperty("snapshotQuality", value);
520
599
  }
521
600
  }
522
601
  const CanvasEvents = [
@@ -9820,7 +9899,7 @@
9820
9899
  const _whiteColor = new Color( 1, 1, 1 );
9821
9900
  const _frustum = new Frustum();
9822
9901
  const _frustumArray = new FrustumArray();
9823
- const _box$1 = new Box3();
9902
+ const _box$1$1 = new Box3();
9824
9903
  const _sphere$2 = new Sphere();
9825
9904
  const _vector$5 = new Vector3();
9826
9905
  const _forward$1 = new Vector3();
@@ -9983,8 +10062,8 @@
9983
10062
  if ( instanceInfo[ i ].active === false ) continue;
9984
10063
  const geometryId = instanceInfo[ i ].geometryIndex;
9985
10064
  this.getMatrixAt( i, _matrix$1 );
9986
- this.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 );
9987
- boundingBox.union( _box$1 );
10065
+ this.getBoundingBoxAt( geometryId, _box$1$1 ).applyMatrix4( _matrix$1 );
10066
+ boundingBox.union( _box$1$1 );
9988
10067
  }
9989
10068
  }
9990
10069
  computeBoundingSphere() {
@@ -10244,8 +10323,8 @@
10244
10323
  const geometryInfo = this._geometryInfo[ geometryId ];
10245
10324
  if ( geometryInfo.boundingSphere === null ) {
10246
10325
  const sphere = new Sphere();
10247
- this.getBoundingBoxAt( geometryId, _box$1 );
10248
- _box$1.getCenter( sphere.center );
10326
+ this.getBoundingBoxAt( geometryId, _box$1$1 );
10327
+ _box$1$1.getCenter( sphere.center );
10249
10328
  const index = geometry.index;
10250
10329
  const position = geometry.attributes.position;
10251
10330
  let maxRadiusSq = 0;
@@ -10713,8 +10792,8 @@
10713
10792
  object: object
10714
10793
  };
10715
10794
  }
10716
- const _start$2 = new Vector3();
10717
- const _end$2 = new Vector3();
10795
+ const _start$3 = new Vector3();
10796
+ const _end$3 = new Vector3();
10718
10797
  class LineSegments extends Line$1 {
10719
10798
  constructor( geometry, material ) {
10720
10799
  super( geometry, material );
@@ -10727,10 +10806,10 @@
10727
10806
  const positionAttribute = geometry.attributes.position;
10728
10807
  const lineDistances = [];
10729
10808
  for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
10730
- _start$2.fromBufferAttribute( positionAttribute, i );
10731
- _end$2.fromBufferAttribute( positionAttribute, i + 1 );
10809
+ _start$3.fromBufferAttribute( positionAttribute, i );
10810
+ _end$3.fromBufferAttribute( positionAttribute, i + 1 );
10732
10811
  lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
10733
- lineDistances[ i + 1 ] = lineDistances[ i ] + _start$2.distanceTo( _end$2 );
10812
+ lineDistances[ i + 1 ] = lineDistances[ i ] + _start$3.distanceTo( _end$3 );
10734
10813
  }
10735
10814
  geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
10736
10815
  } else {
@@ -10771,8 +10850,8 @@
10771
10850
  }
10772
10851
  }
10773
10852
  const _inverseMatrix = new Matrix4();
10774
- const _ray = new Ray();
10775
- const _sphere = new Sphere();
10853
+ const _ray$4 = new Ray();
10854
+ const _sphere$7 = new Sphere();
10776
10855
  const _position$2 = new Vector3();
10777
10856
  class Points extends Object3D {
10778
10857
  constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
@@ -10797,12 +10876,12 @@
10797
10876
  const threshold = raycaster.params.Points.threshold;
10798
10877
  const drawRange = geometry.drawRange;
10799
10878
  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;
10879
+ _sphere$7.copy( geometry.boundingSphere );
10880
+ _sphere$7.applyMatrix4( matrixWorld );
10881
+ _sphere$7.radius += threshold;
10882
+ if ( raycaster.ray.intersectsSphere( _sphere$7 ) === false ) return;
10804
10883
  _inverseMatrix.copy( matrixWorld ).invert();
10805
- _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
10884
+ _ray$4.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
10806
10885
  const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
10807
10886
  const localThresholdSq = localThreshold * localThreshold;
10808
10887
  const index = geometry.index;
@@ -10844,10 +10923,10 @@
10844
10923
  }
10845
10924
  }
10846
10925
  function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
10847
- const rayPointDistanceSq = _ray.distanceSqToPoint( point );
10926
+ const rayPointDistanceSq = _ray$4.distanceSqToPoint( point );
10848
10927
  if ( rayPointDistanceSq < localThresholdSq ) {
10849
10928
  const intersectPoint = new Vector3();
10850
- _ray.closestPointToPoint( point, intersectPoint );
10929
+ _ray$4.closestPointToPoint( point, intersectPoint );
10851
10930
  intersectPoint.applyMatrix4( matrixWorld );
10852
10931
  const distance = raycaster.ray.origin.distanceTo( intersectPoint );
10853
10932
  if ( distance < raycaster.near || distance > raycaster.far ) return;
@@ -34348,15 +34427,15 @@ void main() {
34348
34427
  const DESKTOP_SNAP_DISTANCE = 10;
34349
34428
  const MOBILE_SNAP_DISTANCE = 50;
34350
34429
  const _vertex = new Vector3();
34351
- const _start$1 = new Vector3();
34352
- const _end$1 = new Vector3();
34353
- const _line = new Line3();
34430
+ const _start$2 = new Vector3();
34431
+ const _end$2 = new Vector3();
34432
+ const _line$1 = new Line3();
34354
34433
  const _center = new Vector3();
34355
34434
  const _projection = new Vector3();
34356
34435
  class Snapper {
34357
- constructor(camera, renderer, canvas) {
34436
+ constructor(camera, clippingPlanes, canvas) {
34358
34437
  this.camera = camera;
34359
- this.renderer = renderer;
34438
+ this.clippingPlanes = clippingPlanes;
34360
34439
  this.canvas = canvas;
34361
34440
  this.threshold = 0.0001;
34362
34441
  this.raycaster = new Raycaster();
@@ -34387,7 +34466,7 @@ void main() {
34387
34466
  };
34388
34467
  let intersects = this.raycaster.intersectObjects(objects, recursive);
34389
34468
  if (clip) {
34390
- const clippingPlanes = this.renderer.clippingPlanes || [];
34469
+ const clippingPlanes = this.clippingPlanes;
34391
34470
  clippingPlanes.forEach((plane) => {
34392
34471
  intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
34393
34472
  });
@@ -34418,7 +34497,7 @@ void main() {
34418
34497
  const object = intersections[0].object;
34419
34498
  const intersectionPoint = intersections[0].point;
34420
34499
  const localPoint = object.worldToLocal(intersectionPoint.clone());
34421
- let snapPoint;
34500
+ let snapPoint = undefined;
34422
34501
  let snapDistance = this.getDetectRadius(intersectionPoint);
34423
34502
  const geometry = object.geometry;
34424
34503
  const positions = geometry.attributes.position.array;
@@ -34439,17 +34518,17 @@ void main() {
34439
34518
  }
34440
34519
  const edgePositions = edges.attributes.position.array;
34441
34520
  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);
34521
+ _start$2.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
34522
+ _end$2.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
34523
+ _line$1.set(_start$2, _end$2);
34524
+ _line$1.getCenter(_center);
34446
34525
  const centerDistance = _center.distanceTo(localPoint);
34447
34526
  if (centerDistance < snapDistance) {
34448
34527
  snapDistance = centerDistance;
34449
34528
  snapPoint = _center.clone();
34450
34529
  continue;
34451
34530
  }
34452
- _line.closestPointToPoint(localPoint, true, _projection);
34531
+ _line$1.closestPointToPoint(localPoint, true, _projection);
34453
34532
  const lineDistance = _projection.distanceTo(localPoint);
34454
34533
  if (lineDistance < snapDistance) {
34455
34534
  snapDistance = lineDistance;
@@ -34474,7 +34553,7 @@ void main() {
34474
34553
  this.orbit.object = this.viewer.camera;
34475
34554
  this.orbit.update();
34476
34555
  };
34477
- this.optionsChange = ({ data: options }) => {
34556
+ this.updateZoomSpeed = ({ data: options }) => {
34478
34557
  this.orbit.zoomSpeed = Math.abs(this.orbit.zoomSpeed) * (options.reverseZoomWheel ? -1 : 1);
34479
34558
  };
34480
34559
  this.controlsStart = () => {
@@ -34533,7 +34612,7 @@ void main() {
34533
34612
  this.viewer.addEventListener("zoom", this.updateControls);
34534
34613
  this.viewer.addEventListener("drawviewpoint", this.updateControls);
34535
34614
  this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
34536
- this.viewer.addEventListener("optionschange", this.optionsChange);
34615
+ this.viewer.addEventListener("optionschange", this.updateZoomSpeed);
34537
34616
  this.viewer.addEventListener("contextmenu", this.stopContextMenu);
34538
34617
  this.updateControls();
34539
34618
  this.updateControlsCamera();
@@ -34545,7 +34624,7 @@ void main() {
34545
34624
  this.viewer.removeEventListener("zoom", this.updateControls);
34546
34625
  this.viewer.removeEventListener("drawviewpoint", this.updateControls);
34547
34626
  this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
34548
- this.viewer.removeEventListener("optionschange", this.optionsChange);
34627
+ this.viewer.removeEventListener("optionschange", this.updateZoomSpeed);
34549
34628
  this.viewer.removeEventListener("contextmenu", this.stopContextMenu);
34550
34629
  this.orbit.removeEventListener("start", this.controlsStart);
34551
34630
  this.orbit.removeEventListener("change", this.controlsChange);
@@ -34557,13 +34636,17 @@ void main() {
34557
34636
  constructor(viewer) {
34558
34637
  super(viewer);
34559
34638
  this.helpers = [];
34560
- this.activeHelper = null;
34639
+ this.activeHelper = undefined;
34640
+ this.transformUpdate = () => {
34641
+ this.viewer.update();
34642
+ };
34561
34643
  this.transformChange = () => {
34562
34644
  if (!this.activeHelper)
34563
34645
  return;
34564
34646
  const plane = this.activeHelper.plane;
34565
34647
  plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
34566
34648
  plane.constant = -this.activeHelper.position.dot(plane.normal);
34649
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34567
34650
  this.viewer.update();
34568
34651
  this.changed = true;
34569
34652
  };
@@ -34575,25 +34658,29 @@ void main() {
34575
34658
  this.orbit.enabled = !event.value;
34576
34659
  this.translate.enabled = !event.value;
34577
34660
  };
34578
- this.updatePlaneSize = () => {
34661
+ this.syncHelpers = () => {
34579
34662
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
34580
- this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
34663
+ const extentsCenter = this.viewer.extents.getCenter(new Vector3());
34664
+ this.helpers.forEach((planeHelper) => {
34665
+ planeHelper.size = extentsSize;
34666
+ planeHelper.position.copy(planeHelper.plane.projectPoint(extentsCenter, new Vector3()));
34667
+ });
34581
34668
  this.viewer.update();
34582
34669
  };
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
34670
  this.clearHelpers = () => {
34589
34671
  this.setActiveHelper();
34590
34672
  this.helpers.forEach((helper) => {
34591
34673
  helper.removeFromParent();
34592
34674
  helper.dispose();
34593
34675
  });
34594
- this.helpers = [];
34676
+ this.helpers.length = 0;
34595
34677
  this.viewer.update();
34596
34678
  };
34679
+ this.updateTransformCamera = () => {
34680
+ this.translate.camera = this.viewer.camera;
34681
+ this.rotate.camera = this.viewer.camera;
34682
+ this.snapper.camera = this.viewer.camera;
34683
+ };
34597
34684
  this.onKeyDown = (event) => {
34598
34685
  if (event.key === "Shift")
34599
34686
  this.rotate.setRotationSnap(Math.PI / 4);
@@ -34637,12 +34724,9 @@ void main() {
34637
34724
  this.transformChange();
34638
34725
  event.stopPropagation();
34639
34726
  };
34640
- if (!viewer.renderer.clippingPlanes)
34641
- viewer.renderer.clippingPlanes = [];
34642
- this.clippingPlanes = viewer.renderer.clippingPlanes;
34643
- this.clippingPlanes.forEach((plane) => this.addHelper(plane));
34727
+ viewer.clippingPlanes.forEach((plane) => this.addHelper(plane));
34644
34728
  const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
34645
- this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
34729
+ this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
34646
34730
  this.snapper.threshold = extentsSize / 10000;
34647
34731
  this.downPosition = new Vector2();
34648
34732
  this.position0 = new Vector3();
@@ -34653,7 +34737,8 @@ void main() {
34653
34737
  this.translate.showX = false;
34654
34738
  this.translate.showY = false;
34655
34739
  this.translate.showZ = true;
34656
- this.translate.addEventListener("change", this.transformChange);
34740
+ this.translate.addEventListener("change", this.transformUpdate);
34741
+ this.translate.addEventListener("objectChange", this.transformChange);
34657
34742
  this.translate.addEventListener("dragging-changed", this.translateDrag);
34658
34743
  this.viewer.helpers.add(this.translate.getHelper());
34659
34744
  this.rotate = new TransformControls(viewer.camera, viewer.canvas);
@@ -34662,15 +34747,18 @@ void main() {
34662
34747
  this.rotate.showX = true;
34663
34748
  this.rotate.showY = true;
34664
34749
  this.rotate.showZ = false;
34665
- this.rotate.addEventListener("change", this.transformChange);
34750
+ this.rotate.addEventListener("change", this.transformUpdate);
34751
+ this.rotate.addEventListener("objectChange", this.transformChange);
34666
34752
  this.rotate.addEventListener("dragging-changed", this.rotateDrag);
34667
34753
  this.viewer.helpers.add(this.rotate.getHelper());
34668
34754
  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);
34755
+ this.viewer.addEventListener("explode", this.syncHelpers);
34756
+ this.viewer.addEventListener("hide", this.syncHelpers);
34757
+ this.viewer.addEventListener("isolate", this.syncHelpers);
34758
+ this.viewer.addEventListener("show", this.syncHelpers);
34759
+ this.viewer.addEventListener("showall", this.syncHelpers);
34673
34760
  this.viewer.addEventListener("clearslices", this.clearHelpers);
34761
+ this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
34674
34762
  this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
34675
34763
  this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
34676
34764
  this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
@@ -34680,23 +34768,27 @@ void main() {
34680
34768
  this.viewer.update();
34681
34769
  }
34682
34770
  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);
34771
+ this.viewer.removeEventListener("explode", this.syncHelpers);
34772
+ this.viewer.removeEventListener("hide", this.syncHelpers);
34773
+ this.viewer.removeEventListener("isolate", this.syncHelpers);
34774
+ this.viewer.removeEventListener("show", this.syncHelpers);
34775
+ this.viewer.removeEventListener("showall", this.syncHelpers);
34687
34776
  this.viewer.removeEventListener("clearslices", this.clearHelpers);
34777
+ this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
34688
34778
  this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
34689
34779
  this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
34690
34780
  this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
34691
34781
  this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
34692
34782
  window.removeEventListener("keydown", this.onKeyDown);
34693
34783
  window.removeEventListener("keyup", this.onKeyUp);
34694
- this.translate.removeEventListener("change", this.transformChange);
34784
+ this.translate.removeEventListener("change", this.transformUpdate);
34785
+ this.translate.removeEventListener("objectChange", this.transformChange);
34695
34786
  this.translate.removeEventListener("dragging-changed", this.translateDrag);
34696
34787
  this.translate.getHelper().removeFromParent();
34697
34788
  this.translate.detach();
34698
34789
  this.translate.dispose();
34699
- this.rotate.removeEventListener("change", this.transformChange);
34790
+ this.rotate.removeEventListener("change", this.transformUpdate);
34791
+ this.rotate.removeEventListener("objectChange", this.transformChange);
34700
34792
  this.rotate.removeEventListener("dragging-changed", this.rotateDrag);
34701
34793
  this.rotate.getHelper().removeFromParent();
34702
34794
  this.rotate.detach();
@@ -34705,8 +34797,8 @@ void main() {
34705
34797
  helper.removeFromParent();
34706
34798
  helper.dispose();
34707
34799
  });
34708
- this.helpers = [];
34709
- this.activeHelper = null;
34800
+ this.helpers.length = 0;
34801
+ this.activeHelper = undefined;
34710
34802
  super.dispose();
34711
34803
  }
34712
34804
  addHelper(plane) {
@@ -34758,9 +34850,10 @@ void main() {
34758
34850
  const extentsCenter = this.viewer.extents.getCenter(new Vector3());
34759
34851
  const constant = -extentsCenter.dot(normal);
34760
34852
  const plane = new Plane(normal, constant);
34761
- this.clippingPlanes.push(plane);
34853
+ this.viewer.clippingPlanes.push(plane);
34762
34854
  const helper = this.addHelper(plane);
34763
34855
  this.setActiveHelper(helper);
34856
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34764
34857
  }
34765
34858
  addPlaneX() {
34766
34859
  this.addPlane(new Vector3(-1, 0, 0));
@@ -34775,13 +34868,14 @@ void main() {
34775
34868
  if (!this.activeHelper)
34776
34869
  return;
34777
34870
  const helper = this.activeHelper;
34778
- const index = this.clippingPlanes.indexOf(helper.plane);
34871
+ const index = this.viewer.clippingPlanes.indexOf(helper.plane);
34779
34872
  if (index !== -1)
34780
- this.clippingPlanes.splice(index, 1);
34873
+ this.viewer.clippingPlanes.splice(index, 1);
34781
34874
  this.helpers = this.helpers.filter((x) => x !== helper);
34782
34875
  helper.removeFromParent();
34783
34876
  helper.dispose();
34784
34877
  this.setActiveHelper(this.helpers[this.helpers.length - 1]);
34878
+ this.viewer.emitEvent({ type: "changecuttingplanes" });
34785
34879
  }
34786
34880
  }
34787
34881
 
@@ -34975,7 +35069,7 @@ void main() {
34975
35069
  this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
34976
35070
  this.overlay.addLine(this.line);
34977
35071
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
34978
- this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
35072
+ this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
34979
35073
  this.snapper.threshold = extentsSize / 10000;
34980
35074
  this.objects = [];
34981
35075
  this.updateObjects();
@@ -36254,8 +36348,8 @@ void main() {
36254
36348
  commands.registerCommand("right", (viewer) => setDefaultViewPosition(viewer, "right"));
36255
36349
  commands.registerCommand("front", (viewer) => setDefaultViewPosition(viewer, "front"));
36256
36350
  commands.registerCommand("back", (viewer) => setDefaultViewPosition(viewer, "back"));
36257
- commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
36258
36351
  commands.registerCommand("se", (viewer) => setDefaultViewPosition(viewer, "se"));
36352
+ commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
36259
36353
  commands.registerCommand("ne", (viewer) => setDefaultViewPosition(viewer, "ne"));
36260
36354
  commands.registerCommand("nw", (viewer) => setDefaultViewPosition(viewer, "nw"));
36261
36355
  commands.registerCommandAlias("clearMarkup", "clearOverlay");
@@ -36278,6 +36372,7 @@ void main() {
36278
36372
  this.syncOptions = () => {
36279
36373
  this.backgroundColor.setHex(0xffffff);
36280
36374
  this.viewer.renderer.setClearColor(this.backgroundColor);
36375
+ this.viewer.update();
36281
36376
  };
36282
36377
  this.viewer = viewer;
36283
36378
  this.backgroundColor = new Color(0xffffff);
@@ -36287,13 +36382,13 @@ void main() {
36287
36382
  }
36288
36383
  dispose() {
36289
36384
  this.viewer.removeEventListener("optionschange", this.syncOptions);
36290
- this.viewer.scene.background = undefined;
36385
+ this.viewer.scene.background = null;
36291
36386
  }
36292
36387
  }
36293
36388
 
36294
36389
  class CameraComponent {
36295
36390
  constructor(viewer) {
36296
- this.optionsChange = () => {
36391
+ this.syncOptions = () => {
36297
36392
  this.switchCameraMode(this.viewer.options.cameraMode);
36298
36393
  };
36299
36394
  this.geometryEnd = () => {
@@ -36324,13 +36419,13 @@ void main() {
36324
36419
  };
36325
36420
  this.viewer = viewer;
36326
36421
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
36327
- this.viewer.addEventListener("optionschange", this.optionsChange);
36328
- this.viewer.addEventListener("initialize", this.optionsChange);
36422
+ this.viewer.addEventListener("optionschange", this.syncOptions);
36423
+ this.viewer.addEventListener("initialize", this.syncOptions);
36329
36424
  }
36330
36425
  dispose() {
36331
36426
  this.viewer.removeEventListener("databasechunk", this.geometryEnd);
36332
- this.viewer.removeEventListener("optionschange", this.optionsChange);
36333
- this.viewer.removeEventListener("initialize", this.optionsChange);
36427
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
36428
+ this.viewer.removeEventListener("initialize", this.syncOptions);
36334
36429
  }
36335
36430
  getCameraMode(camera) {
36336
36431
  return camera.isOrthographicCamera ? "orthographic" : "perspective";
@@ -36353,7 +36448,6 @@ void main() {
36353
36448
  camera.updateProjectionMatrix();
36354
36449
  this.viewer.camera = camera;
36355
36450
  this.viewer.renderPass.camera = camera;
36356
- this.viewer.helpersPass.camera = camera;
36357
36451
  this.viewer.ssaaRenderPass.camera = camera;
36358
36452
  this.viewer.update();
36359
36453
  }
@@ -36364,7 +36458,7 @@ void main() {
36364
36458
  if (mode === this.getCameraMode(currentCamera))
36365
36459
  return;
36366
36460
  const target = this.viewer.target.clone();
36367
- let camera;
36461
+ let camera = null;
36368
36462
  if (currentCamera.isOrthographicCamera) {
36369
36463
  const fov = currentCamera.userData.fov || 45;
36370
36464
  const fieldHeight = (currentCamera.top - currentCamera.bottom) / currentCamera.zoom;
@@ -36497,7 +36591,7 @@ void main() {
36497
36591
  console.log("WebGL Renderer:", this.viewer.info.system.webglRenderer);
36498
36592
  console.log("WebGL Vendor:", this.viewer.info.system.webglVendor);
36499
36593
  this.resize();
36500
- this.optionsChange({ data: this.viewer.options });
36594
+ this.syncOptions({ data: this.viewer.options });
36501
36595
  };
36502
36596
  this.clear = () => {
36503
36597
  this.viewer.info.performance.timeToFirstRender = 0;
@@ -36521,7 +36615,7 @@ void main() {
36521
36615
  this.viewer.info.memory.totalEstimatedGpuBytes = 0;
36522
36616
  this.viewer.info.memory.usedJSHeapSize = 0;
36523
36617
  };
36524
- this.optionsChange = ({ data: options }) => {
36618
+ this.syncOptions = ({ data: options }) => {
36525
36619
  if (options.antialiasing === false)
36526
36620
  this.viewer.info.render.antialiasing = "";
36527
36621
  else if (options.antialiasing === true)
@@ -36596,7 +36690,7 @@ void main() {
36596
36690
  this.frames = 0;
36597
36691
  this.viewer.addEventListener("initialize", this.initialize);
36598
36692
  this.viewer.addEventListener("clear", this.clear);
36599
- this.viewer.addEventListener("optionschange", this.optionsChange);
36693
+ this.viewer.addEventListener("optionschange", this.syncOptions);
36600
36694
  this.viewer.addEventListener("geometrystart", this.geometryStart);
36601
36695
  this.viewer.addEventListener("databasechunk", this.databaseChunk);
36602
36696
  this.viewer.addEventListener("geometryend", this.geometryEnd);
@@ -36607,7 +36701,7 @@ void main() {
36607
36701
  dispose() {
36608
36702
  this.viewer.removeEventListener("initialize", this.initialize);
36609
36703
  this.viewer.removeEventListener("clear", this.clear);
36610
- this.viewer.removeEventListener("optionschange", this.optionsChange);
36704
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
36611
36705
  this.viewer.removeEventListener("geometrystart", this.geometryStart);
36612
36706
  this.viewer.removeEventListener("databasechunk", this.databaseChunk);
36613
36707
  this.viewer.removeEventListener("geometryend", this.geometryEnd);
@@ -36655,7 +36749,6 @@ void main() {
36655
36749
  }
36656
36750
  dispose() {
36657
36751
  this.mutationObserver.disconnect();
36658
- this.mutationObserver = undefined;
36659
36752
  }
36660
36753
  }
36661
36754
 
@@ -36674,7 +36767,7 @@ void main() {
36674
36767
  }
36675
36768
  }
36676
36769
 
36677
- const _box = new Box3();
36770
+ const _box$1 = new Box3();
36678
36771
  const _vector = new Vector3();
36679
36772
  class LineSegmentsGeometry extends InstancedBufferGeometry {
36680
36773
  constructor() {
@@ -36756,8 +36849,8 @@ void main() {
36756
36849
  const end = this.attributes.instanceEnd;
36757
36850
  if ( start !== undefined && end !== undefined ) {
36758
36851
  this.boundingBox.setFromBufferAttribute( start );
36759
- _box.setFromBufferAttribute( end );
36760
- this.boundingBox.union( _box );
36852
+ _box$1.setFromBufferAttribute( end );
36853
+ this.boundingBox.union( _box$1 );
36761
36854
  }
36762
36855
  }
36763
36856
  computeBoundingSphere() {
@@ -37279,9 +37372,9 @@ void main() {
37279
37372
  }
37280
37373
  }
37281
37374
 
37282
- const _start = new Vector3();
37283
- const _end = new Vector3();
37284
- const _viewport = new Vector4();
37375
+ const _start$1 = new Vector3();
37376
+ const _end$1 = new Vector3();
37377
+ const _viewport$1 = new Vector4();
37285
37378
  class Wireframe extends Mesh {
37286
37379
  constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
37287
37380
  super( geometry, material );
@@ -37294,10 +37387,10 @@ void main() {
37294
37387
  const instanceEnd = geometry.attributes.instanceEnd;
37295
37388
  const lineDistances = new Float32Array( 2 * instanceStart.count );
37296
37389
  for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
37297
- _start.fromBufferAttribute( instanceStart, i );
37298
- _end.fromBufferAttribute( instanceEnd, i );
37390
+ _start$1.fromBufferAttribute( instanceStart, i );
37391
+ _end$1.fromBufferAttribute( instanceEnd, i );
37299
37392
  lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
37300
- lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
37393
+ lineDistances[ j + 1 ] = lineDistances[ j ] + _start$1.distanceTo( _end$1 );
37301
37394
  }
37302
37395
  const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 );
37303
37396
  geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) );
@@ -37307,8 +37400,8 @@ void main() {
37307
37400
  onBeforeRender( renderer ) {
37308
37401
  const uniforms = this.material.uniforms;
37309
37402
  if ( uniforms && uniforms.resolution ) {
37310
- renderer.getViewport( _viewport );
37311
- this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
37403
+ renderer.getViewport( _viewport$1 );
37404
+ this.material.uniforms.resolution.value.set( _viewport$1.z, _viewport$1.w );
37312
37405
  }
37313
37406
  }
37314
37407
  }
@@ -37384,28 +37477,38 @@ void main() {
37384
37477
  polygonOffset: true,
37385
37478
  polygonOffsetFactor: 1,
37386
37479
  polygonOffsetUnits: 1,
37480
+ clippingPlanes: this.viewer.clippingPlanes,
37387
37481
  });
37388
37482
  this.edgesMaterial = new LineMaterial({
37389
37483
  linewidth: 1.5,
37390
37484
  resolution: new Vector2(window.innerWidth, window.innerHeight),
37485
+ clippingPlanes: this.viewer.clippingPlanes,
37391
37486
  });
37392
37487
  this.lineMaterial = new LineBasicMaterial({
37393
37488
  transparent: true,
37394
37489
  depthTest: true,
37395
37490
  depthWrite: true,
37491
+ clippingPlanes: this.viewer.clippingPlanes,
37396
37492
  });
37397
37493
  this.lineGlowMaterial = new LineMaterial({
37398
37494
  linewidth: 1.5,
37399
37495
  transparent: true,
37400
37496
  opacity: 0.8,
37401
37497
  resolution: new Vector2(window.innerWidth, window.innerHeight),
37498
+ clippingPlanes: this.viewer.clippingPlanes,
37402
37499
  });
37403
37500
  this.syncHighlightColors();
37404
37501
  };
37405
- this.optionsChange = () => {
37502
+ this.syncOptions = () => {
37406
37503
  this.syncHighlightColors();
37407
37504
  this.viewer.update();
37408
37505
  };
37506
+ this.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
+ };
37409
37512
  this.viewer = viewer;
37410
37513
  const gl2 = viewer.canvas.getContext("webgl2");
37411
37514
  if (gl2) {
@@ -37418,13 +37521,13 @@ void main() {
37418
37521
  });
37419
37522
  }
37420
37523
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
37421
- this.viewer.addEventListener("optionschange", this.optionsChange);
37524
+ this.viewer.addEventListener("optionschange", this.syncOptions);
37422
37525
  this.viewer.addEventListener("resize", this.viewerResize);
37423
37526
  this.geometryEnd();
37424
37527
  }
37425
37528
  dispose() {
37426
37529
  this.viewer.removeEventListener("databasechunk", this.geometryEnd);
37427
- this.viewer.removeEventListener("optionschange", this.optionsChange);
37530
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
37428
37531
  this.viewer.removeEventListener("resize", this.viewerResize);
37429
37532
  }
37430
37533
  highlight(objects) {
@@ -37503,12 +37606,6 @@ void main() {
37503
37606
  wireframe.visible = edgesVisibility;
37504
37607
  });
37505
37608
  }
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
37609
  }
37513
37610
 
37514
37611
  class SelectionComponent {
@@ -37525,7 +37622,7 @@ void main() {
37525
37622
  if (upPosition.distanceTo(this.downPosition) !== 0)
37526
37623
  return;
37527
37624
  const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
37528
- const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
37625
+ const snapper = new Snapper(this.viewer.camera, this.viewer.clippingPlanes, this.viewer.canvas);
37529
37626
  snapper.threshold = extentsSize / 10000;
37530
37627
  let intersections = [];
37531
37628
  this.viewer.models.forEach((model) => {
@@ -37622,9 +37719,1032 @@ void main() {
37622
37719
  }
37623
37720
  }
37624
37721
 
37722
+ class ClippingPlaneComponent {
37723
+ constructor(viewer) {
37724
+ this.applyClippingPlanes = () => {
37725
+ this.viewer.models.forEach((model) => {
37726
+ model.scene.traverse((object) => {
37727
+ if (object.material) {
37728
+ const materials = Array.isArray(object.material) ? object.material : [object.material];
37729
+ materials.forEach((material) => (material.clippingPlanes = this.viewer.clippingPlanes));
37730
+ }
37731
+ });
37732
+ });
37733
+ };
37734
+ this.viewer = viewer;
37735
+ this.viewer.addEventListener("geometryend", this.applyClippingPlanes);
37736
+ this.viewer.addEventListener("changecuttingplanes", this.applyClippingPlanes);
37737
+ }
37738
+ dispose() {
37739
+ this.viewer.removeEventListener("geometryend", this.applyClippingPlanes);
37740
+ this.viewer.removeEventListener("changecuttingplanes", this.applyClippingPlanes);
37741
+ }
37742
+ }
37743
+
37744
+ const _viewport = new Vector4();
37745
+ const _start = new Vector3();
37746
+ const _end = new Vector3();
37747
+ const _start4 = new Vector4();
37748
+ const _end4 = new Vector4();
37749
+ const _ssOrigin = new Vector4();
37750
+ const _ssOrigin3 = new Vector3();
37751
+ const _mvMatrix = new Matrix4();
37752
+ const _line = new Line3();
37753
+ const _closestPoint = new Vector3();
37754
+ const _box = new Box3();
37755
+ const _sphere = new Sphere();
37756
+ const _clipToWorldVector = new Vector4();
37757
+ let _ray, _lineWidth;
37758
+ function getWorldSpaceHalfWidth( camera, distance, resolution ) {
37759
+ _clipToWorldVector.set( 0, 0, - distance, 1.0 ).applyMatrix4( camera.projectionMatrix );
37760
+ _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
37761
+ _clipToWorldVector.x = _lineWidth / resolution.width;
37762
+ _clipToWorldVector.y = _lineWidth / resolution.height;
37763
+ _clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
37764
+ _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
37765
+ return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) );
37766
+ }
37767
+ function raycastWorldUnits( lineSegments, intersects ) {
37768
+ const matrixWorld = lineSegments.matrixWorld;
37769
+ const geometry = lineSegments.geometry;
37770
+ const instanceStart = geometry.attributes.instanceStart;
37771
+ const instanceEnd = geometry.attributes.instanceEnd;
37772
+ const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
37773
+ for ( let i = 0, l = segmentCount; i < l; i ++ ) {
37774
+ _line.start.fromBufferAttribute( instanceStart, i );
37775
+ _line.end.fromBufferAttribute( instanceEnd, i );
37776
+ _line.applyMatrix4( matrixWorld );
37777
+ const pointOnLine = new Vector3();
37778
+ const point = new Vector3();
37779
+ _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
37780
+ const isInside = point.distanceTo( pointOnLine ) < _lineWidth * 0.5;
37781
+ if ( isInside ) {
37782
+ intersects.push( {
37783
+ point,
37784
+ pointOnLine,
37785
+ distance: _ray.origin.distanceTo( point ),
37786
+ object: lineSegments,
37787
+ face: null,
37788
+ faceIndex: i,
37789
+ uv: null,
37790
+ uv1: null,
37791
+ } );
37792
+ }
37793
+ }
37794
+ }
37795
+ function raycastScreenSpace( lineSegments, camera, intersects ) {
37796
+ const projectionMatrix = camera.projectionMatrix;
37797
+ const material = lineSegments.material;
37798
+ const resolution = material.resolution;
37799
+ const matrixWorld = lineSegments.matrixWorld;
37800
+ const geometry = lineSegments.geometry;
37801
+ const instanceStart = geometry.attributes.instanceStart;
37802
+ const instanceEnd = geometry.attributes.instanceEnd;
37803
+ const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
37804
+ const near = - camera.near;
37805
+ _ray.at( 1, _ssOrigin );
37806
+ _ssOrigin.w = 1;
37807
+ _ssOrigin.applyMatrix4( camera.matrixWorldInverse );
37808
+ _ssOrigin.applyMatrix4( projectionMatrix );
37809
+ _ssOrigin.multiplyScalar( 1 / _ssOrigin.w );
37810
+ _ssOrigin.x *= resolution.x / 2;
37811
+ _ssOrigin.y *= resolution.y / 2;
37812
+ _ssOrigin.z = 0;
37813
+ _ssOrigin3.copy( _ssOrigin );
37814
+ _mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
37815
+ for ( let i = 0, l = segmentCount; i < l; i ++ ) {
37816
+ _start4.fromBufferAttribute( instanceStart, i );
37817
+ _end4.fromBufferAttribute( instanceEnd, i );
37818
+ _start4.w = 1;
37819
+ _end4.w = 1;
37820
+ _start4.applyMatrix4( _mvMatrix );
37821
+ _end4.applyMatrix4( _mvMatrix );
37822
+ const isBehindCameraNear = _start4.z > near && _end4.z > near;
37823
+ if ( isBehindCameraNear ) {
37824
+ continue;
37825
+ }
37826
+ if ( _start4.z > near ) {
37827
+ const deltaDist = _start4.z - _end4.z;
37828
+ const t = ( _start4.z - near ) / deltaDist;
37829
+ _start4.lerp( _end4, t );
37830
+ } else if ( _end4.z > near ) {
37831
+ const deltaDist = _end4.z - _start4.z;
37832
+ const t = ( _end4.z - near ) / deltaDist;
37833
+ _end4.lerp( _start4, t );
37834
+ }
37835
+ _start4.applyMatrix4( projectionMatrix );
37836
+ _end4.applyMatrix4( projectionMatrix );
37837
+ _start4.multiplyScalar( 1 / _start4.w );
37838
+ _end4.multiplyScalar( 1 / _end4.w );
37839
+ _start4.x *= resolution.x / 2;
37840
+ _start4.y *= resolution.y / 2;
37841
+ _end4.x *= resolution.x / 2;
37842
+ _end4.y *= resolution.y / 2;
37843
+ _line.start.copy( _start4 );
37844
+ _line.start.z = 0;
37845
+ _line.end.copy( _end4 );
37846
+ _line.end.z = 0;
37847
+ const param = _line.closestPointToPointParameter( _ssOrigin3, true );
37848
+ _line.at( param, _closestPoint );
37849
+ const zPos = MathUtils.lerp( _start4.z, _end4.z, param );
37850
+ const isInClipSpace = zPos >= -1 && zPos <= 1;
37851
+ const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;
37852
+ if ( isInClipSpace && isInside ) {
37853
+ _line.start.fromBufferAttribute( instanceStart, i );
37854
+ _line.end.fromBufferAttribute( instanceEnd, i );
37855
+ _line.start.applyMatrix4( matrixWorld );
37856
+ _line.end.applyMatrix4( matrixWorld );
37857
+ const pointOnLine = new Vector3();
37858
+ const point = new Vector3();
37859
+ _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
37860
+ intersects.push( {
37861
+ point: point,
37862
+ pointOnLine: pointOnLine,
37863
+ distance: _ray.origin.distanceTo( point ),
37864
+ object: lineSegments,
37865
+ face: null,
37866
+ faceIndex: i,
37867
+ uv: null,
37868
+ uv1: null,
37869
+ } );
37870
+ }
37871
+ }
37872
+ }
37873
+ class LineSegments2 extends Mesh {
37874
+ constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
37875
+ super( geometry, material );
37876
+ this.isLineSegments2 = true;
37877
+ this.type = 'LineSegments2';
37878
+ }
37879
+ computeLineDistances() {
37880
+ const geometry = this.geometry;
37881
+ const instanceStart = geometry.attributes.instanceStart;
37882
+ const instanceEnd = geometry.attributes.instanceEnd;
37883
+ const lineDistances = new Float32Array( 2 * instanceStart.count );
37884
+ for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
37885
+ _start.fromBufferAttribute( instanceStart, i );
37886
+ _end.fromBufferAttribute( instanceEnd, i );
37887
+ lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
37888
+ lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
37889
+ }
37890
+ const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 );
37891
+ geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) );
37892
+ geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) );
37893
+ return this;
37894
+ }
37895
+ raycast( raycaster, intersects ) {
37896
+ const worldUnits = this.material.worldUnits;
37897
+ const camera = raycaster.camera;
37898
+ if ( camera === null && ! worldUnits ) {
37899
+ console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.' );
37900
+ }
37901
+ const threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0;
37902
+ _ray = raycaster.ray;
37903
+ const matrixWorld = this.matrixWorld;
37904
+ const geometry = this.geometry;
37905
+ const material = this.material;
37906
+ _lineWidth = material.linewidth + threshold;
37907
+ if ( geometry.boundingSphere === null ) {
37908
+ geometry.computeBoundingSphere();
37909
+ }
37910
+ _sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
37911
+ let sphereMargin;
37912
+ if ( worldUnits ) {
37913
+ sphereMargin = _lineWidth * 0.5;
37914
+ } else {
37915
+ const distanceToSphere = Math.max( camera.near, _sphere.distanceToPoint( _ray.origin ) );
37916
+ sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, material.resolution );
37917
+ }
37918
+ _sphere.radius += sphereMargin;
37919
+ if ( _ray.intersectsSphere( _sphere ) === false ) {
37920
+ return;
37921
+ }
37922
+ if ( geometry.boundingBox === null ) {
37923
+ geometry.computeBoundingBox();
37924
+ }
37925
+ _box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
37926
+ let boxMargin;
37927
+ if ( worldUnits ) {
37928
+ boxMargin = _lineWidth * 0.5;
37929
+ } else {
37930
+ const distanceToBox = Math.max( camera.near, _box.distanceToPoint( _ray.origin ) );
37931
+ boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, material.resolution );
37932
+ }
37933
+ _box.expandByScalar( boxMargin );
37934
+ if ( _ray.intersectsBox( _box ) === false ) {
37935
+ return;
37936
+ }
37937
+ if ( worldUnits ) {
37938
+ raycastWorldUnits( this, intersects );
37939
+ } else {
37940
+ raycastScreenSpace( this, camera, intersects );
37941
+ }
37942
+ }
37943
+ onBeforeRender( renderer ) {
37944
+ const uniforms = this.material.uniforms;
37945
+ if ( uniforms && uniforms.resolution ) {
37946
+ renderer.getViewport( _viewport );
37947
+ this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
37948
+ }
37949
+ }
37950
+ }
37951
+
37952
+ class PointHashGrid {
37953
+ constructor(tolerance = 1e-5) {
37954
+ this.tolerance = tolerance;
37955
+ this.points = [];
37956
+ this.grid = new Map();
37957
+ }
37958
+ _hash(hx, hy, hz) {
37959
+ return `${hx},${hy},${hz}`;
37960
+ }
37961
+ add(v) {
37962
+ const hx = Math.round(v.x / this.tolerance);
37963
+ const hy = Math.round(v.y / this.tolerance);
37964
+ const hz = Math.round(v.z / this.tolerance);
37965
+ for (let i = -1; i <= 1; i++) {
37966
+ for (let j = -1; j <= 1; j++) {
37967
+ for (let k = -1; k <= 1; k++) {
37968
+ const hash = this._hash(hx + i, hy + j, hz + k);
37969
+ const cell = this.grid.get(hash);
37970
+ if (cell) {
37971
+ for (const id of cell) {
37972
+ if (this.points[id].distanceTo(v) <= this.tolerance) return id;
37973
+ }
37974
+ }
37975
+ }
37976
+ }
37977
+ }
37978
+ const id = this.points.length;
37979
+ this.points.push(v.clone());
37980
+ const centerHash = this._hash(hx, hy, hz);
37981
+ if (!this.grid.has(centerHash)) this.grid.set(centerHash, []);
37982
+ this.grid.get(centerHash).push(id);
37983
+ return id;
37984
+ }
37985
+ }
37986
+ class SectionsHelper extends Object3D {
37987
+ constructor() {
37988
+ super();
37989
+ this.type = "SectionsHelper";
37990
+ this.flags = {
37991
+ fillEnabled: true,
37992
+ fillColor: "#fffde7",
37993
+ hatchEnabled: true,
37994
+ hatchColor: "#000000",
37995
+ hatchScale: 8.0,
37996
+ outlineEnabled: true,
37997
+ outlineColor: "#000000",
37998
+ outlineWidth: 2,
37999
+ boundaryOnly: true,
38000
+ showDebugSeams: false,
38001
+ showDebugPoints: false,
38002
+ showDebugSegments: false,
38003
+ showDebugGaps: false,
38004
+ showDebugInfo: false,
38005
+ useObjFillColor: false,
38006
+ useObjOutlineColor: false,
38007
+ };
38008
+ this._caps = [];
38009
+ this._outlines = [];
38010
+ this._debugPoints = [];
38011
+ this._debugSegments = [];
38012
+ this._debugGaps = [];
38013
+ this._vA = new Vector3();
38014
+ this._vB = new Vector3();
38015
+ this._vC = new Vector3();
38016
+ this._worldBox = new Box3();
38017
+ }
38018
+ dispose() {
38019
+ const disposeMesh = (item) => {
38020
+ if (item.geometry) item.geometry.dispose();
38021
+ if (item.material) item.material.dispose();
38022
+ this.remove(item);
38023
+ };
38024
+ this._caps.forEach(disposeMesh);
38025
+ this._outlines.forEach(disposeMesh);
38026
+ this._debugPoints.forEach(disposeMesh);
38027
+ this._debugSegments.forEach(disposeMesh);
38028
+ this._debugGaps.forEach(disposeMesh);
38029
+ this._caps.length = 0;
38030
+ this._outlines.length = 0;
38031
+ this._debugPoints.length = 0;
38032
+ this._debugSegments.length = 0;
38033
+ this._debugGaps.length = 0;
38034
+ }
38035
+ setSize(width, height) {
38036
+ this._outlines.forEach((o) => {
38037
+ if (o.material.resolution) o.material.resolution.set(width, height);
38038
+ });
38039
+ this._debugSegments.forEach((s) => {
38040
+ if (s.material.resolution) s.material.resolution.set(width, height);
38041
+ });
38042
+ }
38043
+ _ensureHelpersCount(count) {
38044
+ const hatchVertexShader = `
38045
+ #include <common>
38046
+ #include <logdepthbuf_pars_vertex>
38047
+ #include <clipping_planes_pars_vertex>
38048
+
38049
+ attribute float aHatchDir;
38050
+ attribute vec3 aFillColor;
38051
+
38052
+ varying vec3 vWP;
38053
+ varying float vHatchDir;
38054
+ varying vec3 vFillColor;
38055
+
38056
+ void main() {
38057
+ vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
38058
+ #include <clipping_planes_vertex>
38059
+
38060
+ vWP = (modelMatrix * vec4(position, 1.0)).xyz;
38061
+ vHatchDir = aHatchDir;
38062
+ vFillColor = aFillColor;
38063
+
38064
+ gl_Position = projectionMatrix * mvPosition;
38065
+ #include <logdepthbuf_vertex>
38066
+ }
38067
+ `;
38068
+ const hatchFragmentShader = `
38069
+ #include <common>
38070
+ #include <logdepthbuf_pars_fragment>
38071
+ #include <clipping_planes_pars_fragment>
38072
+
38073
+ uniform vec3 lineColor;
38074
+ uniform float uHatchScale;
38075
+ uniform float uHatchEnabled;
38076
+
38077
+ varying vec3 vWP;
38078
+ varying float vHatchDir;
38079
+ varying vec3 vFillColor;
38080
+
38081
+ void main() {
38082
+ #include <clipping_planes_fragment>
38083
+ #include <logdepthbuf_fragment>
38084
+
38085
+ float v1 = mod(gl_FragCoord.x + gl_FragCoord.y, uHatchScale);
38086
+ float v2 = mod(gl_FragCoord.x - gl_FragCoord.y, uHatchScale);
38087
+ float v = mix(v1, v2, vHatchDir);
38088
+
38089
+ float hatchMask = step(v, 1.5) * uHatchEnabled;
38090
+ gl_FragColor = vec4(mix(vFillColor, lineColor, hatchMask), 1.0);
38091
+ }
38092
+ `;
38093
+ while (this._caps.length < count) {
38094
+ const capMat = new ShaderMaterial({
38095
+ uniforms: {
38096
+ lineColor: { value: new Color() },
38097
+ uHatchScale: { value: 10.0 },
38098
+ uHatchEnabled: { value: 1.0 },
38099
+ },
38100
+ vertexShader: hatchVertexShader,
38101
+ fragmentShader: hatchFragmentShader,
38102
+ side: DoubleSide,
38103
+ clipping: true,
38104
+ depthTest: true,
38105
+ depthWrite: false,
38106
+ });
38107
+ const capMesh = new Mesh(new BufferGeometry(), capMat);
38108
+ capMesh.renderOrder = 5;
38109
+ this.add(capMesh);
38110
+ this._caps.push(capMesh);
38111
+ const lineMat = new LineMaterial({
38112
+ color: 0xffffff,
38113
+ linewidth: 2,
38114
+ resolution: new Vector2(window.innerWidth, window.innerHeight),
38115
+ depthTest: true,
38116
+ clipping: true,
38117
+ vertexColors: true,
38118
+ });
38119
+ const lineObj = new LineSegments2(new LineSegmentsGeometry(), lineMat);
38120
+ lineObj.renderOrder = 100;
38121
+ this.add(lineObj);
38122
+ this._outlines.push(lineObj);
38123
+ const ptsMat = new PointsMaterial({
38124
+ color: 0x00aaff,
38125
+ size: 6,
38126
+ sizeAttenuation: false,
38127
+ depthTest: false,
38128
+ transparent: true,
38129
+ depthWrite: false,
38130
+ });
38131
+ const pointsObj = new Points(new BufferGeometry(), ptsMat);
38132
+ pointsObj.renderOrder = 200;
38133
+ this.add(pointsObj);
38134
+ this._debugPoints.push(pointsObj);
38135
+ const debugSegMat = new LineMaterial({
38136
+ color: 0x00ff00,
38137
+ linewidth: 4,
38138
+ resolution: new Vector2(window.innerWidth, window.innerHeight),
38139
+ depthTest: false,
38140
+ transparent: true,
38141
+ depthWrite: false,
38142
+ clipping: true,
38143
+ });
38144
+ const debugSegObj = new LineSegments2(new LineSegmentsGeometry(), debugSegMat);
38145
+ debugSegObj.renderOrder = 150;
38146
+ this.add(debugSegObj);
38147
+ this._debugSegments.push(debugSegObj);
38148
+ const gapPtsMat = new PointsMaterial({
38149
+ size: 6,
38150
+ sizeAttenuation: false,
38151
+ depthTest: false,
38152
+ transparent: true,
38153
+ depthWrite: false,
38154
+ vertexColors: true,
38155
+ });
38156
+ const gapsObj = new Points(new BufferGeometry(), gapPtsMat);
38157
+ gapsObj.renderOrder = 250;
38158
+ this.add(gapsObj);
38159
+ this._debugGaps.push(gapsObj);
38160
+ }
38161
+ for (let i = count; i < this._caps.length; i++) {
38162
+ this._caps[i].visible = false;
38163
+ this._outlines[i].visible = false;
38164
+ this._debugPoints[i].visible = false;
38165
+ this._debugSegments[i].visible = false;
38166
+ this._debugGaps[i].visible = false;
38167
+ }
38168
+ }
38169
+ update(objects, extents, planes) {
38170
+ const t0 = performance.now();
38171
+ this._ensureHelpersCount(planes.length);
38172
+ if (planes.length === 0) return;
38173
+ const sphere = extents.getBoundingSphere(new Sphere());
38174
+ const globalRadius = Math.max(sphere.radius, 1e-3);
38175
+ const clippingBias = globalRadius * 1e-4;
38176
+ const biasedPlanes = planes.map((p) => {
38177
+ const bp = p.clone();
38178
+ bp.constant += clippingBias;
38179
+ return bp;
38180
+ });
38181
+ const targetMeshes = [];
38182
+ objects.forEach((obj) => {
38183
+ if (obj.isMesh && obj.material) {
38184
+ const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
38185
+ if (mats.some((m) => m.clippingPlanes)) targetMeshes.push(obj);
38186
+ }
38187
+ });
38188
+ planes.forEach((plane, pIdx) => {
38189
+ const capMesh = this._caps[pIdx];
38190
+ const outlineMesh = this._outlines[pIdx];
38191
+ const debugPtsMesh = this._debugPoints[pIdx];
38192
+ const debugSegsMesh = this._debugSegments[pIdx];
38193
+ const debugGapsMesh = this._debugGaps[pIdx];
38194
+ const hatchColor = new Color(this.flags.hatchColor);
38195
+ hatchColor.convertLinearToSRGB();
38196
+ capMesh.material.uniforms.lineColor.value.set(hatchColor);
38197
+ capMesh.material.uniforms.uHatchScale.value = this.flags.hatchScale;
38198
+ capMesh.material.uniforms.uHatchEnabled.value = this.flags.hatchEnabled ? 1.0 : 0.0;
38199
+ outlineMesh.material.linewidth = this.flags.outlineWidth;
38200
+ const otherBiasedPlanes = biasedPlanes.filter((_, i) => i !== pIdx);
38201
+ capMesh.material.clippingPlanes = otherBiasedPlanes;
38202
+ outlineMesh.material.clippingPlanes = otherBiasedPlanes;
38203
+ debugSegsMesh.material.clippingPlanes = otherBiasedPlanes;
38204
+ const n = plane.normal;
38205
+ const planeOrigin = n.clone().multiplyScalar(-plane.constant);
38206
+ const up = new Vector3(0, 1, 0);
38207
+ if (Math.abs(n.dot(up)) > 0.999) up.set(1, 0, 0);
38208
+ const uAxis = new Vector3().crossVectors(up, n).normalize();
38209
+ const vAxis = new Vector3().crossVectors(n, uAxis).normalize();
38210
+ const positions = [];
38211
+ const indices = [];
38212
+ const hatchDirs = [];
38213
+ const fillColors = [];
38214
+ const combinedOutlinePoints = [];
38215
+ const combinedOutlineColors = [];
38216
+ const rawPts = [];
38217
+ const rawSegs = [];
38218
+ const rawGaps = [];
38219
+ const rawGapColors = [];
38220
+ targetMeshes.forEach((mesh, meshIndex) => {
38221
+ if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();
38222
+ if (!mesh.geometry.boundingSphere) mesh.geometry.computeBoundingSphere();
38223
+ this._worldBox.copy(mesh.geometry.boundingBox).applyMatrix4(mesh.matrixWorld);
38224
+ if (!plane.intersectsBox(this._worldBox)) return;
38225
+ const localScale = new Vector3().setFromMatrixScale(mesh.matrixWorld);
38226
+ const maxScale = Math.max(localScale.x, localScale.y, localScale.z);
38227
+ const localRadius = Math.max(mesh.geometry.boundingSphere.radius * maxScale, 1e-3);
38228
+ const localHashTolerance = Math.max(localRadius * 1e-4, 1e-6);
38229
+ const localEps = Math.max(localRadius * 1e-5, 1e-7);
38230
+ const baseColor = new Color(0xffffff);
38231
+ const om = mesh.userData.originalMaterial;
38232
+ const mm = om ?? (Array.isArray(mesh.material) ? mesh.material[0] : mesh.material);
38233
+ if (mm.color) baseColor.copy(mm.color);
38234
+ const objFillColor = baseColor.clone().lerp(new Color(0x000000), 0.2);
38235
+ const objOutlineColor = baseColor.clone().lerp(new Color(0x000000), 0.85);
38236
+ const hue = ((meshIndex * 137.5) % 360) / 360;
38237
+ const meshGapColor = new Color().setHSL(hue, 1.0, 0.5);
38238
+ const currentHatchDir = meshIndex % 2 === 0 ? 0.0 : 1.0;
38239
+ const fillColor = this.flags.useObjFillColor ? objFillColor : new Color(this.flags.fillColor);
38240
+ const outlineColor = this.flags.useObjOutlineColor ? objOutlineColor : new Color(this.flags.outlineColor);
38241
+ meshGapColor.convertLinearToSRGB();
38242
+ fillColor.convertLinearToSRGB();
38243
+ outlineColor.convertLinearToSRGB();
38244
+ const localEdgeStats = new Map();
38245
+ const localPointGrid = new PointHashGrid(localHashTolerance);
38246
+ this._calculateMeshSegmentsUndirected(mesh, plane, localEdgeStats, localPointGrid, localEps);
38247
+ if (localEdgeStats.size > 0) {
38248
+ const boundaryEdges = [];
38249
+ for (const [key, stat] of localEdgeStats.entries()) {
38250
+ const isBoundary = stat.count % 2 !== 0;
38251
+ const ids = key.split("-");
38252
+ const id0 = Number(ids[0]);
38253
+ const id1 = Number(ids[1]);
38254
+ const p1 = localPointGrid.points[id0];
38255
+ const p2 = localPointGrid.points[id1];
38256
+ if (this.flags.showDebugSeams || (this.flags.boundaryOnly ? isBoundary : true)) {
38257
+ combinedOutlinePoints.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
38258
+ combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
38259
+ combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
38260
+ }
38261
+ if (isBoundary) boundaryEdges.push([id0, id1]);
38262
+ if (this.flags.showDebugSegments) rawSegs.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
38263
+ }
38264
+ if (this.flags.showDebugPoints) {
38265
+ for (const p of localPointGrid.points) rawPts.push(p.x, p.y, p.z);
38266
+ }
38267
+ if (this.flags.fillEnabled && boundaryEdges.length >= 3) {
38268
+ const currentAdj = new Map();
38269
+ for (const edge of boundaryEdges) {
38270
+ const a = edge[0];
38271
+ const b = edge[1];
38272
+ if (!currentAdj.has(a)) currentAdj.set(a, []);
38273
+ if (!currentAdj.has(b)) currentAdj.set(b, []);
38274
+ currentAdj.get(a).push(b);
38275
+ currentAdj.get(b).push(a);
38276
+ }
38277
+ const degree1 = [];
38278
+ for (const [node, neighbors] of currentAdj.entries()) {
38279
+ if (neighbors.length === 1) degree1.push(node);
38280
+ }
38281
+ const stitchTol = Math.max(localRadius * 0.05, 1e-4);
38282
+ for (let i = 0; i < degree1.length; i++) {
38283
+ const n1 = degree1[i];
38284
+ if (currentAdj.get(n1).length !== 1) continue;
38285
+ const p1 = localPointGrid.points[n1];
38286
+ let bestEdgeIdx = -1;
38287
+ let bestProj = null;
38288
+ let bestT = 0;
38289
+ let minDist = stitchTol;
38290
+ const edgeCount = boundaryEdges.length;
38291
+ for (let eIdx = 0; eIdx < edgeCount; eIdx++) {
38292
+ const edge = boundaryEdges[eIdx];
38293
+ const eA = edge[0];
38294
+ const eB = edge[1];
38295
+ if (eA === n1 || eB === n1) continue;
38296
+ const pA = localPointGrid.points[eA];
38297
+ const pB = localPointGrid.points[eB];
38298
+ const lineVec = new Vector3().subVectors(pB, pA);
38299
+ const lineLenSq = lineVec.lengthSq();
38300
+ let proj;
38301
+ let t;
38302
+ if (lineLenSq < 1e-12) {
38303
+ proj = pA.clone();
38304
+ t = 0;
38305
+ } else {
38306
+ const ptVec = new Vector3().subVectors(p1, pA);
38307
+ t = ptVec.dot(lineVec) / lineLenSq;
38308
+ t = Math.max(0, Math.min(1, t));
38309
+ proj = new Vector3().copy(pA).addScaledVector(lineVec, t);
38310
+ }
38311
+ const dist = p1.distanceTo(proj);
38312
+ if (dist < minDist) {
38313
+ minDist = dist;
38314
+ bestEdgeIdx = eIdx;
38315
+ bestProj = proj;
38316
+ bestT = t;
38317
+ }
38318
+ }
38319
+ if (bestEdgeIdx !== -1) {
38320
+ const edge = boundaryEdges[bestEdgeIdx];
38321
+ const eA = edge[0];
38322
+ const eB = edge[1];
38323
+ if (bestT < 0.001) {
38324
+ boundaryEdges.push([n1, eA]);
38325
+ currentAdj.get(n1).push(eA);
38326
+ currentAdj.get(eA).push(n1);
38327
+ p1.copy(localPointGrid.points[eA]);
38328
+ } else if (bestT > 0.999) {
38329
+ boundaryEdges.push([n1, eB]);
38330
+ currentAdj.get(n1).push(eB);
38331
+ currentAdj.get(eB).push(n1);
38332
+ p1.copy(localPointGrid.points[eB]);
38333
+ } else {
38334
+ const newNodeId = localPointGrid.add(bestProj);
38335
+ edge[1] = newNodeId;
38336
+ boundaryEdges.push([newNodeId, eB]);
38337
+ boundaryEdges.push([n1, newNodeId]);
38338
+ const neighborsA = currentAdj.get(eA);
38339
+ neighborsA[neighborsA.indexOf(eB)] = newNodeId;
38340
+ const neighborsB = currentAdj.get(eB);
38341
+ neighborsB[neighborsB.indexOf(eA)] = newNodeId;
38342
+ if (!currentAdj.has(newNodeId)) currentAdj.set(newNodeId, []);
38343
+ currentAdj.get(newNodeId).push(eA, eB, n1);
38344
+ currentAdj.get(n1).push(newNodeId);
38345
+ p1.copy(bestProj);
38346
+ }
38347
+ }
38348
+ }
38349
+ if (this.flags.showDebugGaps) {
38350
+ for (const [node, neighbors] of currentAdj.entries()) {
38351
+ if (neighbors.length !== 2) {
38352
+ const p = localPointGrid.points[node];
38353
+ rawGaps.push(p.x, p.y, p.z);
38354
+ rawGapColors.push(meshGapColor.r, meshGapColor.g, meshGapColor.b);
38355
+ }
38356
+ }
38357
+ }
38358
+ const loops = this._assembleLoopsUndirected(boundaryEdges, localPointGrid, uAxis, vAxis);
38359
+ if (loops.length > 0) {
38360
+ this._triangulateTreeOptimized(
38361
+ loops,
38362
+ planeOrigin,
38363
+ uAxis,
38364
+ vAxis,
38365
+ positions,
38366
+ indices,
38367
+ localRadius,
38368
+ fillColor,
38369
+ currentHatchDir,
38370
+ hatchDirs,
38371
+ fillColors
38372
+ );
38373
+ }
38374
+ }
38375
+ }
38376
+ });
38377
+ if (indices.length > 0) {
38378
+ capMesh.geometry.dispose();
38379
+ capMesh.geometry = new BufferGeometry();
38380
+ capMesh.geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
38381
+ capMesh.geometry.setAttribute("aHatchDir", new Float32BufferAttribute(hatchDirs, 1));
38382
+ capMesh.geometry.setAttribute("aFillColor", new Float32BufferAttribute(fillColors, 3));
38383
+ capMesh.geometry.setIndex(indices);
38384
+ capMesh.geometry.computeVertexNormals();
38385
+ capMesh.visible = this.flags.fillEnabled;
38386
+ } else {
38387
+ capMesh.visible = false;
38388
+ }
38389
+ if (outlineMesh.geometry) outlineMesh.geometry.dispose();
38390
+ outlineMesh.geometry = new LineSegmentsGeometry();
38391
+ if (this.flags.outlineEnabled && combinedOutlinePoints.length >= 6) {
38392
+ outlineMesh.geometry.setPositions(new Float32Array(combinedOutlinePoints));
38393
+ outlineMesh.geometry.setColors(new Float32Array(combinedOutlineColors));
38394
+ outlineMesh.visible = true;
38395
+ } else {
38396
+ outlineMesh.visible = false;
38397
+ }
38398
+ if (this.flags.showDebugPoints && rawPts.length > 0) {
38399
+ debugPtsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawPts, 3));
38400
+ debugPtsMesh.visible = true;
38401
+ } else {
38402
+ debugPtsMesh.visible = false;
38403
+ }
38404
+ if (debugSegsMesh.geometry) debugSegsMesh.geometry.dispose();
38405
+ debugSegsMesh.geometry = new LineSegmentsGeometry();
38406
+ if (this.flags.showDebugSegments && rawSegs.length >= 6) {
38407
+ debugSegsMesh.geometry.setPositions(new Float32Array(rawSegs));
38408
+ debugSegsMesh.visible = true;
38409
+ } else {
38410
+ debugSegsMesh.visible = false;
38411
+ }
38412
+ if (debugGapsMesh.geometry) debugGapsMesh.geometry.dispose();
38413
+ debugGapsMesh.geometry = new BufferGeometry();
38414
+ if (this.flags.showDebugGaps && rawGaps.length > 0) {
38415
+ debugGapsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawGaps, 3));
38416
+ debugGapsMesh.geometry.setAttribute("color", new Float32BufferAttribute(rawGapColors, 3));
38417
+ debugGapsMesh.visible = true;
38418
+ } else {
38419
+ debugGapsMesh.visible = false;
38420
+ }
38421
+ });
38422
+ if (this.flags.showDebugInfo) {
38423
+ console.log(`[SectionsHelper] v7.00 Updated in ${(performance.now() - t0).toFixed(2)} ms`);
38424
+ }
38425
+ }
38426
+ _assembleLoopsUndirected(edges, pointGrid, uAxis, vAxis) {
38427
+ const adj = new Map();
38428
+ for (const edge of edges) {
38429
+ const a = edge[0];
38430
+ const b = edge[1];
38431
+ if (!adj.has(a)) adj.set(a, []);
38432
+ if (!adj.has(b)) adj.set(b, []);
38433
+ adj.get(a).push(b);
38434
+ adj.get(b).push(a);
38435
+ }
38436
+ const loops = [];
38437
+ while (adj.size > 0) {
38438
+ let startNode = -1;
38439
+ for (const key of adj.keys()) {
38440
+ if (adj.get(key).length > 0) {
38441
+ startNode = key;
38442
+ break;
38443
+ }
38444
+ }
38445
+ if (startNode === -1) break;
38446
+ let current = startNode;
38447
+ let prev = -1;
38448
+ const path = [];
38449
+ const pathIndices = new Map();
38450
+ while (true) {
38451
+ path.push(current);
38452
+ pathIndices.set(current, path.length - 1);
38453
+ const neighbors = adj.get(current);
38454
+ if (!neighbors || neighbors.length === 0) break;
38455
+ let nextIdx = 0;
38456
+ if (neighbors.length > 1 && prev !== -1) {
38457
+ const pPrev = pointGrid.points[prev];
38458
+ const pCurr = pointGrid.points[current];
38459
+ const vIn = new Vector3().subVectors(pCurr, pPrev);
38460
+ const in2d = new Vector2(vIn.dot(uAxis), vIn.dot(vAxis));
38461
+ if (in2d.lengthSq() > 1e-10) {
38462
+ in2d.normalize();
38463
+ let minAngle = Infinity;
38464
+ for (let i = 0; i < neighbors.length; i++) {
38465
+ const pNext = pointGrid.points[neighbors[i]];
38466
+ const vOut = new Vector3().subVectors(pNext, pCurr);
38467
+ const out2d = new Vector2(vOut.dot(uAxis), vOut.dot(vAxis));
38468
+ if (out2d.lengthSq() > 1e-10) {
38469
+ out2d.normalize();
38470
+ const angle = Math.atan2(in2d.cross(out2d), in2d.dot(out2d));
38471
+ if (angle < minAngle) {
38472
+ minAngle = angle;
38473
+ nextIdx = i;
38474
+ }
38475
+ }
38476
+ }
38477
+ }
38478
+ }
38479
+ const next = neighbors[nextIdx];
38480
+ neighbors.splice(nextIdx, 1);
38481
+ const nextNeighbors = adj.get(next);
38482
+ if (nextNeighbors) {
38483
+ const revIdx = nextNeighbors.indexOf(current);
38484
+ if (revIdx !== -1) nextNeighbors.splice(revIdx, 1);
38485
+ }
38486
+ prev = current;
38487
+ current = next;
38488
+ if (pathIndices.has(current)) {
38489
+ const loopStartIdx = pathIndices.get(current);
38490
+ const loopNodes = path.slice(loopStartIdx);
38491
+ if (loopNodes.length >= 3) loops.push(loopNodes.map((id) => pointGrid.points[id]));
38492
+ for (let i = loopStartIdx; i < path.length; i++) pathIndices.delete(path[i]);
38493
+ path.length = loopStartIdx;
38494
+ prev = path.length > 1 ? path[path.length - 2] : -1;
38495
+ }
38496
+ }
38497
+ for (const key of adj.keys()) {
38498
+ if (adj.get(key).length === 0) adj.delete(key);
38499
+ }
38500
+ }
38501
+ return loops;
38502
+ }
38503
+ _triangulateTreeOptimized(
38504
+ loops,
38505
+ planeOrigin,
38506
+ uAxis,
38507
+ vAxis,
38508
+ positionsBuffer,
38509
+ indicesBuffer,
38510
+ localRadius,
38511
+ fillColor,
38512
+ hatchDir,
38513
+ hatchDirsBuffer,
38514
+ fillColorsBuffer
38515
+ ) {
38516
+ const shapesData = [];
38517
+ const minArea = localRadius * 1e-5 * (localRadius * 1e-5);
38518
+ loops.forEach((loop) => {
38519
+ const pts2d = loop.map((p) => {
38520
+ const pv = p.clone().sub(planeOrigin);
38521
+ return new Vector2(pv.dot(uAxis), pv.dot(vAxis));
38522
+ });
38523
+ const cleaned = [];
38524
+ for (let k = 0; k < pts2d.length; k++) {
38525
+ const prev = k === 0 ? pts2d[pts2d.length - 1] : pts2d[k - 1];
38526
+ if (pts2d[k].distanceTo(prev) > 1e-5) cleaned.push(pts2d[k]);
38527
+ }
38528
+ if (cleaned.length < 3) return;
38529
+ const area = ShapeUtils.area(cleaned);
38530
+ if (Math.abs(area) > minArea) {
38531
+ shapesData.push({ pts2d: cleaned, absArea: Math.abs(area), depth: 0, parent: -1, holes: [] });
38532
+ }
38533
+ });
38534
+ shapesData.sort((a, b) => b.absArea - a.absArea);
38535
+ for (let i = 0; i < shapesData.length; i++) {
38536
+ for (let j = i - 1; j >= 0; j--) {
38537
+ if (shapesData[i].absArea > shapesData[j].absArea * 0.98) continue;
38538
+ if (this._isLoopInside(shapesData[i].pts2d, shapesData[j].pts2d, localRadius)) {
38539
+ shapesData[i].parent = j;
38540
+ shapesData[i].depth = shapesData[j].depth + 1;
38541
+ break;
38542
+ }
38543
+ }
38544
+ }
38545
+ for (let i = 0; i < shapesData.length; i++) {
38546
+ const shape = shapesData[i];
38547
+ if (shape.depth % 2 === 1 && shape.parent !== -1) {
38548
+ shapesData[shape.parent].holes.push(shape.pts2d);
38549
+ }
38550
+ }
38551
+ for (let i = 0; i < shapesData.length; i++) {
38552
+ const shapeData = shapesData[i];
38553
+ if (shapeData.depth % 2 !== 0) continue;
38554
+ if (ShapeUtils.area(shapeData.pts2d) < 0) {
38555
+ shapeData.pts2d.reverse();
38556
+ }
38557
+ shapeData.holes.forEach((h) => {
38558
+ if (ShapeUtils.area(h) > 0) h.reverse();
38559
+ });
38560
+ const allPoints = [...shapeData.pts2d];
38561
+ shapeData.holes.forEach((h) => allPoints.push(...h));
38562
+ const faces = ShapeUtils.triangulateShape(shapeData.pts2d, shapeData.holes);
38563
+ const vertexOffset = positionsBuffer.length / 3;
38564
+ for (const pt of allPoints) {
38565
+ const p3d = planeOrigin.clone().addScaledVector(uAxis, pt.x).addScaledVector(vAxis, pt.y);
38566
+ positionsBuffer.push(p3d.x, p3d.y, p3d.z);
38567
+ hatchDirsBuffer.push(hatchDir);
38568
+ fillColorsBuffer.push(fillColor.r, fillColor.g, fillColor.b);
38569
+ }
38570
+ for (let f = 0; f < faces.length; f++) {
38571
+ indicesBuffer.push(vertexOffset + faces[f][0], vertexOffset + faces[f][1], vertexOffset + faces[f][2]);
38572
+ }
38573
+ }
38574
+ }
38575
+ _isPointInPoly(pt, poly) {
38576
+ let inside = false;
38577
+ const py = pt.y + 1.119e-7;
38578
+ const px = pt.x;
38579
+ for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
38580
+ if (
38581
+ poly[i].y > py !== poly[j].y > py &&
38582
+ px < ((poly[j].x - poly[i].x) * (py - poly[i].y)) / (poly[j].y - poly[i].y) + poly[i].x
38583
+ ) {
38584
+ inside = !inside;
38585
+ }
38586
+ }
38587
+ return inside;
38588
+ }
38589
+ _isLoopInside(child, parent, localRadius) {
38590
+ let minX1 = Infinity;
38591
+ let maxX1 = -Infinity;
38592
+ let minY1 = Infinity;
38593
+ let maxY1 = -Infinity;
38594
+ for (const p of child) {
38595
+ if (p.x < minX1) minX1 = p.x;
38596
+ if (p.x > maxX1) maxX1 = p.x;
38597
+ if (p.y < minY1) minY1 = p.y;
38598
+ if (p.y > maxY1) maxY1 = p.y;
38599
+ }
38600
+ let minX2 = Infinity;
38601
+ let maxX2 = -Infinity;
38602
+ let minY2 = Infinity;
38603
+ let maxY2 = -Infinity;
38604
+ for (const p of parent) {
38605
+ if (p.x < minX2) minX2 = p.x;
38606
+ if (p.x > maxX2) maxX2 = p.x;
38607
+ if (p.y < minY2) minY2 = p.y;
38608
+ if (p.y > maxY2) maxY2 = p.y;
38609
+ }
38610
+ const margin = Math.max(localRadius * 1e-4, 1e-5);
38611
+ if (minX1 < minX2 - margin || maxX1 > maxX2 + margin || minY1 < minY2 - margin || maxY1 > maxY2 + margin) {
38612
+ return false;
38613
+ }
38614
+ let insideCount = 0;
38615
+ for (let i = 0; i < child.length; i++) {
38616
+ if (this._isPointInPoly(child[i], parent)) {
38617
+ insideCount++;
38618
+ }
38619
+ }
38620
+ return insideCount >= child.length * 0.85;
38621
+ }
38622
+ _calculateMeshSegmentsUndirected(mesh, plane, edgeStats, grid, eps) {
38623
+ const geom = mesh.geometry;
38624
+ const pos = geom.attributes.position;
38625
+ const index = geom.index;
38626
+ const world = mesh.matrixWorld;
38627
+ const count = index ? index.count : pos.count;
38628
+ for (let i = 0; i < count; i += 3) {
38629
+ const i1 = index ? index.getX(i) : i;
38630
+ const i2 = index ? index.getX(i + 1) : i + 1;
38631
+ const i3 = index ? index.getX(i + 2) : i + 2;
38632
+ const v1 = this._vA.fromBufferAttribute(pos, i1).applyMatrix4(world);
38633
+ const v2 = this._vB.fromBufferAttribute(pos, i2).applyMatrix4(world);
38634
+ const v3 = this._vC.fromBufferAttribute(pos, i3).applyMatrix4(world);
38635
+ let d1 = plane.distanceToPoint(v1);
38636
+ let d2 = plane.distanceToPoint(v2);
38637
+ let d3 = plane.distanceToPoint(v3);
38638
+ if (Math.abs(d1) <= eps) d1 = eps;
38639
+ if (Math.abs(d2) <= eps) d2 = eps;
38640
+ if (Math.abs(d3) <= eps) d3 = eps;
38641
+ const s1 = d1 > 0 ? 1 : -1;
38642
+ const s2 = d2 > 0 ? 1 : -1;
38643
+ const s3 = d3 > 0 ? 1 : -1;
38644
+ if (s1 === s2 && s2 === s3) continue;
38645
+ const intersections = [];
38646
+ if (s1 !== s2) {
38647
+ intersections.push(new Vector3().lerpVectors(v1, v2, Math.abs(d1) / (Math.abs(d1) + Math.abs(d2))));
38648
+ }
38649
+ if (s2 !== s3) {
38650
+ intersections.push(new Vector3().lerpVectors(v2, v3, Math.abs(d2) / (Math.abs(d2) + Math.abs(d3))));
38651
+ }
38652
+ if (s3 !== s1) {
38653
+ intersections.push(new Vector3().lerpVectors(v3, v1, Math.abs(d3) / (Math.abs(d3) + Math.abs(d1))));
38654
+ }
38655
+ if (intersections.length >= 2) {
38656
+ const id1 = grid.add(intersections[0]);
38657
+ const id2 = grid.add(intersections[1]);
38658
+ if (id1 !== id2) {
38659
+ const key = id1 < id2 ? `${id1}-${id2}` : `${id2}-${id1}`;
38660
+ const stat = edgeStats.get(key) || { count: 0 };
38661
+ stat.count++;
38662
+ edgeStats.set(key, stat);
38663
+ }
38664
+ }
38665
+ }
38666
+ }
38667
+ }
38668
+
38669
+ class SectionsComponent {
38670
+ constructor(viewer) {
38671
+ this.updateTimerId = 0;
38672
+ this.updateDelay = 250;
38673
+ this.syncOptions = () => {
38674
+ function rgbToHex(c) {
38675
+ const hex = (v = 0) => v.toString(16).padStart(2, "0");
38676
+ return "#" + hex(c.r) + hex(c.g) + hex(c.b);
38677
+ }
38678
+ const options = this.viewer.options;
38679
+ const flags = this.sectionsHelper.flags;
38680
+ flags.fillEnabled = options.enableSectionFill;
38681
+ flags.fillColor = rgbToHex(options.sectionFillColor);
38682
+ flags.useObjFillColor = options.sectionUseObjectColor;
38683
+ flags.hatchEnabled = options.enableSectionHatch;
38684
+ flags.hatchColor = rgbToHex(options.sectionHatchColor);
38685
+ flags.hatchScale = options.sectionHatchScale;
38686
+ flags.outlineEnabled = options.enableSectionOutline;
38687
+ flags.outlineColor = rgbToHex(options.sectionOutlineColor);
38688
+ flags.outlineWidth = options.sectionOutlineWidth;
38689
+ this.syncSections();
38690
+ };
38691
+ this.syncHelper = () => {
38692
+ this.sectionsHelper.removeFromParent();
38693
+ this.viewer.helpers.add(this.sectionsHelper);
38694
+ };
38695
+ this.syncSections = () => {
38696
+ this.sectionsHelper.visible = false;
38697
+ clearTimeout(this.updateTimerId);
38698
+ this.updateTimerId = window.setTimeout(this.updateSections, this.updateDelay);
38699
+ };
38700
+ this.viewerResize = (event) => {
38701
+ this.sectionsHelper.setSize(event.width, event.height);
38702
+ };
38703
+ this.updateSections = () => {
38704
+ const objects = [];
38705
+ this.viewer.models.forEach((model) => objects.push(model.getVisibleObjects()));
38706
+ const objects2 = objects.flat();
38707
+ this.sectionsHelper.update(objects2, this.viewer.extents, this.viewer.clippingPlanes);
38708
+ this.sectionsHelper.visible = true;
38709
+ this.viewer.update();
38710
+ };
38711
+ this.sectionsHelper = new SectionsHelper();
38712
+ this.viewer = viewer;
38713
+ this.viewer.addEventListener("initialize", this.syncHelper);
38714
+ this.viewer.addEventListener("databasechunk", this.syncHelper);
38715
+ this.viewer.addEventListener("drawviewpoint", this.syncHelper);
38716
+ this.viewer.addEventListener("changecuttingplanes", this.syncSections);
38717
+ this.viewer.addEventListener("explode", this.syncSections);
38718
+ this.viewer.addEventListener("hide", this.syncSections);
38719
+ this.viewer.addEventListener("isolate", this.syncSections);
38720
+ this.viewer.addEventListener("show", this.syncSections);
38721
+ this.viewer.addEventListener("showall", this.syncSections);
38722
+ this.viewer.addEventListener("resize", this.viewerResize);
38723
+ this.viewer.addEventListener("optionschange", this.syncOptions);
38724
+ this.syncOptions();
38725
+ }
38726
+ dispose() {
38727
+ clearTimeout(this.updateTimerId);
38728
+ this.sectionsHelper.removeFromParent();
38729
+ this.sectionsHelper.dispose();
38730
+ this.viewer.removeEventListener("initialize", this.syncHelper);
38731
+ this.viewer.removeEventListener("databasechunk", this.syncHelper);
38732
+ this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
38733
+ this.viewer.removeEventListener("changecuttingplanes", this.syncSections);
38734
+ this.viewer.removeEventListener("explode", this.syncSections);
38735
+ this.viewer.removeEventListener("hide", this.syncSections);
38736
+ this.viewer.removeEventListener("isolate", this.syncSections);
38737
+ this.viewer.removeEventListener("show", this.syncSections);
38738
+ this.viewer.removeEventListener("showall", this.syncSections);
38739
+ this.viewer.removeEventListener("resize", this.viewerResize);
38740
+ this.viewer.removeEventListener("optionschange", this.syncOptions);
38741
+ }
38742
+ }
38743
+
37625
38744
  class WCSHelper extends Object3D {
37626
38745
  constructor(camera) {
37627
38746
  super();
38747
+ this.type = "WCSHelper";
37628
38748
  this.camera = camera;
37629
38749
  this.size = 160;
37630
38750
  this.orthoCamera = new OrthographicCamera(-2, 2, 2, -2, 0, 4);
@@ -37684,11 +38804,13 @@ void main() {
37684
38804
  canvas.width = 64;
37685
38805
  canvas.height = 64;
37686
38806
  const context = canvas.getContext("2d");
37687
- context.clearRect(0, 0, 64, 64);
37688
- context.font = "24px Arial";
37689
- context.textAlign = "center";
37690
- context.fillStyle = color.getStyle();
37691
- context.fillText(text, 32, 41);
38807
+ if (context) {
38808
+ context.clearRect(0, 0, 64, 64);
38809
+ context.font = "24px Arial";
38810
+ context.textAlign = "center";
38811
+ context.fillStyle = color.getStyle();
38812
+ context.fillText(text, 32, 41);
38813
+ }
37692
38814
  const texture = new CanvasTexture(canvas);
37693
38815
  texture.colorSpace = SRGBColorSpace;
37694
38816
  return new SpriteMaterial({ map: texture, toneMapped: false });
@@ -37712,7 +38834,7 @@ void main() {
37712
38834
 
37713
38835
  class WCSHelperComponent {
37714
38836
  constructor(viewer) {
37715
- this.geometryEnd = () => {
38837
+ this.syncHelper = () => {
37716
38838
  this.wcsHelper.dispose();
37717
38839
  this.wcsHelper = new WCSHelper(this.viewer.camera);
37718
38840
  };
@@ -37726,14 +38848,14 @@ void main() {
37726
38848
  };
37727
38849
  this.wcsHelper = new WCSHelper(viewer.camera);
37728
38850
  this.viewer = viewer;
37729
- this.viewer.addEventListener("databasechunk", this.geometryEnd);
37730
- this.viewer.addEventListener("drawviewpoint", this.geometryEnd);
38851
+ this.viewer.addEventListener("databasechunk", this.syncHelper);
38852
+ this.viewer.addEventListener("drawviewpoint", this.syncHelper);
37731
38853
  this.viewer.addEventListener("render", this.viewerRender);
37732
38854
  this.viewer.addEventListener("changecameramode", this.updateHelperCamera);
37733
38855
  }
37734
38856
  dispose() {
37735
- this.viewer.removeEventListener("databasechunk", this.geometryEnd);
37736
- this.viewer.removeEventListener("drawviewpoint", this.geometryEnd);
38857
+ this.viewer.removeEventListener("databasechunk", this.syncHelper);
38858
+ this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
37737
38859
  this.viewer.removeEventListener("render", this.viewerRender);
37738
38860
  this.viewer.removeEventListener("changecameramode", this.updateHelperCamera);
37739
38861
  this.wcsHelper.dispose();
@@ -37779,11 +38901,14 @@ void main() {
37779
38901
  components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
37780
38902
  components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
37781
38903
  components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
38904
+ components.registerComponent("ClippingPlaneComponent", (viewer) => new ClippingPlaneComponent(viewer));
38905
+ components.registerComponent("SectionsComponent", (viewer) => new SectionsComponent(viewer));
37782
38906
  components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
37783
38907
  components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
37784
38908
 
37785
38909
  class ModelImpl {
37786
38910
  constructor(scene) {
38911
+ this.id = "";
37787
38912
  this.scene = scene;
37788
38913
  this.handleToObjects = new Map();
37789
38914
  this.originalObjects = new Set();
@@ -37814,8 +38939,8 @@ void main() {
37814
38939
  if (object.material)
37815
38940
  disposeMaterials(object.material);
37816
38941
  }
37817
- this.handleToObjects = undefined;
37818
- this.originalObjects = undefined;
38942
+ this.handleToObjects.clear();
38943
+ this.originalObjects.clear();
37819
38944
  this.scene.traverse(disposeObject);
37820
38945
  this.scene.clear();
37821
38946
  }
@@ -37959,7 +39084,25 @@ void main() {
37959
39084
  return info;
37960
39085
  }
37961
39086
  getExtents(target) {
37962
- this.scene.traverseVisible((object) => target.expandByObject(object));
39087
+ const _box = new Box3();
39088
+ function expandByObject(object, target) {
39089
+ if (!object.geometry)
39090
+ return;
39091
+ object.updateWorldMatrix(false, false);
39092
+ if (object.boundingBox !== undefined) {
39093
+ if (object.boundingBox === null)
39094
+ object.computeBoundingBox();
39095
+ _box.copy(object.boundingBox);
39096
+ }
39097
+ else {
39098
+ if (object.geometry.boundingBox === null)
39099
+ object.geometry.computeBoundingBox();
39100
+ _box.copy(object.geometry.boundingBox);
39101
+ }
39102
+ _box.applyMatrix4(object.matrixWorld);
39103
+ target.union(_box);
39104
+ }
39105
+ this.scene.traverseVisible((object) => expandByObject(object, target));
37963
39106
  return target;
37964
39107
  }
37965
39108
  getObjects() {
@@ -37967,8 +39110,8 @@ void main() {
37967
39110
  }
37968
39111
  getVisibleObjects() {
37969
39112
  const objects = [];
37970
- this.scene.traverseVisible((object) => objects.push(object));
37971
- return objects.filter((object) => object.userData.handle);
39113
+ this.scene.traverseVisible((object) => object.userData.handle && objects.push(object));
39114
+ return objects;
37972
39115
  }
37973
39116
  getObjectsByHandles(handles) {
37974
39117
  if (!Array.isArray(handles))
@@ -38063,44 +39206,54 @@ void main() {
38063
39206
  centersCache.set(handle, target.clone());
38064
39207
  return target;
38065
39208
  };
38066
- function calcExplodeDepth(object, depth) {
38067
- let result = depth;
38068
- object.children.forEach((x) => {
38069
- const objectDepth = calcExplodeDepth(x, depth + 1);
38070
- if (result < objectDepth)
38071
- result = objectDepth;
38072
- });
39209
+ const calcObjectOffset = (object, target) => {
39210
+ const parent = object.parent;
39211
+ if (!parent || parent.userData.originalCenter === undefined)
39212
+ return target;
39213
+ return target.subVectors(object.userData.originalCenter, parent.userData.originalCenter);
39214
+ };
39215
+ const calcObjectDepth = (object) => {
39216
+ if (object.userData.depth !== undefined)
39217
+ return object.userData.depth;
39218
+ const parent = object.parent;
39219
+ const depth = parent && object !== explodeRoot ? calcObjectDepth(parent) + 1 : 0;
39220
+ object.userData.depth = depth;
38073
39221
  object.userData.originalPosition = object.position.clone();
38074
39222
  object.userData.originalCenter = calcObjectCenter(object, new Vector3());
38075
- return result;
38076
- }
39223
+ object.userData.originalOffset = calcObjectOffset(object, new Vector3());
39224
+ return depth;
39225
+ };
38077
39226
  const explodeScale = scale / 100;
38078
39227
  const explodeRoot = this.scene;
38079
- if (!explodeRoot.userData.explodeDepth) {
38080
- explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
39228
+ const explodeObjects = this.getObjects();
39229
+ if (explodeRoot.userData.explodeDepth === undefined) {
39230
+ let maxDepth = 0;
39231
+ explodeObjects.forEach((object) => {
39232
+ const depth = calcObjectDepth(object);
39233
+ if (depth > maxDepth)
39234
+ maxDepth = depth;
39235
+ });
39236
+ explodeRoot.userData.explodeDepth = maxDepth;
38081
39237
  }
38082
39238
  const maxDepth = explodeRoot.userData.explodeDepth;
38083
39239
  const scaledExplodeDepth = explodeScale * maxDepth + 1;
38084
39240
  const explodeDepth = 0 | scaledExplodeDepth;
38085
39241
  const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
38086
- function explodeObject(object, depth) {
39242
+ const explodeObject = (object) => {
38087
39243
  if (object.isCamera)
38088
39244
  return;
38089
- if (object.userData.isHighlightWireframe)
38090
- return;
38091
39245
  object.position.copy(object.userData.originalPosition);
39246
+ const depth = object.userData.depth;
38092
39247
  if (depth > 0 && depth <= explodeDepth) {
38093
39248
  let objectScale = explodeScale * coeff;
38094
39249
  if (depth === explodeDepth)
38095
39250
  objectScale *= currentSegmentFraction;
38096
- const parentCenter = object.parent.userData.originalCenter;
38097
- const objectCenter = object.userData.originalCenter;
38098
- const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
38099
- object.position.add(localOffset);
39251
+ object.position.addScaledVector(object.userData.originalOffset, objectScale);
38100
39252
  }
38101
- object.children.forEach((x) => explodeObject(x, depth + 1));
38102
- }
38103
- explodeObject(explodeRoot, 0);
39253
+ };
39254
+ explodeObjects.forEach((object) => {
39255
+ explodeObject(object);
39256
+ });
38104
39257
  this.scene.updateMatrixWorld();
38105
39258
  return this;
38106
39259
  }
@@ -38203,6 +39356,12 @@ void main() {
38203
39356
  centersCache.set(handle, target.clone());
38204
39357
  return target;
38205
39358
  };
39359
+ const calcObjectOffset = (object, target) => {
39360
+ const parent = object.parent;
39361
+ if (!parent || parent.userData.originalCenter === undefined)
39362
+ return target;
39363
+ return target.subVectors(object.userData.originalCenter, parent.userData.originalCenter);
39364
+ };
38206
39365
  const calcObjectDepth = (object) => {
38207
39366
  if (object.userData.depth !== undefined)
38208
39367
  return object.userData.depth;
@@ -38211,13 +39370,15 @@ void main() {
38211
39370
  object.userData.depth = depth;
38212
39371
  object.userData.originalPosition = object.position.clone();
38213
39372
  object.userData.originalCenter = calcObjectCenter(object, new Vector3());
39373
+ object.userData.originalOffset = calcObjectOffset(object, new Vector3());
38214
39374
  return depth;
38215
39375
  };
38216
39376
  const explodeScale = scale / 100;
38217
39377
  const explodeRoot = this.scene.children[0];
38218
- if (!explodeRoot.userData.explodeDepth) {
39378
+ const explodeObjects = this.getObjects();
39379
+ if (explodeRoot.userData.explodeDepth === undefined) {
38219
39380
  let maxDepth = 0;
38220
- this.gltfLoader.originalObjects.forEach((object) => {
39381
+ explodeObjects.forEach((object) => {
38221
39382
  const depth = calcObjectDepth(object);
38222
39383
  if (depth > maxDepth)
38223
39384
  maxDepth = depth;
@@ -38229,29 +39390,26 @@ void main() {
38229
39390
  const explodeDepth = 0 | scaledExplodeDepth;
38230
39391
  const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
38231
39392
  const offsetCache = new Map();
38232
- const calcObjectOffset = (object, target) => {
39393
+ const calcExplodeOffset = (object, target) => {
38233
39394
  if (offsetCache.has(object))
38234
39395
  return target.copy(offsetCache.get(object));
38235
39396
  const parent = object.parent;
38236
39397
  if (parent && object !== explodeRoot)
38237
- calcObjectOffset(parent, target);
39398
+ calcExplodeOffset(parent, target);
38238
39399
  const depth = object.userData.depth;
38239
39400
  if (depth > 0 && depth <= explodeDepth) {
38240
39401
  let objectScale = explodeScale * coeff;
38241
39402
  if (depth === explodeDepth)
38242
39403
  objectScale *= currentSegmentFraction;
38243
- const parentCenter = parent.userData.originalCenter;
38244
- const objectCenter = object.userData.originalCenter;
38245
- const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
38246
- target.add(localOffset);
39404
+ target.addScaledVector(object.userData.originalOffset, objectScale);
38247
39405
  }
38248
39406
  offsetCache.set(object, target.clone());
38249
39407
  return target;
38250
39408
  };
38251
39409
  const transformMap = new Map();
38252
- this.gltfLoader.originalObjects.forEach((object) => {
38253
- const globalOffset = calcObjectOffset(object, new Vector3());
38254
- transformMap.set(object, new Matrix4().makeTranslation(globalOffset));
39410
+ explodeObjects.forEach((object) => {
39411
+ const offset = calcExplodeOffset(object, new Vector3());
39412
+ transformMap.set(object, new Matrix4().makeTranslation(offset));
38255
39413
  });
38256
39414
  this.gltfLoader.applyObjectTransforms(transformMap);
38257
39415
  this.scene.updateMatrixWorld();
@@ -38322,6 +39480,7 @@ void main() {
38322
39480
  this._nextObjectId = 1;
38323
39481
  this.loadingAborted = false;
38324
39482
  this.criticalError = null;
39483
+ this.embeddedBinaryChunk = null;
38325
39484
  }
38326
39485
  async initialize(loader) {
38327
39486
  const json = await this.loadController.loadJson();
@@ -38330,28 +39489,72 @@ void main() {
38330
39489
  }
38331
39490
  this.json = json;
38332
39491
  this.loader = loader;
38333
- this.uri = this.json.buffers[0].uri || "";
39492
+ const bufferUri = this.json.buffers?.[0]?.uri || "";
39493
+ if (bufferUri.startsWith("data:")) {
39494
+ this.embeddedBinaryChunk = await this._decodeDataUri(bufferUri);
39495
+ this.uri = "";
39496
+ } else {
39497
+ this.uri = bufferUri;
39498
+ }
39499
+ }
39500
+ async _decodeDataUri(dataUri) {
39501
+ try {
39502
+ const response = await fetch(dataUri);
39503
+ return await response.arrayBuffer();
39504
+ } catch (e) {
39505
+ throw new Error(`DynamicLoader: Failed to decode embedded data URI: ${e.message}`);
39506
+ }
38334
39507
  }
38335
39508
  clear() {
38336
- this.json = null;
38337
- this.loadController = null;
38338
- this.pendingRequests = [];
38339
39509
  if (this.batchTimeout) {
38340
39510
  clearTimeout(this.batchTimeout);
38341
39511
  this.batchTimeout = null;
38342
39512
  }
38343
- this.disposeMaterials();
38344
- this.textureCache.clear();
38345
- this.materials.clear();
39513
+ this._rejectPendingRequests();
39514
+ if (this.disposeMaterials) {
39515
+ try {
39516
+ this.disposeMaterials();
39517
+ } catch (e) {
39518
+ console.warn("DynamicLoader: error during disposeMaterials in clear():", e);
39519
+ }
39520
+ }
39521
+ if (this.textureCache) this.textureCache.clear();
39522
+ if (this.materials) this.materials.clear();
39523
+ this.embeddedBinaryChunk = null;
39524
+ this.json = null;
39525
+ this.loadController = null;
39526
+ this.uri = "";
38346
39527
  this.activeChunkLoads = 0;
38347
39528
  this.chunkQueue = [];
38348
39529
  this.loadingAborted = false;
38349
39530
  this.criticalError = null;
38350
39531
  }
39532
+ _rejectPendingRequests() {
39533
+ const pending = this.pendingRequests;
39534
+ this.pendingRequests = [];
39535
+ if (!pending || pending.length === 0) return;
39536
+ const cancelError = new Error("DynamicLoader: Structure cleared while requests pending");
39537
+ for (let i = 0; i < pending.length; i++) {
39538
+ const item = pending[i];
39539
+ if (item && typeof item._reject === "function") {
39540
+ try {
39541
+ item._reject(cancelError);
39542
+ } catch {
39543
+ }
39544
+ }
39545
+ }
39546
+ }
38351
39547
  getJson() {
38352
39548
  return this.json;
38353
39549
  }
38354
39550
  scheduleRequest(request) {
39551
+ if (this.embeddedBinaryChunk && !this.uri) {
39552
+ return Promise.resolve({
39553
+ buffer: this.embeddedBinaryChunk,
39554
+ relOffset: request.offset,
39555
+ length: request.length,
39556
+ });
39557
+ }
38355
39558
  return new Promise((resolve, reject) => {
38356
39559
  if (this.loadingAborted) {
38357
39560
  reject(
@@ -38628,8 +39831,13 @@ void main() {
38628
39831
  return await this.textureLoader.loadAsync(fullUrl);
38629
39832
  } else if (image.bufferView !== undefined) {
38630
39833
  const bufferView = this.json.bufferViews[image.bufferView];
38631
- const array = await this.getBufferView(bufferView.byteOffset || 0, bufferView.byteLength, 5121);
38632
- const blob = new Blob([array], { type: image.mimeType });
39834
+ const { buffer, relOffset } = await this.getBufferView(
39835
+ bufferView.byteOffset || 0,
39836
+ bufferView.byteLength,
39837
+ 5121
39838
+ );
39839
+ const imageBytes = new Uint8Array(buffer, relOffset, bufferView.byteLength);
39840
+ const blob = new Blob([imageBytes], { type: image.mimeType });
38633
39841
  const url = URL.createObjectURL(blob);
38634
39842
  const texture = await this.textureLoader.loadAsync(url);
38635
39843
  URL.revokeObjectURL(url);
@@ -38659,6 +39867,7 @@ void main() {
38659
39867
  })
38660
39868
  );
38661
39869
  }
39870
+ await this.flushBufferRequests();
38662
39871
  await Promise.all(texturePromises);
38663
39872
  }
38664
39873
  loadMaterials() {
@@ -39016,6 +40225,7 @@ void main() {
39016
40225
  return result;
39017
40226
  }
39018
40227
 
40228
+ const DRACO_EXTENSION_NAME = "KHR_draco_mesh_compression";
39019
40229
  const STRUCTURE_ID_SEPARATOR = ":";
39020
40230
  class DynamicGltfLoader {
39021
40231
  constructor(camera, scene, renderer) {
@@ -39090,6 +40300,189 @@ void main() {
39090
40300
  this.transformData = null;
39091
40301
  this.identityTransformData = null;
39092
40302
  this.visibilityMaterials = new Set();
40303
+ this._dracoLoader = null;
40304
+ }
40305
+ setDracoLoader(loader = null) {
40306
+ this._dracoLoader = loader || null;
40307
+ }
40308
+ async _decodeDracoPrimitive(structure, primitive, dracoBufferData) {
40309
+ const dracoExt = primitive.extensions[DRACO_EXTENSION_NAME];
40310
+ const loader = this._dracoLoader;
40311
+ const attributeIDs = {};
40312
+ const attributeTypes = {};
40313
+ const gltfNameToThreeName = new Map();
40314
+ const threeNameToAccessor = new Map();
40315
+ for (const [gltfAttrName, dracoUniqueId] of Object.entries(dracoExt.attributes)) {
40316
+ const threeName = this._gltfAttributeNameToThreeName(gltfAttrName);
40317
+ attributeIDs[threeName] = dracoUniqueId;
40318
+ gltfNameToThreeName.set(gltfAttrName, threeName);
40319
+ const accessorIdx = primitive.attributes[gltfAttrName];
40320
+ if (accessorIdx !== undefined) {
40321
+ const accessor = structure.json.accessors[accessorIdx];
40322
+ attributeTypes[threeName] = this._gltfComponentTypeToTypedArrayName(accessor.componentType);
40323
+ threeNameToAccessor.set(threeName, accessor);
40324
+ }
40325
+ }
40326
+ const geometry = await loader.decodeGeometry(dracoBufferData, {
40327
+ attributeIDs,
40328
+ attributeTypes,
40329
+ useUniqueIDs: true,
40330
+ });
40331
+ for (const [threeName, accessor] of threeNameToAccessor) {
40332
+ const attribute = geometry.getAttribute(threeName);
40333
+ if (!attribute) continue;
40334
+ if (accessor.normalized === true) {
40335
+ attribute.normalized = true;
40336
+ }
40337
+ if (accessor.min) attribute.min = accessor.min;
40338
+ if (accessor.max) attribute.max = accessor.max;
40339
+ }
40340
+ for (const [threeName, accessor] of threeNameToAccessor) {
40341
+ const attribute = geometry.getAttribute(threeName);
40342
+ if (!attribute || !attribute.normalized) continue;
40343
+ const denom = this._normalizedDenominator(accessor.componentType);
40344
+ if (denom <= 0) continue;
40345
+ const src = attribute.array;
40346
+ const inv = 1 / denom;
40347
+ const isSigned = accessor.componentType === 5120 || accessor.componentType === 5122;
40348
+ const out = new Float32Array(src.length);
40349
+ for (let i = 0; i < src.length; i++) {
40350
+ let v = src[i] * inv;
40351
+ if (isSigned && v < -1) v = -1;
40352
+ out[i] = v;
40353
+ }
40354
+ const newAttr = new BufferAttribute(out, attribute.itemSize, false);
40355
+ if (accessor.min) newAttr.min = accessor.min;
40356
+ if (accessor.max) newAttr.max = accessor.max;
40357
+ geometry.setAttribute(threeName, newAttr);
40358
+ }
40359
+ return geometry;
40360
+ }
40361
+ _gltfComponentTypeToTypedArrayName(componentType) {
40362
+ switch (componentType) {
40363
+ case 5120:
40364
+ return "Int8Array";
40365
+ case 5121:
40366
+ return "Uint8Array";
40367
+ case 5122:
40368
+ return "Int16Array";
40369
+ case 5123:
40370
+ return "Uint16Array";
40371
+ case 5125:
40372
+ return "Uint32Array";
40373
+ case 5126:
40374
+ return "Float32Array";
40375
+ default:
40376
+ return "Float32Array";
40377
+ }
40378
+ }
40379
+ _normalizedDenominator(componentType) {
40380
+ switch (componentType) {
40381
+ case 5120:
40382
+ return 127;
40383
+ case 5121:
40384
+ return 255;
40385
+ case 5122:
40386
+ return 32767;
40387
+ case 5123:
40388
+ return 65535;
40389
+ default:
40390
+ return 0;
40391
+ }
40392
+ }
40393
+ _gltfAttributeNameToThreeName(name) {
40394
+ switch (name) {
40395
+ case "POSITION":
40396
+ return "position";
40397
+ case "NORMAL":
40398
+ return "normal";
40399
+ case "TANGENT":
40400
+ return "tangent";
40401
+ case "TEXCOORD_0":
40402
+ return "uv";
40403
+ case "TEXCOORD_1":
40404
+ return "uv2";
40405
+ case "COLOR_0":
40406
+ return "color";
40407
+ case "JOINTS_0":
40408
+ return "skinIndex";
40409
+ case "WEIGHTS_0":
40410
+ return "skinWeight";
40411
+ default:
40412
+ return name.toLowerCase();
40413
+ }
40414
+ }
40415
+ _buildAccessorRequest(structure, accessorIndex, type, primIdx) {
40416
+ const accessor = structure.json.accessors[accessorIndex];
40417
+ const bufferView = structure.json.bufferViews[accessor.bufferView];
40418
+ const components = structure.getNumComponents(accessor.type);
40419
+ const componentSize = structure.getComponentSize(accessor.componentType);
40420
+ const itemBytes = components * componentSize;
40421
+ const accessorByteOffset = accessor.byteOffset || 0;
40422
+ const bvByteOffset = bufferView.byteOffset || 0;
40423
+ const byteStride = bufferView.byteStride || 0;
40424
+ const interleaved = byteStride !== 0 && byteStride !== itemBytes;
40425
+ const offset = bvByteOffset + accessorByteOffset;
40426
+ let length;
40427
+ if (interleaved) {
40428
+ length = (accessor.count - 1) * byteStride + itemBytes;
40429
+ } else {
40430
+ length = accessor.count * itemBytes;
40431
+ }
40432
+ return {
40433
+ offset,
40434
+ length,
40435
+ componentType: accessor.componentType,
40436
+ accessorIndex,
40437
+ type,
40438
+ primIdx,
40439
+ _accessor: accessor,
40440
+ _components: components,
40441
+ _componentSize: componentSize,
40442
+ _itemBytes: itemBytes,
40443
+ _byteStride: byteStride,
40444
+ _interleaved: interleaved,
40445
+ };
40446
+ }
40447
+ _createGeometryAttribute(req) {
40448
+ const accessor = req._accessor;
40449
+ const components = req._components;
40450
+ const count = accessor.count;
40451
+ const stride = req._interleaved ? req._byteStride / req._componentSize : components;
40452
+ const normalized = accessor.normalized === true;
40453
+ const componentType = req.componentType;
40454
+ const src = req.data;
40455
+ if (!req._interleaved && !normalized) {
40456
+ return new BufferAttribute(src, components, false);
40457
+ }
40458
+ if (normalized) {
40459
+ const denom = this._normalizedDenominator(componentType);
40460
+ if (denom > 0) {
40461
+ const out = new Float32Array(count * components);
40462
+ const inv = 1 / denom;
40463
+ const isSignedNormalized = componentType === 5120 || componentType === 5122;
40464
+ for (let i = 0; i < count; i++) {
40465
+ const srcBase = i * stride;
40466
+ const dstBase = i * components;
40467
+ for (let c = 0; c < components; c++) {
40468
+ let v = src[srcBase + c] * inv;
40469
+ if (isSignedNormalized && v < -1) v = -1;
40470
+ out[dstBase + c] = v;
40471
+ }
40472
+ }
40473
+ return new BufferAttribute(out, components, false);
40474
+ }
40475
+ }
40476
+ const TypedArrayCtor = src.constructor;
40477
+ const out = new TypedArrayCtor(count * components);
40478
+ for (let i = 0; i < count; i++) {
40479
+ const srcBase = i * stride;
40480
+ const dstBase = i * components;
40481
+ for (let c = 0; c < components; c++) {
40482
+ out[dstBase + c] = src[srcBase + c];
40483
+ }
40484
+ }
40485
+ return new BufferAttribute(out, components, false);
39093
40486
  }
39094
40487
  createDummyTexture() {
39095
40488
  const data = new Float32Array(16);
@@ -39161,7 +40554,7 @@ void main() {
39161
40554
  if (!this.transformTexture) return;
39162
40555
  this.transformTexture.needsUpdate = true;
39163
40556
  }
39164
- setVisibleEdges(visible) {
40557
+ setVisibleEdges(visible = true) {
39165
40558
  this.visibleEdges = visible;
39166
40559
  }
39167
40560
  getAvailableMemory() {
@@ -39415,78 +40808,51 @@ void main() {
39415
40808
  node.loading = true;
39416
40809
  const meshDef = node.structure.getJson().meshes[node.meshIndex];
39417
40810
  try {
40811
+ if (
40812
+ !this._dracoLoader &&
40813
+ meshDef.primitives &&
40814
+ meshDef.primitives.some((p) => p.extensions && p.extensions[DRACO_EXTENSION_NAME])
40815
+ ) {
40816
+ throw new Error(
40817
+ "primitive uses KHR_draco_mesh_compression but no DRACOLoader is configured. " +
40818
+ "Inject one via dynamicLoader.setDracoLoader(new DRACOLoader()) before opening the file."
40819
+ );
40820
+ }
39418
40821
  const bufferRequests = [];
39419
40822
  const primitiveReqMap = new Map();
40823
+ const dracoPrimitives = new Map();
39420
40824
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39421
40825
  const primitive = meshDef.primitives[primIdx];
39422
40826
  const reqs = [];
39423
- if (primitive.attributes.POSITION !== undefined) {
39424
- const accessorIndex = primitive.attributes.POSITION;
39425
- const accessor = node.structure.json.accessors[accessorIndex];
39426
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39427
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39428
- const components = node.structure.getNumComponents(accessor.type);
39429
- const count = accessor.count;
39430
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39431
- reqs.push({
40827
+ const dracoExt = primitive.extensions && primitive.extensions[DRACO_EXTENSION_NAME];
40828
+ if (dracoExt) {
40829
+ const bufferView = node.structure.json.bufferViews[dracoExt.bufferView];
40830
+ const byteOffset = bufferView.byteOffset || 0;
40831
+ const byteLength = bufferView.byteLength;
40832
+ const dracoReq = {
39432
40833
  offset: byteOffset,
39433
40834
  length: byteLength,
39434
- componentType: accessor.componentType,
39435
- accessorIndex,
39436
- type: "position",
40835
+ componentType: 5121,
40836
+ type: "draco",
39437
40837
  primIdx,
39438
- });
40838
+ };
40839
+ reqs.push(dracoReq);
40840
+ dracoPrimitives.set(primIdx, { req: dracoReq, primitive });
40841
+ primitiveReqMap.set(primIdx, reqs);
40842
+ bufferRequests.push(...reqs);
40843
+ continue;
40844
+ }
40845
+ if (primitive.attributes.POSITION !== undefined) {
40846
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.POSITION, "position", primIdx));
39439
40847
  }
39440
40848
  if (primitive.attributes.NORMAL !== undefined) {
39441
- const accessorIndex = primitive.attributes.NORMAL;
39442
- const accessor = node.structure.json.accessors[accessorIndex];
39443
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39444
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39445
- const components = node.structure.getNumComponents(accessor.type);
39446
- const count = accessor.count;
39447
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39448
- reqs.push({
39449
- offset: byteOffset,
39450
- length: byteLength,
39451
- componentType: accessor.componentType,
39452
- accessorIndex,
39453
- type: "normal",
39454
- primIdx,
39455
- });
40849
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.NORMAL, "normal", primIdx));
39456
40850
  }
39457
40851
  if (primitive.attributes.TEXCOORD_0 !== undefined) {
39458
- const accessorIndex = primitive.attributes.TEXCOORD_0;
39459
- const accessor = node.structure.json.accessors[accessorIndex];
39460
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39461
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39462
- const components = node.structure.getNumComponents(accessor.type);
39463
- const count = accessor.count;
39464
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39465
- reqs.push({
39466
- offset: byteOffset,
39467
- length: byteLength,
39468
- componentType: accessor.componentType,
39469
- accessorIndex,
39470
- type: "uv",
39471
- primIdx,
39472
- });
40852
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.TEXCOORD_0, "uv", primIdx));
39473
40853
  }
39474
40854
  if (primitive.indices !== undefined) {
39475
- const accessorIndex = primitive.indices;
39476
- const accessor = node.structure.json.accessors[accessorIndex];
39477
- const bufferView = node.structure.json.bufferViews[accessor.bufferView];
39478
- const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
39479
- const components = node.structure.getNumComponents(accessor.type);
39480
- const count = accessor.count;
39481
- const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
39482
- reqs.push({
39483
- offset: byteOffset,
39484
- length: byteLength,
39485
- componentType: accessor.componentType,
39486
- accessorIndex,
39487
- type: "index",
39488
- primIdx,
39489
- });
40855
+ reqs.push(this._buildAccessorRequest(node.structure, primitive.indices, "index", primIdx));
39490
40856
  }
39491
40857
  primitiveReqMap.set(primIdx, reqs);
39492
40858
  bufferRequests.push(...reqs);
@@ -39512,29 +40878,31 @@ void main() {
39512
40878
  }
39513
40879
  for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
39514
40880
  const primitive = meshDef.primitives[primIdx];
39515
- const geometry = new BufferGeometry();
39516
40881
  const reqs = primitiveReqMap.get(primIdx);
39517
- if (primitive.attributes.POSITION !== undefined) {
39518
- const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
39519
- const accessor = node.structure.json.accessors[primitive.attributes.POSITION];
39520
- const components = node.structure.getNumComponents(accessor.type);
39521
- geometry.setAttribute("position", new BufferAttribute(req.data, components));
39522
- }
39523
- if (primitive.attributes.NORMAL !== undefined) {
39524
- const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
39525
- const accessor = node.structure.json.accessors[primitive.attributes.NORMAL];
39526
- const components = node.structure.getNumComponents(accessor.type);
39527
- geometry.setAttribute("normal", new BufferAttribute(req.data, components));
39528
- }
39529
- if (primitive.attributes.TEXCOORD_0 !== undefined) {
39530
- const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
39531
- const accessor = node.structure.json.accessors[primitive.attributes.TEXCOORD_0];
39532
- const components = node.structure.getNumComponents(accessor.type);
39533
- geometry.setAttribute("uv", new BufferAttribute(req.data, components));
39534
- }
39535
- if (primitive.indices !== undefined) {
39536
- const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
39537
- geometry.setIndex(new BufferAttribute(req.data, 1));
40882
+ let geometry;
40883
+ if (dracoPrimitives.has(primIdx)) {
40884
+ const dracoReq = reqs.find((r) => r.type === "draco");
40885
+ const dracoBytes = new Uint8Array(dracoReq.data.buffer, dracoReq.data.byteOffset, dracoReq.data.byteLength);
40886
+ const dracoBuffer = dracoBytes.slice().buffer;
40887
+ geometry = await this._decodeDracoPrimitive(node.structure, primitive, dracoBuffer);
40888
+ } else {
40889
+ geometry = new BufferGeometry();
40890
+ if (primitive.attributes.POSITION !== undefined) {
40891
+ const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
40892
+ geometry.setAttribute("position", this._createGeometryAttribute(req));
40893
+ }
40894
+ if (primitive.attributes.NORMAL !== undefined) {
40895
+ const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
40896
+ geometry.setAttribute("normal", this._createGeometryAttribute(req));
40897
+ }
40898
+ if (primitive.attributes.TEXCOORD_0 !== undefined) {
40899
+ const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
40900
+ geometry.setAttribute("uv", this._createGeometryAttribute(req));
40901
+ }
40902
+ if (primitive.indices !== undefined) {
40903
+ const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
40904
+ geometry.setIndex(this._createGeometryAttribute(req));
40905
+ }
39538
40906
  }
39539
40907
  let material;
39540
40908
  if (primitive.material !== undefined) {
@@ -39773,20 +41141,43 @@ void main() {
39773
41141
  const nodeMatrix = new Matrix4();
39774
41142
  const uniqueNodeId = `${structure.id}_${nodeId}`;
39775
41143
  const meshDef = structure.json.meshes[nodeDef.mesh];
41144
+ if (!meshDef || !meshDef.primitives || meshDef.primitives.length === 0) {
41145
+ if (nodeDef.children) {
41146
+ for (const childId of nodeDef.children) {
41147
+ await this.processNodeHierarchy(structure, childId, nodeGroup || parentGroup);
41148
+ }
41149
+ }
41150
+ return nodeGroup;
41151
+ }
39776
41152
  const geometryExtents = new Box3();
39777
41153
  for (const primitive of meshDef.primitives) {
41154
+ if (!primitive.attributes) continue;
39778
41155
  const positionAccessor = structure.json.accessors[primitive.attributes.POSITION];
39779
41156
  if (positionAccessor && positionAccessor.min && positionAccessor.max) {
39780
- const primitiveBox = new Box3(
39781
- new Vector3().fromArray(positionAccessor.min),
39782
- new Vector3().fromArray(positionAccessor.max)
39783
- );
39784
- geometryExtents.union(primitiveBox);
41157
+ const minVec = new Vector3().fromArray(positionAccessor.min);
41158
+ const maxVec = new Vector3().fromArray(positionAccessor.max);
41159
+ if (positionAccessor.normalized === true) {
41160
+ const denom = this._normalizedDenominator(positionAccessor.componentType);
41161
+ if (denom > 0) {
41162
+ minVec.divideScalar(denom);
41163
+ maxVec.divideScalar(denom);
41164
+ if (positionAccessor.componentType === 5120 || positionAccessor.componentType === 5122) {
41165
+ minVec.x = Math.max(minVec.x, -1);
41166
+ minVec.y = Math.max(minVec.y, -1);
41167
+ minVec.z = Math.max(minVec.z, -1);
41168
+ maxVec.x = Math.max(maxVec.x, -1);
41169
+ maxVec.y = Math.max(maxVec.y, -1);
41170
+ maxVec.z = Math.max(maxVec.z, -1);
41171
+ }
41172
+ }
41173
+ }
41174
+ geometryExtents.union(new Box3(minVec, maxVec));
39785
41175
  }
39786
41176
  }
39787
41177
  let isEdge = false;
39788
- if (meshDef.primitives[0].material !== undefined) {
39789
- const material = structure.json.materials[meshDef.primitives[0].material];
41178
+ const firstPrimitive = meshDef.primitives[0];
41179
+ if (firstPrimitive && firstPrimitive.material !== undefined) {
41180
+ const material = structure.json.materials[firstPrimitive.material];
39790
41181
  if (material?.name === "edges") {
39791
41182
  isEdge = true;
39792
41183
  }
@@ -40099,6 +41490,10 @@ void main() {
40099
41490
  vec3 objectNormal = vec3( normal );
40100
41491
  mat3 bm = mat3( batchingMatrix );
40101
41492
  objectNormal = bm * objectNormal;
41493
+ #ifdef USE_TANGENT
41494
+ vec3 objectTangent = vec3( tangent.xyz );
41495
+ objectTangent = bm * objectTangent;
41496
+ #endif
40102
41497
  `
40103
41498
  );
40104
41499
  }
@@ -41271,7 +42666,7 @@ void main() {
41271
42666
  }
41272
42667
  return extent;
41273
42668
  }
41274
- setMaxConcurrentChunks(maxChunks) {
42669
+ setMaxConcurrentChunks(maxChunks = 6) {
41275
42670
  if (maxChunks < 1) {
41276
42671
  console.warn("Max concurrent chunks must be at least 1");
41277
42672
  return;
@@ -41373,10 +42768,10 @@ void main() {
41373
42768
  }
41374
42769
  offset += chunkLength;
41375
42770
  }
41376
- if (typeof this.content === "undefined") {
42771
+ if (this.content === undefined) {
41377
42772
  throw new Error("GLTFBinaryParser: JSON content not found.");
41378
42773
  }
41379
- if (typeof this.body === "undefined") {
42774
+ if (this.body === undefined) {
41380
42775
  throw new Error("GLTFBinaryParser: Binary buffer chunk not found or type not supported.");
41381
42776
  }
41382
42777
  }
@@ -42702,16 +44097,18 @@ void main() {
42702
44097
  if (this.manager)
42703
44098
  this.manager.dispose();
42704
44099
  }
42705
- isSupport(file, format) {
44100
+ isSupport(file, format = "") {
42706
44101
  return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
42707
44102
  /(gltf|glb)$/i.test(format));
42708
44103
  }
42709
- async load(file, format, params) {
44104
+ async load(file, format, params = {}) {
42710
44105
  this.manager = new GLTFLoadingManager(file, params);
42711
44106
  const scene = new Group$1();
42712
44107
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42713
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
42714
- this.gltfLoader.visibleEdges = this.viewer.options.edgeModel;
44108
+ this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
44109
+ this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
44110
+ this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
44111
+ this.gltfLoader.setDracoLoader(params.dracoLoader);
42715
44112
  const modelImpl = new DynamicModelImpl(scene);
42716
44113
  modelImpl.id = params.modelId || this.extractFileName(file);
42717
44114
  modelImpl.gltfLoader = this.gltfLoader;
@@ -42798,8 +44195,10 @@ void main() {
42798
44195
  async load(model, format, params = {}) {
42799
44196
  const scene = new Group$1();
42800
44197
  this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
42801
- this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
44198
+ this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
42802
44199
  this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
44200
+ this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
44201
+ this.gltfLoader.setDracoLoader(params.dracoLoader);
42803
44202
  const modelImpl = new DynamicModelImpl(scene);
42804
44203
  modelImpl.id = model.file.id;
42805
44204
  modelImpl.gltfLoader = this.gltfLoader;
@@ -44015,186 +45414,133 @@ void main() {
44015
45414
  }
44016
45415
 
44017
45416
  class SSAARenderPass extends Pass {
44018
- constructor(scenes, camera, clearColor = 0x000000, clearAlpha = 0) {
44019
- super();
44020
- this.scenes = Array.isArray(scenes) ? scenes : [scenes];
44021
- this.camera = camera;
44022
- this.sampleLevel = 2;
44023
- this.unbiased = true;
44024
- this.stencilBuffer = false;
44025
- this.clearColor = clearColor;
44026
- this.clearAlpha = clearAlpha;
44027
- this._sampleRenderTarget = null;
44028
- this._oldClearColor = new Color();
44029
- this._copyUniforms = UniformsUtils.clone(CopyShader.uniforms);
44030
- this._copyMaterial = new ShaderMaterial({
44031
- uniforms: this._copyUniforms,
44032
- vertexShader: CopyShader.vertexShader,
44033
- fragmentShader: CopyShader.fragmentShader,
44034
- transparent: true,
44035
- depthTest: false,
44036
- depthWrite: false,
44037
- premultipliedAlpha: true,
44038
- blending: AdditiveBlending,
44039
- });
44040
- this._fsQuad = new FullScreenQuad(this._copyMaterial);
44041
- }
44042
- dispose() {
44043
- if (this._sampleRenderTarget) {
44044
- this._sampleRenderTarget.dispose();
44045
- this._sampleRenderTarget = null;
44046
- }
44047
- this._copyMaterial.dispose();
44048
- this._fsQuad.dispose();
44049
- }
44050
- setSize(width, height) {
44051
- if (this._sampleRenderTarget) this._sampleRenderTarget.setSize(width, height);
44052
- }
44053
- render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
44054
- if (!this._sampleRenderTarget) {
44055
- this._sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, {
44056
- type: HalfFloatType,
44057
- stencilBuffer: this.stencilBuffer,
44058
- });
44059
- this._sampleRenderTarget.texture.name = "SSAAMultiRenderPass.sample";
44060
- }
44061
- const jitterOffsets = _JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))];
44062
- const autoClear = renderer.autoClear;
44063
- renderer.autoClear = false;
44064
- renderer.getClearColor(this._oldClearColor);
44065
- const oldClearAlpha = renderer.getClearAlpha();
44066
- const baseSampleWeight = 1.0 / jitterOffsets.length;
44067
- const roundingRange = 1 / 32;
44068
- this._copyUniforms["tDiffuse"].value = this._sampleRenderTarget.texture;
44069
- const viewOffset = {
44070
- fullWidth: readBuffer.width,
44071
- fullHeight: readBuffer.height,
44072
- offsetX: 0,
44073
- offsetY: 0,
44074
- width: readBuffer.width,
44075
- height: readBuffer.height,
44076
- };
44077
- const originalViewOffset = Object.assign({}, this.camera.view);
44078
- if (originalViewOffset.enabled) Object.assign(viewOffset, originalViewOffset);
44079
- for (let i = 0; i < jitterOffsets.length; i++) {
44080
- const jitterOffset = jitterOffsets[i];
44081
- if (this.camera.setViewOffset) {
44082
- this.camera.setViewOffset(
44083
- viewOffset.fullWidth,
44084
- viewOffset.fullHeight,
44085
- viewOffset.offsetX + jitterOffset[0] * 0.0625,
44086
- viewOffset.offsetY + jitterOffset[1] * 0.0625,
44087
- viewOffset.width,
44088
- viewOffset.height
44089
- );
44090
- }
44091
- let sampleWeight = baseSampleWeight;
44092
- if (this.unbiased) {
44093
- const uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length;
44094
- sampleWeight += roundingRange * uniformCenteredDistribution;
44095
- }
44096
- this._copyUniforms["opacity"].value = sampleWeight;
44097
- renderer.setClearColor(this.clearColor, this.clearAlpha);
44098
- renderer.setRenderTarget(this._sampleRenderTarget);
44099
- renderer.clear();
44100
- this.scenes.forEach((scene) => renderer.render(scene, this.camera));
44101
- renderer.setRenderTarget(this.renderToScreen ? null : writeBuffer);
44102
- if (i === 0) {
44103
- renderer.setClearColor(0x000000, 0.0);
44104
- renderer.clear();
44105
- }
44106
- this._fsQuad.render(renderer);
44107
- }
44108
- if (this.camera.setViewOffset && originalViewOffset.enabled) {
44109
- this.camera.setViewOffset(
44110
- originalViewOffset.fullWidth,
44111
- originalViewOffset.fullHeight,
44112
- originalViewOffset.offsetX,
44113
- originalViewOffset.offsetY,
44114
- originalViewOffset.width,
44115
- originalViewOffset.height
44116
- );
44117
- } else if (this.camera.clearViewOffset) {
44118
- this.camera.clearViewOffset();
44119
- }
44120
- renderer.autoClear = autoClear;
44121
- renderer.setClearColor(this._oldClearColor, oldClearAlpha);
44122
- }
45417
+ constructor( scene, camera, clearColor = 0x000000, clearAlpha = 0 ) {
45418
+ super();
45419
+ this.scene = scene;
45420
+ this.camera = camera;
45421
+ this.sampleLevel = 4;
45422
+ this.unbiased = true;
45423
+ this.stencilBuffer = false;
45424
+ this.clearColor = clearColor;
45425
+ this.clearAlpha = clearAlpha;
45426
+ this._sampleRenderTarget = null;
45427
+ this._oldClearColor = new Color();
45428
+ this._copyUniforms = UniformsUtils.clone( CopyShader.uniforms );
45429
+ this._copyMaterial = new ShaderMaterial( {
45430
+ uniforms: this._copyUniforms,
45431
+ vertexShader: CopyShader.vertexShader,
45432
+ fragmentShader: CopyShader.fragmentShader,
45433
+ transparent: true,
45434
+ depthTest: false,
45435
+ depthWrite: false,
45436
+ premultipliedAlpha: true,
45437
+ blending: AdditiveBlending
45438
+ } );
45439
+ this._fsQuad = new FullScreenQuad( this._copyMaterial );
45440
+ }
45441
+ dispose() {
45442
+ if ( this._sampleRenderTarget ) {
45443
+ this._sampleRenderTarget.dispose();
45444
+ this._sampleRenderTarget = null;
45445
+ }
45446
+ this._copyMaterial.dispose();
45447
+ this._fsQuad.dispose();
45448
+ }
45449
+ setSize( width, height ) {
45450
+ if ( this._sampleRenderTarget ) this._sampleRenderTarget.setSize( width, height );
45451
+ }
45452
+ render( renderer, writeBuffer, readBuffer ) {
45453
+ if ( ! this._sampleRenderTarget ) {
45454
+ this._sampleRenderTarget = new WebGLRenderTarget( readBuffer.width, readBuffer.height, { type: HalfFloatType, stencilBuffer: this.stencilBuffer } );
45455
+ this._sampleRenderTarget.texture.name = 'SSAARenderPass.sample';
45456
+ }
45457
+ const jitterOffsets = _JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ];
45458
+ const autoClear = renderer.autoClear;
45459
+ renderer.autoClear = false;
45460
+ renderer.getClearColor( this._oldClearColor );
45461
+ const oldClearAlpha = renderer.getClearAlpha();
45462
+ const baseSampleWeight = 1.0 / jitterOffsets.length;
45463
+ const roundingRange = 1 / 32;
45464
+ this._copyUniforms[ 'tDiffuse' ].value = this._sampleRenderTarget.texture;
45465
+ const viewOffset = {
45466
+ fullWidth: readBuffer.width,
45467
+ fullHeight: readBuffer.height,
45468
+ offsetX: 0,
45469
+ offsetY: 0,
45470
+ width: readBuffer.width,
45471
+ height: readBuffer.height
45472
+ };
45473
+ const originalViewOffset = Object.assign( {}, this.camera.view );
45474
+ if ( originalViewOffset.enabled ) Object.assign( viewOffset, originalViewOffset );
45475
+ for ( let i = 0; i < jitterOffsets.length; i ++ ) {
45476
+ const jitterOffset = jitterOffsets[ i ];
45477
+ if ( this.camera.setViewOffset ) {
45478
+ this.camera.setViewOffset(
45479
+ viewOffset.fullWidth, viewOffset.fullHeight,
45480
+ viewOffset.offsetX + jitterOffset[ 0 ] * 0.0625, viewOffset.offsetY + jitterOffset[ 1 ] * 0.0625,
45481
+ viewOffset.width, viewOffset.height
45482
+ );
45483
+ }
45484
+ let sampleWeight = baseSampleWeight;
45485
+ if ( this.unbiased ) {
45486
+ const uniformCenteredDistribution = ( -0.5 + ( i + 0.5 ) / jitterOffsets.length );
45487
+ sampleWeight += roundingRange * uniformCenteredDistribution;
45488
+ }
45489
+ this._copyUniforms[ 'opacity' ].value = sampleWeight;
45490
+ renderer.setClearColor( this.clearColor, this.clearAlpha );
45491
+ renderer.setRenderTarget( this._sampleRenderTarget );
45492
+ renderer.clear();
45493
+ renderer.render( this.scene, this.camera );
45494
+ renderer.setRenderTarget( this.renderToScreen ? null : writeBuffer );
45495
+ if ( i === 0 ) {
45496
+ renderer.setClearColor( 0x000000, 0.0 );
45497
+ renderer.clear();
45498
+ }
45499
+ this._fsQuad.render( renderer );
45500
+ }
45501
+ if ( this.camera.setViewOffset && originalViewOffset.enabled ) {
45502
+ this.camera.setViewOffset(
45503
+ originalViewOffset.fullWidth, originalViewOffset.fullHeight,
45504
+ originalViewOffset.offsetX, originalViewOffset.offsetY,
45505
+ originalViewOffset.width, originalViewOffset.height
45506
+ );
45507
+ } else if ( this.camera.clearViewOffset ) {
45508
+ this.camera.clearViewOffset();
45509
+ }
45510
+ renderer.autoClear = autoClear;
45511
+ renderer.setClearColor( this._oldClearColor, oldClearAlpha );
45512
+ }
44123
45513
  }
44124
45514
  const _JitterVectors = [
44125
- [[0, 0]],
44126
- [
44127
- [4, 4],
44128
- [-4, -4],
44129
- ],
44130
- [
44131
- [-2, -6],
44132
- [6, -2],
44133
- [-6, 2],
44134
- [2, 6],
44135
- ],
44136
- [
44137
- [1, -3],
44138
- [-1, 3],
44139
- [5, 1],
44140
- [-3, -5],
44141
- [-5, 5],
44142
- [-7, -1],
44143
- [3, 7],
44144
- [7, -7],
44145
- ],
44146
- [
44147
- [1, 1],
44148
- [-1, -3],
44149
- [-3, 2],
44150
- [4, -1],
44151
- [-5, -2],
44152
- [2, 5],
44153
- [5, 3],
44154
- [3, -5],
44155
- [-2, 6],
44156
- [0, -7],
44157
- [-4, -6],
44158
- [-6, 4],
44159
- [-8, 0],
44160
- [7, -4],
44161
- [6, 7],
44162
- [-7, -8],
44163
- ],
44164
- [
44165
- [-4, -7],
44166
- [-7, -5],
44167
- [-3, -5],
44168
- [-5, -4],
44169
- [-1, -4],
44170
- [-2, -2],
44171
- [-6, -1],
44172
- [-4, 0],
44173
- [-7, 1],
44174
- [-1, 2],
44175
- [-6, 3],
44176
- [-3, 3],
44177
- [-7, 6],
44178
- [-3, 6],
44179
- [-5, 7],
44180
- [-1, 7],
44181
- [5, -7],
44182
- [1, -6],
44183
- [6, -5],
44184
- [4, -4],
44185
- [2, -3],
44186
- [7, -2],
44187
- [1, -1],
44188
- [4, -1],
44189
- [2, 1],
44190
- [6, 2],
44191
- [0, 4],
44192
- [4, 4],
44193
- [2, 5],
44194
- [7, 5],
44195
- [5, 6],
44196
- [3, 7],
44197
- ],
45515
+ [
45516
+ [ 0, 0 ]
45517
+ ],
45518
+ [
45519
+ [ 4, 4 ], [ -4, -4 ]
45520
+ ],
45521
+ [
45522
+ [ -2, -6 ], [ 6, -2 ], [ -6, 2 ], [ 2, 6 ]
45523
+ ],
45524
+ [
45525
+ [ 1, -3 ], [ -1, 3 ], [ 5, 1 ], [ -3, -5 ],
45526
+ [ -5, 5 ], [ -7, -1 ], [ 3, 7 ], [ 7, -7 ]
45527
+ ],
45528
+ [
45529
+ [ 1, 1 ], [ -1, -3 ], [ -3, 2 ], [ 4, -1 ],
45530
+ [ -5, -2 ], [ 2, 5 ], [ 5, 3 ], [ 3, -5 ],
45531
+ [ -2, 6 ], [ 0, -7 ], [ -4, -6 ], [ -6, 4 ],
45532
+ [ -8, 0 ], [ 7, -4 ], [ 6, 7 ], [ -7, -8 ]
45533
+ ],
45534
+ [
45535
+ [ -4, -7 ], [ -7, -5 ], [ -3, -5 ], [ -5, -4 ],
45536
+ [ -1, -4 ], [ -2, -2 ], [ -6, -1 ], [ -4, 0 ],
45537
+ [ -7, 1 ], [ -1, 2 ], [ -6, 3 ], [ -3, 3 ],
45538
+ [ -7, 6 ], [ -3, 6 ], [ -5, 7 ], [ -1, 7 ],
45539
+ [ 5, -7 ], [ 1, -6 ], [ 6, -5 ], [ 4, -4 ],
45540
+ [ 2, -3 ], [ 7, -2 ], [ 1, -1 ], [ 4, -1 ],
45541
+ [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ],
45542
+ [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]
45543
+ ]
44198
45544
  ];
44199
45545
 
44200
45546
  const OutputShader = {
@@ -57135,8 +58481,8 @@ js: import "konva/skia-backend";
57135
58481
  this.lineWidth = 4;
57136
58482
  this.lineType = "solid";
57137
58483
  this.fontSize = 34;
57138
- this.changeActiveDragger = (event) => {
57139
- const draggerName = event.data;
58484
+ this.changeActiveDragger = ({ data }) => {
58485
+ const draggerName = data || "";
57140
58486
  this._markupContainer.className = this._container.className
57141
58487
  .split(" ")
57142
58488
  .filter((x) => !x.startsWith("oda-cursor-"))
@@ -57197,19 +58543,19 @@ js: import "konva/skia-backend";
57197
58543
  this._resizeObserver = new ResizeObserver(this.resizeContainer);
57198
58544
  this._resizeObserver.observe(container);
57199
58545
  if (this._viewer) {
57200
- this._viewer.addEventListener("changeactivedragger", this.changeActiveDragger);
57201
- this._viewer.addEventListener("pan", this.pan);
57202
- this._viewer.addEventListener("zoomat", this.zoomAt);
57203
- this._viewer.addEventListener("changecameramode", this.changeCameraMode);
58546
+ this._viewer.on("changeactivedragger", this.changeActiveDragger);
58547
+ this._viewer.on("pan", this.pan);
58548
+ this._viewer.on("zoomat", this.zoomAt);
58549
+ this._viewer.on("changecameramode", this.changeCameraMode);
57204
58550
  }
57205
58551
  }
57206
58552
  dispose() {
57207
58553
  var _a, _b;
57208
58554
  if (this._viewer) {
57209
- this._viewer.removeEventListener("changecameramode", this.changeCameraMode);
57210
- this._viewer.removeEventListener("zoomat", this.zoomAt);
57211
- this._viewer.removeEventListener("pan", this.pan);
57212
- this._viewer.removeEventListener("changeactivedragger", this.changeActiveDragger);
58555
+ this._viewer.off("changecameramode", this.changeCameraMode);
58556
+ this._viewer.off("zoomat", this.zoomAt);
58557
+ this._viewer.off("pan", this.pan);
58558
+ this._viewer.off("changeactivedragger", this.changeActiveDragger);
57213
58559
  }
57214
58560
  (_a = this._resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
57215
58561
  this._resizeObserver = undefined;
@@ -57968,24 +59314,6 @@ js: import "konva/skia-backend";
57968
59314
  }
57969
59315
  }
57970
59316
 
57971
- class Helpers extends Scene {
57972
- constructor() {
57973
- super(...arguments);
57974
- this.oldAutoClear = false;
57975
- this.oldClippingPlanes = [];
57976
- }
57977
- onBeforeRender(renderer) {
57978
- this.oldAutoClear = renderer.autoClear;
57979
- this.oldClippingPlanes = renderer.clippingPlanes;
57980
- renderer.autoClear = false;
57981
- renderer.clippingPlanes = [];
57982
- }
57983
- onAfterRender(renderer) {
57984
- renderer.clippingPlanes = this.oldClippingPlanes;
57985
- renderer.autoClear = this.oldAutoClear;
57986
- }
57987
- }
57988
-
57989
59317
  class Viewer extends EventEmitter2 {
57990
59318
  constructor(client) {
57991
59319
  super();
@@ -57999,9 +59327,9 @@ js: import "konva/skia-backend";
57999
59327
  this.selected = [];
58000
59328
  this.extents = new Box3();
58001
59329
  this.target = new Vector3(0, 0, 0);
59330
+ this.clippingPlanes = [];
58002
59331
  this._activeDragger = null;
58003
59332
  this._components = [];
58004
- this._updateDelay = 1000;
58005
59333
  this._renderNeeded = false;
58006
59334
  this._renderTime = 0;
58007
59335
  this.render = this.render.bind(this);
@@ -58020,7 +59348,9 @@ js: import "konva/skia-backend";
58020
59348
  initialize(canvas, onProgress) {
58021
59349
  this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
58022
59350
  this.scene = new Scene();
58023
- this.helpers = new Helpers();
59351
+ this.helpers = new Group$1();
59352
+ this.helpers.name = "Helpers";
59353
+ this.scene.add(this.helpers);
58024
59354
  const pixelRatio = window.devicePixelRatio;
58025
59355
  const rect = canvas.parentElement.getBoundingClientRect();
58026
59356
  const width = rect.width || 1;
@@ -58042,17 +59372,17 @@ js: import "konva/skia-backend";
58042
59372
  this.renderer.setPixelRatio(pixelRatio);
58043
59373
  this.renderer.setSize(width, height);
58044
59374
  this.renderer.outputColorSpace = LinearSRGBColorSpace;
59375
+ this.renderer.localClippingEnabled = true;
58045
59376
  this.renderPass = new RenderPass(this.scene, this.camera);
58046
- this.helpersPass = new RenderPass(this.helpers, this.camera);
58047
- this.helpersPass.clear = false;
58048
59377
  this.fxaaPass = new FXAAPass();
58049
59378
  this.smaaPass = new SMAAPass();
58050
- this.ssaaRenderPass = new SSAARenderPass([this.scene, this.helpers], this.camera);
59379
+ this.ssaaRenderPass = new SSAARenderPass(this.scene, this.camera);
58051
59380
  this.ssaaRenderPass.unbiased = true;
58052
59381
  this.outputPass = new OutputPass();
58053
- this.composer = new EffectComposer(this.renderer);
59382
+ const renderTarget = new WebGLRenderTarget(1, 1, { samples: 4 });
59383
+ renderTarget.texture.name = "EffectComposer.rt1";
59384
+ this.composer = new EffectComposer(this.renderer, renderTarget);
58054
59385
  this.composer.addPass(this.renderPass);
58055
- this.composer.addPass(this.helpersPass);
58056
59386
  this.composer.addPass(this.smaaPass);
58057
59387
  this.composer.addPass(this.fxaaPass);
58058
59388
  this.composer.addPass(this.ssaaRenderPass);
@@ -58062,7 +59392,9 @@ js: import "konva/skia-backend";
58062
59392
  this.canvasEvents.forEach((x) => canvas.addEventListener(x, this.canvaseventlistener));
58063
59393
  this._markup.initialize(this.canvas, this.canvasEvents, this, this);
58064
59394
  for (const name of components.getComponents().keys()) {
58065
- this._components.push(components.createComponent(name, this));
59395
+ const component = components.createComponent(name, this);
59396
+ if (component)
59397
+ this._components.push(component);
58066
59398
  }
58067
59399
  this.syncOptions();
58068
59400
  this.syncOverlay();
@@ -58083,7 +59415,7 @@ js: import "konva/skia-backend";
58083
59415
  this.removeAllListeners();
58084
59416
  this.setActiveDragger();
58085
59417
  this._components.forEach((component) => component.dispose());
58086
- this._components = [];
59418
+ this._components.length = 0;
58087
59419
  this._markup.dispose();
58088
59420
  if (this.canvas) {
58089
59421
  this.canvasEvents.forEach((x) => this.canvas.removeEventListener(x, this.canvaseventlistener));
@@ -58093,8 +59425,6 @@ js: import "konva/skia-backend";
58093
59425
  this.composer.dispose();
58094
59426
  if (this.renderPass)
58095
59427
  this.renderPass.dispose();
58096
- if (this.helpersPass)
58097
- this.helpersPass.dispose();
58098
59428
  if (this.fxaaPass)
58099
59429
  this.fxaaPass.dispose();
58100
59430
  if (this.smaaPass)
@@ -58110,7 +59440,6 @@ js: import "konva/skia-backend";
58110
59440
  this.camera = undefined;
58111
59441
  this.renderer = undefined;
58112
59442
  this.renderPass = undefined;
58113
- this.helpersPass = undefined;
58114
59443
  this.fxaaPass = undefined;
58115
59444
  this.smaaPass = undefined;
58116
59445
  this.ssaaRenderPass = undefined;
@@ -58142,11 +59471,12 @@ js: import "konva/skia-backend";
58142
59471
  }
58143
59472
  update(force = false) {
58144
59473
  const time = performance.now();
58145
- force = force || time - this._renderTime >= this._updateDelay;
59474
+ if (typeof force === "number" && time - this._renderTime >= force)
59475
+ force = true;
58146
59476
  this._renderNeeded = true;
58147
59477
  if (force)
58148
59478
  this.render(time);
58149
- this.emitEvent({ type: "update", force });
59479
+ this.emitEvent({ type: "update", force: !!force });
58150
59480
  }
58151
59481
  render(time, force = false) {
58152
59482
  if (!this.renderer)
@@ -58160,13 +59490,7 @@ js: import "konva/skia-backend";
58160
59490
  this._renderNeeded = false;
58161
59491
  this.renderer.info.autoReset = false;
58162
59492
  this.renderer.info.reset();
58163
- if (this.options.antialiasing === true || this.options.antialiasing === "msaa") {
58164
- this.renderer.render(this.scene, this.camera);
58165
- this.renderer.render(this.helpers, this.camera);
58166
- }
58167
- else {
58168
- this.composer.render(deltaTime);
58169
- }
59493
+ this.composer.render(deltaTime);
58170
59494
  this.emitEvent({ type: "render", time, deltaTime });
58171
59495
  }
58172
59496
  loadReferences(model) {
@@ -58226,11 +59550,12 @@ js: import "konva/skia-backend";
58226
59550
  this.clearOverlay();
58227
59551
  this.clearSelected();
58228
59552
  this.loaders.forEach((loader) => loader.dispose());
58229
- this.loaders = [];
59553
+ this.loaders.length = 0;
58230
59554
  this.models.forEach((model) => model.dispose());
58231
- this.models = [];
58232
- this.scene.clear();
59555
+ this.models.length = 0;
58233
59556
  this.helpers.clear();
59557
+ this.scene.clear();
59558
+ this.scene.add(this.helpers);
58234
59559
  this.extents.makeEmpty();
58235
59560
  this.syncOptions();
58236
59561
  this.syncOverlay();
@@ -58247,8 +59572,15 @@ js: import "konva/skia-backend";
58247
59572
  this.fxaaPass.enabled = options.antialiasing === "fxaa";
58248
59573
  this.smaaPass.enabled = options.antialiasing === "smaa";
58249
59574
  this.ssaaRenderPass.enabled = options.antialiasing === "ssaa";
58250
- this.renderPass.enabled = !this.ssaaRenderPass.enabled;
58251
- this.helpersPass.enabled = !this.ssaaRenderPass.enabled;
59575
+ this.renderPass.enabled = options.antialiasing !== "ssaa";
59576
+ const samples = options.antialiasing === true || options.antialiasing === "msaa" ? 4 : 0;
59577
+ if (this.composer.renderTarget1.samples !== samples) {
59578
+ const size = this.renderer.getSize(new Vector2());
59579
+ const newRenderTarget = new WebGLRenderTarget(1, 1, { samples });
59580
+ newRenderTarget.texture.name = "EffectComposer.rt1";
59581
+ this.composer.reset(newRenderTarget);
59582
+ this.composer.setSize(size.x, size.y);
59583
+ }
58252
59584
  this.update();
58253
59585
  }
58254
59586
  syncOverlay() {
@@ -58267,7 +59599,8 @@ js: import "konva/skia-backend";
58267
59599
  clearSlices() {
58268
59600
  if (!this.renderer)
58269
59601
  return;
58270
- this.renderer.clippingPlanes = [];
59602
+ this.clippingPlanes.length = 0;
59603
+ this.emitEvent({ type: "changecuttingplanes" });
58271
59604
  this.emitEvent({ type: "clearslices" });
58272
59605
  this.update();
58273
59606
  }
@@ -58336,7 +59669,7 @@ js: import "konva/skia-backend";
58336
59669
  }
58337
59670
  }
58338
59671
  getComponent(name) {
58339
- return this._components.find((component) => component.name === name);
59672
+ return this._components.find((component) => component.name === name) || null;
58340
59673
  }
58341
59674
  drawViewpoint(viewpoint) {
58342
59675
  var _a, _b, _c, _d;
@@ -58363,7 +59696,6 @@ js: import "konva/skia-backend";
58363
59696
  camera.updateMatrixWorld();
58364
59697
  this.camera = camera;
58365
59698
  this.renderPass.camera = camera;
58366
- this.helpersPass.camera = camera;
58367
59699
  this.ssaaRenderPass.camera = camera;
58368
59700
  this.options.cameraMode = "orthographic";
58369
59701
  this.emitEvent({ type: "changecameramode", mode: "orthographic" });
@@ -58386,7 +59718,6 @@ js: import "konva/skia-backend";
58386
59718
  camera.updateMatrixWorld();
58387
59719
  this.camera = camera;
58388
59720
  this.renderPass.camera = camera;
58389
- this.helpersPass.camera = camera;
58390
59721
  this.ssaaRenderPass.camera = camera;
58391
59722
  this.options.cameraMode = "perspective";
58392
59723
  this.emitEvent({ type: "changecameramode", mode: "perspective" });
@@ -58397,8 +59728,9 @@ js: import "konva/skia-backend";
58397
59728
  clipping_planes.forEach((clipping_plane) => {
58398
59729
  const plane = new Plane();
58399
59730
  plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
58400
- this.renderer.clippingPlanes.push(plane);
59731
+ this.clippingPlanes.push(plane);
58401
59732
  });
59733
+ this.emitEvent({ type: "changecuttingplanes" });
58402
59734
  }
58403
59735
  };
58404
59736
  const setSelection = (selection) => {
@@ -58453,7 +59785,7 @@ js: import "konva/skia-backend";
58453
59785
  };
58454
59786
  const getClippingPlanes = () => {
58455
59787
  const clipping_planes = [];
58456
- this.renderer.clippingPlanes.forEach((plane) => {
59788
+ this.clippingPlanes.forEach((plane) => {
58457
59789
  const clipping_plane = {
58458
59790
  location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3())),
58459
59791
  direction: getPoint3dFromVector3(plane.normal),