@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.
- package/dist/xeokit-sdk.cjs.js +985 -400
- package/dist/xeokit-sdk.es.js +980 -401
- package/dist/xeokit-sdk.es5.js +734 -714
- package/dist/xeokit-sdk.min.cjs.js +8 -8
- package/dist/xeokit-sdk.min.es.js +8 -8
- package/dist/xeokit-sdk.min.es5.js +7 -7
- package/package.json +1 -1
- package/src/extras/ContextMenu/ContextMenu.js +25 -16
- package/src/plugins/FastNavPlugin/FastNavPlugin.js +10 -0
- package/src/plugins/SkyboxesPlugin/SkyboxesPlugin.js +24 -49
- package/src/plugins/TreeViewPlugin/RenderService.js +13 -4
- package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +1 -1
- package/src/viewer/Viewer.js +0 -16
- package/src/viewer/scene/CameraControl/lib/controllers/PivotController.js +29 -8
- package/src/viewer/scene/LineSet/LineSet.js +7 -2
- package/src/viewer/scene/skybox/Skybox.js +110 -9
- package/types/plugins/SkyboxesPlugin/SkyboxesPlugin.d.ts +18 -4
- package/types/viewer/scene/CameraControl/CameraControl.d.ts +168 -0
- package/types/viewer/scene/LineSet/LineSet.d.ts +1 -1
- package/types/viewer/scene/camera/CameraPath.d.ts +86 -6
- package/types/viewer/scene/camera/CameraPathAnimation.d.ts +2 -0
- package/types/viewer/scene/geometry/ReadableGeometry.d.ts +14 -0
- package/types/viewer/scene/geometry/VBOGeometry.d.ts +2 -0
- package/types/viewer/scene/geometry/index.d.ts +2 -1
- package/types/viewer/scene/geometry/loaders/index.d.ts +2 -0
- package/types/viewer/scene/geometry/loaders/load3DSGeometry.d.ts +17 -0
- package/types/viewer/scene/geometry/loaders/loadOBJGeometry.d.ts +18 -0
- package/types/viewer/scene/index.d.ts +2 -0
- package/types/viewer/scene/input/input.d.ts +117 -0
- package/types/viewer/scene/lights/AmbientLight.d.ts +41 -0
- package/types/viewer/scene/lights/CubeTexture.d.ts +27 -0
- package/types/viewer/scene/lights/DirLight.d.ts +77 -0
- package/types/viewer/scene/lights/LightMap.d.ts +27 -0
- package/types/viewer/scene/lights/PointLight.d.ts +135 -0
- package/types/viewer/scene/lights/ReflectionMap.d.ts +26 -0
- package/types/viewer/scene/lights/index.d.ts +4 -1
- package/types/viewer/scene/marker/Marker.d.ts +5 -0
- package/types/viewer/scene/materials/EmphasisMaterial.d.ts +5 -0
- package/types/viewer/scene/materials/Fresnel.d.ts +25 -62
- package/types/viewer/scene/materials/LambertMaterial.d.ts +192 -0
- package/types/viewer/scene/materials/MetallicMaterial.d.ts +359 -0
- package/types/viewer/scene/materials/PhongMaterial.d.ts +5 -0
- package/types/viewer/scene/materials/PointsMaterial.d.ts +5 -0
- package/types/viewer/scene/materials/SpecularMaterial.d.ts +342 -0
- package/types/viewer/scene/materials/Texture.d.ts +36 -78
- package/types/viewer/scene/materials/index.d.ts +2 -0
- package/types/viewer/scene/models/SceneModel.d.ts +134 -7
- package/types/viewer/scene/models/SceneModelEntity.d.ts +65 -0
- package/types/viewer/scene/models/SceneModelMesh.d.ts +12 -0
- package/types/viewer/scene/paths/CubicBezierCurve.d.ts +146 -0
- package/types/viewer/scene/paths/Curve.d.ts +75 -0
- package/types/viewer/scene/paths/Path.d.ts +119 -0
- package/types/viewer/scene/paths/QuadraticBezierCurve.d.ts +124 -0
- package/types/viewer/scene/paths/SplineCurve.d.ts +84 -0
- package/types/viewer/scene/paths/index.d.ts +5 -0
- package/types/viewer/scene/scene/Scene.d.ts +102 -0
- package/types/viewer/scene/sectionPlane/SectionPlane.d.ts +41 -0
- package/types/viewer/scene/skybox/Skybox.d.ts +59 -0
- package/types/viewer/scene/skybox/index.d.ts +1 -0
- package/types/viewer/scene/webgl/PickResult.d.ts +19 -0
package/dist/xeokit-sdk.cjs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* xeokit-sdk v2.6.
|
|
3
|
-
* Commit:
|
|
4
|
-
* Built: 2025-
|
|
2
|
+
* xeokit-sdk v2.6.75
|
|
3
|
+
* Commit: c9b6b9ca6ba5bea44b4e84678d4f9ffbf152086d
|
|
4
|
+
* Built: 2025-04-17T10:44:28.149Z
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
@@ -334,6 +334,7 @@ class ContextMenu {
|
|
|
334
334
|
* @param {Boolean} [cfg.enabled=true] Whether this ````ContextMenu```` is initially enabled. {@link ContextMenu#show} does nothing while this is ````false````.
|
|
335
335
|
* @param {Boolean} [cfg.hideOnMouseDown=true] Whether this ````ContextMenu```` automatically hides whenever we mouse-down or tap anywhere in the page.
|
|
336
336
|
* @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.
|
|
337
|
+
* @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````.
|
|
337
338
|
*/
|
|
338
339
|
constructor(cfg = {}) {
|
|
339
340
|
|
|
@@ -348,7 +349,9 @@ class ContextMenu {
|
|
|
348
349
|
this._itemMap = {}; // Items mapped to their IDs
|
|
349
350
|
this._shown = false; // True when the ContextMenu is visible
|
|
350
351
|
this._nextId = 0;
|
|
351
|
-
|
|
352
|
+
this._parentNode = cfg.parentNode || document.body;
|
|
353
|
+
this._offsetParent = (this._parentNode instanceof ShadowRoot) ? this._parentNode.host : this._parentNode;
|
|
354
|
+
|
|
352
355
|
/**
|
|
353
356
|
* Subscriptions to events fired at this ContextMenu.
|
|
354
357
|
* @private
|
|
@@ -356,12 +359,12 @@ class ContextMenu {
|
|
|
356
359
|
this._eventSubs = {};
|
|
357
360
|
|
|
358
361
|
if (cfg.hideOnMouseDown !== false) {
|
|
359
|
-
|
|
362
|
+
this._parentNode.addEventListener("mousedown", (event) => {
|
|
360
363
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
361
364
|
this.hide();
|
|
362
365
|
}
|
|
363
366
|
});
|
|
364
|
-
|
|
367
|
+
this._parentNode.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
|
|
365
368
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
366
369
|
this.hide();
|
|
367
370
|
}
|
|
@@ -560,7 +563,7 @@ class ContextMenu {
|
|
|
560
563
|
for (let i = 0, len = this._menuList.length; i < len; i++) {
|
|
561
564
|
const menu = this._menuList[i];
|
|
562
565
|
const menuElement = menu.menuElement;
|
|
563
|
-
menuElement.
|
|
566
|
+
menuElement.remove();
|
|
564
567
|
}
|
|
565
568
|
this._itemsCfg = [];
|
|
566
569
|
this._rootMenu = null;
|
|
@@ -665,7 +668,10 @@ class ContextMenu {
|
|
|
665
668
|
const groups = menu.groups;
|
|
666
669
|
const html = [];
|
|
667
670
|
|
|
668
|
-
|
|
671
|
+
const menuElement= document.createElement("div");
|
|
672
|
+
menuElement.classList.add("xeokit-context-menu", menu.id);
|
|
673
|
+
menuElement.style.zIndex = 300000;
|
|
674
|
+
menuElement.style.position = "absolute";
|
|
669
675
|
|
|
670
676
|
html.push('<ul>');
|
|
671
677
|
|
|
@@ -716,13 +722,10 @@ class ContextMenu {
|
|
|
716
722
|
}
|
|
717
723
|
|
|
718
724
|
html.push('</ul>');
|
|
719
|
-
html.push('</div>');
|
|
720
725
|
|
|
721
726
|
const htmlString = html.join("");
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const menuElement = document.querySelector("." + menu.id);
|
|
727
|
+
menuElement.innerHTML = htmlString;
|
|
728
|
+
this._parentNode.appendChild(menuElement);
|
|
726
729
|
|
|
727
730
|
menu.menuElement = menuElement;
|
|
728
731
|
|
|
@@ -756,7 +759,7 @@ class ContextMenu {
|
|
|
756
759
|
const item = groupItems[j];
|
|
757
760
|
const itemSubMenu = item.subMenu;
|
|
758
761
|
|
|
759
|
-
item.itemElement =
|
|
762
|
+
item.itemElement = this._parentNode.querySelector(`#${item.id}`);
|
|
760
763
|
|
|
761
764
|
if (!item.itemElement) {
|
|
762
765
|
console.error("ContextMenu item element not found: " + item.id);
|
|
@@ -788,21 +791,22 @@ class ContextMenu {
|
|
|
788
791
|
|
|
789
792
|
const itemRect = itemElement.getBoundingClientRect();
|
|
790
793
|
subMenuElement.getBoundingClientRect();
|
|
794
|
+
const offsetRect = self._offsetParent.getBoundingClientRect();
|
|
791
795
|
|
|
792
796
|
const subMenuWidth = 200; // TODO
|
|
793
|
-
const showOnRight = (itemRect.right + subMenuWidth) <
|
|
794
|
-
const showOnLeft = (itemRect.left - subMenuWidth) >
|
|
795
|
-
|
|
797
|
+
const showOnRight = (itemRect.right + subMenuWidth) < offsetRect.right;
|
|
798
|
+
const showOnLeft = (itemRect.left - subMenuWidth) > offsetRect.left;
|
|
799
|
+
|
|
796
800
|
if(showOnRight)
|
|
797
|
-
self._showMenu(subMenu.id, itemRect.right - 5, itemRect.top - 1);
|
|
801
|
+
self._showMenu(subMenu.id, itemRect.right + window.scrollX - 5, itemRect.top + window.scrollY - 1);
|
|
798
802
|
else if (showOnLeft)
|
|
799
|
-
self._showMenu(subMenu.id, itemRect.left - subMenuWidth, itemRect.top - 1);
|
|
803
|
+
self._showMenu(subMenu.id, itemRect.left - subMenuWidth + window.scrollX, itemRect.top + window.scrollY - 1);
|
|
800
804
|
else {
|
|
801
|
-
const spaceOnLeft = itemRect.left, spaceOnRight =
|
|
805
|
+
const spaceOnLeft = itemRect.left - offsetRect.left, spaceOnRight = offsetRect.right - itemRect.right;
|
|
802
806
|
if(spaceOnRight > spaceOnLeft)
|
|
803
|
-
self._showMenu(subMenu.id, itemRect.right - 5 - (subMenuWidth - spaceOnRight), itemRect.top - 1);
|
|
807
|
+
self._showMenu(subMenu.id, itemRect.right - 5 - (subMenuWidth - spaceOnRight), itemRect.top + window.scrollY - 1);
|
|
804
808
|
else
|
|
805
|
-
self._showMenu(subMenu.id, itemRect.left - spaceOnLeft, itemRect.top - 1);
|
|
809
|
+
self._showMenu(subMenu.id, itemRect.left - spaceOnLeft, itemRect.top + window.scrollY - 1);
|
|
806
810
|
}
|
|
807
811
|
|
|
808
812
|
lastSubMenu = subMenu;
|
|
@@ -995,14 +999,21 @@ class ContextMenu {
|
|
|
995
999
|
menuElement.style.display = 'block';
|
|
996
1000
|
const menuHeight = menuElement.offsetHeight;
|
|
997
1001
|
const menuWidth = menuElement.offsetWidth;
|
|
998
|
-
|
|
999
|
-
|
|
1002
|
+
|
|
1003
|
+
const offsetRect = this._offsetParent.getBoundingClientRect();
|
|
1004
|
+
|
|
1005
|
+
const bottomContainerBorder = offsetRect.bottom + window.scrollY;
|
|
1006
|
+
const rightContainerBorder = offsetRect.right + window.scrollX;
|
|
1007
|
+
if ((pageY + menuHeight) > bottomContainerBorder) {
|
|
1008
|
+
pageY = bottomContainerBorder- menuHeight;
|
|
1000
1009
|
}
|
|
1001
|
-
if ((pageX + menuWidth) >
|
|
1002
|
-
pageX =
|
|
1010
|
+
if ((pageX + menuWidth) > rightContainerBorder) {
|
|
1011
|
+
pageX = rightContainerBorder - menuWidth;
|
|
1003
1012
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
menuElement.style.left = pageX - offsetRect.left - window.scrollX + 'px';
|
|
1016
|
+
menuElement.style.top = pageY - offsetRect.top - window.scrollY + 'px';
|
|
1006
1017
|
}
|
|
1007
1018
|
|
|
1008
1019
|
_hideMenuElement(menuElement) {
|
|
@@ -11659,9 +11670,28 @@ const tmpVec4b = math.vec4();
|
|
|
11659
11670
|
const tmpVec4c = math.vec4();
|
|
11660
11671
|
const tmpVec4d = math.vec4();
|
|
11661
11672
|
const tmpMat4 = math.mat4();
|
|
11673
|
+
const tmpRay = {
|
|
11674
|
+
origin: math.vec3(),
|
|
11675
|
+
direction: math.vec3()
|
|
11676
|
+
};
|
|
11662
11677
|
|
|
11663
11678
|
const nop = () => { };
|
|
11664
11679
|
|
|
11680
|
+
const planeIntersect$1 = function(p0, n, origin, direction) {
|
|
11681
|
+
const t = (p0 - math.dotVec3(origin, n)) / math.dotVec3(direction, n);
|
|
11682
|
+
if (t < 0)
|
|
11683
|
+
{
|
|
11684
|
+
return null;
|
|
11685
|
+
}
|
|
11686
|
+
else
|
|
11687
|
+
{
|
|
11688
|
+
const worldPos = math.vec3();
|
|
11689
|
+
math.mulVec3Scalar(direction, t, worldPos);
|
|
11690
|
+
math.addVec3(origin, worldPos, worldPos);
|
|
11691
|
+
return worldPos;
|
|
11692
|
+
}
|
|
11693
|
+
};
|
|
11694
|
+
|
|
11665
11695
|
function transformToNode(from, to, vec) {
|
|
11666
11696
|
const fromRec = from.getBoundingClientRect();
|
|
11667
11697
|
const toRec = to.getBoundingClientRect();
|
|
@@ -11923,9 +11953,15 @@ class Label3D {
|
|
|
11923
11953
|
this._mid = math.vec3();
|
|
11924
11954
|
this._end = math.vec3();
|
|
11925
11955
|
this._yOff = 0;
|
|
11926
|
-
this._betweenWires = false;
|
|
11927
11956
|
this.__visible = true;
|
|
11928
11957
|
|
|
11958
|
+
this._updatePos = () => {
|
|
11959
|
+
toClipSpace(camera, this._start, tmpVec4a);
|
|
11960
|
+
math.mulVec4Scalar(tmpVec4a, 1.0 / tmpVec4a[3]);
|
|
11961
|
+
toCanvasSpace(scene.canvas.canvas, parentElement, tmpVec4a, tmpVec2a);
|
|
11962
|
+
this._label.setPos(tmpVec2a[0], tmpVec2a[1]);
|
|
11963
|
+
};
|
|
11964
|
+
|
|
11929
11965
|
const setPosOnWire = (p0, p1, yOff) => {
|
|
11930
11966
|
p0[0] += p1[0];
|
|
11931
11967
|
p0[1] += p1[1];
|
|
@@ -11933,36 +11969,44 @@ class Label3D {
|
|
|
11933
11969
|
this._label.setPos(p0[0], p0[1] + yOff);
|
|
11934
11970
|
};
|
|
11935
11971
|
|
|
11936
|
-
this.
|
|
11937
|
-
|
|
11938
|
-
|
|
11972
|
+
this._updatePosBetween = () => {
|
|
11973
|
+
const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
|
|
11974
|
+
const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d);
|
|
11975
|
+
this._label.setCulled(! (visibleA || visibleB));
|
|
11976
|
+
if (visibleA && visibleB) {
|
|
11977
|
+
tmpVec2b[0] += tmpVec2d[0];
|
|
11978
|
+
tmpVec2b[1] += tmpVec2d[1];
|
|
11979
|
+
math.mulVec2Scalar(tmpVec2b, .5);
|
|
11980
|
+
|
|
11981
|
+
tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
|
|
11982
|
+
tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
|
|
11983
|
+
math.mulVec2Scalar(tmpVec2b, 1/3);
|
|
11984
|
+
this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
|
|
11985
|
+
} else if (visibleA) {
|
|
11986
|
+
setPosOnWire(tmpVec2a, tmpVec2b, 0);
|
|
11987
|
+
} else if (visibleB) {
|
|
11988
|
+
setPosOnWire(tmpVec2c, tmpVec2d, 0);
|
|
11939
11989
|
}
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
&&
|
|
11961
|
-
(math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
|
|
11962
|
-
this._label.setCulled(!visible);
|
|
11963
|
-
if (visible) {
|
|
11964
|
-
setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
|
|
11965
|
-
}
|
|
11990
|
+
};
|
|
11991
|
+
|
|
11992
|
+
this._updatePosOnWire = () => {
|
|
11993
|
+
const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
|
|
11994
|
+
&&
|
|
11995
|
+
(math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
|
|
11996
|
+
this._label.setCulled(!visible);
|
|
11997
|
+
if (visible) {
|
|
11998
|
+
setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
|
|
11999
|
+
}
|
|
12000
|
+
};
|
|
12001
|
+
|
|
12002
|
+
let posUpdate = () => { };
|
|
12003
|
+
this._setUpdatePositions = (_posUpdate) => {
|
|
12004
|
+
posUpdate = _posUpdate;
|
|
12005
|
+
this._updatePositions();
|
|
12006
|
+
};
|
|
12007
|
+
this._updatePositions = () => {
|
|
12008
|
+
if (this.__visible) {
|
|
12009
|
+
posUpdate();
|
|
11966
12010
|
}
|
|
11967
12011
|
};
|
|
11968
12012
|
|
|
@@ -11980,21 +12024,24 @@ class Label3D {
|
|
|
11980
12024
|
};
|
|
11981
12025
|
}
|
|
11982
12026
|
|
|
12027
|
+
setPos(p0) {
|
|
12028
|
+
this._start.set(p0);
|
|
12029
|
+
this._setUpdatePositions(this._updatePos);
|
|
12030
|
+
}
|
|
12031
|
+
|
|
11983
12032
|
setPosOnWire(p0, p1, yOff, labelMinAxisLength) {
|
|
11984
12033
|
this._start.set(p0);
|
|
11985
12034
|
this._end.set(p1);
|
|
11986
12035
|
this._yOff = yOff;
|
|
11987
12036
|
this._labelMinAxisLength = labelMinAxisLength;
|
|
11988
|
-
this.
|
|
11989
|
-
this._updatePositions();
|
|
12037
|
+
this._setUpdatePositions(this._updatePosOnWire);
|
|
11990
12038
|
}
|
|
11991
12039
|
|
|
11992
12040
|
setPosBetween(p0, p1, p2) {
|
|
11993
12041
|
this._start.set(p0);
|
|
11994
12042
|
this._mid.set(p1);
|
|
11995
12043
|
this._end.set(p2);
|
|
11996
|
-
this.
|
|
11997
|
-
this._updatePositions();
|
|
12044
|
+
this._setUpdatePositions(this._updatePosBetween);
|
|
11998
12045
|
}
|
|
11999
12046
|
|
|
12000
12047
|
setFillColor(value) {
|
|
@@ -12097,6 +12144,51 @@ class Wire3D {
|
|
|
12097
12144
|
|
|
12098
12145
|
}
|
|
12099
12146
|
|
|
12147
|
+
const marker3D = function(scene, color) {
|
|
12148
|
+
const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
|
|
12149
|
+
borderColor: "white",
|
|
12150
|
+
fillColor: color,
|
|
12151
|
+
zIndex: 100
|
|
12152
|
+
});
|
|
12153
|
+
|
|
12154
|
+
return {
|
|
12155
|
+
update: function(worldPos) {
|
|
12156
|
+
if (worldPos)
|
|
12157
|
+
{
|
|
12158
|
+
marker.worldPos = worldPos;
|
|
12159
|
+
}
|
|
12160
|
+
marker.setVisible(!!worldPos);
|
|
12161
|
+
},
|
|
12162
|
+
|
|
12163
|
+
setFillColor: c => marker.setFillColor(c),
|
|
12164
|
+
setHighlighted: h => marker.setHighlighted(h),
|
|
12165
|
+
getCanvasPos: () => marker.canvasPos,
|
|
12166
|
+
getWorldPos: () => marker.worldPos,
|
|
12167
|
+
destroy: () => marker.destroy()
|
|
12168
|
+
};
|
|
12169
|
+
};
|
|
12170
|
+
|
|
12171
|
+
const wire3D = function(scene, color) {
|
|
12172
|
+
const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
|
|
12173
|
+
color: color,
|
|
12174
|
+
thickness: 1,
|
|
12175
|
+
thicknessClickable: 6 // TODO: Remove to make not clickable?
|
|
12176
|
+
});
|
|
12177
|
+
wire.setVisible(false);
|
|
12178
|
+
return {
|
|
12179
|
+
update: (startWorldPos, endWorldPos) => {
|
|
12180
|
+
if (endWorldPos)
|
|
12181
|
+
{
|
|
12182
|
+
wire.setEnds(startWorldPos, endWorldPos);
|
|
12183
|
+
}
|
|
12184
|
+
wire.setVisible(!!endWorldPos);
|
|
12185
|
+
},
|
|
12186
|
+
|
|
12187
|
+
setColor: c => wire.setColor(c),
|
|
12188
|
+
destroy: () => wire.destroy()
|
|
12189
|
+
};
|
|
12190
|
+
};
|
|
12191
|
+
|
|
12100
12192
|
function activateDraggableDot(dot, cfg) {
|
|
12101
12193
|
const extractCFG = function(propName, defaultValue) {
|
|
12102
12194
|
if (propName in cfg) {
|
|
@@ -12411,6 +12503,482 @@ const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
|
12411
12503
|
};
|
|
12412
12504
|
};
|
|
12413
12505
|
|
|
12506
|
+
const triangulateEarClipping = function(planeCoords) {
|
|
12507
|
+
const polygonVertices = [ ];
|
|
12508
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
12509
|
+
polygonVertices.push(i);
|
|
12510
|
+
|
|
12511
|
+
const isCCW = (function() {
|
|
12512
|
+
const ba = math.vec2();
|
|
12513
|
+
const bc = math.vec2();
|
|
12514
|
+
|
|
12515
|
+
let anglesSum = 0;
|
|
12516
|
+
|
|
12517
|
+
for (let i = 0; i < polygonVertices.length; ++i)
|
|
12518
|
+
{
|
|
12519
|
+
const a = planeCoords[polygonVertices[i]];
|
|
12520
|
+
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
12521
|
+
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
12522
|
+
|
|
12523
|
+
math.subVec2(a, b, ba);
|
|
12524
|
+
math.subVec2(c, b, bc);
|
|
12525
|
+
|
|
12526
|
+
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
12527
|
+
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
12528
|
+
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
12529
|
+
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
12530
|
+
}
|
|
12531
|
+
|
|
12532
|
+
return anglesSum < (polygonVertices.length * Math.PI);
|
|
12533
|
+
})();
|
|
12534
|
+
|
|
12535
|
+
const pointInTriangle = (function() {
|
|
12536
|
+
const sign = (p1, p2, p3) => {
|
|
12537
|
+
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
12538
|
+
};
|
|
12539
|
+
|
|
12540
|
+
return (pt, v1, v2, v3) => {
|
|
12541
|
+
const d1 = sign(pt, v1, v2);
|
|
12542
|
+
const d2 = sign(pt, v2, v3);
|
|
12543
|
+
const d3 = sign(pt, v3, v1);
|
|
12544
|
+
|
|
12545
|
+
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
12546
|
+
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
12547
|
+
|
|
12548
|
+
return !(has_neg && has_pos);
|
|
12549
|
+
};
|
|
12550
|
+
})();
|
|
12551
|
+
|
|
12552
|
+
const baseTriangles = [ ];
|
|
12553
|
+
|
|
12554
|
+
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
12555
|
+
vertices.forEach((v, i) => {
|
|
12556
|
+
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
12557
|
+
v.next = vertices[(i + 1) % vertices.length];
|
|
12558
|
+
});
|
|
12559
|
+
|
|
12560
|
+
const ba = math.vec2();
|
|
12561
|
+
const bc = math.vec2();
|
|
12562
|
+
|
|
12563
|
+
while (vertices.length > 2) {
|
|
12564
|
+
let earIdx = 0;
|
|
12565
|
+
while (true) {
|
|
12566
|
+
if (earIdx >= vertices.length)
|
|
12567
|
+
{
|
|
12568
|
+
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
12569
|
+
}
|
|
12570
|
+
const v = vertices[earIdx];
|
|
12571
|
+
|
|
12572
|
+
const a = planeCoords[v.prev.idx];
|
|
12573
|
+
const b = planeCoords[v.idx];
|
|
12574
|
+
const c = planeCoords[v.next.idx];
|
|
12575
|
+
|
|
12576
|
+
math.subVec2(a, b, ba);
|
|
12577
|
+
math.subVec2(c, b, bc);
|
|
12578
|
+
|
|
12579
|
+
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
12580
|
+
&&
|
|
12581
|
+
vertices.every( // no other vertices inside
|
|
12582
|
+
vv => ((vv === v)
|
|
12583
|
+
||
|
|
12584
|
+
(vv === v.prev)
|
|
12585
|
+
||
|
|
12586
|
+
(vv === v.next)
|
|
12587
|
+
||
|
|
12588
|
+
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
12589
|
+
break;
|
|
12590
|
+
++earIdx;
|
|
12591
|
+
}
|
|
12592
|
+
|
|
12593
|
+
const ear = vertices[earIdx];
|
|
12594
|
+
vertices.splice(earIdx, 1);
|
|
12595
|
+
|
|
12596
|
+
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
12597
|
+
|
|
12598
|
+
const prev = ear.prev;
|
|
12599
|
+
prev.next = ear.next;
|
|
12600
|
+
const next = ear.next;
|
|
12601
|
+
next.prev = ear.prev;
|
|
12602
|
+
}
|
|
12603
|
+
|
|
12604
|
+
return [ planeCoords, baseTriangles, isCCW ];
|
|
12605
|
+
};
|
|
12606
|
+
|
|
12607
|
+
const addMousePressListener = function(element, onChange) {
|
|
12608
|
+
const moveTolerance = 4;
|
|
12609
|
+
|
|
12610
|
+
const copyElementPos = (event, out) => {
|
|
12611
|
+
out[0] = event.clientX;
|
|
12612
|
+
out[1] = event.clientY;
|
|
12613
|
+
transformToNode(element.ownerDocument.documentElement, element, out);
|
|
12614
|
+
return out;
|
|
12615
|
+
};
|
|
12616
|
+
|
|
12617
|
+
let buttonDown = false;
|
|
12618
|
+
|
|
12619
|
+
const cleanups = [ ];
|
|
12620
|
+
const cleanup = () => cleanups.forEach(c => c());
|
|
12621
|
+
|
|
12622
|
+
const addElementEventListener = (type, listener) => {
|
|
12623
|
+
element.addEventListener(type, listener);
|
|
12624
|
+
cleanups.push(() => element.removeEventListener(type, listener));
|
|
12625
|
+
};
|
|
12626
|
+
|
|
12627
|
+
const downPos = math.vec2();
|
|
12628
|
+
addElementEventListener("mousedown", function(event) {
|
|
12629
|
+
if (event.which === 1) {
|
|
12630
|
+
buttonDown = true;
|
|
12631
|
+
onChange(copyElementPos(event, downPos));
|
|
12632
|
+
}
|
|
12633
|
+
});
|
|
12634
|
+
|
|
12635
|
+
addElementEventListener("mousemove", function(event) {
|
|
12636
|
+
copyElementPos(event, tmpVec2a);
|
|
12637
|
+
if (buttonDown && (math.distVec2(downPos, tmpVec2a) > moveTolerance)) {
|
|
12638
|
+
buttonDown = false;
|
|
12639
|
+
}
|
|
12640
|
+
if (buttonDown || (! event.buttons & 1)) {
|
|
12641
|
+
onChange(tmpVec2a);
|
|
12642
|
+
}
|
|
12643
|
+
});
|
|
12644
|
+
|
|
12645
|
+
addElementEventListener("mouseup", function(event) {
|
|
12646
|
+
if ((event.which === 1) && buttonDown) {
|
|
12647
|
+
const commit = onChange(copyElementPos(event, tmpVec2a));
|
|
12648
|
+
if (commit) {
|
|
12649
|
+
cleanup();
|
|
12650
|
+
commit();
|
|
12651
|
+
}
|
|
12652
|
+
}
|
|
12653
|
+
});
|
|
12654
|
+
|
|
12655
|
+
return cleanup;
|
|
12656
|
+
};
|
|
12657
|
+
|
|
12658
|
+
const addTouchPressListener = function(element, cameraControl, pointerCircle, onChange) {
|
|
12659
|
+
const longTouchTimeoutMs = 300;
|
|
12660
|
+
const moveTolerance = 20;
|
|
12661
|
+
const startPos = math.vec2();
|
|
12662
|
+
|
|
12663
|
+
const copyElementPos = (event, out) => {
|
|
12664
|
+
out[0] = event.clientX;
|
|
12665
|
+
out[1] = event.clientY;
|
|
12666
|
+
transformToNode(element.ownerDocument.documentElement, element, out);
|
|
12667
|
+
return out;
|
|
12668
|
+
};
|
|
12669
|
+
|
|
12670
|
+
let longTouchTimeout = null;
|
|
12671
|
+
let onSingleTouchMove = nop;
|
|
12672
|
+
let startTouchIdentifier;
|
|
12673
|
+
|
|
12674
|
+
const resetAction = function() {
|
|
12675
|
+
clearTimeout(longTouchTimeout);
|
|
12676
|
+
pointerCircle.stop();
|
|
12677
|
+
cameraControl.active = true;
|
|
12678
|
+
onSingleTouchMove = nop;
|
|
12679
|
+
startTouchIdentifier = null;
|
|
12680
|
+
};
|
|
12681
|
+
|
|
12682
|
+
const cleanups = [ ];
|
|
12683
|
+
const cleanup = () => cleanups.forEach(c => c());
|
|
12684
|
+
|
|
12685
|
+
const addElementEventListener = (type, listener) => {
|
|
12686
|
+
element.addEventListener(type, listener, {passive: true});
|
|
12687
|
+
cleanups.push(() => element.removeEventListener(type, listener));
|
|
12688
|
+
};
|
|
12689
|
+
|
|
12690
|
+
addElementEventListener("touchstart", function(event) {
|
|
12691
|
+
const touches = event.touches;
|
|
12692
|
+
|
|
12693
|
+
if (touches.length !== 1)
|
|
12694
|
+
{
|
|
12695
|
+
resetAction();
|
|
12696
|
+
onChange(null);
|
|
12697
|
+
}
|
|
12698
|
+
else
|
|
12699
|
+
{
|
|
12700
|
+
const touch = touches[0];
|
|
12701
|
+
copyElementPos(touch, startPos);
|
|
12702
|
+
|
|
12703
|
+
startTouchIdentifier = touch.identifier;
|
|
12704
|
+
|
|
12705
|
+
onSingleTouchMove = elementPos => {
|
|
12706
|
+
if (math.distVec2(startPos, elementPos) > moveTolerance)
|
|
12707
|
+
{
|
|
12708
|
+
resetAction();
|
|
12709
|
+
}
|
|
12710
|
+
};
|
|
12711
|
+
|
|
12712
|
+
longTouchTimeout = setTimeout(
|
|
12713
|
+
function() {
|
|
12714
|
+
pointerCircle.start(startPos);
|
|
12715
|
+
|
|
12716
|
+
longTouchTimeout = setTimeout(
|
|
12717
|
+
function() {
|
|
12718
|
+
pointerCircle.stop();
|
|
12719
|
+
cameraControl.active = false;
|
|
12720
|
+
onSingleTouchMove = onChange;
|
|
12721
|
+
onSingleTouchMove(startPos);
|
|
12722
|
+
},
|
|
12723
|
+
longTouchTimeoutMs);
|
|
12724
|
+
},
|
|
12725
|
+
250);
|
|
12726
|
+
}
|
|
12727
|
+
});
|
|
12728
|
+
|
|
12729
|
+
// element.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
12730
|
+
|
|
12731
|
+
addElementEventListener("touchmove", function(event) {
|
|
12732
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
12733
|
+
if (touch)
|
|
12734
|
+
{
|
|
12735
|
+
onSingleTouchMove(copyElementPos(touch, tmpVec2a));
|
|
12736
|
+
}
|
|
12737
|
+
});
|
|
12738
|
+
|
|
12739
|
+
addElementEventListener("touchend", function(event) {
|
|
12740
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
12741
|
+
if (touch)
|
|
12742
|
+
{
|
|
12743
|
+
const commit = onChange(copyElementPos(touch, tmpVec2a));
|
|
12744
|
+
resetAction();
|
|
12745
|
+
if (commit) {
|
|
12746
|
+
cleanup();
|
|
12747
|
+
commit();
|
|
12748
|
+
} else {
|
|
12749
|
+
onChange(null);
|
|
12750
|
+
}
|
|
12751
|
+
}
|
|
12752
|
+
});
|
|
12753
|
+
|
|
12754
|
+
return () => {
|
|
12755
|
+
resetAction();
|
|
12756
|
+
cleanup();
|
|
12757
|
+
};
|
|
12758
|
+
};
|
|
12759
|
+
|
|
12760
|
+
const startPolygonCreate = function(scene, pointerLens, addPressListener, pickRayResult, onChange, onConclude) {
|
|
12761
|
+
const canvas = scene.canvas.canvas;
|
|
12762
|
+
|
|
12763
|
+
const updatePointerLens = (pointerLens
|
|
12764
|
+
? function(canvasPos, isSnapped) {
|
|
12765
|
+
pointerLens.visible = !! canvasPos;
|
|
12766
|
+
if (canvasPos)
|
|
12767
|
+
{
|
|
12768
|
+
pointerLens.canvasPos = canvasPos;
|
|
12769
|
+
pointerLens.snapped = !! isSnapped;
|
|
12770
|
+
}
|
|
12771
|
+
}
|
|
12772
|
+
: () => { });
|
|
12773
|
+
|
|
12774
|
+
const testLastSegmentIntersects = (function() {
|
|
12775
|
+
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
12776
|
+
(q[0] >= Math.min(p[0], r[0])) &&
|
|
12777
|
+
(q[1] <= Math.max(p[1], r[1])) &&
|
|
12778
|
+
(q[1] >= Math.min(p[1], r[1])));
|
|
12779
|
+
|
|
12780
|
+
const orient = (p, q, r) => {
|
|
12781
|
+
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
12782
|
+
// collinear
|
|
12783
|
+
// clockwise
|
|
12784
|
+
// counterclockwise
|
|
12785
|
+
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
12786
|
+
};
|
|
12787
|
+
|
|
12788
|
+
return function(pos2D, lastSegmentClosesLoop) {
|
|
12789
|
+
const s = lastSegmentClosesLoop ? 1 : 0;
|
|
12790
|
+
const a = pos2D[(pos2D.length - 2 + s) % pos2D.length];
|
|
12791
|
+
const b = pos2D[(pos2D.length - 1 + s) % pos2D.length];
|
|
12792
|
+
|
|
12793
|
+
for (let i = s; i < pos2D.length - 2 - 1 + s; ++i) {
|
|
12794
|
+
const c = pos2D[i];
|
|
12795
|
+
const d = pos2D[i + 1];
|
|
12796
|
+
|
|
12797
|
+
const o1 = orient(a, b, c);
|
|
12798
|
+
const o2 = orient(a, b, d);
|
|
12799
|
+
const o3 = orient(c, d, a);
|
|
12800
|
+
const o4 = orient(c, d, b);
|
|
12801
|
+
|
|
12802
|
+
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
12803
|
+
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
12804
|
+
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
12805
|
+
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
12806
|
+
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
12807
|
+
{
|
|
12808
|
+
return true;
|
|
12809
|
+
}
|
|
12810
|
+
}
|
|
12811
|
+
|
|
12812
|
+
return false;
|
|
12813
|
+
};
|
|
12814
|
+
})();
|
|
12815
|
+
|
|
12816
|
+
const getPlane = (points) => (points.length >= 3) && (function() {
|
|
12817
|
+
const u = math.normalizeVec3(math.subVec3(points[1], points[0], math.vec3()));
|
|
12818
|
+
const v20 = math.normalizeVec3(math.subVec3(points[2], points[0], tmpVec3a$2));
|
|
12819
|
+
const normal = math.normalizeVec3(math.cross3Vec3(u, v20, math.vec3()));
|
|
12820
|
+
const v = math.normalizeVec3(math.cross3Vec3(normal, u, math.vec3()));
|
|
12821
|
+
return {
|
|
12822
|
+
normal: normal,
|
|
12823
|
+
origin: math.vec3(points[0]),
|
|
12824
|
+
u: u,
|
|
12825
|
+
v: v
|
|
12826
|
+
};
|
|
12827
|
+
})();
|
|
12828
|
+
|
|
12829
|
+
const vertices = [ ];
|
|
12830
|
+
let currentInteraction;
|
|
12831
|
+
|
|
12832
|
+
(function selectNextPoint() {
|
|
12833
|
+
const plane = getPlane(vertices);
|
|
12834
|
+
|
|
12835
|
+
const canvasPos2Ray = (canvasPos, dst) => (math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, dst.origin, dst.direction), dst);
|
|
12836
|
+
|
|
12837
|
+
const pickRay = (ray) => {
|
|
12838
|
+
const pickResult = pickRayResult(ray);
|
|
12839
|
+
const snapWorldPos = pickResult && pickResult.entity && ((! plane) || pickResult.snapped) && pickResult.worldPos;
|
|
12840
|
+
if (plane) {
|
|
12841
|
+
const originDistance = math.dotVec3(plane.normal, plane.origin);
|
|
12842
|
+
const snapPlaneDist = (snapWorldPos
|
|
12843
|
+
? ((originDistance - math.dotVec3(snapWorldPos, plane.normal)))
|
|
12844
|
+
: window.Infinity);
|
|
12845
|
+
if (Math.abs(snapPlaneDist) < 0.0001) {
|
|
12846
|
+
const ret = math.vec3();
|
|
12847
|
+
return {
|
|
12848
|
+
worldPos: math.addVec3(snapWorldPos, math.mulVec3Scalar(plane.normal, snapPlaneDist, ret), ret),
|
|
12849
|
+
snapped: true
|
|
12850
|
+
};
|
|
12851
|
+
} else {
|
|
12852
|
+
return {
|
|
12853
|
+
worldPos: planeIntersect$1(originDistance, plane.normal, ray.origin, ray.direction),
|
|
12854
|
+
snapped: false
|
|
12855
|
+
};
|
|
12856
|
+
}
|
|
12857
|
+
} else {
|
|
12858
|
+
return {
|
|
12859
|
+
worldPos: snapWorldPos,
|
|
12860
|
+
snapped: pickResult && pickResult.snapped
|
|
12861
|
+
};
|
|
12862
|
+
}
|
|
12863
|
+
};
|
|
12864
|
+
|
|
12865
|
+
let placeVertex = false;
|
|
12866
|
+
const removePressListener = addPressListener(
|
|
12867
|
+
(inputCanvasPos) => {
|
|
12868
|
+
const rayPick = inputCanvasPos && pickRay(canvasPos2Ray(inputCanvasPos, tmpRay));
|
|
12869
|
+
const worldPos = rayPick && rayPick.worldPos;
|
|
12870
|
+
return onWorldPos(worldPos, inputCanvasPos, rayPick && rayPick.snapped);
|
|
12871
|
+
});
|
|
12872
|
+
|
|
12873
|
+
const onWorldPos = (worldPos, inputCanvasPos, rayPickSnapped) => {
|
|
12874
|
+
const canvasPos = worldPos ? scene.camera.projectWorldPos(worldPos) : inputCanvasPos;
|
|
12875
|
+
const firstMarker = (vertices.length > 0) && (function() {
|
|
12876
|
+
const v = vertices[0];
|
|
12877
|
+
return {
|
|
12878
|
+
canvasPos: scene.camera.projectWorldPos(v),
|
|
12879
|
+
worldPos: v
|
|
12880
|
+
};
|
|
12881
|
+
})();
|
|
12882
|
+
const snapToFirst = (vertices.length >= 3) && ((canvasPos && (math.distVec2(canvasPos, firstMarker.canvasPos) < 10))
|
|
12883
|
+
||
|
|
12884
|
+
(worldPos && math.compareVec3(worldPos, firstMarker.worldPos)));
|
|
12885
|
+
|
|
12886
|
+
updatePointerLens(snapToFirst ? firstMarker.canvasPos : canvasPos, snapToFirst || rayPickSnapped);
|
|
12887
|
+
|
|
12888
|
+
const lastPointOverlaps = (inputCanvasPos
|
|
12889
|
+
&&
|
|
12890
|
+
((! worldPos)
|
|
12891
|
+
||
|
|
12892
|
+
((vertices.length < 3)
|
|
12893
|
+
? vertices.some(v => math.compareVec3(v, worldPos))
|
|
12894
|
+
: math.compareVec3(vertices[vertices.length - 1], worldPos))));
|
|
12895
|
+
|
|
12896
|
+
const points = vertices.concat(((! snapToFirst) && worldPos && (! lastPointOverlaps)) ? [worldPos] : []);
|
|
12897
|
+
|
|
12898
|
+
const curPlane = (! lastPointOverlaps) && (plane || getPlane(points));
|
|
12899
|
+
|
|
12900
|
+
const uvs = curPlane && points.map(p => {
|
|
12901
|
+
math.subVec3(p, curPlane.origin, tmpVec3a$2);
|
|
12902
|
+
return math.vec2([ math.dotVec3(tmpVec3a$2, curPlane.u), math.dotVec3(tmpVec3a$2, curPlane.v) ]);
|
|
12903
|
+
});
|
|
12904
|
+
|
|
12905
|
+
const isValid = (! lastPointOverlaps) && (! (uvs && testLastSegmentIntersects(uvs, snapToFirst)));
|
|
12906
|
+
const geometry = isValid && uvs && (snapToFirst || (! testLastSegmentIntersects(uvs, true))) && (function() {
|
|
12907
|
+
try {
|
|
12908
|
+
const [ baseVertices, baseTriangles, isCCW ] = triangulateEarClipping(uvs);
|
|
12909
|
+
return {
|
|
12910
|
+
faces: baseTriangles,
|
|
12911
|
+
vertices: baseVertices.map(uv => math.addVec3(
|
|
12912
|
+
curPlane.origin,
|
|
12913
|
+
math.addVec3(
|
|
12914
|
+
math.mulVec3Scalar(curPlane.u, uv[0], tmpVec3a$2),
|
|
12915
|
+
math.mulVec3Scalar(curPlane.v, uv[1], tmpVec3b$2),
|
|
12916
|
+
tmpVec3a$2),
|
|
12917
|
+
math.vec3()))
|
|
12918
|
+
};
|
|
12919
|
+
} catch (e) {
|
|
12920
|
+
console.warn("e", e);
|
|
12921
|
+
return false;
|
|
12922
|
+
}
|
|
12923
|
+
})();
|
|
12924
|
+
|
|
12925
|
+
onChange(points, snapToFirst, isValid, geometry);
|
|
12926
|
+
|
|
12927
|
+
return placeVertex = (isValid && (snapToFirst
|
|
12928
|
+
? () => {
|
|
12929
|
+
updatePointerLens(null);
|
|
12930
|
+
onConclude();
|
|
12931
|
+
}
|
|
12932
|
+
: () => {
|
|
12933
|
+
vertices.push(math.vec3(worldPos));
|
|
12934
|
+
updatePointerLens(null);
|
|
12935
|
+
selectNextPoint();
|
|
12936
|
+
}));
|
|
12937
|
+
};
|
|
12938
|
+
|
|
12939
|
+
currentInteraction = {
|
|
12940
|
+
closePolygon: (() => {
|
|
12941
|
+
const commit = (vertices.length >= 3) && onWorldPos(vertices[0]);
|
|
12942
|
+
if (commit) {
|
|
12943
|
+
removePressListener();
|
|
12944
|
+
commit();
|
|
12945
|
+
}
|
|
12946
|
+
return !! commit;
|
|
12947
|
+
}),
|
|
12948
|
+
placeVertex: () => {
|
|
12949
|
+
if (placeVertex) {
|
|
12950
|
+
removePressListener();
|
|
12951
|
+
placeVertex();
|
|
12952
|
+
}
|
|
12953
|
+
return !!placeVertex;
|
|
12954
|
+
},
|
|
12955
|
+
popVertex: () => {
|
|
12956
|
+
if (vertices.length > 0) {
|
|
12957
|
+
removePressListener();
|
|
12958
|
+
vertices.pop();
|
|
12959
|
+
selectNextPoint();
|
|
12960
|
+
return true;
|
|
12961
|
+
} else {
|
|
12962
|
+
return false;
|
|
12963
|
+
}
|
|
12964
|
+
},
|
|
12965
|
+
removePressListener: removePressListener,
|
|
12966
|
+
updateOnChange: () => onWorldPos()
|
|
12967
|
+
};
|
|
12968
|
+
})();
|
|
12969
|
+
|
|
12970
|
+
return {
|
|
12971
|
+
cancel: () => {
|
|
12972
|
+
currentInteraction.removePressListener();
|
|
12973
|
+
updatePointerLens(null);
|
|
12974
|
+
},
|
|
12975
|
+
closePolygon: () => currentInteraction.closePolygon(),
|
|
12976
|
+
placeVertex: () => currentInteraction.placeVertex(),
|
|
12977
|
+
popVertex: () => currentInteraction.popVertex(),
|
|
12978
|
+
updateOnChange: () => currentInteraction.updateOnChange()
|
|
12979
|
+
};
|
|
12980
|
+
};
|
|
12981
|
+
|
|
12414
12982
|
const tmpVec3a$1 = math.vec3();
|
|
12415
12983
|
const tmpVec3b$1 = math.vec3();
|
|
12416
12984
|
|
|
@@ -14830,6 +15398,8 @@ const tempVec3a$M = math.vec3();
|
|
|
14830
15398
|
const tempVec3b$B = math.vec3();
|
|
14831
15399
|
const tempVec3c$w = math.vec3();
|
|
14832
15400
|
|
|
15401
|
+
const px = x => x + "px";
|
|
15402
|
+
|
|
14833
15403
|
/**
|
|
14834
15404
|
* A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
|
|
14835
15405
|
*
|
|
@@ -15036,22 +15606,29 @@ class Annotation extends Marker {
|
|
|
15036
15606
|
* @private
|
|
15037
15607
|
*/
|
|
15038
15608
|
_updateWithCurWidths() {
|
|
15039
|
-
const px = x => x + "px";
|
|
15040
15609
|
const boundary = this.scene.canvas.boundary;
|
|
15041
15610
|
const left = boundary[0] + this.canvasPos[0];
|
|
15042
15611
|
const top = boundary[1] + this.canvasPos[1];
|
|
15043
|
-
|
|
15044
|
-
const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
|
|
15045
|
-
const markerCenter = left + markerDir * (markerWidth / 2 - 12);
|
|
15046
|
-
this._marker.style.left = px(markerCenter - markerWidth / 2);
|
|
15047
|
-
this._marker.style.top = px(top - 12);
|
|
15048
|
-
this._marker.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
|
|
15049
|
-
|
|
15050
|
-
const labelWidth = this._curLabelWidth;
|
|
15051
|
-
const labelDir = Math.sign(this._labelPosition);
|
|
15052
|
-
this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
|
|
15612
|
+
this._marker.style.top = px(top - 12);
|
|
15053
15613
|
this._label.style.top = px(top - 17);
|
|
15054
|
-
|
|
15614
|
+
|
|
15615
|
+
if (this._markerAlign === "legacy") {
|
|
15616
|
+
this._marker.style.left = px(left - 12);
|
|
15617
|
+
this._label.style.left = px(left + 40);
|
|
15618
|
+
} else {
|
|
15619
|
+
const markerWidth = this._curMarkerWidth;
|
|
15620
|
+
const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
|
|
15621
|
+
const markerCenter = left + markerDir * (markerWidth / 2 - 12);
|
|
15622
|
+
this._marker.style.left = px(markerCenter - markerWidth / 2);
|
|
15623
|
+
|
|
15624
|
+
const labelWidth = this._curLabelWidth;
|
|
15625
|
+
const labelDir = Math.sign(this._labelPosition);
|
|
15626
|
+
this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
|
|
15627
|
+
}
|
|
15628
|
+
|
|
15629
|
+
const zIndex = 90005 + Math.floor(this._viewPos[2]) + 1;
|
|
15630
|
+
this._marker.style["z-index"] = zIndex;
|
|
15631
|
+
this._label.style["z-index"] = zIndex;
|
|
15055
15632
|
}
|
|
15056
15633
|
|
|
15057
15634
|
/**
|
|
@@ -15082,7 +15659,8 @@ class Annotation extends Marker {
|
|
|
15082
15659
|
* @private
|
|
15083
15660
|
*/
|
|
15084
15661
|
_updatePosition() {
|
|
15085
|
-
|
|
15662
|
+
const isLegacy = this._markerAlign === "legacy";
|
|
15663
|
+
if ((! isLegacy) && (this._curMarkerWidth === undefined)) {
|
|
15086
15664
|
this._updateIfWidthsChanged();
|
|
15087
15665
|
} else {
|
|
15088
15666
|
// Update position with cached width values
|
|
@@ -15090,7 +15668,9 @@ class Annotation extends Marker {
|
|
|
15090
15668
|
// so they don't interfere with e.g. interactive scene manipulation
|
|
15091
15669
|
this._updateWithCurWidths();
|
|
15092
15670
|
window.clearTimeout(this._widthTimeout);
|
|
15093
|
-
|
|
15671
|
+
if (! isLegacy) {
|
|
15672
|
+
this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
|
|
15673
|
+
}
|
|
15094
15674
|
}
|
|
15095
15675
|
}
|
|
15096
15676
|
|
|
@@ -15128,10 +15708,10 @@ class Annotation extends Marker {
|
|
|
15128
15708
|
/**
|
|
15129
15709
|
* Sets the horizontal alignment of the Annotation's marker HTML.
|
|
15130
15710
|
*
|
|
15131
|
-
* @param {String} align Either "left", "center", "right" (default "left")
|
|
15711
|
+
* @param {String} align Either "left", "center", "right", "legacy" (default "left")
|
|
15132
15712
|
*/
|
|
15133
15713
|
setMarkerAlign(align) {
|
|
15134
|
-
const valid = [ "left", "center", "right" ];
|
|
15714
|
+
const valid = [ "left", "center", "right", "legacy" ];
|
|
15135
15715
|
if (! valid.includes(align)) {
|
|
15136
15716
|
this.error("Param 'align' should be one of: " + JSON.stringify(valid));
|
|
15137
15717
|
} else {
|
|
@@ -26514,6 +27094,65 @@ class ReadableGeometry extends Geometry {
|
|
|
26514
27094
|
return this._obb;
|
|
26515
27095
|
}
|
|
26516
27096
|
|
|
27097
|
+
_getMetrics() {
|
|
27098
|
+
if (! ("_metrics" in this)) {
|
|
27099
|
+
switch (this._state.primitiveName) {
|
|
27100
|
+
case "solid":
|
|
27101
|
+
case "surface":
|
|
27102
|
+
case "triangles": {
|
|
27103
|
+
const indices = this._state.indices;
|
|
27104
|
+
const positions = this._state.positions;
|
|
27105
|
+
const getPos = (i, out) => {
|
|
27106
|
+
const idx = indices[i] * 3;
|
|
27107
|
+
for (let j = 0; j < 3; ++j) {
|
|
27108
|
+
out[j] = positions[idx + j];
|
|
27109
|
+
} return out;
|
|
27110
|
+
};
|
|
27111
|
+
const tmp = [ math.vec3(), math.vec3(), math.vec3(), math.vec3() ];
|
|
27112
|
+
let totalArea = 0;
|
|
27113
|
+
const centroid = math.vec3([ 0, 0, 0 ]);
|
|
27114
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
27115
|
+
const v0 = getPos(i, tmp[0]);
|
|
27116
|
+
const v1 = getPos(i+1, tmp[1]);
|
|
27117
|
+
const v2 = getPos(i+2, tmp[2]);
|
|
27118
|
+
math.addVec3(v0, v1, tmp[3]);
|
|
27119
|
+
math.addVec3(v2, tmp[3], tmp[3]);
|
|
27120
|
+
const faceArea = math.lenVec3(
|
|
27121
|
+
math.cross3Vec3(
|
|
27122
|
+
math.subVec3(v1, v0, tmp[1]),
|
|
27123
|
+
math.subVec3(v2, v0, tmp[2]),
|
|
27124
|
+
tmp[0])) / 2;
|
|
27125
|
+
totalArea += faceArea;
|
|
27126
|
+
math.mulVec3Scalar(tmp[3], faceArea, tmp[3]);
|
|
27127
|
+
math.addVec3(centroid, tmp[3], centroid);
|
|
27128
|
+
}
|
|
27129
|
+
this._metrics = { surfaceArea: totalArea, centroid: math.mulVec3Scalar(centroid, 1 / totalArea / 3, centroid) };
|
|
27130
|
+
break;
|
|
27131
|
+
}
|
|
27132
|
+
default:
|
|
27133
|
+
this._metrics = { surfaceArea: 0 };
|
|
27134
|
+
break;
|
|
27135
|
+
}
|
|
27136
|
+
}
|
|
27137
|
+
return this._metrics;
|
|
27138
|
+
}
|
|
27139
|
+
|
|
27140
|
+
/**
|
|
27141
|
+
* Returns the surface area of this Mesh.
|
|
27142
|
+
* @returns {number}
|
|
27143
|
+
*/
|
|
27144
|
+
get surfaceArea() {
|
|
27145
|
+
return this._getMetrics().surfaceArea;
|
|
27146
|
+
}
|
|
27147
|
+
|
|
27148
|
+
/**
|
|
27149
|
+
* Returns the centroid of this Mesh.
|
|
27150
|
+
* @returns {number}
|
|
27151
|
+
*/
|
|
27152
|
+
get centroid() {
|
|
27153
|
+
return this._getMetrics().centroid;
|
|
27154
|
+
}
|
|
27155
|
+
|
|
26517
27156
|
/**
|
|
26518
27157
|
* Approximate number of triangles in this ReadableGeometry.
|
|
26519
27158
|
*
|
|
@@ -40062,7 +40701,7 @@ function buildPlaneGeometry(cfg = {}) {
|
|
|
40062
40701
|
positions[offset + 1] = centerY;
|
|
40063
40702
|
positions[offset + 2] = -z + centerZ;
|
|
40064
40703
|
|
|
40065
|
-
normals[offset +
|
|
40704
|
+
normals[offset + 1] = 1;
|
|
40066
40705
|
|
|
40067
40706
|
uvs[offset2] = (ix) / planeX;
|
|
40068
40707
|
uvs[offset2 + 1] = ((planeZ - iz) / planeZ);
|
|
@@ -43360,8 +43999,7 @@ class SectionCaps {
|
|
|
43360
43999
|
if(!this._resourcesAllocated) {
|
|
43361
44000
|
this._resourcesAllocated = true;
|
|
43362
44001
|
this._sectionPlanes = [];
|
|
43363
|
-
this.
|
|
43364
|
-
this._indicesMap = {};
|
|
44002
|
+
this._sceneModelsData = {};
|
|
43365
44003
|
this._dirtyMap = {};
|
|
43366
44004
|
this._prevIntersectionModelsMap = {};
|
|
43367
44005
|
this._sectionPlaneTimeout = null;
|
|
@@ -43376,7 +44014,8 @@ class SectionCaps {
|
|
|
43376
44014
|
this._sectionPlanes.push(sectionPlane);
|
|
43377
44015
|
sectionPlane.on('pos', onSectionPlaneUpdated);
|
|
43378
44016
|
sectionPlane.on('dir', onSectionPlaneUpdated);
|
|
43379
|
-
sectionPlane.
|
|
44017
|
+
sectionPlane.on('active', onSectionPlaneUpdated);
|
|
44018
|
+
sectionPlane.once('destroyed', (() => {
|
|
43380
44019
|
const sectionPlaneId = sectionPlane.id;
|
|
43381
44020
|
if (sectionPlaneId) {
|
|
43382
44021
|
this._sectionPlanes = this._sectionPlanes.filter((sectionPlane) => sectionPlane.id !== sectionPlaneId);
|
|
@@ -43393,13 +44032,19 @@ class SectionCaps {
|
|
|
43393
44032
|
|
|
43394
44033
|
this._onTick = this.scene.on("tick", () => {
|
|
43395
44034
|
//on ticks we only check if there is a model that we have saved vertices for,
|
|
43396
|
-
//but it's no more available on the scene
|
|
43397
|
-
|
|
43398
|
-
|
|
43399
|
-
|
|
43400
|
-
delete this.
|
|
43401
|
-
|
|
43402
|
-
}
|
|
44035
|
+
//but it's no more available on the scene, or if its visibility changed
|
|
44036
|
+
let dirty = false;
|
|
44037
|
+
for(const sceneModelId in this._sceneModelsData) {
|
|
44038
|
+
if(!this.scene.models[sceneModelId]){
|
|
44039
|
+
delete this._sceneModelsData[sceneModelId];
|
|
44040
|
+
dirty = true;
|
|
44041
|
+
} else if (this._sceneModelsData[sceneModelId].visible !== (!!this.scene.models[sceneModelId].visible)) {
|
|
44042
|
+
this._sceneModelsData[sceneModelId].visible = !!this.scene.models[sceneModelId].visible;
|
|
44043
|
+
dirty = true;
|
|
44044
|
+
}
|
|
44045
|
+
}
|
|
44046
|
+
if (dirty) {
|
|
44047
|
+
this._update();
|
|
43403
44048
|
}
|
|
43404
44049
|
});
|
|
43405
44050
|
}
|
|
@@ -43416,8 +44061,8 @@ class SectionCaps {
|
|
|
43416
44061
|
this._deletePreviousModels();
|
|
43417
44062
|
this._updateTimeout = setTimeout(() => {
|
|
43418
44063
|
clearTimeout(this._updateTimeout);
|
|
43419
|
-
const sceneModels = Object.
|
|
43420
|
-
this._addHatches(sceneModels, this._sectionPlanes);
|
|
44064
|
+
const sceneModels = Object.values(this.scene.models).filter(sceneModel => sceneModel.visible);
|
|
44065
|
+
this._addHatches(sceneModels, this._sectionPlanes.filter(sectionPlane => sectionPlane.active));
|
|
43421
44066
|
this._setAllDirty(false);
|
|
43422
44067
|
}, 100);
|
|
43423
44068
|
}
|
|
@@ -43430,21 +44075,9 @@ class SectionCaps {
|
|
|
43430
44075
|
|
|
43431
44076
|
_addHatches(sceneModels, planes) {
|
|
43432
44077
|
|
|
43433
|
-
if (planes.length <= 0) return;
|
|
43434
|
-
|
|
43435
44078
|
planes.forEach((plane) => {
|
|
43436
44079
|
sceneModels.forEach((sceneModel) => {
|
|
43437
|
-
|
|
43438
|
-
//we create a plane equation that will be used to slice through each triangle
|
|
43439
|
-
const planeEquation = {
|
|
43440
|
-
A: plane.dir[0],
|
|
43441
|
-
B: plane.dir[1],
|
|
43442
|
-
C: plane.dir[2],
|
|
43443
|
-
D: -(plane.dir[0] * plane.pos[0] + plane.dir[1] * plane.pos[1] + plane.dir[2] * plane.pos[2])
|
|
43444
|
-
};
|
|
43445
|
-
//#endregion
|
|
43446
|
-
|
|
43447
|
-
if(!this._doesPlaneIntersectBoundingBox(sceneModel.aabb, planeEquation)) return;
|
|
44080
|
+
if(!this._doesPlaneIntersectBoundingBox(sceneModel.aabb, plane)) return;
|
|
43448
44081
|
|
|
43449
44082
|
if(!this._dirtyMap[sceneModel.id]) return;
|
|
43450
44083
|
|
|
@@ -43466,39 +44099,35 @@ class SectionCaps {
|
|
|
43466
44099
|
|
|
43467
44100
|
const object = objects[objectId];
|
|
43468
44101
|
|
|
43469
|
-
if(!this._doesPlaneIntersectBoundingBox(object.aabb,
|
|
44102
|
+
if(!this._doesPlaneIntersectBoundingBox(object.aabb, plane)) return;
|
|
43470
44103
|
|
|
43471
|
-
if(!this.
|
|
43472
|
-
this.
|
|
43473
|
-
|
|
44104
|
+
if(!this._sceneModelsData[sceneModel.id]) {
|
|
44105
|
+
this._sceneModelsData[sceneModel.id] = {
|
|
44106
|
+
verticesMap: new Map(),
|
|
44107
|
+
indicesMap: new Map()
|
|
44108
|
+
};
|
|
43474
44109
|
}
|
|
43475
44110
|
|
|
43476
|
-
|
|
44111
|
+
const sceneModelData = this._sceneModelsData[sceneModel.id];
|
|
43477
44112
|
|
|
43478
|
-
if(!
|
|
44113
|
+
if(!sceneModelData.verticesMap.has(objectId)) {
|
|
43479
44114
|
const isSolid = object.meshes[0].isSolid();
|
|
44115
|
+
const vertices = [ ];
|
|
44116
|
+
const indices = [ ];
|
|
43480
44117
|
if(isSolid && object.capMaterial) {
|
|
43481
|
-
object.getEachVertex(
|
|
43482
|
-
|
|
43483
|
-
});
|
|
43484
|
-
object.getEachIndex((_indices) => {
|
|
43485
|
-
indices.push(_indices);
|
|
43486
|
-
});
|
|
44118
|
+
object.getEachVertex(v => vertices.push(v[0], v[1], v[2]));
|
|
44119
|
+
object.getEachIndex(i => indices.push(i));
|
|
43487
44120
|
}
|
|
43488
|
-
|
|
43489
|
-
|
|
43490
|
-
}
|
|
43491
|
-
else {
|
|
43492
|
-
vertices = this._verticesMap[sceneModel.id].get(objectId);
|
|
43493
|
-
indices = this._indicesMap[sceneModel.id].get(objectId);
|
|
44121
|
+
sceneModelData.verticesMap.set(objectId, vertices);
|
|
44122
|
+
sceneModelData.indicesMap.set(objectId, indices);
|
|
43494
44123
|
}
|
|
43495
|
-
|
|
44124
|
+
|
|
44125
|
+
const vertices = sceneModelData.verticesMap.get(objectId);
|
|
44126
|
+
const indices = sceneModelData.indicesMap.get(objectId);
|
|
44127
|
+
|
|
43496
44128
|
const capSegments = [];
|
|
43497
44129
|
const vertCount = indices.length;
|
|
43498
|
-
|
|
43499
|
-
// Preallocate intersection result array
|
|
43500
|
-
const intersectionBuffer = new Float32Array(3);
|
|
43501
|
-
|
|
44130
|
+
|
|
43502
44131
|
for (let i = 0; i < vertCount; i += 3) {
|
|
43503
44132
|
// Reuse triangle buffer instead of creating new arrays
|
|
43504
44133
|
for (let j = 0; j < 3; j++) {
|
|
@@ -43515,21 +44144,15 @@ class SectionCaps {
|
|
|
43515
44144
|
for (let i = 0; i < 3; i++) {
|
|
43516
44145
|
const p1 = triangle[i];
|
|
43517
44146
|
const p2 = triangle[(i + 1) % 3];
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
const
|
|
43521
|
-
|
|
43522
|
-
|
|
44147
|
+
|
|
44148
|
+
const d1 = plane.dist + math.dotVec3(plane.dir, p1);
|
|
44149
|
+
const d2 = plane.dist + math.dotVec3(plane.dir, p2);
|
|
44150
|
+
|
|
43523
44151
|
if (d1 * d2 > 0) continue;
|
|
43524
|
-
|
|
44152
|
+
|
|
43525
44153
|
const t = -d1 / (d2 - d1);
|
|
43526
|
-
|
|
43527
|
-
|
|
43528
|
-
intersectionBuffer[1] = p1[1] + t * (p2[1] - p1[1]);
|
|
43529
|
-
intersectionBuffer[2] = p1[2] + t * (p2[2] - p1[2]);
|
|
43530
|
-
|
|
43531
|
-
// Clone the buffer for storage
|
|
43532
|
-
intersections.push(new Float32Array(intersectionBuffer));
|
|
44154
|
+
|
|
44155
|
+
intersections.push(math.lerpVec3(t, 0, 1, p1, p2, math.vec3()));
|
|
43533
44156
|
}
|
|
43534
44157
|
|
|
43535
44158
|
if(intersections.length === 2) capSegments.push(intersections);
|
|
@@ -43809,7 +44432,7 @@ class SectionCaps {
|
|
|
43809
44432
|
|
|
43810
44433
|
}
|
|
43811
44434
|
|
|
43812
|
-
_doesPlaneIntersectBoundingBox(bb,
|
|
44435
|
+
_doesPlaneIntersectBoundingBox(bb, plane) {
|
|
43813
44436
|
const min = [bb[0], bb[1], bb[2]];
|
|
43814
44437
|
const max = [bb[3], bb[4], bb[5]];
|
|
43815
44438
|
|
|
@@ -43829,10 +44452,7 @@ class SectionCaps {
|
|
|
43829
44452
|
let hasNegative = false;
|
|
43830
44453
|
|
|
43831
44454
|
for (const corner of corners) {
|
|
43832
|
-
const distance =
|
|
43833
|
-
planeEquation.B * corner[1] +
|
|
43834
|
-
planeEquation.C * corner[2] +
|
|
43835
|
-
planeEquation.D;
|
|
44455
|
+
const distance = plane.dist + math.dotVec3(plane.dir, corner);
|
|
43836
44456
|
|
|
43837
44457
|
if (distance > 0) hasPositive = true;
|
|
43838
44458
|
if (distance < 0) hasNegative = true;
|
|
@@ -44327,13 +44947,12 @@ class Scene extends Component {
|
|
|
44327
44947
|
* configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
|
|
44328
44948
|
* 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
|
|
44329
44949
|
* your expected usage.
|
|
44330
|
-
* @throws {String} Throws an exception when
|
|
44950
|
+
* @throws {String} Throws an exception when canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement.
|
|
44331
44951
|
*/
|
|
44332
44952
|
constructor(viewer, cfg = {}) {
|
|
44333
44953
|
|
|
44334
44954
|
super(null, cfg);
|
|
44335
|
-
|
|
44336
|
-
const canvas = cfg.canvasElement || document.getElementById(cfg.canvasId);
|
|
44955
|
+
const canvas = cfg.canvasElement || document.querySelector(`#${cfg.canvasId}`);
|
|
44337
44956
|
|
|
44338
44957
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
|
44339
44958
|
throw "Mandatory config expected: valid canvasId or canvasElement";
|
|
@@ -88573,7 +89192,7 @@ class LineSet extends Component {
|
|
|
88573
89192
|
* @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted.
|
|
88574
89193
|
* @param {Number[]} cfg.positions World-space 3D vertex positions.
|
|
88575
89194
|
* @param {Number[]} [cfg.indices] Indices to connect ````positions```` into line segments. Note that these are separate line segments, not a polyline.
|
|
88576
|
-
* @param {Number[]} [cfg.color=[
|
|
89195
|
+
* @param {Number[]} [cfg.color=[1,1,1]] The color of this ````LineSet````. This is both emissive and diffuse.
|
|
88577
89196
|
* @param {Boolean} [cfg.visible=true] Indicates whether or not this ````LineSet```` is visible.
|
|
88578
89197
|
* @param {Number} [cfg.opacity=1.0] ````LineSet````'s initial opacity factor.
|
|
88579
89198
|
*/
|
|
@@ -88593,6 +89212,9 @@ class LineSet extends Component {
|
|
|
88593
89212
|
}
|
|
88594
89213
|
}
|
|
88595
89214
|
|
|
89215
|
+
this._color = cfg.color || [1, 1, 1];
|
|
89216
|
+
this._opacity = cfg.opacity || 1.0;
|
|
89217
|
+
|
|
88596
89218
|
this._sceneModel = new SceneModel(this, {
|
|
88597
89219
|
isModel: false // Don't register in Scene.models
|
|
88598
89220
|
});
|
|
@@ -88601,7 +89223,9 @@ class LineSet extends Component {
|
|
|
88601
89223
|
id: "linesMesh",
|
|
88602
89224
|
primitive: "lines",
|
|
88603
89225
|
positions: this._positions,
|
|
88604
|
-
indices: this._indices
|
|
89226
|
+
indices: this._indices,
|
|
89227
|
+
color: this._color,
|
|
89228
|
+
opacity: this._opacity,
|
|
88605
89229
|
});
|
|
88606
89230
|
|
|
88607
89231
|
this._sceneModel.createEntity({
|
|
@@ -92329,6 +92953,7 @@ class FastNavPlugin extends Plugin {
|
|
|
92329
92953
|
* @param {Number} [cfg.scaleCanvasResolutionFactor=0.6] The factor by which we downscale the canvas resolution whenever we interact with the Viewer.
|
|
92330
92954
|
* @param {Boolean} [cfg.delayBeforeRestore=true] Whether to temporarily have a delay before restoring normal rendering after we stop interacting with the Viewer.
|
|
92331
92955
|
* @param {Number} [cfg.delayBeforeRestoreSeconds=0.5] Delay in seconds before restoring normal rendering after we stop interacting with the Viewer.
|
|
92956
|
+
* @param {Function} [cfg.onMoved] Optional callback function fired during moving mode, should return the callback function that will be fired when the interaction stops.
|
|
92332
92957
|
*/
|
|
92333
92958
|
constructor(viewer, cfg = {}) {
|
|
92334
92959
|
|
|
@@ -92344,6 +92969,8 @@ class FastNavPlugin extends Plugin {
|
|
|
92344
92969
|
this._scaleCanvasResolutionFactor = cfg.scaleCanvasResolutionFactor || 0.6;
|
|
92345
92970
|
this._delayBeforeRestore = (cfg.delayBeforeRestore !== false);
|
|
92346
92971
|
this._delayBeforeRestoreSeconds = cfg.delayBeforeRestoreSeconds || 0.5;
|
|
92972
|
+
this._onMoved = cfg.onMoved;
|
|
92973
|
+
this._onStopped = null;
|
|
92347
92974
|
|
|
92348
92975
|
let timer = this._delayBeforeRestoreSeconds * 1000;
|
|
92349
92976
|
let fastMode = false;
|
|
@@ -92362,6 +92989,10 @@ class FastNavPlugin extends Plugin {
|
|
|
92362
92989
|
} else {
|
|
92363
92990
|
viewer.scene.canvas.resolutionScale = this._defaultScaleCanvasResolutionFactor;
|
|
92364
92991
|
}
|
|
92992
|
+
if (this._onMoved) {
|
|
92993
|
+
this._onStopped = this._onMoved();
|
|
92994
|
+
}
|
|
92995
|
+
|
|
92365
92996
|
fastMode = true;
|
|
92366
92997
|
}
|
|
92367
92998
|
};
|
|
@@ -92373,6 +93004,9 @@ class FastNavPlugin extends Plugin {
|
|
|
92373
93004
|
viewer.scene._renderer.setPBREnabled(true);
|
|
92374
93005
|
viewer.scene._renderer.setSAOEnabled(true);
|
|
92375
93006
|
viewer.scene._renderer.setTransparentEnabled(true);
|
|
93007
|
+
if (this._onStopped) {
|
|
93008
|
+
this._onStopped();
|
|
93009
|
+
}
|
|
92376
93010
|
fastMode = false;
|
|
92377
93011
|
};
|
|
92378
93012
|
|
|
@@ -97699,8 +98333,8 @@ class Skybox extends Component {
|
|
|
97699
98333
|
* @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well.
|
|
97700
98334
|
* @param {*} [cfg] Skybox configuration
|
|
97701
98335
|
* @param {String} [cfg.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted.
|
|
97702
|
-
* @param {String} [cfg.src=null] Path to skybox texture
|
|
97703
|
-
* @param {
|
|
98336
|
+
* @param {String | String[]} [cfg.src=null] Path to skybox texture
|
|
98337
|
+
* @param {Number} [cfg.encoding=LinearEncoding] Texture encoding format. See the {@link Texture#encoding} property for more info.
|
|
97704
98338
|
* @param {Number} [cfg.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face.
|
|
97705
98339
|
* @param {Boolean} [cfg.active=true] True when this Skybox is visible.
|
|
97706
98340
|
*/
|
|
@@ -97708,6 +98342,32 @@ class Skybox extends Component {
|
|
|
97708
98342
|
|
|
97709
98343
|
super(owner, cfg);
|
|
97710
98344
|
|
|
98345
|
+
const useMultipleTexture = typeof cfg.src === "object" && cfg.src !== null;
|
|
98346
|
+
|
|
98347
|
+
if (useMultipleTexture) {
|
|
98348
|
+
this._createCombinedTexture(cfg).then(combinedTexture => {
|
|
98349
|
+
this._createSkyboxMesh(cfg, combinedTexture);
|
|
98350
|
+
}).catch(e => this.error(e));
|
|
98351
|
+
} else {
|
|
98352
|
+
this._createSkyboxMesh(cfg);
|
|
98353
|
+
}
|
|
98354
|
+
}
|
|
98355
|
+
|
|
98356
|
+
/**
|
|
98357
|
+
*
|
|
98358
|
+
* @private
|
|
98359
|
+
* @param {*} cfg
|
|
98360
|
+
* @param {Texture} combinedTexture
|
|
98361
|
+
*/
|
|
98362
|
+
_createSkyboxMesh(cfg, combinedTexture = null) {
|
|
98363
|
+
const texture = combinedTexture || new Texture(this, {
|
|
98364
|
+
src: cfg.src,
|
|
98365
|
+
flipY: true,
|
|
98366
|
+
wrapS: ClampToEdgeWrapping,
|
|
98367
|
+
wrapT: ClampToEdgeWrapping,
|
|
98368
|
+
encoding: cfg.encoding || LinearEncoding
|
|
98369
|
+
});
|
|
98370
|
+
|
|
97711
98371
|
this._skyboxMesh = new Mesh(this, {
|
|
97712
98372
|
|
|
97713
98373
|
geometry: new ReadableGeometry(this, { // Box-shaped geometry
|
|
@@ -97738,13 +98398,7 @@ class Skybox extends Component {
|
|
|
97738
98398
|
diffuse: [0, 0, 0],
|
|
97739
98399
|
specular: [0, 0, 0],
|
|
97740
98400
|
emissive: [1, 1, 1],
|
|
97741
|
-
emissiveMap:
|
|
97742
|
-
src: cfg.src,
|
|
97743
|
-
flipY: true,
|
|
97744
|
-
wrapS: "clampToEdge",
|
|
97745
|
-
wrapT: "clampToEdge",
|
|
97746
|
-
encoding: cfg.encoding || "sRGB"
|
|
97747
|
-
}),
|
|
98401
|
+
emissiveMap: texture,
|
|
97748
98402
|
backfaces: true // Show interior faces of our skybox geometry
|
|
97749
98403
|
}),
|
|
97750
98404
|
// stationary: true,
|
|
@@ -97758,6 +98412,86 @@ class Skybox extends Component {
|
|
|
97758
98412
|
this.active = cfg.active;
|
|
97759
98413
|
}
|
|
97760
98414
|
|
|
98415
|
+
/**
|
|
98416
|
+
*
|
|
98417
|
+
* @private
|
|
98418
|
+
* @param {*} cfg
|
|
98419
|
+
* @returns {Texture}
|
|
98420
|
+
*/
|
|
98421
|
+
async _createCombinedTexture(cfg) {
|
|
98422
|
+
const [
|
|
98423
|
+
posX,
|
|
98424
|
+
negX,
|
|
98425
|
+
posY,
|
|
98426
|
+
negY,
|
|
98427
|
+
posZ,
|
|
98428
|
+
negZ
|
|
98429
|
+
] = cfg.src;
|
|
98430
|
+
|
|
98431
|
+
if (!posX || !negX || !posY || !negY || !posZ || !negZ) {
|
|
98432
|
+
throw new Error("All six skybox textures must be provided");
|
|
98433
|
+
}
|
|
98434
|
+
|
|
98435
|
+
const canvas = document.createElement('canvas');
|
|
98436
|
+
const ctx = canvas.getContext('2d');
|
|
98437
|
+
|
|
98438
|
+
const loadImage = src => {
|
|
98439
|
+
return new Promise((resolve, reject) => {
|
|
98440
|
+
const img = new Image();
|
|
98441
|
+
img.crossOrigin = "anonymous";
|
|
98442
|
+
img.onload = () => resolve(img);
|
|
98443
|
+
img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
|
|
98444
|
+
img.src = src;
|
|
98445
|
+
});
|
|
98446
|
+
};
|
|
98447
|
+
|
|
98448
|
+
try {
|
|
98449
|
+
const [imgPosX, imgNegX, imgPosY, imgNegY, imgPosZ, imgNegZ] = await Promise.all([
|
|
98450
|
+
loadImage(posX),
|
|
98451
|
+
loadImage(negX),
|
|
98452
|
+
loadImage(posY),
|
|
98453
|
+
loadImage(negY),
|
|
98454
|
+
loadImage(posZ),
|
|
98455
|
+
loadImage(negZ)
|
|
98456
|
+
]);
|
|
98457
|
+
|
|
98458
|
+
const imageSize = imgPosX.width;
|
|
98459
|
+
if (
|
|
98460
|
+
imgNegX.width !== imageSize || imgPosY.width !== imageSize ||
|
|
98461
|
+
imgNegY.width !== imageSize || imgPosZ.width !== imageSize ||
|
|
98462
|
+
imgNegZ.width !== imageSize
|
|
98463
|
+
) {
|
|
98464
|
+
throw new Error("All skybox textures must have the same dimensions");
|
|
98465
|
+
}
|
|
98466
|
+
|
|
98467
|
+
// Set canvas size for the Christ cross layout (3×4 grid)
|
|
98468
|
+
canvas.width = imageSize * 4;
|
|
98469
|
+
canvas.height = imageSize * 3;
|
|
98470
|
+
|
|
98471
|
+
ctx.fillStyle = 'black';
|
|
98472
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
98473
|
+
|
|
98474
|
+
ctx.drawImage(imgNegX, imageSize * 0, imageSize * 1, imageSize, imageSize); // -X (left)
|
|
98475
|
+
ctx.drawImage(imgPosX, imageSize * 2, imageSize * 1, imageSize, imageSize); // +X (right)
|
|
98476
|
+
ctx.drawImage(imgPosY, imageSize * 1, imageSize * 0, imageSize, imageSize); // +Y (top)
|
|
98477
|
+
ctx.drawImage(imgNegY, imageSize * 1, imageSize * 2, imageSize, imageSize); // -Y (bottom)
|
|
98478
|
+
ctx.drawImage(imgPosZ, imageSize * 1, imageSize * 1, imageSize, imageSize); // +Z (front)
|
|
98479
|
+
ctx.drawImage(imgNegZ, imageSize * 3, imageSize * 1, imageSize, imageSize); // -Z (back)
|
|
98480
|
+
|
|
98481
|
+
const combinedTexture = new Texture(this, {
|
|
98482
|
+
image: canvas,
|
|
98483
|
+
flipY: true,
|
|
98484
|
+
wrapS: ClampToEdgeWrapping,
|
|
98485
|
+
wrapT: ClampToEdgeWrapping,
|
|
98486
|
+
encoding: cfg.encoding || LinearEncoding
|
|
98487
|
+
});
|
|
98488
|
+
|
|
98489
|
+
return combinedTexture;
|
|
98490
|
+
} catch (error) {
|
|
98491
|
+
console.error("Error creating combined skybox texture:", error);
|
|
98492
|
+
throw error;
|
|
98493
|
+
}
|
|
98494
|
+
}
|
|
97761
98495
|
|
|
97762
98496
|
/**
|
|
97763
98497
|
* Sets the size of this Skybox, given as the distance from the center at [0,0,0] to each face.
|
|
@@ -97952,6 +98686,9 @@ const tempVec4a$5 = math.vec4();
|
|
|
97952
98686
|
const tempVec4b$5 = math.vec4();
|
|
97953
98687
|
const tempVec4c = math.vec4();
|
|
97954
98688
|
|
|
98689
|
+
const TOP_LIMIT = 0.001;
|
|
98690
|
+
const BOTTOM_LIMIT = Math.PI - 0.001;
|
|
98691
|
+
|
|
97955
98692
|
|
|
97956
98693
|
/** @private */
|
|
97957
98694
|
class PivotController {
|
|
@@ -98127,14 +98864,9 @@ class PivotController {
|
|
|
98127
98864
|
*/
|
|
98128
98865
|
startPivot() {
|
|
98129
98866
|
|
|
98130
|
-
if (this._cameraLookingDownwards()) {
|
|
98131
|
-
this._pivoting = false;
|
|
98132
|
-
return false;
|
|
98133
|
-
}
|
|
98134
|
-
|
|
98135
98867
|
const camera = this._scene.camera;
|
|
98136
98868
|
|
|
98137
|
-
let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.
|
|
98869
|
+
let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.up);
|
|
98138
98870
|
math.transformPoint3(lookat, this.getPivotPos(), this._cameraOffset);
|
|
98139
98871
|
|
|
98140
98872
|
const pivotPos = this.getPivotPos();
|
|
@@ -98237,8 +98969,31 @@ class PivotController {
|
|
|
98237
98969
|
dx = -dx;
|
|
98238
98970
|
}
|
|
98239
98971
|
this._azimuth += -dx * .01;
|
|
98240
|
-
|
|
98241
|
-
|
|
98972
|
+
|
|
98973
|
+
const isMovingUp = dy < 0;
|
|
98974
|
+
const isMovingDown = dy > 0;
|
|
98975
|
+
|
|
98976
|
+
// Track if we're at limits - only check if we're very close to the limit
|
|
98977
|
+
const atTopLimit = Math.abs(this._polar - TOP_LIMIT) < 0.005;
|
|
98978
|
+
const atBottomLimit = Math.abs(this._polar - BOTTOM_LIMIT) < 0.005;
|
|
98979
|
+
|
|
98980
|
+
let newPolar = this._polar + dy * .01;
|
|
98981
|
+
|
|
98982
|
+
// Case 1: At top limit and trying to go beyond
|
|
98983
|
+
if (atTopLimit && isMovingUp) {
|
|
98984
|
+
newPolar = TOP_LIMIT;
|
|
98985
|
+
}
|
|
98986
|
+
// Case 2: At bottom limit and trying to go beyond
|
|
98987
|
+
else if (atBottomLimit && isMovingDown) {
|
|
98988
|
+
newPolar = BOTTOM_LIMIT;
|
|
98989
|
+
}
|
|
98990
|
+
// Case 3: Normal rotation or moving away from a limit
|
|
98991
|
+
else {
|
|
98992
|
+
newPolar = math.clamp(newPolar, TOP_LIMIT, BOTTOM_LIMIT);
|
|
98993
|
+
}
|
|
98994
|
+
|
|
98995
|
+
this._polar = newPolar;
|
|
98996
|
+
|
|
98242
98997
|
const pos = [
|
|
98243
98998
|
this._radius * Math.sin(this._polar) * Math.sin(this._azimuth),
|
|
98244
98999
|
this._radius * Math.cos(this._polar),
|
|
@@ -111788,22 +112543,6 @@ class Viewer {
|
|
|
111788
112543
|
this.sendToPlugins("snapshotStarting"); // Tells plugins to hide things that shouldn't be in snapshot
|
|
111789
112544
|
}
|
|
111790
112545
|
|
|
111791
|
-
const captured = {};
|
|
111792
|
-
for (let i = 0, len = this._plugins.length; i < len; i++) {
|
|
111793
|
-
const plugin = this._plugins[i];
|
|
111794
|
-
if (plugin.getContainerElement) {
|
|
111795
|
-
const container = plugin.getContainerElement();
|
|
111796
|
-
if (container !== document.body) {
|
|
111797
|
-
if (!captured[container.id]) {
|
|
111798
|
-
captured[container.id] = true;
|
|
111799
|
-
html2canvas(container).then(function (canvas) {
|
|
111800
|
-
document.body.appendChild(canvas);
|
|
111801
|
-
});
|
|
111802
|
-
}
|
|
111803
|
-
}
|
|
111804
|
-
}
|
|
111805
|
-
}
|
|
111806
|
-
|
|
111807
112546
|
// firing "rendering" is necessary to trigger DTX{Lines,Triangles}Layer::_uploadDeferredFlags
|
|
111808
112547
|
this.scene.fire("rendering", { }, true);
|
|
111809
112548
|
|
|
@@ -123581,6 +124320,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
123581
124320
|
const cubeColor = "lightgrey";
|
|
123582
124321
|
const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)";
|
|
123583
124322
|
const textColor = cfg.textColor || "black";
|
|
124323
|
+
const parentNode = cfg.canvasElement || document.body;
|
|
123584
124324
|
|
|
123585
124325
|
const height = 500;
|
|
123586
124326
|
const width = height + (height / 3);
|
|
@@ -123690,8 +124430,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
123690
124430
|
this._textureCanvas.style.visibility = "hidden";
|
|
123691
124431
|
this._textureCanvas.style["z-index"] = 2000000;
|
|
123692
124432
|
|
|
123693
|
-
|
|
123694
|
-
body.appendChild(this._textureCanvas);
|
|
124433
|
+
parentNode.appendChild(this._textureCanvas);
|
|
123695
124434
|
|
|
123696
124435
|
const context = this._textureCanvas.getContext("2d");
|
|
123697
124436
|
|
|
@@ -123961,7 +124700,7 @@ class NavCubePlugin extends Plugin {
|
|
|
123961
124700
|
this._navCubeScene = new Scene(viewer, {
|
|
123962
124701
|
canvasId: cfg.canvasId,
|
|
123963
124702
|
canvasElement: cfg.canvasElement,
|
|
123964
|
-
transparent: true
|
|
124703
|
+
transparent: true,
|
|
123965
124704
|
});
|
|
123966
124705
|
|
|
123967
124706
|
this._navCubeCanvas = this._navCubeScene.canvas.canvas;
|
|
@@ -124194,7 +124933,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124194
124933
|
}
|
|
124195
124934
|
});
|
|
124196
124935
|
|
|
124197
|
-
|
|
124936
|
+
self._navCubeCanvas.addEventListener("mouseup", self._onMouseUp = function (e) {
|
|
124198
124937
|
if (e.which !== 1) {// Left button
|
|
124199
124938
|
return;
|
|
124200
124939
|
}
|
|
@@ -124211,7 +124950,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124211
124950
|
if (hit.uv) {
|
|
124212
124951
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
124213
124952
|
if (areaId >= 0) {
|
|
124214
|
-
|
|
124953
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124215
124954
|
if (lastAreaId >= 0) {
|
|
124216
124955
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124217
124956
|
self._repaint();
|
|
@@ -124237,7 +124976,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124237
124976
|
self._repaint();
|
|
124238
124977
|
lastAreaId = -1;
|
|
124239
124978
|
}
|
|
124240
|
-
|
|
124979
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124241
124980
|
if (lastAreaId >= 0) {
|
|
124242
124981
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124243
124982
|
self._repaint();
|
|
@@ -124256,7 +124995,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124256
124995
|
}
|
|
124257
124996
|
});
|
|
124258
124997
|
|
|
124259
|
-
|
|
124998
|
+
self._navCubeCanvas.addEventListener("mousemove", self._onMouseMove = function (e) {
|
|
124260
124999
|
if (lastAreaId >= 0) {
|
|
124261
125000
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124262
125001
|
self._repaint();
|
|
@@ -124268,7 +125007,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124268
125007
|
if (down) {
|
|
124269
125008
|
var posX = e.clientX;
|
|
124270
125009
|
var posY = e.clientY;
|
|
124271
|
-
|
|
125010
|
+
self._navCubeCanvas.style.cursor = "move";
|
|
124272
125011
|
actionMove(posX, posY);
|
|
124273
125012
|
return;
|
|
124274
125013
|
}
|
|
@@ -124282,7 +125021,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124282
125021
|
});
|
|
124283
125022
|
if (hit) {
|
|
124284
125023
|
if (hit.uv) {
|
|
124285
|
-
|
|
125024
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124286
125025
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
124287
125026
|
if (areaId === lastAreaId) {
|
|
124288
125027
|
return;
|
|
@@ -124297,7 +125036,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124297
125036
|
}
|
|
124298
125037
|
}
|
|
124299
125038
|
} else {
|
|
124300
|
-
|
|
125039
|
+
self._navCubeCanvas.style.cursor = "default";
|
|
124301
125040
|
if (lastAreaId >= 0) {
|
|
124302
125041
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124303
125042
|
self._repaint();
|
|
@@ -124560,8 +125299,8 @@ class NavCubePlugin extends Plugin {
|
|
|
124560
125299
|
this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave);
|
|
124561
125300
|
this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown);
|
|
124562
125301
|
|
|
124563
|
-
|
|
124564
|
-
|
|
125302
|
+
this._navCubeCanvas.removeEventListener("mousemove", this._onMouseMove);
|
|
125303
|
+
this._navCubeCanvas.removeEventListener("mouseup", this._onMouseUp);
|
|
124565
125304
|
|
|
124566
125305
|
this._navCubeCanvas = null;
|
|
124567
125306
|
this._cubeTextureCanvas.destroy();
|
|
@@ -125955,8 +126694,8 @@ class Control {
|
|
|
125955
126694
|
const canvasPos = math.vec2();
|
|
125956
126695
|
|
|
125957
126696
|
const copyCanvasPos = (event, vec2) => {
|
|
125958
|
-
vec2[0] = event.
|
|
125959
|
-
vec2[1] = event.
|
|
126697
|
+
vec2[0] = event.pageX;
|
|
126698
|
+
vec2[1] = event.pageY;
|
|
125960
126699
|
transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
|
|
125961
126700
|
};
|
|
125962
126701
|
|
|
@@ -129454,46 +130193,27 @@ class FaceAlignedSectionPlanesPlugin extends Plugin {
|
|
|
129454
130193
|
* });
|
|
129455
130194
|
*
|
|
129456
130195
|
* // Add a GLTFModelsPlugin
|
|
129457
|
-
* var
|
|
129458
|
-
* id: "GLTFModels" // Default value
|
|
129459
|
-
* });
|
|
130196
|
+
* var xktLoaderPlugin = new XKTLoaderPlugin(viewer);
|
|
129460
130197
|
*
|
|
129461
130198
|
* // Add a SkyboxesPlugin
|
|
129462
|
-
* var skyboxesPlugin = new SkyboxesPlugin(viewer
|
|
129463
|
-
*
|
|
129464
|
-
*
|
|
130199
|
+
* var skyboxesPlugin = new SkyboxesPlugin(viewer);
|
|
130200
|
+
*
|
|
130201
|
+
* // Create a skybox
|
|
130202
|
+
* skyBoxesPlugin.createSkybox({
|
|
130203
|
+
* src: [
|
|
130204
|
+
* "./assets/images/posx.jpg",
|
|
130205
|
+
* "./assets/images/negx.jpg",
|
|
130206
|
+
* "./assets/images/posy.jpg",
|
|
130207
|
+
* "./assets/images/negy.jpg",
|
|
130208
|
+
* "./assets/images/posz.jpg",
|
|
130209
|
+
* "./assets/images/negz.jpg"
|
|
130210
|
+
* ]
|
|
130211
|
+
* })
|
|
129465
130212
|
*
|
|
129466
|
-
* // Load
|
|
129467
|
-
* const model =
|
|
130213
|
+
* // Load an XKT model
|
|
130214
|
+
* const model = xktLoaderPlugin.load({
|
|
129468
130215
|
* id: "myModel",
|
|
129469
|
-
* src: "./models/
|
|
129470
|
-
* });
|
|
129471
|
-
*
|
|
129472
|
-
* // Create three directional World-space lights. "World" means that they will appear as if part
|
|
129473
|
-
* // of the world, instead of "View", where they move with the user's head.
|
|
129474
|
-
*
|
|
129475
|
-
* skyboxesPlugin.createLight({
|
|
129476
|
-
* id: "keyLight",
|
|
129477
|
-
* dir: [0.8, -0.6, -0.8],
|
|
129478
|
-
* color: [1.0, 0.3, 0.3],
|
|
129479
|
-
* intensity: 1.0,
|
|
129480
|
-
* space: "world"
|
|
129481
|
-
* });
|
|
129482
|
-
*
|
|
129483
|
-
* skyboxesPlugin.createLight({
|
|
129484
|
-
* id: "fillLight",
|
|
129485
|
-
* dir: [-0.8, -0.4, -0.4],
|
|
129486
|
-
* color: [0.3, 1.0, 0.3],
|
|
129487
|
-
* intensity: 1.0,
|
|
129488
|
-
* space: "world"
|
|
129489
|
-
* });
|
|
129490
|
-
*
|
|
129491
|
-
* skyboxesPlugin.createDirLight({
|
|
129492
|
-
* id: "rimLight",
|
|
129493
|
-
* dir: [0.2, -0.8, 0.8],
|
|
129494
|
-
* color: [0.6, 0.6, 0.6],
|
|
129495
|
-
* intensity: 1.0,
|
|
129496
|
-
* space: "world"
|
|
130216
|
+
* src: "./models/xkt/myModel.xkt"
|
|
129497
130217
|
* });
|
|
129498
130218
|
*
|
|
129499
130219
|
* @class SkyboxesPlugin
|
|
@@ -129519,23 +130239,17 @@ class SkyboxesPlugin extends Plugin {
|
|
|
129519
130239
|
/**
|
|
129520
130240
|
Creates a skybox.
|
|
129521
130241
|
|
|
129522
|
-
@param {String} id Unique ID to assign to the skybox.
|
|
129523
130242
|
@param {Object} params Skybox configuration.
|
|
130243
|
+
@param {String} [params.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted.
|
|
130244
|
+
@param {String | String[]} [params.src=null] Path to skybox texture
|
|
130245
|
+
@param {Number} [params.encoding=LinearEncoding] Texture encoding format. See the {@link Texture#encoding} property for more info.
|
|
130246
|
+
@param {Number} [params.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face.
|
|
129524
130247
|
@param {Boolean} [params.active=true] Whether the skybox plane is initially active. Only skyboxes while this is true.
|
|
129525
130248
|
@returns {Skybox} The new skybox.
|
|
129526
130249
|
*/
|
|
129527
|
-
createSkybox(
|
|
129528
|
-
|
|
129529
|
-
|
|
129530
|
-
return this;
|
|
129531
|
-
}
|
|
129532
|
-
var skybox = new Skybox(this.viewer.scene, {
|
|
129533
|
-
id: id,
|
|
129534
|
-
pos: params.pos,
|
|
129535
|
-
dir: params.dir,
|
|
129536
|
-
active: true
|
|
129537
|
-
});
|
|
129538
|
-
this.skyboxes[id] = skybox;
|
|
130250
|
+
createSkybox(params) {
|
|
130251
|
+
const skybox = new Skybox(this.viewer.scene, params);
|
|
130252
|
+
this.skyboxes[skybox.id] = skybox;
|
|
129539
130253
|
return skybox;
|
|
129540
130254
|
}
|
|
129541
130255
|
|
|
@@ -130198,6 +130912,15 @@ class STLLoaderPlugin extends Plugin {
|
|
|
130198
130912
|
*/
|
|
130199
130913
|
class RenderService {
|
|
130200
130914
|
|
|
130915
|
+
/**
|
|
130916
|
+
* @constructor
|
|
130917
|
+
*
|
|
130918
|
+
* @param {HTMLElement} treeViewContainer Container element for the tree which uses this render service.
|
|
130919
|
+
*/
|
|
130920
|
+
constructor(treeViewContainer) {
|
|
130921
|
+
this._treeViewContainer = treeViewContainer;
|
|
130922
|
+
}
|
|
130923
|
+
|
|
130201
130924
|
/*
|
|
130202
130925
|
* Creates the root node of the tree.
|
|
130203
130926
|
* @return {HTMLElement} The root node of the tree.
|
|
@@ -130322,7 +131045,7 @@ class RenderService {
|
|
|
130322
131045
|
}
|
|
130323
131046
|
|
|
130324
131047
|
getSwitchElement(nodeId) {
|
|
130325
|
-
return
|
|
131048
|
+
return this._treeViewContainer.querySelector(`[id="switch-${nodeId}"]`);
|
|
130326
131049
|
}
|
|
130327
131050
|
|
|
130328
131051
|
isChecked(element) {
|
|
@@ -130330,7 +131053,7 @@ class RenderService {
|
|
|
130330
131053
|
}
|
|
130331
131054
|
|
|
130332
131055
|
setCheckbox(nodeId, checked, indeterminate = false) {
|
|
130333
|
-
const checkbox =
|
|
131056
|
+
const checkbox = this._treeViewContainer.querySelector(`[id="checkbox-${nodeId}"]`);
|
|
130334
131057
|
if (checkbox) {
|
|
130335
131058
|
if (checked !== checkbox.checked) {
|
|
130336
131059
|
checkbox.checked = checked;
|
|
@@ -130345,7 +131068,7 @@ class RenderService {
|
|
|
130345
131068
|
}
|
|
130346
131069
|
|
|
130347
131070
|
setXRayed(nodeId, xrayed) {
|
|
130348
|
-
const treeNode =
|
|
131071
|
+
const treeNode = this._treeViewContainer.querySelector(`[id="${nodeId}"]`);
|
|
130349
131072
|
if (treeNode) {
|
|
130350
131073
|
if (xrayed) {
|
|
130351
131074
|
treeNode.classList.add('xrayed-node');
|
|
@@ -130356,7 +131079,7 @@ class RenderService {
|
|
|
130356
131079
|
}
|
|
130357
131080
|
|
|
130358
131081
|
setHighlighted(nodeId, highlighted) {
|
|
130359
|
-
const treeNode =
|
|
131082
|
+
const treeNode = this._treeViewContainer.querySelector(`[id="${nodeId}"]`);
|
|
130360
131083
|
if (treeNode) {
|
|
130361
131084
|
if (highlighted) {
|
|
130362
131085
|
treeNode.scrollIntoView({block: "center"});
|
|
@@ -130782,7 +131505,7 @@ class TreeViewPlugin extends Plugin {
|
|
|
130782
131505
|
this._sortNodes = cfg.sortNodes;
|
|
130783
131506
|
this._pruneEmptyNodes = cfg.pruneEmptyNodes;
|
|
130784
131507
|
this._showListItemElementId = null;
|
|
130785
|
-
this._renderService = cfg.renderService || new RenderService();
|
|
131508
|
+
this._renderService = cfg.renderService || new RenderService(this._containerElement);
|
|
130786
131509
|
this._showIndeterminate = cfg.showIndeterminate ?? false;
|
|
130787
131510
|
this._showProjectNode = cfg.showProjectNode ?? false;
|
|
130788
131511
|
this._elevationSortFunction = cfg.elevationSortFunction ?? undefined;
|
|
@@ -168436,151 +169159,6 @@ const hex2rgb = function(color) {
|
|
|
168436
169159
|
return [ rgb(0), rgb(2), rgb(4) ];
|
|
168437
169160
|
};
|
|
168438
169161
|
|
|
168439
|
-
const triangulateEarClipping = function(planeCoords) {
|
|
168440
|
-
|
|
168441
|
-
const polygonVertices = [ ];
|
|
168442
|
-
for (let i = 0; i < planeCoords.length; ++i)
|
|
168443
|
-
polygonVertices.push(i);
|
|
168444
|
-
|
|
168445
|
-
const isCCW = (function() {
|
|
168446
|
-
const ba = math.vec2();
|
|
168447
|
-
const bc = math.vec2();
|
|
168448
|
-
|
|
168449
|
-
let anglesSum = 0;
|
|
168450
|
-
|
|
168451
|
-
for (let i = 0; i < polygonVertices.length; ++i)
|
|
168452
|
-
{
|
|
168453
|
-
const a = planeCoords[polygonVertices[i]];
|
|
168454
|
-
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
168455
|
-
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
168456
|
-
|
|
168457
|
-
math.subVec2(a, b, ba);
|
|
168458
|
-
math.subVec2(c, b, bc);
|
|
168459
|
-
|
|
168460
|
-
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
168461
|
-
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
168462
|
-
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
168463
|
-
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
168464
|
-
}
|
|
168465
|
-
|
|
168466
|
-
return anglesSum < (polygonVertices.length * Math.PI);
|
|
168467
|
-
})();
|
|
168468
|
-
|
|
168469
|
-
const pointInTriangle = (function() {
|
|
168470
|
-
const sign = (p1, p2, p3) => {
|
|
168471
|
-
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
168472
|
-
};
|
|
168473
|
-
|
|
168474
|
-
return (pt, v1, v2, v3) => {
|
|
168475
|
-
const d1 = sign(pt, v1, v2);
|
|
168476
|
-
const d2 = sign(pt, v2, v3);
|
|
168477
|
-
const d3 = sign(pt, v3, v1);
|
|
168478
|
-
|
|
168479
|
-
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
168480
|
-
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
168481
|
-
|
|
168482
|
-
return !(has_neg && has_pos);
|
|
168483
|
-
};
|
|
168484
|
-
})();
|
|
168485
|
-
|
|
168486
|
-
const baseTriangles = [ ];
|
|
168487
|
-
|
|
168488
|
-
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
168489
|
-
vertices.forEach((v, i) => {
|
|
168490
|
-
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
168491
|
-
v.next = vertices[(i + 1) % vertices.length];
|
|
168492
|
-
});
|
|
168493
|
-
|
|
168494
|
-
const ba = math.vec2();
|
|
168495
|
-
const bc = math.vec2();
|
|
168496
|
-
|
|
168497
|
-
while (vertices.length > 2) {
|
|
168498
|
-
let earIdx = 0;
|
|
168499
|
-
while (true) {
|
|
168500
|
-
if (earIdx >= vertices.length)
|
|
168501
|
-
{
|
|
168502
|
-
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
168503
|
-
}
|
|
168504
|
-
const v = vertices[earIdx];
|
|
168505
|
-
|
|
168506
|
-
const a = planeCoords[v.prev.idx];
|
|
168507
|
-
const b = planeCoords[v.idx];
|
|
168508
|
-
const c = planeCoords[v.next.idx];
|
|
168509
|
-
|
|
168510
|
-
math.subVec2(a, b, ba);
|
|
168511
|
-
math.subVec2(c, b, bc);
|
|
168512
|
-
|
|
168513
|
-
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
168514
|
-
&&
|
|
168515
|
-
vertices.every( // no other vertices inside
|
|
168516
|
-
vv => ((vv === v)
|
|
168517
|
-
||
|
|
168518
|
-
(vv === v.prev)
|
|
168519
|
-
||
|
|
168520
|
-
(vv === v.next)
|
|
168521
|
-
||
|
|
168522
|
-
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
168523
|
-
break;
|
|
168524
|
-
++earIdx;
|
|
168525
|
-
}
|
|
168526
|
-
|
|
168527
|
-
const ear = vertices[earIdx];
|
|
168528
|
-
vertices.splice(earIdx, 1);
|
|
168529
|
-
|
|
168530
|
-
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
168531
|
-
|
|
168532
|
-
const prev = ear.prev;
|
|
168533
|
-
prev.next = ear.next;
|
|
168534
|
-
const next = ear.next;
|
|
168535
|
-
next.prev = ear.prev;
|
|
168536
|
-
}
|
|
168537
|
-
|
|
168538
|
-
return [ planeCoords, baseTriangles, isCCW ];
|
|
168539
|
-
};
|
|
168540
|
-
|
|
168541
|
-
const marker3D = function(scene, color) {
|
|
168542
|
-
const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
|
|
168543
|
-
borderColor: "white",
|
|
168544
|
-
fillColor: color,
|
|
168545
|
-
zIndex: 100
|
|
168546
|
-
});
|
|
168547
|
-
|
|
168548
|
-
return {
|
|
168549
|
-
update: function(worldPos) {
|
|
168550
|
-
if (worldPos)
|
|
168551
|
-
{
|
|
168552
|
-
marker.worldPos = worldPos;
|
|
168553
|
-
}
|
|
168554
|
-
marker.setVisible(!!worldPos);
|
|
168555
|
-
},
|
|
168556
|
-
|
|
168557
|
-
setHighlighted: h => marker.setHighlighted(h),
|
|
168558
|
-
getCanvasPos: () => marker.canvasPos,
|
|
168559
|
-
getWorldPos: () => marker.worldPos,
|
|
168560
|
-
destroy: () => marker.destroy()
|
|
168561
|
-
};
|
|
168562
|
-
};
|
|
168563
|
-
|
|
168564
|
-
const wire3D = function(scene, color, startWorldPos) {
|
|
168565
|
-
const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
|
|
168566
|
-
color: color,
|
|
168567
|
-
thickness: 1,
|
|
168568
|
-
thicknessClickable: 6
|
|
168569
|
-
});
|
|
168570
|
-
wire.setVisible(false);
|
|
168571
|
-
return {
|
|
168572
|
-
update: endWorldPos => {
|
|
168573
|
-
if (endWorldPos)
|
|
168574
|
-
{
|
|
168575
|
-
wire.setEnds(startWorldPos, endWorldPos);
|
|
168576
|
-
}
|
|
168577
|
-
wire.setVisible(!!endWorldPos);
|
|
168578
|
-
},
|
|
168579
|
-
|
|
168580
|
-
destroy: () => wire.destroy()
|
|
168581
|
-
};
|
|
168582
|
-
};
|
|
168583
|
-
|
|
168584
169162
|
const basePolygon3D = function(scene, color, alpha) {
|
|
168585
169163
|
let mesh = null;
|
|
168586
169164
|
|
|
@@ -169560,7 +170138,8 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169560
170138
|
|
|
169561
170139
|
(function selectNextPoint(markers) {
|
|
169562
170140
|
const marker = marker3D(scene, zoneColor);
|
|
169563
|
-
const wire = (markers.length > 0) && wire3D(scene, zoneColor
|
|
170141
|
+
const wire = (markers.length > 0) && wire3D(scene, zoneColor);
|
|
170142
|
+
const wireStart = wire && markers[markers.length - 1].getWorldPos();
|
|
169564
170143
|
|
|
169565
170144
|
cleanups.push(() => {
|
|
169566
170145
|
marker.destroy();
|
|
@@ -169620,7 +170199,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169620
170199
|
() => {
|
|
169621
170200
|
updatePointerLens(null);
|
|
169622
170201
|
marker.update(null);
|
|
169623
|
-
wire && wire.update(null);
|
|
170202
|
+
wire && wire.update(wireStart, null);
|
|
169624
170203
|
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
169625
170204
|
},
|
|
169626
170205
|
(canvasPos, worldPos) => {
|
|
@@ -169628,7 +170207,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169628
170207
|
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
169629
170208
|
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
169630
170209
|
marker.update((! snappedFirst) && worldPos);
|
|
169631
|
-
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
170210
|
+
wire && wire.update(wireStart, snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
169632
170211
|
if ((markers.length >= 2))
|
|
169633
170212
|
{
|
|
169634
170213
|
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
@@ -169672,7 +170251,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169672
170251
|
else
|
|
169673
170252
|
{
|
|
169674
170253
|
marker.update(worldPos);
|
|
169675
|
-
wire && wire.update(worldPos);
|
|
170254
|
+
wire && wire.update(wireStart, worldPos);
|
|
169676
170255
|
selectNextPoint(markers.concat(marker));
|
|
169677
170256
|
}
|
|
169678
170257
|
});
|
|
@@ -170290,6 +170869,8 @@ exports.ZonesPolysurfaceTouchControl = ZonesPolysurfaceTouchControl;
|
|
|
170290
170869
|
exports.ZonesTouchControl = ZonesTouchControl;
|
|
170291
170870
|
exports.activateDraggableDot = activateDraggableDot;
|
|
170292
170871
|
exports.activateDraggableDots = activateDraggableDots;
|
|
170872
|
+
exports.addMousePressListener = addMousePressListener;
|
|
170873
|
+
exports.addTouchPressListener = addTouchPressListener;
|
|
170293
170874
|
exports.buildBoxGeometry = buildBoxGeometry;
|
|
170294
170875
|
exports.buildBoxLinesGeometry = buildBoxLinesGeometry;
|
|
170295
170876
|
exports.buildBoxLinesGeometryFromAABB = buildBoxLinesGeometryFromAABB;
|
|
@@ -170309,6 +170890,7 @@ exports.getPlaneRTCPos = getPlaneRTCPos;
|
|
|
170309
170890
|
exports.isTriangleMeshSolid = isTriangleMeshSolid;
|
|
170310
170891
|
exports.load3DSGeometry = load3DSGeometry;
|
|
170311
170892
|
exports.loadOBJGeometry = loadOBJGeometry;
|
|
170893
|
+
exports.marker3D = marker3D;
|
|
170312
170894
|
exports.math = math;
|
|
170313
170895
|
exports.meshSurfaceArea = meshSurfaceArea;
|
|
170314
170896
|
exports.meshVolume = meshVolume;
|
|
@@ -170316,9 +170898,12 @@ exports.os = os;
|
|
|
170316
170898
|
exports.rtcToWorldPos = rtcToWorldPos;
|
|
170317
170899
|
exports.sRGBEncoding = sRGBEncoding;
|
|
170318
170900
|
exports.setFrustum = setFrustum;
|
|
170901
|
+
exports.startPolygonCreate = startPolygonCreate;
|
|
170319
170902
|
exports.stats = stats;
|
|
170320
170903
|
exports.touchPointSelector = touchPointSelector;
|
|
170321
170904
|
exports.transformToNode = transformToNode;
|
|
170905
|
+
exports.triangulateEarClipping = triangulateEarClipping;
|
|
170322
170906
|
exports.utils = utils;
|
|
170907
|
+
exports.wire3D = wire3D;
|
|
170323
170908
|
exports.worldToRTCPos = worldToRTCPos;
|
|
170324
170909
|
exports.worldToRTCPositions = worldToRTCPositions;
|