@xeokit/xeokit-sdk 2.6.72 → 2.6.75

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 (60) hide show
  1. package/dist/xeokit-sdk.cjs.js +985 -400
  2. package/dist/xeokit-sdk.es.js +980 -401
  3. package/dist/xeokit-sdk.es5.js +734 -714
  4. package/dist/xeokit-sdk.min.cjs.js +8 -8
  5. package/dist/xeokit-sdk.min.es.js +8 -8
  6. package/dist/xeokit-sdk.min.es5.js +7 -7
  7. package/package.json +1 -1
  8. package/src/extras/ContextMenu/ContextMenu.js +25 -16
  9. package/src/plugins/FastNavPlugin/FastNavPlugin.js +10 -0
  10. package/src/plugins/SkyboxesPlugin/SkyboxesPlugin.js +24 -49
  11. package/src/plugins/TreeViewPlugin/RenderService.js +13 -4
  12. package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +1 -1
  13. package/src/viewer/Viewer.js +0 -16
  14. package/src/viewer/scene/CameraControl/lib/controllers/PivotController.js +29 -8
  15. package/src/viewer/scene/LineSet/LineSet.js +7 -2
  16. package/src/viewer/scene/skybox/Skybox.js +110 -9
  17. package/types/plugins/SkyboxesPlugin/SkyboxesPlugin.d.ts +18 -4
  18. package/types/viewer/scene/CameraControl/CameraControl.d.ts +168 -0
  19. package/types/viewer/scene/LineSet/LineSet.d.ts +1 -1
  20. package/types/viewer/scene/camera/CameraPath.d.ts +86 -6
  21. package/types/viewer/scene/camera/CameraPathAnimation.d.ts +2 -0
  22. package/types/viewer/scene/geometry/ReadableGeometry.d.ts +14 -0
  23. package/types/viewer/scene/geometry/VBOGeometry.d.ts +2 -0
  24. package/types/viewer/scene/geometry/index.d.ts +2 -1
  25. package/types/viewer/scene/geometry/loaders/index.d.ts +2 -0
  26. package/types/viewer/scene/geometry/loaders/load3DSGeometry.d.ts +17 -0
  27. package/types/viewer/scene/geometry/loaders/loadOBJGeometry.d.ts +18 -0
  28. package/types/viewer/scene/index.d.ts +2 -0
  29. package/types/viewer/scene/input/input.d.ts +117 -0
  30. package/types/viewer/scene/lights/AmbientLight.d.ts +41 -0
  31. package/types/viewer/scene/lights/CubeTexture.d.ts +27 -0
  32. package/types/viewer/scene/lights/DirLight.d.ts +77 -0
  33. package/types/viewer/scene/lights/LightMap.d.ts +27 -0
  34. package/types/viewer/scene/lights/PointLight.d.ts +135 -0
  35. package/types/viewer/scene/lights/ReflectionMap.d.ts +26 -0
  36. package/types/viewer/scene/lights/index.d.ts +4 -1
  37. package/types/viewer/scene/marker/Marker.d.ts +5 -0
  38. package/types/viewer/scene/materials/EmphasisMaterial.d.ts +5 -0
  39. package/types/viewer/scene/materials/Fresnel.d.ts +25 -62
  40. package/types/viewer/scene/materials/LambertMaterial.d.ts +192 -0
  41. package/types/viewer/scene/materials/MetallicMaterial.d.ts +359 -0
  42. package/types/viewer/scene/materials/PhongMaterial.d.ts +5 -0
  43. package/types/viewer/scene/materials/PointsMaterial.d.ts +5 -0
  44. package/types/viewer/scene/materials/SpecularMaterial.d.ts +342 -0
  45. package/types/viewer/scene/materials/Texture.d.ts +36 -78
  46. package/types/viewer/scene/materials/index.d.ts +2 -0
  47. package/types/viewer/scene/models/SceneModel.d.ts +134 -7
  48. package/types/viewer/scene/models/SceneModelEntity.d.ts +65 -0
  49. package/types/viewer/scene/models/SceneModelMesh.d.ts +12 -0
  50. package/types/viewer/scene/paths/CubicBezierCurve.d.ts +146 -0
  51. package/types/viewer/scene/paths/Curve.d.ts +75 -0
  52. package/types/viewer/scene/paths/Path.d.ts +119 -0
  53. package/types/viewer/scene/paths/QuadraticBezierCurve.d.ts +124 -0
  54. package/types/viewer/scene/paths/SplineCurve.d.ts +84 -0
  55. package/types/viewer/scene/paths/index.d.ts +5 -0
  56. package/types/viewer/scene/scene/Scene.d.ts +102 -0
  57. package/types/viewer/scene/sectionPlane/SectionPlane.d.ts +41 -0
  58. package/types/viewer/scene/skybox/Skybox.d.ts +59 -0
  59. package/types/viewer/scene/skybox/index.d.ts +1 -0
  60. package/types/viewer/scene/webgl/PickResult.d.ts +19 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
- * xeokit-sdk v2.6.71
3
- * Commit: 7443626ab66b3eab0018b1ed0ee05d3bfa9f8eae
4
- * Built: 2025-03-21T09:02:29.217Z
2
+ * xeokit-sdk v2.6.75
3
+ * Commit: c9b6b9ca6ba5bea44b4e84678d4f9ffbf152086d
4
+ * Built: 2025-04-17T10:44:28.149Z
5
5
  */
6
6
 
7
7
  /** @private */
