@xeokit/xeokit-sdk 2.6.71 → 2.6.73
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 +767 -295
- package/dist/xeokit-sdk.es.js +762 -296
- package/dist/xeokit-sdk.es5.js +535 -525
- 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 +11 -9
- package/src/plugins/AnnotationsPlugin/Annotation.js +28 -16
- package/src/plugins/NavCubePlugin/CubeTextureCanvas.js +2 -2
- package/src/plugins/NavCubePlugin/NavCubePlugin.js +10 -10
- package/src/plugins/SectionPlanesPlugin/Control.js +2 -2
- package/src/plugins/ZonesPlugin/ZonesPlugin.js +6 -151
- package/src/plugins/lib/ui/index.js +592 -34
- package/src/viewer/scene/geometry/ReadableGeometry.js +60 -0
- package/src/viewer/scene/geometry/builders/buildPlaneGeometry.js +1 -1
- package/src/viewer/scene/scene/Scene.js +2 -3
- package/src/viewer/scene/sectionCaps/SectionCaps.js +46 -65
- package/types/plugins/NavCubePlugin/NavCubePlugin.d.ts +1 -1
- package/types/viewer/scene/ImagePlane/ImagePlane.d.ts +397 -0
- package/types/viewer/scene/ImagePlane/index.d.ts +1 -0
- package/types/viewer/scene/geometry/builders/index.d.ts +1 -0
- package/types/viewer/scene/index.d.ts +1 -0
package/dist/xeokit-sdk.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* xeokit-sdk v2.6.
|
|
3
|
-
* Commit:
|
|
4
|
-
* Built: 2025-
|
|
2
|
+
* xeokit-sdk v2.6.73
|
|
3
|
+
* Commit: 3b3bb2ad8abfdf189cf4ba7f67d6798375772b7b
|
|
4
|
+
* Built: 2025-04-10T16:46:49.684Z
|
|
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,6 +345,7 @@ 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;
|
|
348
|
+
this._parentNode = cfg.parentNode || document.body;
|
|
347
349
|
|
|
348
350
|
/**
|
|
349
351
|
* Subscriptions to events fired at this ContextMenu.
|
|
@@ -352,12 +354,12 @@ class ContextMenu {
|
|
|
352
354
|
this._eventSubs = {};
|
|
353
355
|
|
|
354
356
|
if (cfg.hideOnMouseDown !== false) {
|
|
355
|
-
|
|
357
|
+
this._parentNode.addEventListener("mousedown", (event) => {
|
|
356
358
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
357
359
|
this.hide();
|
|
358
360
|
}
|
|
359
361
|
});
|
|
360
|
-
|
|
362
|
+
this._parentNode.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
|
|
361
363
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
362
364
|
this.hide();
|
|
363
365
|
}
|
|
@@ -661,7 +663,10 @@ class ContextMenu {
|
|
|
661
663
|
const groups = menu.groups;
|
|
662
664
|
const html = [];
|
|
663
665
|
|
|
664
|
-
|
|
666
|
+
const menuElement= document.createElement("div");
|
|
667
|
+
menuElement.classList.add("xeokit-context-menu", menu.id);
|
|
668
|
+
menuElement.style.zIndex = 300000;
|
|
669
|
+
menuElement.style.position = "absolute";
|
|
665
670
|
|
|
666
671
|
html.push('<ul>');
|
|
667
672
|
|
|
@@ -712,13 +717,10 @@ class ContextMenu {
|
|
|
712
717
|
}
|
|
713
718
|
|
|
714
719
|
html.push('</ul>');
|
|
715
|
-
html.push('</div>');
|
|
716
720
|
|
|
717
721
|
const htmlString = html.join("");
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const menuElement = document.querySelector("." + menu.id);
|
|
722
|
+
menuElement.innerHTML = htmlString;
|
|
723
|
+
this._parentNode.appendChild(menuElement);
|
|
722
724
|
|
|
723
725
|
menu.menuElement = menuElement;
|
|
724
726
|
|
|
@@ -752,7 +754,7 @@ class ContextMenu {
|
|
|
752
754
|
const item = groupItems[j];
|
|
753
755
|
const itemSubMenu = item.subMenu;
|
|
754
756
|
|
|
755
|
-
item.itemElement =
|
|
757
|
+
item.itemElement = this._parentNode.querySelector(`#${item.id}`);
|
|
756
758
|
|
|
757
759
|
if (!item.itemElement) {
|
|
758
760
|
console.error("ContextMenu item element not found: " + item.id);
|
|
@@ -11655,9 +11657,28 @@ const tmpVec4b = math.vec4();
|
|
|
11655
11657
|
const tmpVec4c = math.vec4();
|
|
11656
11658
|
const tmpVec4d = math.vec4();
|
|
11657
11659
|
const tmpMat4 = math.mat4();
|
|
11660
|
+
const tmpRay = {
|
|
11661
|
+
origin: math.vec3(),
|
|
11662
|
+
direction: math.vec3()
|
|
11663
|
+
};
|
|
11658
11664
|
|
|
11659
11665
|
const nop = () => { };
|
|
11660
11666
|
|
|
11667
|
+
const planeIntersect$1 = function(p0, n, origin, direction) {
|
|
11668
|
+
const t = (p0 - math.dotVec3(origin, n)) / math.dotVec3(direction, n);
|
|
11669
|
+
if (t < 0)
|
|
11670
|
+
{
|
|
11671
|
+
return null;
|
|
11672
|
+
}
|
|
11673
|
+
else
|
|
11674
|
+
{
|
|
11675
|
+
const worldPos = math.vec3();
|
|
11676
|
+
math.mulVec3Scalar(direction, t, worldPos);
|
|
11677
|
+
math.addVec3(origin, worldPos, worldPos);
|
|
11678
|
+
return worldPos;
|
|
11679
|
+
}
|
|
11680
|
+
};
|
|
11681
|
+
|
|
11661
11682
|
function transformToNode(from, to, vec) {
|
|
11662
11683
|
const fromRec = from.getBoundingClientRect();
|
|
11663
11684
|
const toRec = to.getBoundingClientRect();
|
|
@@ -11919,9 +11940,15 @@ class Label3D {
|
|
|
11919
11940
|
this._mid = math.vec3();
|
|
11920
11941
|
this._end = math.vec3();
|
|
11921
11942
|
this._yOff = 0;
|
|
11922
|
-
this._betweenWires = false;
|
|
11923
11943
|
this.__visible = true;
|
|
11924
11944
|
|
|
11945
|
+
this._updatePos = () => {
|
|
11946
|
+
toClipSpace(camera, this._start, tmpVec4a);
|
|
11947
|
+
math.mulVec4Scalar(tmpVec4a, 1.0 / tmpVec4a[3]);
|
|
11948
|
+
toCanvasSpace(scene.canvas.canvas, parentElement, tmpVec4a, tmpVec2a);
|
|
11949
|
+
this._label.setPos(tmpVec2a[0], tmpVec2a[1]);
|
|
11950
|
+
};
|
|
11951
|
+
|
|
11925
11952
|
const setPosOnWire = (p0, p1, yOff) => {
|
|
11926
11953
|
p0[0] += p1[0];
|
|
11927
11954
|
p0[1] += p1[1];
|
|
@@ -11929,36 +11956,44 @@ class Label3D {
|
|
|
11929
11956
|
this._label.setPos(p0[0], p0[1] + yOff);
|
|
11930
11957
|
};
|
|
11931
11958
|
|
|
11932
|
-
this.
|
|
11933
|
-
|
|
11934
|
-
|
|
11959
|
+
this._updatePosBetween = () => {
|
|
11960
|
+
const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
|
|
11961
|
+
const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d);
|
|
11962
|
+
this._label.setCulled(! (visibleA || visibleB));
|
|
11963
|
+
if (visibleA && visibleB) {
|
|
11964
|
+
tmpVec2b[0] += tmpVec2d[0];
|
|
11965
|
+
tmpVec2b[1] += tmpVec2d[1];
|
|
11966
|
+
math.mulVec2Scalar(tmpVec2b, .5);
|
|
11967
|
+
|
|
11968
|
+
tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
|
|
11969
|
+
tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
|
|
11970
|
+
math.mulVec2Scalar(tmpVec2b, 1/3);
|
|
11971
|
+
this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
|
|
11972
|
+
} else if (visibleA) {
|
|
11973
|
+
setPosOnWire(tmpVec2a, tmpVec2b, 0);
|
|
11974
|
+
} else if (visibleB) {
|
|
11975
|
+
setPosOnWire(tmpVec2c, tmpVec2d, 0);
|
|
11935
11976
|
}
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
&&
|
|
11957
|
-
(math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
|
|
11958
|
-
this._label.setCulled(!visible);
|
|
11959
|
-
if (visible) {
|
|
11960
|
-
setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
|
|
11961
|
-
}
|
|
11977
|
+
};
|
|
11978
|
+
|
|
11979
|
+
this._updatePosOnWire = () => {
|
|
11980
|
+
const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
|
|
11981
|
+
&&
|
|
11982
|
+
(math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
|
|
11983
|
+
this._label.setCulled(!visible);
|
|
11984
|
+
if (visible) {
|
|
11985
|
+
setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
|
|
11986
|
+
}
|
|
11987
|
+
};
|
|
11988
|
+
|
|
11989
|
+
let posUpdate = () => { };
|
|
11990
|
+
this._setUpdatePositions = (_posUpdate) => {
|
|
11991
|
+
posUpdate = _posUpdate;
|
|
11992
|
+
this._updatePositions();
|
|
11993
|
+
};
|
|
11994
|
+
this._updatePositions = () => {
|
|
11995
|
+
if (this.__visible) {
|
|
11996
|
+
posUpdate();
|
|
11962
11997
|
}
|
|
11963
11998
|
};
|
|
11964
11999
|
|
|
@@ -11976,21 +12011,24 @@ class Label3D {
|
|
|
11976
12011
|
};
|
|
11977
12012
|
}
|
|
11978
12013
|
|
|
12014
|
+
setPos(p0) {
|
|
12015
|
+
this._start.set(p0);
|
|
12016
|
+
this._setUpdatePositions(this._updatePos);
|
|
12017
|
+
}
|
|
12018
|
+
|
|
11979
12019
|
setPosOnWire(p0, p1, yOff, labelMinAxisLength) {
|
|
11980
12020
|
this._start.set(p0);
|
|
11981
12021
|
this._end.set(p1);
|
|
11982
12022
|
this._yOff = yOff;
|
|
11983
12023
|
this._labelMinAxisLength = labelMinAxisLength;
|
|
11984
|
-
this.
|
|
11985
|
-
this._updatePositions();
|
|
12024
|
+
this._setUpdatePositions(this._updatePosOnWire);
|
|
11986
12025
|
}
|
|
11987
12026
|
|
|
11988
12027
|
setPosBetween(p0, p1, p2) {
|
|
11989
12028
|
this._start.set(p0);
|
|
11990
12029
|
this._mid.set(p1);
|
|
11991
12030
|
this._end.set(p2);
|
|
11992
|
-
this.
|
|
11993
|
-
this._updatePositions();
|
|
12031
|
+
this._setUpdatePositions(this._updatePosBetween);
|
|
11994
12032
|
}
|
|
11995
12033
|
|
|
11996
12034
|
setFillColor(value) {
|
|
@@ -12093,6 +12131,51 @@ class Wire3D {
|
|
|
12093
12131
|
|
|
12094
12132
|
}
|
|
12095
12133
|
|
|
12134
|
+
const marker3D = function(scene, color) {
|
|
12135
|
+
const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
|
|
12136
|
+
borderColor: "white",
|
|
12137
|
+
fillColor: color,
|
|
12138
|
+
zIndex: 100
|
|
12139
|
+
});
|
|
12140
|
+
|
|
12141
|
+
return {
|
|
12142
|
+
update: function(worldPos) {
|
|
12143
|
+
if (worldPos)
|
|
12144
|
+
{
|
|
12145
|
+
marker.worldPos = worldPos;
|
|
12146
|
+
}
|
|
12147
|
+
marker.setVisible(!!worldPos);
|
|
12148
|
+
},
|
|
12149
|
+
|
|
12150
|
+
setFillColor: c => marker.setFillColor(c),
|
|
12151
|
+
setHighlighted: h => marker.setHighlighted(h),
|
|
12152
|
+
getCanvasPos: () => marker.canvasPos,
|
|
12153
|
+
getWorldPos: () => marker.worldPos,
|
|
12154
|
+
destroy: () => marker.destroy()
|
|
12155
|
+
};
|
|
12156
|
+
};
|
|
12157
|
+
|
|
12158
|
+
const wire3D = function(scene, color) {
|
|
12159
|
+
const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
|
|
12160
|
+
color: color,
|
|
12161
|
+
thickness: 1,
|
|
12162
|
+
thicknessClickable: 6 // TODO: Remove to make not clickable?
|
|
12163
|
+
});
|
|
12164
|
+
wire.setVisible(false);
|
|
12165
|
+
return {
|
|
12166
|
+
update: (startWorldPos, endWorldPos) => {
|
|
12167
|
+
if (endWorldPos)
|
|
12168
|
+
{
|
|
12169
|
+
wire.setEnds(startWorldPos, endWorldPos);
|
|
12170
|
+
}
|
|
12171
|
+
wire.setVisible(!!endWorldPos);
|
|
12172
|
+
},
|
|
12173
|
+
|
|
12174
|
+
setColor: c => wire.setColor(c),
|
|
12175
|
+
destroy: () => wire.destroy()
|
|
12176
|
+
};
|
|
12177
|
+
};
|
|
12178
|
+
|
|
12096
12179
|
function activateDraggableDot(dot, cfg) {
|
|
12097
12180
|
const extractCFG = function(propName, defaultValue) {
|
|
12098
12181
|
if (propName in cfg) {
|
|
@@ -12407,6 +12490,482 @@ const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
|
12407
12490
|
};
|
|
12408
12491
|
};
|
|
12409
12492
|
|
|
12493
|
+
const triangulateEarClipping = function(planeCoords) {
|
|
12494
|
+
const polygonVertices = [ ];
|
|
12495
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
12496
|
+
polygonVertices.push(i);
|
|
12497
|
+
|
|
12498
|
+
const isCCW = (function() {
|
|
12499
|
+
const ba = math.vec2();
|
|
12500
|
+
const bc = math.vec2();
|
|
12501
|
+
|
|
12502
|
+
let anglesSum = 0;
|
|
12503
|
+
|
|
12504
|
+
for (let i = 0; i < polygonVertices.length; ++i)
|
|
12505
|
+
{
|
|
12506
|
+
const a = planeCoords[polygonVertices[i]];
|
|
12507
|
+
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
12508
|
+
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
12509
|
+
|
|
12510
|
+
math.subVec2(a, b, ba);
|
|
12511
|
+
math.subVec2(c, b, bc);
|
|
12512
|
+
|
|
12513
|
+
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
12514
|
+
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
12515
|
+
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
12516
|
+
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
12517
|
+
}
|
|
12518
|
+
|
|
12519
|
+
return anglesSum < (polygonVertices.length * Math.PI);
|
|
12520
|
+
})();
|
|
12521
|
+
|
|
12522
|
+
const pointInTriangle = (function() {
|
|
12523
|
+
const sign = (p1, p2, p3) => {
|
|
12524
|
+
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
12525
|
+
};
|
|
12526
|
+
|
|
12527
|
+
return (pt, v1, v2, v3) => {
|
|
12528
|
+
const d1 = sign(pt, v1, v2);
|
|
12529
|
+
const d2 = sign(pt, v2, v3);
|
|
12530
|
+
const d3 = sign(pt, v3, v1);
|
|
12531
|
+
|
|
12532
|
+
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
12533
|
+
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
12534
|
+
|
|
12535
|
+
return !(has_neg && has_pos);
|
|
12536
|
+
};
|
|
12537
|
+
})();
|
|
12538
|
+
|
|
12539
|
+
const baseTriangles = [ ];
|
|
12540
|
+
|
|
12541
|
+
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
12542
|
+
vertices.forEach((v, i) => {
|
|
12543
|
+
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
12544
|
+
v.next = vertices[(i + 1) % vertices.length];
|
|
12545
|
+
});
|
|
12546
|
+
|
|
12547
|
+
const ba = math.vec2();
|
|
12548
|
+
const bc = math.vec2();
|
|
12549
|
+
|
|
12550
|
+
while (vertices.length > 2) {
|
|
12551
|
+
let earIdx = 0;
|
|
12552
|
+
while (true) {
|
|
12553
|
+
if (earIdx >= vertices.length)
|
|
12554
|
+
{
|
|
12555
|
+
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
12556
|
+
}
|
|
12557
|
+
const v = vertices[earIdx];
|
|
12558
|
+
|
|
12559
|
+
const a = planeCoords[v.prev.idx];
|
|
12560
|
+
const b = planeCoords[v.idx];
|
|
12561
|
+
const c = planeCoords[v.next.idx];
|
|
12562
|
+
|
|
12563
|
+
math.subVec2(a, b, ba);
|
|
12564
|
+
math.subVec2(c, b, bc);
|
|
12565
|
+
|
|
12566
|
+
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
12567
|
+
&&
|
|
12568
|
+
vertices.every( // no other vertices inside
|
|
12569
|
+
vv => ((vv === v)
|
|
12570
|
+
||
|
|
12571
|
+
(vv === v.prev)
|
|
12572
|
+
||
|
|
12573
|
+
(vv === v.next)
|
|
12574
|
+
||
|
|
12575
|
+
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
12576
|
+
break;
|
|
12577
|
+
++earIdx;
|
|
12578
|
+
}
|
|
12579
|
+
|
|
12580
|
+
const ear = vertices[earIdx];
|
|
12581
|
+
vertices.splice(earIdx, 1);
|
|
12582
|
+
|
|
12583
|
+
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
12584
|
+
|
|
12585
|
+
const prev = ear.prev;
|
|
12586
|
+
prev.next = ear.next;
|
|
12587
|
+
const next = ear.next;
|
|
12588
|
+
next.prev = ear.prev;
|
|
12589
|
+
}
|
|
12590
|
+
|
|
12591
|
+
return [ planeCoords, baseTriangles, isCCW ];
|
|
12592
|
+
};
|
|
12593
|
+
|
|
12594
|
+
const addMousePressListener = function(element, onChange) {
|
|
12595
|
+
const moveTolerance = 4;
|
|
12596
|
+
|
|
12597
|
+
const copyElementPos = (event, out) => {
|
|
12598
|
+
out[0] = event.clientX;
|
|
12599
|
+
out[1] = event.clientY;
|
|
12600
|
+
transformToNode(element.ownerDocument.documentElement, element, out);
|
|
12601
|
+
return out;
|
|
12602
|
+
};
|
|
12603
|
+
|
|
12604
|
+
let buttonDown = false;
|
|
12605
|
+
|
|
12606
|
+
const cleanups = [ ];
|
|
12607
|
+
const cleanup = () => cleanups.forEach(c => c());
|
|
12608
|
+
|
|
12609
|
+
const addElementEventListener = (type, listener) => {
|
|
12610
|
+
element.addEventListener(type, listener);
|
|
12611
|
+
cleanups.push(() => element.removeEventListener(type, listener));
|
|
12612
|
+
};
|
|
12613
|
+
|
|
12614
|
+
const downPos = math.vec2();
|
|
12615
|
+
addElementEventListener("mousedown", function(event) {
|
|
12616
|
+
if (event.which === 1) {
|
|
12617
|
+
buttonDown = true;
|
|
12618
|
+
onChange(copyElementPos(event, downPos));
|
|
12619
|
+
}
|
|
12620
|
+
});
|
|
12621
|
+
|
|
12622
|
+
addElementEventListener("mousemove", function(event) {
|
|
12623
|
+
copyElementPos(event, tmpVec2a);
|
|
12624
|
+
if (buttonDown && (math.distVec2(downPos, tmpVec2a) > moveTolerance)) {
|
|
12625
|
+
buttonDown = false;
|
|
12626
|
+
}
|
|
12627
|
+
if (buttonDown || (! event.buttons & 1)) {
|
|
12628
|
+
onChange(tmpVec2a);
|
|
12629
|
+
}
|
|
12630
|
+
});
|
|
12631
|
+
|
|
12632
|
+
addElementEventListener("mouseup", function(event) {
|
|
12633
|
+
if ((event.which === 1) && buttonDown) {
|
|
12634
|
+
const commit = onChange(copyElementPos(event, tmpVec2a));
|
|
12635
|
+
if (commit) {
|
|
12636
|
+
cleanup();
|
|
12637
|
+
commit();
|
|
12638
|
+
}
|
|
12639
|
+
}
|
|
12640
|
+
});
|
|
12641
|
+
|
|
12642
|
+
return cleanup;
|
|
12643
|
+
};
|
|
12644
|
+
|
|
12645
|
+
const addTouchPressListener = function(element, cameraControl, pointerCircle, onChange) {
|
|
12646
|
+
const longTouchTimeoutMs = 300;
|
|
12647
|
+
const moveTolerance = 20;
|
|
12648
|
+
const startPos = math.vec2();
|
|
12649
|
+
|
|
12650
|
+
const copyElementPos = (event, out) => {
|
|
12651
|
+
out[0] = event.clientX;
|
|
12652
|
+
out[1] = event.clientY;
|
|
12653
|
+
transformToNode(element.ownerDocument.documentElement, element, out);
|
|
12654
|
+
return out;
|
|
12655
|
+
};
|
|
12656
|
+
|
|
12657
|
+
let longTouchTimeout = null;
|
|
12658
|
+
let onSingleTouchMove = nop;
|
|
12659
|
+
let startTouchIdentifier;
|
|
12660
|
+
|
|
12661
|
+
const resetAction = function() {
|
|
12662
|
+
clearTimeout(longTouchTimeout);
|
|
12663
|
+
pointerCircle.stop();
|
|
12664
|
+
cameraControl.active = true;
|
|
12665
|
+
onSingleTouchMove = nop;
|
|
12666
|
+
startTouchIdentifier = null;
|
|
12667
|
+
};
|
|
12668
|
+
|
|
12669
|
+
const cleanups = [ ];
|
|
12670
|
+
const cleanup = () => cleanups.forEach(c => c());
|
|
12671
|
+
|
|
12672
|
+
const addElementEventListener = (type, listener) => {
|
|
12673
|
+
element.addEventListener(type, listener, {passive: true});
|
|
12674
|
+
cleanups.push(() => element.removeEventListener(type, listener));
|
|
12675
|
+
};
|
|
12676
|
+
|
|
12677
|
+
addElementEventListener("touchstart", function(event) {
|
|
12678
|
+
const touches = event.touches;
|
|
12679
|
+
|
|
12680
|
+
if (touches.length !== 1)
|
|
12681
|
+
{
|
|
12682
|
+
resetAction();
|
|
12683
|
+
onChange(null);
|
|
12684
|
+
}
|
|
12685
|
+
else
|
|
12686
|
+
{
|
|
12687
|
+
const touch = touches[0];
|
|
12688
|
+
copyElementPos(touch, startPos);
|
|
12689
|
+
|
|
12690
|
+
startTouchIdentifier = touch.identifier;
|
|
12691
|
+
|
|
12692
|
+
onSingleTouchMove = elementPos => {
|
|
12693
|
+
if (math.distVec2(startPos, elementPos) > moveTolerance)
|
|
12694
|
+
{
|
|
12695
|
+
resetAction();
|
|
12696
|
+
}
|
|
12697
|
+
};
|
|
12698
|
+
|
|
12699
|
+
longTouchTimeout = setTimeout(
|
|
12700
|
+
function() {
|
|
12701
|
+
pointerCircle.start(startPos);
|
|
12702
|
+
|
|
12703
|
+
longTouchTimeout = setTimeout(
|
|
12704
|
+
function() {
|
|
12705
|
+
pointerCircle.stop();
|
|
12706
|
+
cameraControl.active = false;
|
|
12707
|
+
onSingleTouchMove = onChange;
|
|
12708
|
+
onSingleTouchMove(startPos);
|
|
12709
|
+
},
|
|
12710
|
+
longTouchTimeoutMs);
|
|
12711
|
+
},
|
|
12712
|
+
250);
|
|
12713
|
+
}
|
|
12714
|
+
});
|
|
12715
|
+
|
|
12716
|
+
// element.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
12717
|
+
|
|
12718
|
+
addElementEventListener("touchmove", function(event) {
|
|
12719
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
12720
|
+
if (touch)
|
|
12721
|
+
{
|
|
12722
|
+
onSingleTouchMove(copyElementPos(touch, tmpVec2a));
|
|
12723
|
+
}
|
|
12724
|
+
});
|
|
12725
|
+
|
|
12726
|
+
addElementEventListener("touchend", function(event) {
|
|
12727
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
12728
|
+
if (touch)
|
|
12729
|
+
{
|
|
12730
|
+
const commit = onChange(copyElementPos(touch, tmpVec2a));
|
|
12731
|
+
resetAction();
|
|
12732
|
+
if (commit) {
|
|
12733
|
+
cleanup();
|
|
12734
|
+
commit();
|
|
12735
|
+
} else {
|
|
12736
|
+
onChange(null);
|
|
12737
|
+
}
|
|
12738
|
+
}
|
|
12739
|
+
});
|
|
12740
|
+
|
|
12741
|
+
return () => {
|
|
12742
|
+
resetAction();
|
|
12743
|
+
cleanup();
|
|
12744
|
+
};
|
|
12745
|
+
};
|
|
12746
|
+
|
|
12747
|
+
const startPolygonCreate = function(scene, pointerLens, addPressListener, pickRayResult, onChange, onConclude) {
|
|
12748
|
+
const canvas = scene.canvas.canvas;
|
|
12749
|
+
|
|
12750
|
+
const updatePointerLens = (pointerLens
|
|
12751
|
+
? function(canvasPos, isSnapped) {
|
|
12752
|
+
pointerLens.visible = !! canvasPos;
|
|
12753
|
+
if (canvasPos)
|
|
12754
|
+
{
|
|
12755
|
+
pointerLens.canvasPos = canvasPos;
|
|
12756
|
+
pointerLens.snapped = !! isSnapped;
|
|
12757
|
+
}
|
|
12758
|
+
}
|
|
12759
|
+
: () => { });
|
|
12760
|
+
|
|
12761
|
+
const testLastSegmentIntersects = (function() {
|
|
12762
|
+
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
12763
|
+
(q[0] >= Math.min(p[0], r[0])) &&
|
|
12764
|
+
(q[1] <= Math.max(p[1], r[1])) &&
|
|
12765
|
+
(q[1] >= Math.min(p[1], r[1])));
|
|
12766
|
+
|
|
12767
|
+
const orient = (p, q, r) => {
|
|
12768
|
+
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
12769
|
+
// collinear
|
|
12770
|
+
// clockwise
|
|
12771
|
+
// counterclockwise
|
|
12772
|
+
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
12773
|
+
};
|
|
12774
|
+
|
|
12775
|
+
return function(pos2D, lastSegmentClosesLoop) {
|
|
12776
|
+
const s = lastSegmentClosesLoop ? 1 : 0;
|
|
12777
|
+
const a = pos2D[(pos2D.length - 2 + s) % pos2D.length];
|
|
12778
|
+
const b = pos2D[(pos2D.length - 1 + s) % pos2D.length];
|
|
12779
|
+
|
|
12780
|
+
for (let i = s; i < pos2D.length - 2 - 1 + s; ++i) {
|
|
12781
|
+
const c = pos2D[i];
|
|
12782
|
+
const d = pos2D[i + 1];
|
|
12783
|
+
|
|
12784
|
+
const o1 = orient(a, b, c);
|
|
12785
|
+
const o2 = orient(a, b, d);
|
|
12786
|
+
const o3 = orient(c, d, a);
|
|
12787
|
+
const o4 = orient(c, d, b);
|
|
12788
|
+
|
|
12789
|
+
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
12790
|
+
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
12791
|
+
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
12792
|
+
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
12793
|
+
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
12794
|
+
{
|
|
12795
|
+
return true;
|
|
12796
|
+
}
|
|
12797
|
+
}
|
|
12798
|
+
|
|
12799
|
+
return false;
|
|
12800
|
+
};
|
|
12801
|
+
})();
|
|
12802
|
+
|
|
12803
|
+
const getPlane = (points) => (points.length >= 3) && (function() {
|
|
12804
|
+
const u = math.normalizeVec3(math.subVec3(points[1], points[0], math.vec3()));
|
|
12805
|
+
const v20 = math.normalizeVec3(math.subVec3(points[2], points[0], tmpVec3a$2));
|
|
12806
|
+
const normal = math.normalizeVec3(math.cross3Vec3(u, v20, math.vec3()));
|
|
12807
|
+
const v = math.normalizeVec3(math.cross3Vec3(normal, u, math.vec3()));
|
|
12808
|
+
return {
|
|
12809
|
+
normal: normal,
|
|
12810
|
+
origin: math.vec3(points[0]),
|
|
12811
|
+
u: u,
|
|
12812
|
+
v: v
|
|
12813
|
+
};
|
|
12814
|
+
})();
|
|
12815
|
+
|
|
12816
|
+
const vertices = [ ];
|
|
12817
|
+
let currentInteraction;
|
|
12818
|
+
|
|
12819
|
+
(function selectNextPoint() {
|
|
12820
|
+
const plane = getPlane(vertices);
|
|
12821
|
+
|
|
12822
|
+
const canvasPos2Ray = (canvasPos, dst) => (math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, dst.origin, dst.direction), dst);
|
|
12823
|
+
|
|
12824
|
+
const pickRay = (ray) => {
|
|
12825
|
+
const pickResult = pickRayResult(ray);
|
|
12826
|
+
const snapWorldPos = pickResult && pickResult.entity && ((! plane) || pickResult.snapped) && pickResult.worldPos;
|
|
12827
|
+
if (plane) {
|
|
12828
|
+
const originDistance = math.dotVec3(plane.normal, plane.origin);
|
|
12829
|
+
const snapPlaneDist = (snapWorldPos
|
|
12830
|
+
? ((originDistance - math.dotVec3(snapWorldPos, plane.normal)))
|
|
12831
|
+
: window.Infinity);
|
|
12832
|
+
if (Math.abs(snapPlaneDist) < 0.0001) {
|
|
12833
|
+
const ret = math.vec3();
|
|
12834
|
+
return {
|
|
12835
|
+
worldPos: math.addVec3(snapWorldPos, math.mulVec3Scalar(plane.normal, snapPlaneDist, ret), ret),
|
|
12836
|
+
snapped: true
|
|
12837
|
+
};
|
|
12838
|
+
} else {
|
|
12839
|
+
return {
|
|
12840
|
+
worldPos: planeIntersect$1(originDistance, plane.normal, ray.origin, ray.direction),
|
|
12841
|
+
snapped: false
|
|
12842
|
+
};
|
|
12843
|
+
}
|
|
12844
|
+
} else {
|
|
12845
|
+
return {
|
|
12846
|
+
worldPos: snapWorldPos,
|
|
12847
|
+
snapped: pickResult && pickResult.snapped
|
|
12848
|
+
};
|
|
12849
|
+
}
|
|
12850
|
+
};
|
|
12851
|
+
|
|
12852
|
+
let placeVertex = false;
|
|
12853
|
+
const removePressListener = addPressListener(
|
|
12854
|
+
(inputCanvasPos) => {
|
|
12855
|
+
const rayPick = inputCanvasPos && pickRay(canvasPos2Ray(inputCanvasPos, tmpRay));
|
|
12856
|
+
const worldPos = rayPick && rayPick.worldPos;
|
|
12857
|
+
return onWorldPos(worldPos, inputCanvasPos, rayPick && rayPick.snapped);
|
|
12858
|
+
});
|
|
12859
|
+
|
|
12860
|
+
const onWorldPos = (worldPos, inputCanvasPos, rayPickSnapped) => {
|
|
12861
|
+
const canvasPos = worldPos ? scene.camera.projectWorldPos(worldPos) : inputCanvasPos;
|
|
12862
|
+
const firstMarker = (vertices.length > 0) && (function() {
|
|
12863
|
+
const v = vertices[0];
|
|
12864
|
+
return {
|
|
12865
|
+
canvasPos: scene.camera.projectWorldPos(v),
|
|
12866
|
+
worldPos: v
|
|
12867
|
+
};
|
|
12868
|
+
})();
|
|
12869
|
+
const snapToFirst = (vertices.length >= 3) && ((canvasPos && (math.distVec2(canvasPos, firstMarker.canvasPos) < 10))
|
|
12870
|
+
||
|
|
12871
|
+
(worldPos && math.compareVec3(worldPos, firstMarker.worldPos)));
|
|
12872
|
+
|
|
12873
|
+
updatePointerLens(snapToFirst ? firstMarker.canvasPos : canvasPos, snapToFirst || rayPickSnapped);
|
|
12874
|
+
|
|
12875
|
+
const lastPointOverlaps = (inputCanvasPos
|
|
12876
|
+
&&
|
|
12877
|
+
((! worldPos)
|
|
12878
|
+
||
|
|
12879
|
+
((vertices.length < 3)
|
|
12880
|
+
? vertices.some(v => math.compareVec3(v, worldPos))
|
|
12881
|
+
: math.compareVec3(vertices[vertices.length - 1], worldPos))));
|
|
12882
|
+
|
|
12883
|
+
const points = vertices.concat(((! snapToFirst) && worldPos && (! lastPointOverlaps)) ? [worldPos] : []);
|
|
12884
|
+
|
|
12885
|
+
const curPlane = (! lastPointOverlaps) && (plane || getPlane(points));
|
|
12886
|
+
|
|
12887
|
+
const uvs = curPlane && points.map(p => {
|
|
12888
|
+
math.subVec3(p, curPlane.origin, tmpVec3a$2);
|
|
12889
|
+
return math.vec2([ math.dotVec3(tmpVec3a$2, curPlane.u), math.dotVec3(tmpVec3a$2, curPlane.v) ]);
|
|
12890
|
+
});
|
|
12891
|
+
|
|
12892
|
+
const isValid = (! lastPointOverlaps) && (! (uvs && testLastSegmentIntersects(uvs, snapToFirst)));
|
|
12893
|
+
const geometry = isValid && uvs && (snapToFirst || (! testLastSegmentIntersects(uvs, true))) && (function() {
|
|
12894
|
+
try {
|
|
12895
|
+
const [ baseVertices, baseTriangles, isCCW ] = triangulateEarClipping(uvs);
|
|
12896
|
+
return {
|
|
12897
|
+
faces: baseTriangles,
|
|
12898
|
+
vertices: baseVertices.map(uv => math.addVec3(
|
|
12899
|
+
curPlane.origin,
|
|
12900
|
+
math.addVec3(
|
|
12901
|
+
math.mulVec3Scalar(curPlane.u, uv[0], tmpVec3a$2),
|
|
12902
|
+
math.mulVec3Scalar(curPlane.v, uv[1], tmpVec3b$2),
|
|
12903
|
+
tmpVec3a$2),
|
|
12904
|
+
math.vec3()))
|
|
12905
|
+
};
|
|
12906
|
+
} catch (e) {
|
|
12907
|
+
console.warn("e", e);
|
|
12908
|
+
return false;
|
|
12909
|
+
}
|
|
12910
|
+
})();
|
|
12911
|
+
|
|
12912
|
+
onChange(points, snapToFirst, isValid, geometry);
|
|
12913
|
+
|
|
12914
|
+
return placeVertex = (isValid && (snapToFirst
|
|
12915
|
+
? () => {
|
|
12916
|
+
updatePointerLens(null);
|
|
12917
|
+
onConclude();
|
|
12918
|
+
}
|
|
12919
|
+
: () => {
|
|
12920
|
+
vertices.push(math.vec3(worldPos));
|
|
12921
|
+
updatePointerLens(null);
|
|
12922
|
+
selectNextPoint();
|
|
12923
|
+
}));
|
|
12924
|
+
};
|
|
12925
|
+
|
|
12926
|
+
currentInteraction = {
|
|
12927
|
+
closePolygon: (() => {
|
|
12928
|
+
const commit = (vertices.length >= 3) && onWorldPos(vertices[0]);
|
|
12929
|
+
if (commit) {
|
|
12930
|
+
removePressListener();
|
|
12931
|
+
commit();
|
|
12932
|
+
}
|
|
12933
|
+
return !! commit;
|
|
12934
|
+
}),
|
|
12935
|
+
placeVertex: () => {
|
|
12936
|
+
if (placeVertex) {
|
|
12937
|
+
removePressListener();
|
|
12938
|
+
placeVertex();
|
|
12939
|
+
}
|
|
12940
|
+
return !!placeVertex;
|
|
12941
|
+
},
|
|
12942
|
+
popVertex: () => {
|
|
12943
|
+
if (vertices.length > 0) {
|
|
12944
|
+
removePressListener();
|
|
12945
|
+
vertices.pop();
|
|
12946
|
+
selectNextPoint();
|
|
12947
|
+
return true;
|
|
12948
|
+
} else {
|
|
12949
|
+
return false;
|
|
12950
|
+
}
|
|
12951
|
+
},
|
|
12952
|
+
removePressListener: removePressListener,
|
|
12953
|
+
updateOnChange: () => onWorldPos()
|
|
12954
|
+
};
|
|
12955
|
+
})();
|
|
12956
|
+
|
|
12957
|
+
return {
|
|
12958
|
+
cancel: () => {
|
|
12959
|
+
currentInteraction.removePressListener();
|
|
12960
|
+
updatePointerLens(null);
|
|
12961
|
+
},
|
|
12962
|
+
closePolygon: () => currentInteraction.closePolygon(),
|
|
12963
|
+
placeVertex: () => currentInteraction.placeVertex(),
|
|
12964
|
+
popVertex: () => currentInteraction.popVertex(),
|
|
12965
|
+
updateOnChange: () => currentInteraction.updateOnChange()
|
|
12966
|
+
};
|
|
12967
|
+
};
|
|
12968
|
+
|
|
12410
12969
|
const tmpVec3a$1 = math.vec3();
|
|
12411
12970
|
const tmpVec3b$1 = math.vec3();
|
|
12412
12971
|
|
|
@@ -14826,6 +15385,8 @@ const tempVec3a$M = math.vec3();
|
|
|
14826
15385
|
const tempVec3b$B = math.vec3();
|
|
14827
15386
|
const tempVec3c$w = math.vec3();
|
|
14828
15387
|
|
|
15388
|
+
const px = x => x + "px";
|
|
15389
|
+
|
|
14829
15390
|
/**
|
|
14830
15391
|
* A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
|
|
14831
15392
|
*
|
|
@@ -15032,22 +15593,29 @@ class Annotation extends Marker {
|
|
|
15032
15593
|
* @private
|
|
15033
15594
|
*/
|
|
15034
15595
|
_updateWithCurWidths() {
|
|
15035
|
-
const px = x => x + "px";
|
|
15036
15596
|
const boundary = this.scene.canvas.boundary;
|
|
15037
15597
|
const left = boundary[0] + this.canvasPos[0];
|
|
15038
15598
|
const top = boundary[1] + this.canvasPos[1];
|
|
15039
|
-
|
|
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);
|
|
15599
|
+
this._marker.style.top = px(top - 12);
|
|
15049
15600
|
this._label.style.top = px(top - 17);
|
|
15050
|
-
|
|
15601
|
+
|
|
15602
|
+
if (this._markerAlign === "legacy") {
|
|
15603
|
+
this._marker.style.left = px(left - 12);
|
|
15604
|
+
this._label.style.left = px(left + 40);
|
|
15605
|
+
} else {
|
|
15606
|
+
const markerWidth = this._curMarkerWidth;
|
|
15607
|
+
const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
|
|
15608
|
+
const markerCenter = left + markerDir * (markerWidth / 2 - 12);
|
|
15609
|
+
this._marker.style.left = px(markerCenter - markerWidth / 2);
|
|
15610
|
+
|
|
15611
|
+
const labelWidth = this._curLabelWidth;
|
|
15612
|
+
const labelDir = Math.sign(this._labelPosition);
|
|
15613
|
+
this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
|
|
15614
|
+
}
|
|
15615
|
+
|
|
15616
|
+
const zIndex = 90005 + Math.floor(this._viewPos[2]) + 1;
|
|
15617
|
+
this._marker.style["z-index"] = zIndex;
|
|
15618
|
+
this._label.style["z-index"] = zIndex;
|
|
15051
15619
|
}
|
|
15052
15620
|
|
|
15053
15621
|
/**
|
|
@@ -15078,7 +15646,8 @@ class Annotation extends Marker {
|
|
|
15078
15646
|
* @private
|
|
15079
15647
|
*/
|
|
15080
15648
|
_updatePosition() {
|
|
15081
|
-
|
|
15649
|
+
const isLegacy = this._markerAlign === "legacy";
|
|
15650
|
+
if ((! isLegacy) && (this._curMarkerWidth === undefined)) {
|
|
15082
15651
|
this._updateIfWidthsChanged();
|
|
15083
15652
|
} else {
|
|
15084
15653
|
// Update position with cached width values
|
|
@@ -15086,7 +15655,9 @@ class Annotation extends Marker {
|
|
|
15086
15655
|
// so they don't interfere with e.g. interactive scene manipulation
|
|
15087
15656
|
this._updateWithCurWidths();
|
|
15088
15657
|
window.clearTimeout(this._widthTimeout);
|
|
15089
|
-
|
|
15658
|
+
if (! isLegacy) {
|
|
15659
|
+
this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
|
|
15660
|
+
}
|
|
15090
15661
|
}
|
|
15091
15662
|
}
|
|
15092
15663
|
|
|
@@ -15124,10 +15695,10 @@ class Annotation extends Marker {
|
|
|
15124
15695
|
/**
|
|
15125
15696
|
* Sets the horizontal alignment of the Annotation's marker HTML.
|
|
15126
15697
|
*
|
|
15127
|
-
* @param {String} align Either "left", "center", "right" (default "left")
|
|
15698
|
+
* @param {String} align Either "left", "center", "right", "legacy" (default "left")
|
|
15128
15699
|
*/
|
|
15129
15700
|
setMarkerAlign(align) {
|
|
15130
|
-
const valid = [ "left", "center", "right" ];
|
|
15701
|
+
const valid = [ "left", "center", "right", "legacy" ];
|
|
15131
15702
|
if (! valid.includes(align)) {
|
|
15132
15703
|
this.error("Param 'align' should be one of: " + JSON.stringify(valid));
|
|
15133
15704
|
} else {
|
|
@@ -26510,6 +27081,65 @@ class ReadableGeometry extends Geometry {
|
|
|
26510
27081
|
return this._obb;
|
|
26511
27082
|
}
|
|
26512
27083
|
|
|
27084
|
+
_getMetrics() {
|
|
27085
|
+
if (! ("_metrics" in this)) {
|
|
27086
|
+
switch (this._state.primitiveName) {
|
|
27087
|
+
case "solid":
|
|
27088
|
+
case "surface":
|
|
27089
|
+
case "triangles": {
|
|
27090
|
+
const indices = this._state.indices;
|
|
27091
|
+
const positions = this._state.positions;
|
|
27092
|
+
const getPos = (i, out) => {
|
|
27093
|
+
const idx = indices[i] * 3;
|
|
27094
|
+
for (let j = 0; j < 3; ++j) {
|
|
27095
|
+
out[j] = positions[idx + j];
|
|
27096
|
+
} return out;
|
|
27097
|
+
};
|
|
27098
|
+
const tmp = [ math.vec3(), math.vec3(), math.vec3(), math.vec3() ];
|
|
27099
|
+
let totalArea = 0;
|
|
27100
|
+
const centroid = math.vec3([ 0, 0, 0 ]);
|
|
27101
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
27102
|
+
const v0 = getPos(i, tmp[0]);
|
|
27103
|
+
const v1 = getPos(i+1, tmp[1]);
|
|
27104
|
+
const v2 = getPos(i+2, tmp[2]);
|
|
27105
|
+
math.addVec3(v0, v1, tmp[3]);
|
|
27106
|
+
math.addVec3(v2, tmp[3], tmp[3]);
|
|
27107
|
+
const faceArea = math.lenVec3(
|
|
27108
|
+
math.cross3Vec3(
|
|
27109
|
+
math.subVec3(v1, v0, tmp[1]),
|
|
27110
|
+
math.subVec3(v2, v0, tmp[2]),
|
|
27111
|
+
tmp[0])) / 2;
|
|
27112
|
+
totalArea += faceArea;
|
|
27113
|
+
math.mulVec3Scalar(tmp[3], faceArea, tmp[3]);
|
|
27114
|
+
math.addVec3(centroid, tmp[3], centroid);
|
|
27115
|
+
}
|
|
27116
|
+
this._metrics = { surfaceArea: totalArea, centroid: math.mulVec3Scalar(centroid, 1 / totalArea / 3, centroid) };
|
|
27117
|
+
break;
|
|
27118
|
+
}
|
|
27119
|
+
default:
|
|
27120
|
+
this._metrics = { surfaceArea: 0 };
|
|
27121
|
+
break;
|
|
27122
|
+
}
|
|
27123
|
+
}
|
|
27124
|
+
return this._metrics;
|
|
27125
|
+
}
|
|
27126
|
+
|
|
27127
|
+
/**
|
|
27128
|
+
* Returns the surface area of this Mesh.
|
|
27129
|
+
* @returns {number}
|
|
27130
|
+
*/
|
|
27131
|
+
get surfaceArea() {
|
|
27132
|
+
return this._getMetrics().surfaceArea;
|
|
27133
|
+
}
|
|
27134
|
+
|
|
27135
|
+
/**
|
|
27136
|
+
* Returns the centroid of this Mesh.
|
|
27137
|
+
* @returns {number}
|
|
27138
|
+
*/
|
|
27139
|
+
get centroid() {
|
|
27140
|
+
return this._getMetrics().centroid;
|
|
27141
|
+
}
|
|
27142
|
+
|
|
26513
27143
|
/**
|
|
26514
27144
|
* Approximate number of triangles in this ReadableGeometry.
|
|
26515
27145
|
*
|
|
@@ -40058,7 +40688,7 @@ function buildPlaneGeometry(cfg = {}) {
|
|
|
40058
40688
|
positions[offset + 1] = centerY;
|
|
40059
40689
|
positions[offset + 2] = -z + centerZ;
|
|
40060
40690
|
|
|
40061
|
-
normals[offset +
|
|
40691
|
+
normals[offset + 1] = 1;
|
|
40062
40692
|
|
|
40063
40693
|
uvs[offset2] = (ix) / planeX;
|
|
40064
40694
|
uvs[offset2 + 1] = ((planeZ - iz) / planeZ);
|
|
@@ -43356,8 +43986,7 @@ class SectionCaps {
|
|
|
43356
43986
|
if(!this._resourcesAllocated) {
|
|
43357
43987
|
this._resourcesAllocated = true;
|
|
43358
43988
|
this._sectionPlanes = [];
|
|
43359
|
-
this.
|
|
43360
|
-
this._indicesMap = {};
|
|
43989
|
+
this._sceneModelsData = {};
|
|
43361
43990
|
this._dirtyMap = {};
|
|
43362
43991
|
this._prevIntersectionModelsMap = {};
|
|
43363
43992
|
this._sectionPlaneTimeout = null;
|
|
@@ -43372,7 +44001,8 @@ class SectionCaps {
|
|
|
43372
44001
|
this._sectionPlanes.push(sectionPlane);
|
|
43373
44002
|
sectionPlane.on('pos', onSectionPlaneUpdated);
|
|
43374
44003
|
sectionPlane.on('dir', onSectionPlaneUpdated);
|
|
43375
|
-
sectionPlane.
|
|
44004
|
+
sectionPlane.on('active', onSectionPlaneUpdated);
|
|
44005
|
+
sectionPlane.once('destroyed', (() => {
|
|
43376
44006
|
const sectionPlaneId = sectionPlane.id;
|
|
43377
44007
|
if (sectionPlaneId) {
|
|
43378
44008
|
this._sectionPlanes = this._sectionPlanes.filter((sectionPlane) => sectionPlane.id !== sectionPlaneId);
|
|
@@ -43389,13 +44019,19 @@ class SectionCaps {
|
|
|
43389
44019
|
|
|
43390
44020
|
this._onTick = this.scene.on("tick", () => {
|
|
43391
44021
|
//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
|
-
|
|
43394
|
-
|
|
43395
|
-
|
|
43396
|
-
delete this.
|
|
43397
|
-
|
|
43398
|
-
}
|
|
44022
|
+
//but it's no more available on the scene, or if its visibility changed
|
|
44023
|
+
let dirty = false;
|
|
44024
|
+
for(const sceneModelId in this._sceneModelsData) {
|
|
44025
|
+
if(!this.scene.models[sceneModelId]){
|
|
44026
|
+
delete this._sceneModelsData[sceneModelId];
|
|
44027
|
+
dirty = true;
|
|
44028
|
+
} else if (this._sceneModelsData[sceneModelId].visible !== (!!this.scene.models[sceneModelId].visible)) {
|
|
44029
|
+
this._sceneModelsData[sceneModelId].visible = !!this.scene.models[sceneModelId].visible;
|
|
44030
|
+
dirty = true;
|
|
44031
|
+
}
|
|
44032
|
+
}
|
|
44033
|
+
if (dirty) {
|
|
44034
|
+
this._update();
|
|
43399
44035
|
}
|
|
43400
44036
|
});
|
|
43401
44037
|
}
|
|
@@ -43412,8 +44048,8 @@ class SectionCaps {
|
|
|
43412
44048
|
this._deletePreviousModels();
|
|
43413
44049
|
this._updateTimeout = setTimeout(() => {
|
|
43414
44050
|
clearTimeout(this._updateTimeout);
|
|
43415
|
-
const sceneModels = Object.
|
|
43416
|
-
this._addHatches(sceneModels, this._sectionPlanes);
|
|
44051
|
+
const sceneModels = Object.values(this.scene.models).filter(sceneModel => sceneModel.visible);
|
|
44052
|
+
this._addHatches(sceneModels, this._sectionPlanes.filter(sectionPlane => sectionPlane.active));
|
|
43417
44053
|
this._setAllDirty(false);
|
|
43418
44054
|
}, 100);
|
|
43419
44055
|
}
|
|
@@ -43426,21 +44062,9 @@ class SectionCaps {
|
|
|
43426
44062
|
|
|
43427
44063
|
_addHatches(sceneModels, planes) {
|
|
43428
44064
|
|
|
43429
|
-
if (planes.length <= 0) return;
|
|
43430
|
-
|
|
43431
44065
|
planes.forEach((plane) => {
|
|
43432
44066
|
sceneModels.forEach((sceneModel) => {
|
|
43433
|
-
|
|
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;
|
|
44067
|
+
if(!this._doesPlaneIntersectBoundingBox(sceneModel.aabb, plane)) return;
|
|
43444
44068
|
|
|
43445
44069
|
if(!this._dirtyMap[sceneModel.id]) return;
|
|
43446
44070
|
|
|
@@ -43462,39 +44086,35 @@ class SectionCaps {
|
|
|
43462
44086
|
|
|
43463
44087
|
const object = objects[objectId];
|
|
43464
44088
|
|
|
43465
|
-
if(!this._doesPlaneIntersectBoundingBox(object.aabb,
|
|
44089
|
+
if(!this._doesPlaneIntersectBoundingBox(object.aabb, plane)) return;
|
|
43466
44090
|
|
|
43467
|
-
if(!this.
|
|
43468
|
-
this.
|
|
43469
|
-
|
|
44091
|
+
if(!this._sceneModelsData[sceneModel.id]) {
|
|
44092
|
+
this._sceneModelsData[sceneModel.id] = {
|
|
44093
|
+
verticesMap: new Map(),
|
|
44094
|
+
indicesMap: new Map()
|
|
44095
|
+
};
|
|
43470
44096
|
}
|
|
43471
44097
|
|
|
43472
|
-
|
|
44098
|
+
const sceneModelData = this._sceneModelsData[sceneModel.id];
|
|
43473
44099
|
|
|
43474
|
-
if(!
|
|
44100
|
+
if(!sceneModelData.verticesMap.has(objectId)) {
|
|
43475
44101
|
const isSolid = object.meshes[0].isSolid();
|
|
44102
|
+
const vertices = [ ];
|
|
44103
|
+
const indices = [ ];
|
|
43476
44104
|
if(isSolid && object.capMaterial) {
|
|
43477
|
-
object.getEachVertex(
|
|
43478
|
-
|
|
43479
|
-
});
|
|
43480
|
-
object.getEachIndex((_indices) => {
|
|
43481
|
-
indices.push(_indices);
|
|
43482
|
-
});
|
|
44105
|
+
object.getEachVertex(v => vertices.push(v[0], v[1], v[2]));
|
|
44106
|
+
object.getEachIndex(i => indices.push(i));
|
|
43483
44107
|
}
|
|
43484
|
-
|
|
43485
|
-
|
|
44108
|
+
sceneModelData.verticesMap.set(objectId, vertices);
|
|
44109
|
+
sceneModelData.indicesMap.set(objectId, indices);
|
|
43486
44110
|
}
|
|
43487
|
-
|
|
43488
|
-
|
|
43489
|
-
|
|
43490
|
-
|
|
43491
|
-
|
|
44111
|
+
|
|
44112
|
+
const vertices = sceneModelData.verticesMap.get(objectId);
|
|
44113
|
+
const indices = sceneModelData.indicesMap.get(objectId);
|
|
44114
|
+
|
|
43492
44115
|
const capSegments = [];
|
|
43493
44116
|
const vertCount = indices.length;
|
|
43494
|
-
|
|
43495
|
-
// Preallocate intersection result array
|
|
43496
|
-
const intersectionBuffer = new Float32Array(3);
|
|
43497
|
-
|
|
44117
|
+
|
|
43498
44118
|
for (let i = 0; i < vertCount; i += 3) {
|
|
43499
44119
|
// Reuse triangle buffer instead of creating new arrays
|
|
43500
44120
|
for (let j = 0; j < 3; j++) {
|
|
@@ -43511,21 +44131,15 @@ class SectionCaps {
|
|
|
43511
44131
|
for (let i = 0; i < 3; i++) {
|
|
43512
44132
|
const p1 = triangle[i];
|
|
43513
44133
|
const p2 = triangle[(i + 1) % 3];
|
|
43514
|
-
|
|
43515
|
-
|
|
43516
|
-
const
|
|
43517
|
-
|
|
43518
|
-
|
|
44134
|
+
|
|
44135
|
+
const d1 = plane.dist + math.dotVec3(plane.dir, p1);
|
|
44136
|
+
const d2 = plane.dist + math.dotVec3(plane.dir, p2);
|
|
44137
|
+
|
|
43519
44138
|
if (d1 * d2 > 0) continue;
|
|
43520
|
-
|
|
44139
|
+
|
|
43521
44140
|
const t = -d1 / (d2 - d1);
|
|
43522
|
-
|
|
43523
|
-
|
|
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));
|
|
44141
|
+
|
|
44142
|
+
intersections.push(math.lerpVec3(t, 0, 1, p1, p2, math.vec3()));
|
|
43529
44143
|
}
|
|
43530
44144
|
|
|
43531
44145
|
if(intersections.length === 2) capSegments.push(intersections);
|
|
@@ -43805,7 +44419,7 @@ class SectionCaps {
|
|
|
43805
44419
|
|
|
43806
44420
|
}
|
|
43807
44421
|
|
|
43808
|
-
_doesPlaneIntersectBoundingBox(bb,
|
|
44422
|
+
_doesPlaneIntersectBoundingBox(bb, plane) {
|
|
43809
44423
|
const min = [bb[0], bb[1], bb[2]];
|
|
43810
44424
|
const max = [bb[3], bb[4], bb[5]];
|
|
43811
44425
|
|
|
@@ -43825,10 +44439,7 @@ class SectionCaps {
|
|
|
43825
44439
|
let hasNegative = false;
|
|
43826
44440
|
|
|
43827
44441
|
for (const corner of corners) {
|
|
43828
|
-
const distance =
|
|
43829
|
-
planeEquation.B * corner[1] +
|
|
43830
|
-
planeEquation.C * corner[2] +
|
|
43831
|
-
planeEquation.D;
|
|
44442
|
+
const distance = plane.dist + math.dotVec3(plane.dir, corner);
|
|
43832
44443
|
|
|
43833
44444
|
if (distance > 0) hasPositive = true;
|
|
43834
44445
|
if (distance < 0) hasNegative = true;
|
|
@@ -44323,13 +44934,12 @@ class Scene extends Component {
|
|
|
44323
44934
|
* configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
|
|
44324
44935
|
* 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
44936
|
* your expected usage.
|
|
44326
|
-
* @throws {String} Throws an exception when
|
|
44937
|
+
* @throws {String} Throws an exception when canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement.
|
|
44327
44938
|
*/
|
|
44328
44939
|
constructor(viewer, cfg = {}) {
|
|
44329
44940
|
|
|
44330
44941
|
super(null, cfg);
|
|
44331
|
-
|
|
44332
|
-
const canvas = cfg.canvasElement || document.getElementById(cfg.canvasId);
|
|
44942
|
+
const canvas = cfg.canvasElement || document.querySelector(`#${cfg.canvasId}`);
|
|
44333
44943
|
|
|
44334
44944
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
|
44335
44945
|
throw "Mandatory config expected: valid canvasId or canvasElement";
|
|
@@ -123577,6 +124187,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
123577
124187
|
const cubeColor = "lightgrey";
|
|
123578
124188
|
const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)";
|
|
123579
124189
|
const textColor = cfg.textColor || "black";
|
|
124190
|
+
const parentNode = cfg.canvasElement || document.body;
|
|
123580
124191
|
|
|
123581
124192
|
const height = 500;
|
|
123582
124193
|
const width = height + (height / 3);
|
|
@@ -123686,8 +124297,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
123686
124297
|
this._textureCanvas.style.visibility = "hidden";
|
|
123687
124298
|
this._textureCanvas.style["z-index"] = 2000000;
|
|
123688
124299
|
|
|
123689
|
-
|
|
123690
|
-
body.appendChild(this._textureCanvas);
|
|
124300
|
+
parentNode.appendChild(this._textureCanvas);
|
|
123691
124301
|
|
|
123692
124302
|
const context = this._textureCanvas.getContext("2d");
|
|
123693
124303
|
|
|
@@ -123957,7 +124567,7 @@ class NavCubePlugin extends Plugin {
|
|
|
123957
124567
|
this._navCubeScene = new Scene(viewer, {
|
|
123958
124568
|
canvasId: cfg.canvasId,
|
|
123959
124569
|
canvasElement: cfg.canvasElement,
|
|
123960
|
-
transparent: true
|
|
124570
|
+
transparent: true,
|
|
123961
124571
|
});
|
|
123962
124572
|
|
|
123963
124573
|
this._navCubeCanvas = this._navCubeScene.canvas.canvas;
|
|
@@ -124190,7 +124800,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124190
124800
|
}
|
|
124191
124801
|
});
|
|
124192
124802
|
|
|
124193
|
-
|
|
124803
|
+
self._navCubeCanvas.addEventListener("mouseup", self._onMouseUp = function (e) {
|
|
124194
124804
|
if (e.which !== 1) {// Left button
|
|
124195
124805
|
return;
|
|
124196
124806
|
}
|
|
@@ -124207,7 +124817,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124207
124817
|
if (hit.uv) {
|
|
124208
124818
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
124209
124819
|
if (areaId >= 0) {
|
|
124210
|
-
|
|
124820
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124211
124821
|
if (lastAreaId >= 0) {
|
|
124212
124822
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124213
124823
|
self._repaint();
|
|
@@ -124233,7 +124843,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124233
124843
|
self._repaint();
|
|
124234
124844
|
lastAreaId = -1;
|
|
124235
124845
|
}
|
|
124236
|
-
|
|
124846
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124237
124847
|
if (lastAreaId >= 0) {
|
|
124238
124848
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124239
124849
|
self._repaint();
|
|
@@ -124252,7 +124862,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124252
124862
|
}
|
|
124253
124863
|
});
|
|
124254
124864
|
|
|
124255
|
-
|
|
124865
|
+
self._navCubeCanvas.addEventListener("mousemove", self._onMouseMove = function (e) {
|
|
124256
124866
|
if (lastAreaId >= 0) {
|
|
124257
124867
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124258
124868
|
self._repaint();
|
|
@@ -124264,7 +124874,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124264
124874
|
if (down) {
|
|
124265
124875
|
var posX = e.clientX;
|
|
124266
124876
|
var posY = e.clientY;
|
|
124267
|
-
|
|
124877
|
+
self._navCubeCanvas.style.cursor = "move";
|
|
124268
124878
|
actionMove(posX, posY);
|
|
124269
124879
|
return;
|
|
124270
124880
|
}
|
|
@@ -124278,7 +124888,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124278
124888
|
});
|
|
124279
124889
|
if (hit) {
|
|
124280
124890
|
if (hit.uv) {
|
|
124281
|
-
|
|
124891
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
124282
124892
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
124283
124893
|
if (areaId === lastAreaId) {
|
|
124284
124894
|
return;
|
|
@@ -124293,7 +124903,7 @@ class NavCubePlugin extends Plugin {
|
|
|
124293
124903
|
}
|
|
124294
124904
|
}
|
|
124295
124905
|
} else {
|
|
124296
|
-
|
|
124906
|
+
self._navCubeCanvas.style.cursor = "default";
|
|
124297
124907
|
if (lastAreaId >= 0) {
|
|
124298
124908
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
124299
124909
|
self._repaint();
|
|
@@ -124556,8 +125166,8 @@ class NavCubePlugin extends Plugin {
|
|
|
124556
125166
|
this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave);
|
|
124557
125167
|
this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown);
|
|
124558
125168
|
|
|
124559
|
-
|
|
124560
|
-
|
|
125169
|
+
this._navCubeCanvas.removeEventListener("mousemove", this._onMouseMove);
|
|
125170
|
+
this._navCubeCanvas.removeEventListener("mouseup", this._onMouseUp);
|
|
124561
125171
|
|
|
124562
125172
|
this._navCubeCanvas = null;
|
|
124563
125173
|
this._cubeTextureCanvas.destroy();
|
|
@@ -125951,8 +126561,8 @@ class Control {
|
|
|
125951
126561
|
const canvasPos = math.vec2();
|
|
125952
126562
|
|
|
125953
126563
|
const copyCanvasPos = (event, vec2) => {
|
|
125954
|
-
vec2[0] = event.
|
|
125955
|
-
vec2[1] = event.
|
|
126564
|
+
vec2[0] = event.pageX;
|
|
126565
|
+
vec2[1] = event.pageY;
|
|
125956
126566
|
transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
|
|
125957
126567
|
};
|
|
125958
126568
|
|
|
@@ -168432,151 +169042,6 @@ const hex2rgb = function(color) {
|
|
|
168432
169042
|
return [ rgb(0), rgb(2), rgb(4) ];
|
|
168433
169043
|
};
|
|
168434
169044
|
|
|
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
169045
|
const basePolygon3D = function(scene, color, alpha) {
|
|
168581
169046
|
let mesh = null;
|
|
168582
169047
|
|
|
@@ -169556,7 +170021,8 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169556
170021
|
|
|
169557
170022
|
(function selectNextPoint(markers) {
|
|
169558
170023
|
const marker = marker3D(scene, zoneColor);
|
|
169559
|
-
const wire = (markers.length > 0) && wire3D(scene, zoneColor
|
|
170024
|
+
const wire = (markers.length > 0) && wire3D(scene, zoneColor);
|
|
170025
|
+
const wireStart = wire && markers[markers.length - 1].getWorldPos();
|
|
169560
170026
|
|
|
169561
170027
|
cleanups.push(() => {
|
|
169562
170028
|
marker.destroy();
|
|
@@ -169616,7 +170082,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169616
170082
|
() => {
|
|
169617
170083
|
updatePointerLens(null);
|
|
169618
170084
|
marker.update(null);
|
|
169619
|
-
wire && wire.update(null);
|
|
170085
|
+
wire && wire.update(wireStart, null);
|
|
169620
170086
|
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
169621
170087
|
},
|
|
169622
170088
|
(canvasPos, worldPos) => {
|
|
@@ -169624,7 +170090,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169624
170090
|
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
169625
170091
|
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
169626
170092
|
marker.update((! snappedFirst) && worldPos);
|
|
169627
|
-
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
170093
|
+
wire && wire.update(wireStart, snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
169628
170094
|
if ((markers.length >= 2))
|
|
169629
170095
|
{
|
|
169630
170096
|
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
@@ -169668,7 +170134,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
|
|
|
169668
170134
|
else
|
|
169669
170135
|
{
|
|
169670
170136
|
marker.update(worldPos);
|
|
169671
|
-
wire && wire.update(worldPos);
|
|
170137
|
+
wire && wire.update(wireStart, worldPos);
|
|
169672
170138
|
selectNextPoint(markers.concat(marker));
|
|
169673
170139
|
}
|
|
169674
170140
|
});
|
|
@@ -170103,4 +170569,4 @@ class ZoneTranslateTouchControl extends ZoneTranslateControl {
|
|
|
170103
170569
|
}
|
|
170104
170570
|
}
|
|
170105
170571
|
|
|
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 };
|
|
170572
|
+
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 };
|