@@ -330,6 +330,7 @@ class ContextMenu {
330
330
  * @param {Boolean} [cfg.enabled=true] Whether this ````ContextMenu```` is initially enabled. {@link ContextMenu#show} does nothing while this is ````false````.
331
331
  * @param {Boolean} [cfg.hideOnMouseDown=true] Whether this ````ContextMenu```` automatically hides whenever we mouse-down or tap anywhere in the page.
332
332
  * @param {Boolean} [cfg.hideOnAction=true] Whether this ````ContextMenu```` automatically hides after we select a menu item. Se false if we want the menu to remain shown and show any updates to its item titles, after we've selected an item.
333
+ * @param {Node | undefined} [cfg.parentNode] Optional reference to an existing DOM Node (e.g. ShadowRoot), to which the menu's HTML element will be appended, defaults to ````document.body````.
333
334
  */
334
335
  constructor(cfg = {}) {
335
336
 
@@ -344,7 +345,9 @@ class ContextMenu {
344
345
  this._itemMap = {}; // Items mapped to their IDs
345
346
  this._shown = false; // True when the ContextMenu is visible
346
347
  this._nextId = 0;
347
-
348
+ this._parentNode = cfg.parentNode || document.body;
349
+ this._offsetParent = (this._parentNode instanceof ShadowRoot) ? this._parentNode.host : this._parentNode;
350
+
348
351
  /**
349
352
  * Subscriptions to events fired at this ContextMenu.
350
353
  * @private
@@ -352,12 +355,12 @@ class ContextMenu {
352
355
  this._eventSubs = {};
353
356
 
354
357
  if (cfg.hideOnMouseDown !== false) {
355
- document.addEventListener("mousedown", (event) => {
358
+ this._parentNode.addEventListener("mousedown", (event) => {
356
359
  if (!event.target.classList.contains("xeokit-context-menu-item")) {
357
360
  this.hide();
358
361
  }
359
362
  });
360
- document.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
363
+ this._parentNode.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
361
364
  if (!event.target.classList.contains("xeokit-context-menu-item")) {
362
365
  this.hide();
363
366
  }
@@ -556,7 +559,7 @@ class ContextMenu {
556
559
  for (let i = 0, len = this._menuList.length; i < len; i++) {
557
560
  const menu = this._menuList[i];
558
561
  const menuElement = menu.menuElement;
559
- menuElement.parentElement.removeChild(menuElement);
562
+ menuElement.remove();
560
563
  }
561
564
  this._itemsCfg = [];
562
565
  this._rootMenu = null;
@@ -661,7 +664,10 @@ class ContextMenu {
661
664
  const groups = menu.groups;
662
665
  const html = [];
663
666
 
664
- html.push('<div class="xeokit-context-menu ' + menu.id + '" style="z-index:300000; position: absolute;">');
667
+ const menuElement= document.createElement("div");
668
+ menuElement.classList.add("xeokit-context-menu", menu.id);
669
+ menuElement.style.zIndex = 300000;
670
+ menuElement.style.position = "absolute";
665
671
 
666
672
  html.push('<ul>');
667
673
 
@@ -712,13 +718,10 @@ class ContextMenu {
712
718
  }
713
719
 
714
720
  html.push('</ul>');
715
- html.push('</div>');
716
721
 
717
722
  const htmlString = html.join("");
718
-
719
- document.body.insertAdjacentHTML('beforeend', htmlString);
720
-
721
- const menuElement = document.querySelector("." + menu.id);
723
+ menuElement.innerHTML = htmlString;
724
+ this._parentNode.appendChild(menuElement);
722
725
 
723
726
  menu.menuElement = menuElement;
724
727
 
@@ -752,7 +755,7 @@ class ContextMenu {
752
755
  const item = groupItems[j];
753
756
  const itemSubMenu = item.subMenu;
754
757
 
755
- item.itemElement = document.getElementById(item.id);
758
+ item.itemElement = this._parentNode.querySelector(`#${item.id}`);
756
759
 
757
760
  if (!item.itemElement) {
758
761
  console.error("ContextMenu item element not found: " + item.id);
@@ -784,21 +787,22 @@ class ContextMenu {
784
787
 
785
788
  const itemRect = itemElement.getBoundingClientRect();
786
789
  subMenuElement.getBoundingClientRect();
790
+ const offsetRect = self._offsetParent.getBoundingClientRect();
787
791
 
788
792
  const subMenuWidth = 200; // TODO
789
- const showOnRight = (itemRect.right + subMenuWidth) < window.innerWidth;
790
- const showOnLeft = (itemRect.left - subMenuWidth) > 0;
791
-
793
+ const showOnRight = (itemRect.right + subMenuWidth) < offsetRect.right;
794
+ const showOnLeft = (itemRect.left - subMenuWidth) > offsetRect.left;
795
+
792
796
  if(showOnRight)
793
- self._showMenu(subMenu.id, itemRect.right - 5, itemRect.top - 1);
797
+ self._showMenu(subMenu.id, itemRect.right + window.scrollX - 5, itemRect.top + window.scrollY - 1);
794
798
  else if (showOnLeft)
795
- self._showMenu(subMenu.id, itemRect.left - subMenuWidth, itemRect.top - 1);
799
+ self._showMenu(subMenu.id, itemRect.left - subMenuWidth + window.scrollX, itemRect.top + window.scrollY - 1);
796
800
  else {
797
- const spaceOnLeft = itemRect.left, spaceOnRight = window.innerWidth - itemRect.right;
801
+ const spaceOnLeft = itemRect.left - offsetRect.left, spaceOnRight = offsetRect.right - itemRect.right;
798
802
  if(spaceOnRight > spaceOnLeft)
799
- self._showMenu(subMenu.id, itemRect.right - 5 - (subMenuWidth - spaceOnRight), itemRect.top - 1);
803
+ self._showMenu(subMenu.id, itemRect.right - 5 - (subMenuWidth - spaceOnRight), itemRect.top + window.scrollY - 1);
800
804
  else
801
- self._showMenu(subMenu.id, itemRect.left - spaceOnLeft, itemRect.top - 1);
805
+ self._showMenu(subMenu.id, itemRect.left - spaceOnLeft, itemRect.top + window.scrollY - 1);
802
806
  }
803
807
 
804
808
  lastSubMenu = subMenu;
@@ -991,14 +995,21 @@ class ContextMenu {
991
995
  menuElement.style.display = 'block';
992
996
  const menuHeight = menuElement.offsetHeight;
993
997
  const menuWidth = menuElement.offsetWidth;
994
- if ((pageY + menuHeight) > window.innerHeight) {
995
- pageY = window.innerHeight - menuHeight;
998
+
999
+ const offsetRect = this._offsetParent.getBoundingClientRect();
1000
+
1001
+ const bottomContainerBorder = offsetRect.bottom + window.scrollY;
1002
+ const rightContainerBorder = offsetRect.right + window.scrollX;
1003
+ if ((pageY + menuHeight) > bottomContainerBorder) {
1004
+ pageY = bottomContainerBorder- menuHeight;
996
1005
  }
997
- if ((pageX + menuWidth) > window.innerWidth) {
998
- pageX = window.innerWidth - menuWidth;
1006
+ if ((pageX + menuWidth) > rightContainerBorder) {
1007
+ pageX = rightContainerBorder - menuWidth;
999
1008
  }
1000
- menuElement.style.left = pageX + 'px';
1001
- menuElement.style.top = pageY + 'px';
1009
+
1010
+
1011
+ menuElement.style.left = pageX - offsetRect.left - window.scrollX + 'px';
1012
+ menuElement.style.top = pageY - offsetRect.top - window.scrollY + 'px';
1002
1013
  }
1003
1014
 
1004
1015
  _hideMenuElement(menuElement) {
@@ -11655,9 +11666,28 @@ const tmpVec4b = math.vec4();
11655
11666
  const tmpVec4c = math.vec4();
11656
11667
  const tmpVec4d = math.vec4();
11657
11668
  const tmpMat4 = math.mat4();
11669
+ const tmpRay = {
11670
+ origin: math.vec3(),
11671
+ direction: math.vec3()
11672
+ };
11658
11673
 
11659
11674
  const nop = () => { };
11660
11675
 
11676
+ const planeIntersect$1 = function(p0, n, origin, direction) {
11677
+ const t = (p0 - math.dotVec3(origin, n)) / math.dotVec3(direction, n);
11678
+ if (t < 0)
11679
+ {
11680
+ return null;
11681
+ }
11682
+ else
11683
+ {
11684
+ const worldPos = math.vec3();
11685
+ math.mulVec3Scalar(direction, t, worldPos);
11686
+ math.addVec3(origin, worldPos, worldPos);
11687
+ return worldPos;
11688
+ }
11689
+ };
11690
+
11661
11691
  function transformToNode(from, to, vec) {
11662
11692
  const fromRec = from.getBoundingClientRect();
11663
11693
  const toRec = to.getBoundingClientRect();
@@ -11919,9 +11949,15 @@ class Label3D {
11919
11949
  this._mid = math.vec3();
11920
11950
  this._end = math.vec3();
11921
11951
  this._yOff = 0;
11922
- this._betweenWires = false;
11923
11952
  this.__visible = true;
11924
11953
 
11954
+ this._updatePos = () => {
11955
+ toClipSpace(camera, this._start, tmpVec4a);
11956
+ math.mulVec4Scalar(tmpVec4a, 1.0 / tmpVec4a[3]);
11957
+ toCanvasSpace(scene.canvas.canvas, parentElement, tmpVec4a, tmpVec2a);
11958
+ this._label.setPos(tmpVec2a[0], tmpVec2a[1]);
11959
+ };
11960
+
11925
11961
  const setPosOnWire = (p0, p1, yOff) => {
11926
11962
  p0[0] += p1[0];
11927
11963
  p0[1] += p1[1];
@@ -11929,36 +11965,44 @@ class Label3D {
11929
11965
  this._label.setPos(p0[0], p0[1] + yOff);
11930
11966
  };
11931
11967
 
11932
- this._updatePositions = () => {
11933
- if (! this.__visible) {
11934
- return;
11968
+ this._updatePosBetween = () => {
11969
+ const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
11970
+ const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d);
11971
+ this._label.setCulled(! (visibleA || visibleB));
11972
+ if (visibleA && visibleB) {
11973
+ tmpVec2b[0] += tmpVec2d[0];
11974
+ tmpVec2b[1] += tmpVec2d[1];
11975
+ math.mulVec2Scalar(tmpVec2b, .5);
11976
+
11977
+ tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
11978
+ tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
11979
+ math.mulVec2Scalar(tmpVec2b, 1/3);
11980
+ this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
11981
+ } else if (visibleA) {
11982
+ setPosOnWire(tmpVec2a, tmpVec2b, 0);
11983
+ } else if (visibleB) {
11984
+ setPosOnWire(tmpVec2c, tmpVec2d, 0);
11935
11985
  }
11936
- if (this._betweenWires) {
11937
- const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
11938
- const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d);
11939
- this._label.setCulled(! (visibleA || visibleB));
11940
- if (visibleA && visibleB) {
11941
- tmpVec2b[0] += tmpVec2d[0];
11942
- tmpVec2b[1] += tmpVec2d[1];
11943
- math.mulVec2Scalar(tmpVec2b, .5);
11944
-
11945
- tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
11946
- tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
11947
- math.mulVec2Scalar(tmpVec2b, 1/3);
11948
- this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
11949
- } else if (visibleA) {
11950
- setPosOnWire(tmpVec2a, tmpVec2b, 0);
11951
- } else if (visibleB) {
11952
- setPosOnWire(tmpVec2c, tmpVec2d, 0);
11953
- }
11954
- } else {
11955
- const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
11956
- &&
11957
- (math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
11958
- this._label.setCulled(!visible);
11959
- if (visible) {
11960
- setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
11961
- }
11986
+ };
11987
+
11988
+ this._updatePosOnWire = () => {
11989
+ const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
11990
+ &&
11991
+ (math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
11992
+ this._label.setCulled(!visible);
11993
+ if (visible) {
11994
+ setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
11995
+ }
11996
+ };
11997
+
11998
+ let posUpdate = () => { };
11999
+ this._setUpdatePositions = (_posUpdate) => {
12000
+ posUpdate = _posUpdate;
12001
+ this._updatePositions();
12002
+ };
12003
+ this._updatePositions = () => {
12004
+ if (this.__visible) {
12005
+ posUpdate();
11962
12006
  }
11963
12007
  };
11964
12008
 
@@ -11976,21 +12020,24 @@ class Label3D {
11976
12020
  };
11977
12021
  }
11978
12022
 
12023
+ setPos(p0) {
12024
+ this._start.set(p0);
12025
+ this._setUpdatePositions(this._updatePos);
12026
+ }
12027
+
11979
12028
  setPosOnWire(p0, p1, yOff, labelMinAxisLength) {
11980
12029
  this._start.set(p0);
11981
12030
  this._end.set(p1);
11982
12031
  this._yOff = yOff;
11983
12032
  this._labelMinAxisLength = labelMinAxisLength;
11984
- this._betweenWires = false;
11985
- this._updatePositions();
12033
+ this._setUpdatePositions(this._updatePosOnWire);
11986
12034
  }
11987
12035
 
11988
12036
  setPosBetween(p0, p1, p2) {
11989
12037
  this._start.set(p0);
11990
12038
  this._mid.set(p1);
11991
12039
  this._end.set(p2);
11992
- this._betweenWires = true;
11993
- this._updatePositions();
12040
+ this._setUpdatePositions(this._updatePosBetween);
11994
12041
  }
11995
12042
 
11996
12043
  setFillColor(value) {
@@ -12093,6 +12140,51 @@ class Wire3D {
12093
12140
 
12094
12141
  }
12095
12142
 
12143
+ const marker3D = function(scene, color) {
12144
+ const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
12145
+ borderColor: "white",
12146
+ fillColor: color,
12147
+ zIndex: 100
12148
+ });
12149
+
12150
+ return {
12151
+ update: function(worldPos) {
12152
+ if (worldPos)
12153
+ {
12154
+ marker.worldPos = worldPos;
12155
+ }
12156
+ marker.setVisible(!!worldPos);
12157
+ },
12158
+
12159
+ setFillColor: c => marker.setFillColor(c),
12160
+ setHighlighted: h => marker.setHighlighted(h),
12161
+ getCanvasPos: () => marker.canvasPos,
12162
+ getWorldPos: () => marker.worldPos,
12163
+ destroy: () => marker.destroy()
12164
+ };
12165
+ };
12166
+
12167
+ const wire3D = function(scene, color) {
12168
+ const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
12169
+ color: color,
12170
+ thickness: 1,
12171
+ thicknessClickable: 6 // TODO: Remove to make not clickable?
12172
+ });
12173
+ wire.setVisible(false);
12174
+ return {
12175
+ update: (startWorldPos, endWorldPos) => {
12176
+ if (endWorldPos)
12177
+ {
12178
+ wire.setEnds(startWorldPos, endWorldPos);
12179
+ }
12180
+ wire.setVisible(!!endWorldPos);
12181
+ },
12182
+
12183
+ setColor: c => wire.setColor(c),
12184
+ destroy: () => wire.destroy()
12185
+ };
12186
+ };
12187
+
12096
12188
  function activateDraggableDot(dot, cfg) {
12097
12189
  const extractCFG = function(propName, defaultValue) {
12098
12190
  if (propName in cfg) {
@@ -12407,6 +12499,482 @@ const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
12407
12499
  };
12408
12500
  };
12409
12501
 
12502
+ const triangulateEarClipping = function(planeCoords) {
12503
+ const polygonVertices = [ ];
12504
+ for (let i = 0; i < planeCoords.length; ++i)
12505
+ polygonVertices.push(i);
12506
+
12507
+ const isCCW = (function() {
12508
+ const ba = math.vec2();
12509
+ const bc = math.vec2();
12510
+
12511
+ let anglesSum = 0;
12512
+
12513
+ for (let i = 0; i < polygonVertices.length; ++i)
12514
+ {
12515
+ const a = planeCoords[polygonVertices[i]];
12516
+ const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
12517
+ const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
12518
+
12519
+ math.subVec2(a, b, ba);
12520
+ math.subVec2(c, b, bc);
12521
+
12522
+ const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
12523
+ const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
12524
+ const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
12525
+ anglesSum += convex ? angle : (2 * Math.PI - angle);
12526
+ }
12527
+
12528
+ return anglesSum < (polygonVertices.length * Math.PI);
12529
+ })();
12530
+
12531
+ const pointInTriangle = (function() {
12532
+ const sign = (p1, p2, p3) => {
12533
+ return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
12534
+ };
12535
+
12536
+ return (pt, v1, v2, v3) => {
12537
+ const d1 = sign(pt, v1, v2);
12538
+ const d2 = sign(pt, v2, v3);
12539
+ const d3 = sign(pt, v3, v1);
12540
+
12541
+ const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
12542
+ const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
12543
+
12544
+ return !(has_neg && has_pos);
12545
+ };
12546
+ })();
12547
+
12548
+ const baseTriangles = [ ];
12549
+
12550
+ const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
12551
+ vertices.forEach((v, i) => {
12552
+ v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
12553
+ v.next = vertices[(i + 1) % vertices.length];
12554
+ });
12555
+
12556
+ const ba = math.vec2();
12557
+ const bc = math.vec2();
12558
+
12559
+ while (vertices.length > 2) {
12560
+ let earIdx = 0;
12561
+ while (true) {
12562
+ if (earIdx >= vertices.length)
12563
+ {
12564
+ throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
12565
+ }
12566
+ const v = vertices[earIdx];
12567
+
12568
+ const a = planeCoords[v.prev.idx];
12569
+ const b = planeCoords[v.idx];
12570
+ const c = planeCoords[v.next.idx];
12571
+
12572
+ math.subVec2(a, b, ba);
12573
+ math.subVec2(c, b, bc);
12574
+
12575
+ if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
12576
+ &&
12577
+ vertices.every( // no other vertices inside
12578
+ vv => ((vv === v)
12579
+ ||
12580
+ (vv === v.prev)
12581
+ ||
12582
+ (vv === v.next)
12583
+ ||
12584
+ !pointInTriangle(planeCoords[vv.idx], a, b, c))))
12585
+ break;
12586
+ ++earIdx;
12587
+ }
12588
+
12589
+ const ear = vertices[earIdx];
12590
+ vertices.splice(earIdx, 1);
12591
+
12592
+ baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
12593
+
12594
+ const prev = ear.prev;
12595
+ prev.next = ear.next;
12596
+ const next = ear.next;
12597
+ next.prev = ear.prev;
12598
+ }
12599
+
12600
+ return [ planeCoords, baseTriangles, isCCW ];
12601
+ };
12602
+
12603
+ const addMousePressListener = function(element, onChange) {
12604
+ const moveTolerance = 4;
12605
+
12606
+ const copyElementPos = (event, out) => {
12607
+ out[0] = event.clientX;
12608
+ out[1] = event.clientY;
12609
+ transformToNode(element.ownerDocument.documentElement, element, out);
12610
+ return out;
12611
+ };
12612
+
12613
+ let buttonDown = false;
12614
+
12615
+ const cleanups = [ ];
12616
+ const cleanup = () => cleanups.forEach(c => c());
12617
+
12618
+ const addElementEventListener = (type, listener) => {
12619
+ element.addEventListener(type, listener);
12620
+ cleanups.push(() => element.removeEventListener(type, listener));
12621
+ };
12622
+
12623
+ const downPos = math.vec2();
12624
+ addElementEventListener("mousedown", function(event) {
12625
+ if (event.which === 1) {
12626
+ buttonDown = true;
12627
+ onChange(copyElementPos(event, downPos));
12628
+ }
12629
+ });
12630
+
12631
+ addElementEventListener("mousemove", function(event) {
12632
+ copyElementPos(event, tmpVec2a);
12633
+ if (buttonDown && (math.distVec2(downPos, tmpVec2a) > moveTolerance)) {
12634
+ buttonDown = false;
12635
+ }
12636
+ if (buttonDown || (! event.buttons & 1)) {
12637
+ onChange(tmpVec2a);
12638
+ }
12639
+ });
12640
+
12641
+ addElementEventListener("mouseup", function(event) {
12642
+ if ((event.which === 1) && buttonDown) {
12643
+ const commit = onChange(copyElementPos(event, tmpVec2a));
12644
+ if (commit) {
12645
+ cleanup();
12646
+ commit();
12647
+ }
12648
+ }
12649
+ });
12650
+
12651
+ return cleanup;
12652
+ };
12653
+
12654
+ const addTouchPressListener = function(element, cameraControl, pointerCircle, onChange) {
12655
+ const longTouchTimeoutMs = 300;
12656
+ const moveTolerance = 20;
12657
+ const startPos = math.vec2();
12658
+
12659
+ const copyElementPos = (event, out) => {
12660
+ out[0] = event.clientX;
12661
+ out[1] = event.clientY;
12662
+ transformToNode(element.ownerDocument.documentElement, element, out);
12663
+ return out;
12664
+ };
12665
+
12666
+ let longTouchTimeout = null;
12667
+ let onSingleTouchMove = nop;
12668
+ let startTouchIdentifier;
12669
+
12670
+ const resetAction = function() {
12671
+ clearTimeout(longTouchTimeout);
12672
+ pointerCircle.stop();
12673
+ cameraControl.active = true;
12674
+ onSingleTouchMove = nop;
12675
+ startTouchIdentifier = null;
12676
+ };
12677
+
12678
+ const cleanups = [ ];
12679
+ const cleanup = () => cleanups.forEach(c => c());
12680
+
12681
+ const addElementEventListener = (type, listener) => {
12682
+ element.addEventListener(type, listener, {passive: true});
12683
+ cleanups.push(() => element.removeEventListener(type, listener));
12684
+ };
12685
+
12686
+ addElementEventListener("touchstart", function(event) {
12687
+ const touches = event.touches;
12688
+
12689
+ if (touches.length !== 1)
12690
+ {
12691
+ resetAction();
12692
+ onChange(null);
12693
+ }
12694
+ else
12695
+ {
12696
+ const touch = touches[0];
12697
+ copyElementPos(touch, startPos);
12698
+
12699
+ startTouchIdentifier = touch.identifier;
12700
+
12701
+ onSingleTouchMove = elementPos => {
12702
+ if (math.distVec2(startPos, elementPos) > moveTolerance)
12703
+ {
12704
+ resetAction();
12705
+ }
12706
+ };
12707
+
12708
+ longTouchTimeout = setTimeout(
12709
+ function() {
12710
+ pointerCircle.start(startPos);
12711
+
12712
+ longTouchTimeout = setTimeout(
12713
+ function() {
12714
+ pointerCircle.stop();
12715
+ cameraControl.active = false;
12716
+ onSingleTouchMove = onChange;
12717
+ onSingleTouchMove(startPos);
12718
+ },
12719
+ longTouchTimeoutMs);
12720
+ },
12721
+ 250);
12722
+ }
12723
+ });
12724
+
12725
+ // element.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
12726
+
12727
+ addElementEventListener("touchmove", function(event) {
12728
+ const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
12729
+ if (touch)
12730
+ {
12731
+ onSingleTouchMove(copyElementPos(touch, tmpVec2a));
12732
+ }
12733
+ });
12734
+
12735
+ addElementEventListener("touchend", function(event) {
12736
+ const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
12737
+ if (touch)
12738
+ {
12739
+ const commit = onChange(copyElementPos(touch, tmpVec2a));
12740
+ resetAction();
12741
+ if (commit) {
12742
+ cleanup();
12743
+ commit();
12744
+ } else {
12745
+ onChange(null);
12746
+ }
12747
+ }
12748
+ });
12749
+
12750
+ return () => {
12751
+ resetAction();
12752
+ cleanup();
12753
+ };
12754
+ };
12755
+
12756
+ const startPolygonCreate = function(scene, pointerLens, addPressListener, pickRayResult, onChange, onConclude) {
12757
+ const canvas = scene.canvas.canvas;
12758
+
12759
+ const updatePointerLens = (pointerLens
12760
+ ? function(canvasPos, isSnapped) {
12761
+ pointerLens.visible = !! canvasPos;
12762
+ if (canvasPos)
12763
+ {
12764
+ pointerLens.canvasPos = canvasPos;
12765
+ pointerLens.snapped = !! isSnapped;
12766
+ }
12767
+ }
12768
+ : () => { });
12769
+
12770
+ const testLastSegmentIntersects = (function() {
12771
+ const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
12772
+ (q[0] >= Math.min(p[0], r[0])) &&
12773
+ (q[1] <= Math.max(p[1], r[1])) &&
12774
+ (q[1] >= Math.min(p[1], r[1])));
12775
+
12776
+ const orient = (p, q, r) => {
12777
+ const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
12778
+ // collinear
12779
+ // clockwise
12780
+ // counterclockwise
12781
+ return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
12782
+ };
12783
+
12784
+ return function(pos2D, lastSegmentClosesLoop) {
12785
+ const s = lastSegmentClosesLoop ? 1 : 0;
12786
+ const a = pos2D[(pos2D.length - 2 + s) % pos2D.length];
12787
+ const b = pos2D[(pos2D.length - 1 + s) % pos2D.length];
12788
+
12789
+ for (let i = s; i < pos2D.length - 2 - 1 + s; ++i) {
12790
+ const c = pos2D[i];
12791
+ const d = pos2D[i + 1];
12792
+
12793
+ const o1 = orient(a, b, c);
12794
+ const o2 = orient(a, b, d);
12795
+ const o3 = orient(c, d, a);
12796
+ const o4 = orient(c, d, b);
12797
+
12798
+ if (((o1 !== o2) && (o3 !== o4)) || // General case
12799
+ ((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
12800
+ ((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
12801
+ ((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
12802
+ ((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
12803
+ {
12804
+ return true;
12805
+ }
12806
+ }
12807
+
12808
+ return false;
12809
+ };
12810
+ })();
12811
+
12812
+ const getPlane = (points) => (points.length >= 3) && (function() {
12813
+ const u = math.normalizeVec3(math.subVec3(points[1], points[0], math.vec3()));
12814
+ const v20 = math.normalizeVec3(math.subVec3(points[2], points[0], tmpVec3a$2));
12815
+ const normal = math.normalizeVec3(math.cross3Vec3(u, v20, math.vec3()));
12816
+ const v = math.normalizeVec3(math.cross3Vec3(normal, u, math.vec3()));
12817
+ return {
12818
+ normal: normal,
12819
+ origin: math.vec3(points[0]),
12820
+ u: u,
12821
+ v: v
12822
+ };
12823
+ })();
12824
+
12825
+ const vertices = [ ];
12826
+ let currentInteraction;
12827
+
12828
+ (function selectNextPoint() {
12829
+ const plane = getPlane(vertices);
12830
+
12831
+ const canvasPos2Ray = (canvasPos, dst) => (math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, dst.origin, dst.direction), dst);
12832
+
12833
+ const pickRay = (ray) => {
12834
+ const pickResult = pickRayResult(ray);
12835
+ const snapWorldPos = pickResult && pickResult.entity && ((! plane) || pickResult.snapped) && pickResult.worldPos;
12836
+ if (plane) {
12837
+ const originDistance = math.dotVec3(plane.normal, plane.origin);
12838
+ const snapPlaneDist = (snapWorldPos
12839
+ ? ((originDistance - math.dotVec3(snapWorldPos, plane.normal)))
12840
+ : window.Infinity);
12841
+ if (Math.abs(snapPlaneDist) < 0.0001) {
12842
+ const ret = math.vec3();
12843
+ return {
12844
+ worldPos: math.addVec3(snapWorldPos, math.mulVec3Scalar(plane.normal, snapPlaneDist, ret), ret),
12845
+ snapped: true
12846
+ };
12847
+ } else {
12848
+ return {
12849
+ worldPos: planeIntersect$1(originDistance, plane.normal, ray.origin, ray.direction),
12850
+ snapped: false
12851
+ };
12852
+ }
12853
+ } else {
12854
+ return {
12855
+ worldPos: snapWorldPos,
12856
+ snapped: pickResult && pickResult.snapped
12857
+ };
12858
+ }
12859
+ };
12860
+
12861
+ let placeVertex = false;
12862
+ const removePressListener = addPressListener(
12863
+ (inputCanvasPos) => {
12864
+ const rayPick = inputCanvasPos && pickRay(canvasPos2Ray(inputCanvasPos, tmpRay));
12865
+ const worldPos = rayPick && rayPick.worldPos;
12866
+ return onWorldPos(worldPos, inputCanvasPos, rayPick && rayPick.snapped);
12867
+ });
12868
+
12869
+ const onWorldPos = (worldPos, inputCanvasPos, rayPickSnapped) => {
12870
+ const canvasPos = worldPos ? scene.camera.projectWorldPos(worldPos) : inputCanvasPos;
12871
+ const firstMarker = (vertices.length > 0) && (function() {
12872
+ const v = vertices[0];
12873
+ return {
12874
+ canvasPos: scene.camera.projectWorldPos(v),
12875
+ worldPos: v
12876
+ };
12877
+ })();
12878
+ const snapToFirst = (vertices.length >= 3) && ((canvasPos && (math.distVec2(canvasPos, firstMarker.canvasPos) < 10))
12879
+ ||
12880
+ (worldPos && math.compareVec3(worldPos, firstMarker.worldPos)));
12881
+
12882
+ updatePointerLens(snapToFirst ? firstMarker.canvasPos : canvasPos, snapToFirst || rayPickSnapped);
12883
+
12884
+ const lastPointOverlaps = (inputCanvasPos
12885
+ &&
12886
+ ((! worldPos)
12887
+ ||
12888
+ ((vertices.length < 3)
12889
+ ? vertices.some(v => math.compareVec3(v, worldPos))
12890
+ : math.compareVec3(vertices[vertices.length - 1], worldPos))));
12891
+
12892
+ const points = vertices.concat(((! snapToFirst) && worldPos && (! lastPointOverlaps)) ? [worldPos] : []);
12893
+
12894
+ const curPlane = (! lastPointOverlaps) && (plane || getPlane(points));
12895
+
12896
+ const uvs = curPlane && points.map(p => {
12897
+ math.subVec3(p, curPlane.origin, tmpVec3a$2);
12898
+ return math.vec2([ math.dotVec3(tmpVec3a$2, curPlane.u), math.dotVec3(tmpVec3a$2, curPlane.v) ]);
12899
+ });
12900
+
12901
+ const isValid = (! lastPointOverlaps) && (! (uvs && testLastSegmentIntersects(uvs, snapToFirst)));
12902
+ const geometry = isValid && uvs && (snapToFirst || (! testLastSegmentIntersects(uvs, true))) && (function() {
12903
+ try {
12904
+ const [ baseVertices, baseTriangles, isCCW ] = triangulateEarClipping(uvs);
12905
+ return {
12906
+ faces: baseTriangles,
12907
+ vertices: baseVertices.map(uv => math.addVec3(
12908
+ curPlane.origin,
12909
+ math.addVec3(
12910
+ math.mulVec3Scalar(curPlane.u, uv[0], tmpVec3a$2),
12911
+ math.mulVec3Scalar(curPlane.v, uv[1], tmpVec3b$2),
12912
+ tmpVec3a$2),
12913
+ math.vec3()))
12914
+ };
12915
+ } catch (e) {
12916
+ console.warn("e", e);
12917
+ return false;
12918
+ }
12919
+ })();
12920
+
12921
+ onChange(points, snapToFirst, isValid, geometry);
12922
+
12923
+ return placeVertex = (isValid && (snapToFirst
12924
+ ? () => {
12925
+ updatePointerLens(null);
12926
+ onConclude();
12927
+ }
12928
+ : () => {
12929
+ vertices.push(math.vec3(worldPos));
12930
+ updatePointerLens(null);
12931
+ selectNextPoint();
12932
+ }));
12933
+ };
12934
+
12935
+ currentInteraction = {
12936
+ closePolygon: (() => {
12937
+ const commit = (vertices.length >= 3) && onWorldPos(vertices[0]);
12938
+ if (commit) {
12939
+ removePressListener();
12940
+ commit();
12941
+ }
12942
+ return !! commit;
12943
+ }),
12944
+ placeVertex: () => {
12945
+ if (placeVertex) {
12946
+ removePressListener();
12947
+ placeVertex();
12948
+ }
12949
+ return !!placeVertex;
12950
+ },
12951
+ popVertex: () => {
12952
+ if (vertices.length > 0) {
12953
+ removePressListener();
12954
+ vertices.pop();
12955
+ selectNextPoint();
12956
+ return true;
12957
+ } else {
12958
+ return false;
12959
+ }
12960
+ },
12961
+ removePressListener: removePressListener,
12962
+ updateOnChange: () => onWorldPos()
12963
+ };
12964
+ })();
12965
+
12966
+ return {
12967
+ cancel: () => {
12968
+ currentInteraction.removePressListener();
12969
+ updatePointerLens(null);
12970
+ },
12971
+ closePolygon: () => currentInteraction.closePolygon(),
12972
+ placeVertex: () => currentInteraction.placeVertex(),
12973
+ popVertex: () => currentInteraction.popVertex(),
12974
+ updateOnChange: () => currentInteraction.updateOnChange()
12975
+ };
12976
+ };
12977
+
12410
12978
  const tmpVec3a$1 = math.vec3();
12411
12979
  const tmpVec3b$1 = math.vec3();
12412
12980
 
@@ -14826,6 +15394,8 @@ const tempVec3a$M = math.vec3();
14826
15394
  const tempVec3b$B = math.vec3();
14827
15395
  const tempVec3c$w = math.vec3();
14828
15396
 
15397
+ const px = x => x + "px";
15398
+
14829
15399
  /**
14830
15400
  * A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
14831
15401
  *
@@ -15032,22 +15602,29 @@ class Annotation extends Marker {
15032
15602
  * @private
15033
15603
  */
15034
15604
  _updateWithCurWidths() {
15035
- const px = x => x + "px";
15036
15605
  const boundary = this.scene.canvas.boundary;
15037
15606
  const left = boundary[0] + this.canvasPos[0];
15038
15607
  const top = boundary[1] + this.canvasPos[1];
15039
- const markerWidth = this._curMarkerWidth;
15040
- const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
15041
- const markerCenter = left + markerDir * (markerWidth / 2 - 12);
15042
- this._marker.style.left = px(markerCenter - markerWidth / 2);
15043
- this._marker.style.top = px(top - 12);
15044
- this._marker.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
15045
-
15046
- const labelWidth = this._curLabelWidth;
15047
- const labelDir = Math.sign(this._labelPosition);
15048
- this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
15608
+ this._marker.style.top = px(top - 12);
15049
15609
  this._label.style.top = px(top - 17);
15050
- this._label.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
15610
+
15611
+ if (this._markerAlign === "legacy") {
15612
+ this._marker.style.left = px(left - 12);
15613
+ this._label.style.left = px(left + 40);
15614
+ } else {
15615
+ const markerWidth = this._curMarkerWidth;
15616
+ const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
15617
+ const markerCenter = left + markerDir * (markerWidth / 2 - 12);
15618
+ this._marker.style.left = px(markerCenter - markerWidth / 2);
15619
+
15620
+ const labelWidth = this._curLabelWidth;
15621
+ const labelDir = Math.sign(this._labelPosition);
15622
+ this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
15623
+ }
15624
+
15625
+ const zIndex = 90005 + Math.floor(this._viewPos[2]) + 1;
15626
+ this._marker.style["z-index"] = zIndex;
15627
+ this._label.style["z-index"] = zIndex;
15051
15628
  }
15052
15629
 
15053
15630
  /**
@@ -15078,7 +15655,8 @@ class Annotation extends Marker {
15078
15655
  * @private
15079
15656
  */
15080
15657
  _updatePosition() {
15081
- if (this._curMarkerWidth === undefined) {
15658
+ const isLegacy = this._markerAlign === "legacy";
15659
+ if ((! isLegacy) && (this._curMarkerWidth === undefined)) {
15082
15660
  this._updateIfWidthsChanged();
15083
15661
  } else {
15084
15662
  // Update position with cached width values
@@ -15086,7 +15664,9 @@ class Annotation extends Marker {
15086
15664
  // so they don't interfere with e.g. interactive scene manipulation
15087
15665
  this._updateWithCurWidths();
15088
15666
  window.clearTimeout(this._widthTimeout);
15089
- this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
15667
+ if (! isLegacy) {
15668
+ this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
15669
+ }
15090
15670
  }
15091
15671
  }
15092
15672
 
@@ -15124,10 +15704,10 @@ class Annotation extends Marker {
15124
15704
  /**
15125
15705
  * Sets the horizontal alignment of the Annotation's marker HTML.
15126
15706
  *
15127
- * @param {String} align Either "left", "center", "right" (default "left")
15707
+ * @param {String} align Either "left", "center", "right", "legacy" (default "left")
15128
15708
  */
15129
15709
  setMarkerAlign(align) {
15130
- const valid = [ "left", "center", "right" ];
15710
+ const valid = [ "left", "center", "right", "legacy" ];
15131
15711
  if (! valid.includes(align)) {
15132
15712
  this.error("Param 'align' should be one of: " + JSON.stringify(valid));
15133
15713
  } else {
@@ -26510,6 +27090,65 @@ class ReadableGeometry extends Geometry {
26510
27090
  return this._obb;
26511
27091
  }
26512
27092
 
27093
+ _getMetrics() {
27094
+ if (! ("_metrics" in this)) {
27095
+ switch (this._state.primitiveName) {
27096
+ case "solid":
27097
+ case "surface":
27098
+ case "triangles": {
27099
+ const indices = this._state.indices;
27100
+ const positions = this._state.positions;
27101
+ const getPos = (i, out) => {
27102
+ const idx = indices[i] * 3;
27103
+ for (let j = 0; j < 3; ++j) {
27104
+ out[j] = positions[idx + j];
27105
+ } return out;
27106
+ };
27107
+ const tmp = [ math.vec3(), math.vec3(), math.vec3(), math.vec3() ];
27108
+ let totalArea = 0;
27109
+ const centroid = math.vec3([ 0, 0, 0 ]);
27110
+ for (let i = 0; i < indices.length; i += 3) {
27111
+ const v0 = getPos(i, tmp[0]);
27112
+ const v1 = getPos(i+1, tmp[1]);
27113
+ const v2 = getPos(i+2, tmp[2]);
27114
+ math.addVec3(v0, v1, tmp[3]);
27115
+ math.addVec3(v2, tmp[3], tmp[3]);
27116
+ const faceArea = math.lenVec3(
27117
+ math.cross3Vec3(
27118
+ math.subVec3(v1, v0, tmp[1]),
27119
+ math.subVec3(v2, v0, tmp[2]),
27120
+ tmp[0])) / 2;
27121
+ totalArea += faceArea;
27122
+ math.mulVec3Scalar(tmp[3], faceArea, tmp[3]);
27123
+ math.addVec3(centroid, tmp[3], centroid);
27124
+ }
27125
+ this._metrics = { surfaceArea: totalArea, centroid: math.mulVec3Scalar(centroid, 1 / totalArea / 3, centroid) };
27126
+ break;
27127
+ }
27128
+ default:
27129
+ this._metrics = { surfaceArea: 0 };
27130
+ break;
27131
+ }
27132
+ }
27133
+ return this._metrics;
27134
+ }
27135
+
27136
+ /**
27137
+ * Returns the surface area of this Mesh.
27138
+ * @returns {number}
27139
+ */
27140
+ get surfaceArea() {
27141
+ return this._getMetrics().surfaceArea;
27142
+ }
27143
+
27144
+ /**
27145
+ * Returns the centroid of this Mesh.
27146
+ * @returns {number}
27147
+ */
27148
+ get centroid() {
27149
+ return this._getMetrics().centroid;
27150
+ }
27151
+
26513
27152
  /**
26514
27153
  * Approximate number of triangles in this ReadableGeometry.
26515
27154
  *
@@ -40058,7 +40697,7 @@ function buildPlaneGeometry(cfg = {}) {
40058
40697
  positions[offset + 1] = centerY;
40059
40698
  positions[offset + 2] = -z + centerZ;
40060
40699
 
40061
- normals[offset + 2] = -1;
40700
+ normals[offset + 1] = 1;
40062
40701
 
40063
40702
  uvs[offset2] = (ix) / planeX;
40064
40703
  uvs[offset2 + 1] = ((planeZ - iz) / planeZ);
@@ -43356,8 +43995,7 @@ class SectionCaps {
43356
43995
  if(!this._resourcesAllocated) {
43357
43996
  this._resourcesAllocated = true;
43358
43997
  this._sectionPlanes = [];
43359
- this._verticesMap = {};
43360
- this._indicesMap = {};
43998
+ this._sceneModelsData = {};
43361
43999
  this._dirtyMap = {};
43362
44000
  this._prevIntersectionModelsMap = {};
43363
44001
  this._sectionPlaneTimeout = null;
@@ -43372,7 +44010,8 @@ class SectionCaps {
43372
44010
  this._sectionPlanes.push(sectionPlane);
43373
44011
  sectionPlane.on('pos', onSectionPlaneUpdated);
43374
44012
  sectionPlane.on('dir', onSectionPlaneUpdated);
43375
- sectionPlane.once('destroyed', ((sectionPlane) => {
44013
+ sectionPlane.on('active', onSectionPlaneUpdated);
44014
+ sectionPlane.once('destroyed', (() => {
43376
44015
  const sectionPlaneId = sectionPlane.id;
43377
44016
  if (sectionPlaneId) {
43378
44017
  this._sectionPlanes = this._sectionPlanes.filter((sectionPlane) => sectionPlane.id !== sectionPlaneId);
@@ -43389,13 +44028,19 @@ class SectionCaps {
43389
44028
 
43390
44029
  this._onTick = this.scene.on("tick", () => {
43391
44030
  //on ticks we only check if there is a model that we have saved vertices for,
43392
- //but it's no more available on the scene
43393
- for(const key in this._verticesMap) {
43394
- if(!this.scene.models[key]){
43395
- delete this._verticesMap[key];
43396
- delete this._indicesMap[key];
43397
- this._update();
43398
- }
44031
+ //but it's no more available on the scene, or if its visibility changed
44032
+ let dirty = false;
44033
+ for(const sceneModelId in this._sceneModelsData) {
44034
+ if(!this.scene.models[sceneModelId]){
44035
+ delete this._sceneModelsData[sceneModelId];
44036
+ dirty = true;
44037
+ } else if (this._sceneModelsData[sceneModelId].visible !== (!!this.scene.models[sceneModelId].visible)) {
44038
+ this._sceneModelsData[sceneModelId].visible = !!this.scene.models[sceneModelId].visible;
44039
+ dirty = true;
44040
+ }
44041
+ }
44042
+ if (dirty) {
44043
+ this._update();
43399
44044
  }
43400
44045
  });
43401
44046
  }
@@ -43412,8 +44057,8 @@ class SectionCaps {
43412
44057
  this._deletePreviousModels();
43413
44058
  this._updateTimeout = setTimeout(() => {
43414
44059
  clearTimeout(this._updateTimeout);
43415
- const sceneModels = Object.keys(this.scene.models).map((key) => this.scene.models[key]);
43416
- this._addHatches(sceneModels, this._sectionPlanes);
44060
+ const sceneModels = Object.values(this.scene.models).filter(sceneModel => sceneModel.visible);
44061
+ this._addHatches(sceneModels, this._sectionPlanes.filter(sectionPlane => sectionPlane.active));
43417
44062
  this._setAllDirty(false);
43418
44063
  }, 100);
43419
44064
  }
@@ -43426,21 +44071,9 @@ class SectionCaps {
43426
44071
 
43427
44072
  _addHatches(sceneModels, planes) {
43428
44073
 
43429
- if (planes.length <= 0) return;
43430
-
43431
44074
  planes.forEach((plane) => {
43432
44075
  sceneModels.forEach((sceneModel) => {
43433
- //#region creating a plane equation
43434
- //we create a plane equation that will be used to slice through each triangle
43435
- const planeEquation = {
43436
- A: plane.dir[0],
43437
- B: plane.dir[1],
43438
- C: plane.dir[2],
43439
- D: -(plane.dir[0] * plane.pos[0] + plane.dir[1] * plane.pos[1] + plane.dir[2] * plane.pos[2])
43440
- };
43441
- //#endregion
43442
-
43443
- if(!this._doesPlaneIntersectBoundingBox(sceneModel.aabb, planeEquation)) return;
44076
+ if(!this._doesPlaneIntersectBoundingBox(sceneModel.aabb, plane)) return;
43444
44077
 
43445
44078
  if(!this._dirtyMap[sceneModel.id]) return;
43446
44079
 
@@ -43462,39 +44095,35 @@ class SectionCaps {
43462
44095
 
43463
44096
  const object = objects[objectId];
43464
44097
 
43465
- if(!this._doesPlaneIntersectBoundingBox(object.aabb, planeEquation)) return;
44098
+ if(!this._doesPlaneIntersectBoundingBox(object.aabb, plane)) return;
43466
44099
 
43467
- if(!this._verticesMap[sceneModel.id]) {
43468
- this._verticesMap[sceneModel.id] = new Map();
43469
- this._indicesMap[sceneModel.id] = new Map();
44100
+ if(!this._sceneModelsData[sceneModel.id]) {
44101
+ this._sceneModelsData[sceneModel.id] = {
44102
+ verticesMap: new Map(),
44103
+ indicesMap: new Map()
44104
+ };
43470
44105
  }
43471
44106
 
43472
- let vertices = [], indices = [];
44107
+ const sceneModelData = this._sceneModelsData[sceneModel.id];
43473
44108
 
43474
- if(!this._verticesMap[sceneModel.id].has(objectId)) {
44109
+ if(!sceneModelData.verticesMap.has(objectId)) {
43475
44110
  const isSolid = object.meshes[0].isSolid();
44111
+ const vertices = [ ];
44112
+ const indices = [ ];
43476
44113
  if(isSolid && object.capMaterial) {
43477
- object.getEachVertex((_vertices) => {
43478
- vertices.push(_vertices[0], _vertices[1], _vertices[2]);
43479
- });
43480
- object.getEachIndex((_indices) => {
43481
- indices.push(_indices);
43482
- });
44114
+ object.getEachVertex(v => vertices.push(v[0], v[1], v[2]));
44115
+ object.getEachIndex(i => indices.push(i));
43483
44116
  }
43484
- this._verticesMap[sceneModel.id].set(objectId, vertices);
43485
- this._indicesMap[sceneModel.id].set(objectId, indices);
43486
- }
43487
- else {
43488
- vertices = this._verticesMap[sceneModel.id].get(objectId);
43489
- indices = this._indicesMap[sceneModel.id].get(objectId);
44117
+ sceneModelData.verticesMap.set(objectId, vertices);
44118
+ sceneModelData.indicesMap.set(objectId, indices);
43490
44119
  }
43491
-
44120
+
44121
+ const vertices = sceneModelData.verticesMap.get(objectId);
44122
+ const indices = sceneModelData.indicesMap.get(objectId);
44123
+
43492
44124
  const capSegments = [];
43493
44125
  const vertCount = indices.length;
43494
-
43495
- // Preallocate intersection result array
43496
- const intersectionBuffer = new Float32Array(3);
43497
-
44126
+
43498
44127
  for (let i = 0; i < vertCount; i += 3) {
43499
44128
  // Reuse triangle buffer instead of creating new arrays
43500
44129
  for (let j = 0; j < 3; j++) {
@@ -43511,21 +44140,15 @@ class SectionCaps {
43511
44140
  for (let i = 0; i < 3; i++) {
43512
44141
  const p1 = triangle[i];
43513
44142
  const p2 = triangle[(i + 1) % 3];
43514
-
43515
- // Inline the distance calculations to avoid function calls
43516
- const d1 = planeEquation.A * p1[0] + planeEquation.B * p1[1] + planeEquation.C * p1[2] + planeEquation.D;
43517
- const d2 = planeEquation.A * p2[0] + planeEquation.B * p2[1] + planeEquation.C * p2[2] + planeEquation.D;
43518
-
44143
+
44144
+ const d1 = plane.dist + math.dotVec3(plane.dir, p1);
44145
+ const d2 = plane.dist + math.dotVec3(plane.dir, p2);
44146
+
43519
44147
  if (d1 * d2 > 0) continue;
43520
-
44148
+
43521
44149
  const t = -d1 / (d2 - d1);
43522
- // Reuse intersection buffer
43523
- intersectionBuffer[0] = p1[0] + t * (p2[0] - p1[0]);
43524
- intersectionBuffer[1] = p1[1] + t * (p2[1] - p1[1]);
43525
- intersectionBuffer[2] = p1[2] + t * (p2[2] - p1[2]);
43526
-
43527
- // Clone the buffer for storage
43528
- intersections.push(new Float32Array(intersectionBuffer));
44150
+
44151
+ intersections.push(math.lerpVec3(t, 0, 1, p1, p2, math.vec3()));
43529
44152
  }
43530
44153
 
43531
44154
  if(intersections.length === 2) capSegments.push(intersections);
@@ -43805,7 +44428,7 @@ class SectionCaps {
43805
44428
 
43806
44429
  }
43807
44430
 
43808
- _doesPlaneIntersectBoundingBox(bb, planeEquation) {
44431
+ _doesPlaneIntersectBoundingBox(bb, plane) {
43809
44432
  const min = [bb[0], bb[1], bb[2]];
43810
44433
  const max = [bb[3], bb[4], bb[5]];
43811
44434
 
@@ -43825,10 +44448,7 @@ class SectionCaps {
43825
44448
  let hasNegative = false;
43826
44449
 
43827
44450
  for (const corner of corners) {
43828
- const distance = planeEquation.A * corner[0] +
43829
- planeEquation.B * corner[1] +
43830
- planeEquation.C * corner[2] +
43831
- planeEquation.D;
44451
+ const distance = plane.dist + math.dotVec3(plane.dir, corner);
43832
44452
 
43833
44453
  if (distance > 0) hasPositive = true;
43834
44454
  if (distance < 0) hasNegative = true;
@@ -44323,13 +44943,12 @@ class Scene extends Component {
44323
44943
  * configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
44324
44944
  * responsiveness. It is important to consider that each SectionPlane imposes rendering performance, so it is recommended to set this value to a quantity that aligns with
44325
44945
  * your expected usage.
44326
- * @throws {String} Throws an exception when both canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement.
44946
+ * @throws {String} Throws an exception when canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement.
44327
44947
  */
44328
44948
  constructor(viewer, cfg = {}) {
44329
44949
 
44330
44950
  super(null, cfg);
44331
-
44332
- const canvas = cfg.canvasElement || document.getElementById(cfg.canvasId);
44951
+ const canvas = cfg.canvasElement || document.querySelector(`#${cfg.canvasId}`);
44333
44952
 
44334
44953
  if (!(canvas instanceof HTMLCanvasElement)) {
44335
44954
  throw "Mandatory config expected: valid canvasId or canvasElement";
@@ -88569,7 +89188,7 @@ class LineSet extends Component {
88569
89188
  * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted.
88570
89189
  * @param {Number[]} cfg.positions World-space 3D vertex positions.
88571
89190
  * @param {Number[]} [cfg.indices] Indices to connect ````positions```` into line segments. Note that these are separate line segments, not a polyline.
88572
- * @param {Number[]} [cfg.color=[0,0,0]] The color of this ````LineSet````. This is both emissive and diffuse.
89191
+ * @param {Number[]} [cfg.color=[1,1,1]] The color of this ````LineSet````. This is both emissive and diffuse.
88573
89192
  * @param {Boolean} [cfg.visible=true] Indicates whether or not this ````LineSet```` is visible.
88574
89193
  * @param {Number} [cfg.opacity=1.0] ````LineSet````'s initial opacity factor.
88575
89194
  */
@@ -88589,6 +89208,9 @@ class LineSet extends Component {
88589
89208
  }
88590
89209
  }
88591
89210
 
89211
+ this._color = cfg.color || [1, 1, 1];
89212
+ this._opacity = cfg.opacity || 1.0;
89213
+
88592
89214
  this._sceneModel = new SceneModel(this, {
88593
89215
  isModel: false // Don't register in Scene.models
88594
89216
  });
@@ -88597,7 +89219,9 @@ class LineSet extends Component {
88597
89219
  id: "linesMesh",
88598
89220
  primitive: "lines",
88599
89221
  positions: this._positions,
88600
- indices: this._indices
89222
+ indices: this._indices,
89223
+ color: this._color,
89224
+ opacity: this._opacity,
88601
89225
  });
88602
89226
 
88603
89227
  this._sceneModel.createEntity({
@@ -92325,6 +92949,7 @@ class FastNavPlugin extends Plugin {
92325
92949
  * @param {Number} [cfg.scaleCanvasResolutionFactor=0.6] The factor by which we downscale the canvas resolution whenever we interact with the Viewer.
92326
92950
  * @param {Boolean} [cfg.delayBeforeRestore=true] Whether to temporarily have a delay before restoring normal rendering after we stop interacting with the Viewer.
92327
92951
  * @param {Number} [cfg.delayBeforeRestoreSeconds=0.5] Delay in seconds before restoring normal rendering after we stop interacting with the Viewer.
92952
+ * @param {Function} [cfg.onMoved] Optional callback function fired during moving mode, should return the callback function that will be fired when the interaction stops.
92328
92953
  */
92329
92954
  constructor(viewer, cfg = {}) {
92330
92955
 
@@ -92340,6 +92965,8 @@ class FastNavPlugin extends Plugin {
92340
92965
  this._scaleCanvasResolutionFactor = cfg.scaleCanvasResolutionFactor || 0.6;
92341
92966
  this._delayBeforeRestore = (cfg.delayBeforeRestore !== false);
92342
92967
  this._delayBeforeRestoreSeconds = cfg.delayBeforeRestoreSeconds || 0.5;
92968
+ this._onMoved = cfg.onMoved;
92969
+ this._onStopped = null;
92343
92970
 
92344
92971
  let timer = this._delayBeforeRestoreSeconds * 1000;
92345
92972
  let fastMode = false;
@@ -92358,6 +92985,10 @@ class FastNavPlugin extends Plugin {
92358
92985
  } else {
92359
92986
  viewer.scene.canvas.resolutionScale = this._defaultScaleCanvasResolutionFactor;
92360
92987
  }
92988
+ if (this._onMoved) {
92989
+ this._onStopped = this._onMoved();
92990
+ }
92991
+
92361
92992
  fastMode = true;
92362
92993
  }
92363
92994
  };
@@ -92369,6 +93000,9 @@ class FastNavPlugin extends Plugin {
92369
93000
  viewer.scene._renderer.setPBREnabled(true);
92370
93001
  viewer.scene._renderer.setSAOEnabled(true);
92371
93002
  viewer.scene._renderer.setTransparentEnabled(true);
93003
+ if (this._onStopped) {
93004
+ this._onStopped();
93005
+ }
92372
93006
  fastMode = false;
92373
93007
  };
92374
93008
 
@@ -97695,8 +98329,8 @@ class Skybox extends Component {
97695
98329
  * @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well.
97696
98330
  * @param {*} [cfg] Skybox configuration
97697
98331
  * @param {String} [cfg.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted.
97698
- * @param {String} [cfg.src=null] Path to skybox texture
97699
- * @param {String} [cfg.encoding="linear"] Texture encoding format. See the {@link Texture#encoding} property for more info.
98332
+ * @param {String | String[]} [cfg.src=null] Path to skybox texture
98333
+ * @param {Number} [cfg.encoding=LinearEncoding] Texture encoding format. See the {@link Texture#encoding} property for more info.
97700
98334
  * @param {Number} [cfg.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face.
97701
98335
  * @param {Boolean} [cfg.active=true] True when this Skybox is visible.
97702
98336
  */
@@ -97704,6 +98338,32 @@ class Skybox extends Component {
97704
98338
 
97705
98339
  super(owner, cfg);
97706
98340
 
98341
+ const useMultipleTexture = typeof cfg.src === "object" && cfg.src !== null;
98342
+
98343
+ if (useMultipleTexture) {
98344
+ this._createCombinedTexture(cfg).then(combinedTexture => {
98345
+ this._createSkyboxMesh(cfg, combinedTexture);
98346
+ }).catch(e => this.error(e));
98347
+ } else {
98348
+ this._createSkyboxMesh(cfg);
98349
+ }
98350
+ }
98351
+
98352
+ /**
98353
+ *
98354
+ * @private
98355
+ * @param {*} cfg
98356
+ * @param {Texture} combinedTexture
98357
+ */
98358
+ _createSkyboxMesh(cfg, combinedTexture = null) {
98359
+ const texture = combinedTexture || new Texture(this, {
98360
+ src: cfg.src,
98361
+ flipY: true,
98362
+ wrapS: ClampToEdgeWrapping,
98363
+ wrapT: ClampToEdgeWrapping,
98364
+ encoding: cfg.encoding || LinearEncoding
98365
+ });
98366
+
97707
98367
  this._skyboxMesh = new Mesh(this, {
97708
98368
 
97709
98369
  geometry: new ReadableGeometry(this, { // Box-shaped geometry
@@ -97734,13 +98394,7 @@ class Skybox extends Component {
97734
98394
  diffuse: [0, 0, 0],
97735
98395
  specular: [0, 0, 0],
97736
98396
  emissive: [1, 1, 1],
97737
- emissiveMap: new Texture(this, {
97738
- src: cfg.src,
97739
- flipY: true,
97740
- wrapS: "clampToEdge",
97741
- wrapT: "clampToEdge",
97742
- encoding: cfg.encoding || "sRGB"
97743
- }),
98397
+ emissiveMap: texture,
97744
98398
  backfaces: true // Show interior faces of our skybox geometry
97745
98399
  }),
97746
98400
  // stationary: true,
@@ -97754,6 +98408,86 @@ class Skybox extends Component {
97754
98408
  this.active = cfg.active;
97755
98409
  }
97756
98410
 
98411
+ /**
98412
+ *
98413
+ * @private
98414
+ * @param {*} cfg
98415
+ * @returns {Texture}
98416
+ */
98417
+ async _createCombinedTexture(cfg) {
98418
+ const [
98419
+ posX,
98420
+ negX,
98421
+ posY,
98422
+ negY,
98423
+ posZ,
98424
+ negZ
98425
+ ] = cfg.src;
98426
+
98427
+ if (!posX || !negX || !posY || !negY || !posZ || !negZ) {
98428
+ throw new Error("All six skybox textures must be provided");
98429
+ }
98430
+
98431
+ const canvas = document.createElement('canvas');
98432
+ const ctx = canvas.getContext('2d');
98433
+
98434
+ const loadImage = src => {
98435
+ return new Promise((resolve, reject) => {
98436
+ const img = new Image();
98437
+ img.crossOrigin = "anonymous";
98438
+ img.onload = () => resolve(img);
98439
+ img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
98440
+ img.src = src;
98441
+ });
98442
+ };
98443
+
98444
+ try {
98445
+ const [imgPosX, imgNegX, imgPosY, imgNegY, imgPosZ, imgNegZ] = await Promise.all([
98446
+ loadImage(posX),
98447
+ loadImage(negX),
98448
+ loadImage(posY),
98449
+ loadImage(negY),
98450
+ loadImage(posZ),
98451
+ loadImage(negZ)
98452
+ ]);
98453
+
98454
+ const imageSize = imgPosX.width;
98455
+ if (
98456
+ imgNegX.width !== imageSize || imgPosY.width !== imageSize ||
98457
+ imgNegY.width !== imageSize || imgPosZ.width !== imageSize ||
98458
+ imgNegZ.width !== imageSize
98459
+ ) {
98460
+ throw new Error("All skybox textures must have the same dimensions");
98461
+ }
98462
+
98463
+ // Set canvas size for the Christ cross layout (3×4 grid)
98464
+ canvas.width = imageSize * 4;
98465
+ canvas.height = imageSize * 3;
98466
+
98467
+ ctx.fillStyle = 'black';
98468
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
98469
+
98470
+ ctx.drawImage(imgNegX, imageSize * 0, imageSize * 1, imageSize, imageSize); // -X (left)
98471
+ ctx.drawImage(imgPosX, imageSize * 2, imageSize * 1, imageSize, imageSize); // +X (right)
98472
+ ctx.drawImage(imgPosY, imageSize * 1, imageSize * 0, imageSize, imageSize); // +Y (top)
98473
+ ctx.drawImage(imgNegY, imageSize * 1, imageSize * 2, imageSize, imageSize); // -Y (bottom)
98474
+ ctx.drawImage(imgPosZ, imageSize * 1, imageSize * 1, imageSize, imageSize); // +Z (front)
98475
+ ctx.drawImage(imgNegZ, imageSize * 3, imageSize * 1, imageSize, imageSize); // -Z (back)
98476
+
98477
+ const combinedTexture = new Texture(this, {
98478
+ image: canvas,
98479
+ flipY: true,
98480
+ wrapS: ClampToEdgeWrapping,
98481
+ wrapT: ClampToEdgeWrapping,
98482
+ encoding: cfg.encoding || LinearEncoding
98483
+ });
98484
+
98485
+ return combinedTexture;
98486
+ } catch (error) {
98487
+ console.error("Error creating combined skybox texture:", error);
98488
+ throw error;
98489
+ }
98490
+ }
97757
98491
 
97758
98492
  /**
97759
98493
  * Sets the size of this Skybox, given as the distance from the center at [0,0,0] to each face.
@@ -97948,6 +98682,9 @@ const tempVec4a$5 = math.vec4();
97948
98682
  const tempVec4b$5 = math.vec4();
97949
98683
  const tempVec4c = math.vec4();
97950
98684
 
98685
+ const TOP_LIMIT = 0.001;
98686
+ const BOTTOM_LIMIT = Math.PI - 0.001;
98687
+
97951
98688
 
97952
98689
  /** @private */
97953
98690
  class PivotController {
@@ -98123,14 +98860,9 @@ class PivotController {
98123
98860
  */
98124
98861
  startPivot() {
98125
98862
 
98126
- if (this._cameraLookingDownwards()) {
98127
- this._pivoting = false;
98128
- return false;
98129
- }
98130
-
98131
98863
  const camera = this._scene.camera;
98132
98864
 
98133
- let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.worldUp);
98865
+ let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.up);
98134
98866
  math.transformPoint3(lookat, this.getPivotPos(), this._cameraOffset);
98135
98867
 
98136
98868
  const pivotPos = this.getPivotPos();
@@ -98233,8 +98965,31 @@ class PivotController {
98233
98965
  dx = -dx;
98234
98966
  }
98235
98967
  this._azimuth += -dx * .01;
98236
- this._polar += dy * .01;
98237
- this._polar = math.clamp(this._polar, .001, Math.PI - .001);
98968
+
98969
+ const isMovingUp = dy < 0;
98970
+ const isMovingDown = dy > 0;
98971
+
98972
+ // Track if we're at limits - only check if we're very close to the limit
98973
+ const atTopLimit = Math.abs(this._polar - TOP_LIMIT) < 0.005;
98974
+ const atBottomLimit = Math.abs(this._polar - BOTTOM_LIMIT) < 0.005;
98975
+
98976
+ let newPolar = this._polar + dy * .01;
98977
+
98978
+ // Case 1: At top limit and trying to go beyond
98979
+ if (atTopLimit && isMovingUp) {
98980
+ newPolar = TOP_LIMIT;
98981
+ }
98982
+ // Case 2: At bottom limit and trying to go beyond
98983
+ else if (atBottomLimit && isMovingDown) {
98984
+ newPolar = BOTTOM_LIMIT;
98985
+ }
98986
+ // Case 3: Normal rotation or moving away from a limit
98987
+ else {
98988
+ newPolar = math.clamp(newPolar, TOP_LIMIT, BOTTOM_LIMIT);
98989
+ }
98990
+
98991
+ this._polar = newPolar;
98992
+
98238
98993
  const pos = [
98239
98994
  this._radius * Math.sin(this._polar) * Math.sin(this._azimuth),
98240
98995
  this._radius * Math.cos(this._polar),
@@ -111784,22 +112539,6 @@ class Viewer {
111784
112539
  this.sendToPlugins("snapshotStarting"); // Tells plugins to hide things that shouldn't be in snapshot
111785
112540
  }
111786
112541
 
111787
- const captured = {};
111788
- for (let i = 0, len = this._plugins.length; i < len; i++) {
111789
- const plugin = this._plugins[i];
111790
- if (plugin.getContainerElement) {
111791
- const container = plugin.getContainerElement();
111792
- if (container !== document.body) {
111793
- if (!captured[container.id]) {
111794
- captured[container.id] = true;
111795
- html2canvas(container).then(function (canvas) {
111796
- document.body.appendChild(canvas);
111797
- });
111798
- }
111799
- }
111800
- }
111801
- }
111802
-
111803
112542
  // firing "rendering" is necessary to trigger DTX{Lines,Triangles}Layer::_uploadDeferredFlags
111804
112543
  this.scene.fire("rendering", { }, true);
111805
112544
 
@@ -123577,6 +124316,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
123577
124316
  const cubeColor = "lightgrey";
123578
124317
  const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)";
123579
124318
  const textColor = cfg.textColor || "black";
124319
+ const parentNode = cfg.canvasElement || document.body;
123580
124320
 
123581
124321
  const height = 500;
123582
124322
  const width = height + (height / 3);
@@ -123686,8 +124426,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
123686
124426
  this._textureCanvas.style.visibility = "hidden";
123687
124427
  this._textureCanvas.style["z-index"] = 2000000;
123688
124428
 
123689
- const body = document.getElementsByTagName("body")[0];
123690
- body.appendChild(this._textureCanvas);
124429
+ parentNode.appendChild(this._textureCanvas);
123691
124430
 
123692
124431
  const context = this._textureCanvas.getContext("2d");
123693
124432
 
@@ -123957,7 +124696,7 @@ class NavCubePlugin extends Plugin {
123957
124696
  this._navCubeScene = new Scene(viewer, {
123958
124697
  canvasId: cfg.canvasId,
123959
124698
  canvasElement: cfg.canvasElement,
123960
- transparent: true
124699
+ transparent: true,
123961
124700
  });
123962
124701
 
123963
124702
  this._navCubeCanvas = this._navCubeScene.canvas.canvas;
@@ -124190,7 +124929,7 @@ class NavCubePlugin extends Plugin {
124190
124929
  }
124191
124930
  });
124192
124931
 
124193
- document.addEventListener("mouseup", self._onMouseUp = function (e) {
124932
+ self._navCubeCanvas.addEventListener("mouseup", self._onMouseUp = function (e) {
124194
124933
  if (e.which !== 1) {// Left button
124195
124934
  return;
124196
124935
  }
@@ -124207,7 +124946,7 @@ class NavCubePlugin extends Plugin {
124207
124946
  if (hit.uv) {
124208
124947
  var areaId = self._cubeTextureCanvas.getArea(hit.uv);
124209
124948
  if (areaId >= 0) {
124210
- document.body.style.cursor = "pointer";
124949
+ self._navCubeCanvas.style.cursor = "pointer";
124211
124950
  if (lastAreaId >= 0) {
124212
124951
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
124213
124952
  self._repaint();
@@ -124233,7 +124972,7 @@ class NavCubePlugin extends Plugin {
124233
124972
  self._repaint();
124234
124973
  lastAreaId = -1;
124235
124974
  }
124236
- document.body.style.cursor = "pointer";
124975
+ self._navCubeCanvas.style.cursor = "pointer";
124237
124976
  if (lastAreaId >= 0) {
124238
124977
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
124239
124978
  self._repaint();
@@ -124252,7 +124991,7 @@ class NavCubePlugin extends Plugin {
124252
124991
  }
124253
124992
  });
124254
124993
 
124255
- document.addEventListener("mousemove", self._onMouseMove = function (e) {
124994
+ self._navCubeCanvas.addEventListener("mousemove", self._onMouseMove = function (e) {
124256
124995
  if (lastAreaId >= 0) {
124257
124996
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
124258
124997
  self._repaint();
@@ -124264,7 +125003,7 @@ class NavCubePlugin extends Plugin {
124264
125003
  if (down) {
124265
125004
  var posX = e.clientX;
124266
125005
  var posY = e.clientY;
124267
- document.body.style.cursor = "move";
125006
+ self._navCubeCanvas.style.cursor = "move";
124268
125007
  actionMove(posX, posY);
124269
125008
  return;
124270
125009
  }
@@ -124278,7 +125017,7 @@ class NavCubePlugin extends Plugin {
124278
125017
  });
124279
125018
  if (hit) {
124280
125019
  if (hit.uv) {
124281
- document.body.style.cursor = "pointer";
125020
+ self._navCubeCanvas.style.cursor = "pointer";
124282
125021
  var areaId = self._cubeTextureCanvas.getArea(hit.uv);
124283
125022
  if (areaId === lastAreaId) {
124284
125023
  return;
@@ -124293,7 +125032,7 @@ class NavCubePlugin extends Plugin {
124293
125032
  }
124294
125033
  }
124295
125034
  } else {
124296
- document.body.style.cursor = "default";
125035
+ self._navCubeCanvas.style.cursor = "default";
124297
125036
  if (lastAreaId >= 0) {
124298
125037
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
124299
125038
  self._repaint();
@@ -124556,8 +125295,8 @@ class NavCubePlugin extends Plugin {
124556
125295
  this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave);
124557
125296
  this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown);
124558
125297
 
124559
- document.removeEventListener("mousemove", this._onMouseMove);
124560
- document.removeEventListener("mouseup", this._onMouseUp);
125298
+ this._navCubeCanvas.removeEventListener("mousemove", this._onMouseMove);
125299
+ this._navCubeCanvas.removeEventListener("mouseup", this._onMouseUp);
124561
125300
 
124562
125301
  this._navCubeCanvas = null;
124563
125302
  this._cubeTextureCanvas.destroy();
@@ -125951,8 +126690,8 @@ class Control {
125951
126690
  const canvasPos = math.vec2();
125952
126691
 
125953
126692
  const copyCanvasPos = (event, vec2) => {
125954
- vec2[0] = event.clientX;
125955
- vec2[1] = event.clientY;
126693
+ vec2[0] = event.pageX;
126694
+ vec2[1] = event.pageY;
125956
126695
  transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
125957
126696
  };
125958
126697
 
@@ -129450,46 +130189,27 @@ class FaceAlignedSectionPlanesPlugin extends Plugin {
129450
130189
  * });
129451
130190
  *
129452
130191
  * // Add a GLTFModelsPlugin
129453
- * var gltfLoaderPlugin = new GLTFModelsPlugin(viewer, {
129454
- * id: "GLTFModels" // Default value
129455
- * });
130192
+ * var xktLoaderPlugin = new XKTLoaderPlugin(viewer);
129456
130193
  *
129457
130194
  * // Add a SkyboxesPlugin
129458
- * var skyboxesPlugin = new SkyboxesPlugin(viewer, {
129459
- * id: "Skyboxes" // Default value
129460
- * });
130195
+ * var skyboxesPlugin = new SkyboxesPlugin(viewer);
130196
+ *
130197
+ * // Create a skybox
130198
+ * skyBoxesPlugin.createSkybox({
130199
+ * src: [
130200
+ * "./assets/images/posx.jpg",
130201
+ * "./assets/images/negx.jpg",
130202
+ * "./assets/images/posy.jpg",
130203
+ * "./assets/images/negy.jpg",
130204
+ * "./assets/images/posz.jpg",
130205
+ * "./assets/images/negz.jpg"
130206
+ * ]
130207
+ * })
129461
130208
  *
129462
- * // Load a glTF model
129463
- * const model = gltfLoaderPlugin.load({
130209
+ * // Load an XKT model
130210
+ * const model = xktLoaderPlugin.load({
129464
130211
  * id: "myModel",
129465
- * src: "./models/gltf/mygltfmodel.gltf"
129466
- * });
129467
- *
129468
- * // Create three directional World-space lights. "World" means that they will appear as if part
129469
- * // of the world, instead of "View", where they move with the user's head.
129470
- *
129471
- * skyboxesPlugin.createLight({
129472
- * id: "keyLight",
129473
- * dir: [0.8, -0.6, -0.8],
129474
- * color: [1.0, 0.3, 0.3],
129475
- * intensity: 1.0,
129476
- * space: "world"
129477
- * });
129478
- *
129479
- * skyboxesPlugin.createLight({
129480
- * id: "fillLight",
129481
- * dir: [-0.8, -0.4, -0.4],
129482
- * color: [0.3, 1.0, 0.3],
129483
- * intensity: 1.0,
129484
- * space: "world"
129485
- * });
129486
- *
129487
- * skyboxesPlugin.createDirLight({
129488
- * id: "rimLight",
129489
- * dir: [0.2, -0.8, 0.8],
129490
- * color: [0.6, 0.6, 0.6],
129491
- * intensity: 1.0,
129492
- * space: "world"
130212
+ * src: "./models/xkt/myModel.xkt"
129493
130213
  * });
129494
130214
  *
129495
130215
  * @class SkyboxesPlugin
@@ -129515,23 +130235,17 @@ class SkyboxesPlugin extends Plugin {
129515
130235
  /**
129516
130236
  Creates a skybox.
129517
130237
 
129518
- @param {String} id Unique ID to assign to the skybox.
129519
130238
  @param {Object} params Skybox configuration.
130239
+ @param {String} [params.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted.
130240
+ @param {String | String[]} [params.src=null] Path to skybox texture
130241
+ @param {Number} [params.encoding=LinearEncoding] Texture encoding format. See the {@link Texture#encoding} property for more info.
130242
+ @param {Number} [params.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face.
129520
130243
  @param {Boolean} [params.active=true] Whether the skybox plane is initially active. Only skyboxes while this is true.
129521
130244
  @returns {Skybox} The new skybox.
129522
130245
  */
129523
- createSkybox(id, params) {
129524
- if (this.viewer.scene.components[id]) {
129525
- this.error("Component with this ID already exists: " + id);
129526
- return this;
129527
- }
129528
- var skybox = new Skybox(this.viewer.scene, {
129529
- id: id,
129530
- pos: params.pos,
129531
- dir: params.dir,
129532
- active: true
129533
- });
129534
- this.skyboxes[id] = skybox;
130246
+ createSkybox(params) {
130247
+ const skybox = new Skybox(this.viewer.scene, params);
130248
+ this.skyboxes[skybox.id] = skybox;
129535
130249
  return skybox;
129536
130250
  }
129537
130251
 
@@ -130194,6 +130908,15 @@ class STLLoaderPlugin extends Plugin {
130194
130908
  */
130195
130909
  class RenderService {
130196
130910
 
130911
+ /**
130912
+ * @constructor
130913
+ *
130914
+ * @param {HTMLElement} treeViewContainer Container element for the tree which uses this render service.
130915
+ */
130916
+ constructor(treeViewContainer) {
130917
+ this._treeViewContainer = treeViewContainer;
130918
+ }
130919
+
130197
130920
  /*
130198
130921
  * Creates the root node of the tree.
130199
130922
  * @return {HTMLElement} The root node of the tree.
@@ -130318,7 +131041,7 @@ class RenderService {
130318
131041
  }
130319
131042
 
130320
131043
  getSwitchElement(nodeId) {
130321
- return document.getElementById(`switch-${nodeId}`);
131044
+ return this._treeViewContainer.querySelector(`[id="switch-${nodeId}"]`);
130322
131045
  }
130323
131046
 
130324
131047
  isChecked(element) {
@@ -130326,7 +131049,7 @@ class RenderService {
130326
131049
  }
130327
131050
 
130328
131051
  setCheckbox(nodeId, checked, indeterminate = false) {
130329
- const checkbox = document.getElementById(`checkbox-${nodeId}`);
131052
+ const checkbox = this._treeViewContainer.querySelector(`[id="checkbox-${nodeId}"]`);
130330
131053
  if (checkbox) {
130331
131054
  if (checked !== checkbox.checked) {
130332
131055
  checkbox.checked = checked;
@@ -130341,7 +131064,7 @@ class RenderService {
130341
131064
  }
130342
131065
 
130343
131066
  setXRayed(nodeId, xrayed) {
130344
- const treeNode = document.getElementById(nodeId);
131067
+ const treeNode = this._treeViewContainer.querySelector(`[id="${nodeId}"]`);
130345
131068
  if (treeNode) {
130346
131069
  if (xrayed) {
130347
131070
  treeNode.classList.add('xrayed-node');
@@ -130352,7 +131075,7 @@ class RenderService {
130352
131075
  }
130353
131076
 
130354
131077
  setHighlighted(nodeId, highlighted) {
130355
- const treeNode = document.getElementById(nodeId);
131078
+ const treeNode = this._treeViewContainer.querySelector(`[id="${nodeId}"]`);
130356
131079
  if (treeNode) {
130357
131080
  if (highlighted) {
130358
131081
  treeNode.scrollIntoView({block: "center"});
@@ -130778,7 +131501,7 @@ class TreeViewPlugin extends Plugin {
130778
131501
  this._sortNodes = cfg.sortNodes;
130779
131502
  this._pruneEmptyNodes = cfg.pruneEmptyNodes;
130780
131503
  this._showListItemElementId = null;
130781
- this._renderService = cfg.renderService || new RenderService();
131504
+ this._renderService = cfg.renderService || new RenderService(this._containerElement);
130782
131505
  this._showIndeterminate = cfg.showIndeterminate ?? false;
130783
131506
  this._showProjectNode = cfg.showProjectNode ?? false;
130784
131507
  this._elevationSortFunction = cfg.elevationSortFunction ?? undefined;
@@ -168432,151 +169155,6 @@ const hex2rgb = function(color) {
168432
169155
  return [ rgb(0), rgb(2), rgb(4) ];
168433
169156
  };
168434
169157
 
168435
- const triangulateEarClipping = function(planeCoords) {
168436
-
168437
- const polygonVertices = [ ];
168438
- for (let i = 0; i < planeCoords.length; ++i)
168439
- polygonVertices.push(i);
168440
-
168441
- const isCCW = (function() {
168442
- const ba = math.vec2();
168443
- const bc = math.vec2();
168444
-
168445
- let anglesSum = 0;
168446
-
168447
- for (let i = 0; i < polygonVertices.length; ++i)
168448
- {
168449
- const a = planeCoords[polygonVertices[i]];
168450
- const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
168451
- const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
168452
-
168453
- math.subVec2(a, b, ba);
168454
- math.subVec2(c, b, bc);
168455
-
168456
- const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
168457
- const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
168458
- const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
168459
- anglesSum += convex ? angle : (2 * Math.PI - angle);
168460
- }
168461
-
168462
- return anglesSum < (polygonVertices.length * Math.PI);
168463
- })();
168464
-
168465
- const pointInTriangle = (function() {
168466
- const sign = (p1, p2, p3) => {
168467
- return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
168468
- };
168469
-
168470
- return (pt, v1, v2, v3) => {
168471
- const d1 = sign(pt, v1, v2);
168472
- const d2 = sign(pt, v2, v3);
168473
- const d3 = sign(pt, v3, v1);
168474
-
168475
- const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
168476
- const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
168477
-
168478
- return !(has_neg && has_pos);
168479
- };
168480
- })();
168481
-
168482
- const baseTriangles = [ ];
168483
-
168484
- const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
168485
- vertices.forEach((v, i) => {
168486
- v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
168487
- v.next = vertices[(i + 1) % vertices.length];
168488
- });
168489
-
168490
- const ba = math.vec2();
168491
- const bc = math.vec2();
168492
-
168493
- while (vertices.length > 2) {
168494
- let earIdx = 0;
168495
- while (true) {
168496
- if (earIdx >= vertices.length)
168497
- {
168498
- throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
168499
- }
168500
- const v = vertices[earIdx];
168501
-
168502
- const a = planeCoords[v.prev.idx];
168503
- const b = planeCoords[v.idx];
168504
- const c = planeCoords[v.next.idx];
168505
-
168506
- math.subVec2(a, b, ba);
168507
- math.subVec2(c, b, bc);
168508
-
168509
- if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
168510
- &&
168511
- vertices.every( // no other vertices inside
168512
- vv => ((vv === v)
168513
- ||
168514
- (vv === v.prev)
168515
- ||
168516
- (vv === v.next)
168517
- ||
168518
- !pointInTriangle(planeCoords[vv.idx], a, b, c))))
168519
- break;
168520
- ++earIdx;
168521
- }
168522
-
168523
- const ear = vertices[earIdx];
168524
- vertices.splice(earIdx, 1);
168525
-
168526
- baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
168527
-
168528
- const prev = ear.prev;
168529
- prev.next = ear.next;
168530
- const next = ear.next;
168531
- next.prev = ear.prev;
168532
- }
168533
-
168534
- return [ planeCoords, baseTriangles, isCCW ];
168535
- };
168536
-
168537
- const marker3D = function(scene, color) {
168538
- const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
168539
- borderColor: "white",
168540
- fillColor: color,
168541
- zIndex: 100
168542
- });
168543
-
168544
- return {
168545
- update: function(worldPos) {
168546
- if (worldPos)
168547
- {
168548
- marker.worldPos = worldPos;
168549
- }
168550
- marker.setVisible(!!worldPos);
168551
- },
168552
-
168553
- setHighlighted: h => marker.setHighlighted(h),
168554
- getCanvasPos: () => marker.canvasPos,
168555
- getWorldPos: () => marker.worldPos,
168556
- destroy: () => marker.destroy()
168557
- };
168558
- };
168559
-
168560
- const wire3D = function(scene, color, startWorldPos) {
168561
- const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
168562
- color: color,
168563
- thickness: 1,
168564
- thicknessClickable: 6
168565
- });
168566
- wire.setVisible(false);
168567
- return {
168568
- update: endWorldPos => {
168569
- if (endWorldPos)
168570
- {
168571
- wire.setEnds(startWorldPos, endWorldPos);
168572
- }
168573
- wire.setVisible(!!endWorldPos);
168574
- },
168575
-
168576
- destroy: () => wire.destroy()
168577
- };
168578
- };
168579
-
168580
169158
  const basePolygon3D = function(scene, color, alpha) {
168581
169159
  let mesh = null;
168582
169160
 
@@ -169556,7 +170134,8 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
169556
170134
 
169557
170135
  (function selectNextPoint(markers) {
169558
170136
  const marker = marker3D(scene, zoneColor);
169559
- const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
170137
+ const wire = (markers.length > 0) && wire3D(scene, zoneColor);
170138
+ const wireStart = wire && markers[markers.length - 1].getWorldPos();
169560
170139
 
169561
170140
  cleanups.push(() => {
169562
170141
  marker.destroy();
@@ -169616,7 +170195,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
169616
170195
  () => {
169617
170196
  updatePointerLens(null);
169618
170197
  marker.update(null);
169619
- wire && wire.update(null);
170198
+ wire && wire.update(wireStart, null);
169620
170199
  basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
169621
170200
  },
169622
170201
  (canvasPos, worldPos) => {
@@ -169624,7 +170203,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
169624
170203
  firstMarker && firstMarker.setHighlighted(!! snappedFirst);
169625
170204
  updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
169626
170205
  marker.update((! snappedFirst) && worldPos);
169627
- wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
170206
+ wire && wire.update(wireStart, snappedFirst ? snappedFirst.worldPos : worldPos);
169628
170207
  if ((markers.length >= 2))
169629
170208
  {
169630
170209
  const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
@@ -169668,7 +170247,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
169668
170247
  else
169669
170248
  {
169670
170249
  marker.update(worldPos);
169671
- wire && wire.update(worldPos);
170250
+ wire && wire.update(wireStart, worldPos);
169672
170251
  selectNextPoint(markers.concat(marker));
169673
170252
  }
169674
170253
  });
@@ -170103,4 +170682,4 @@ class ZoneTranslateTouchControl extends ZoneTranslateControl {
170103
170682
  }
170104
170683
  }
170105
170684
 
170106
- export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, CxConverterIFCLoaderPlugin, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditControl, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, Dot3D, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, Label3D, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MeshSurfaceArea, MeshVolume, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, Wire3D, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, activateDraggableDot, activateDraggableDots, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildLineGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createRTCViewMat, frustumIntersectsAABB3, getKTX2TextureTranscoder, getPlaneRTCPos, isTriangleMeshSolid, load3DSGeometry, loadOBJGeometry, math, meshSurfaceArea, meshVolume, os, rtcToWorldPos, sRGBEncoding, setFrustum, stats, touchPointSelector, transformToNode, utils, worldToRTCPos, worldToRTCPositions };
170685
+ export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, CxConverterIFCLoaderPlugin, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditControl, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, Dot3D, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, Label3D, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MeshSurfaceArea, MeshVolume, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, Wire3D, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, activateDraggableDot, activateDraggableDots, addMousePressListener, addTouchPressListener, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildLineGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createRTCViewMat, frustumIntersectsAABB3, getKTX2TextureTranscoder, getPlaneRTCPos, isTriangleMeshSolid, load3DSGeometry, loadOBJGeometry, marker3D, math, meshSurfaceArea, meshVolume, os, rtcToWorldPos, sRGBEncoding, setFrustum, startPolygonCreate, stats, touchPointSelector, transformToNode, triangulateEarClipping, utils, wire3D, worldToRTCPos, worldToRTCPositions };