@xeokit/xeokit-sdk 2.6.17 → 2.6.20
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 +2262 -40
- package/dist/xeokit-sdk.es.js +2252 -41
- package/dist/xeokit-sdk.es5.js +190 -52
- package/dist/xeokit-sdk.min.cjs.js +4 -4
- package/dist/xeokit-sdk.min.es.js +5 -5
- package/dist/xeokit-sdk.min.es5.js +4 -4
- package/package.json +2 -2
- package/src/extras/PointerLens/PointerLens.js +2 -2
- package/src/plugins/AnnotationsPlugin/Annotation.js +1 -0
- package/src/plugins/CityJSONLoaderPlugin/CityJSONDefaultDataSource.js +15 -2
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +1 -1
- package/src/plugins/DotBIMLoaderPlugin/DotBIMDefaultDataSource.js +15 -2
- package/src/plugins/GLTFLoaderPlugin/GLTFDefaultDataSource.js +18 -5
- package/src/plugins/LASLoaderPlugin/LASDefaultDataSource.js +15 -1
- package/src/plugins/STLLoaderPlugin/STLDefaultDataSource.js +17 -0
- package/src/plugins/WebIFCLoaderPlugin/WebIFCDefaultDataSource.js +16 -1
- package/src/plugins/XKTLoaderPlugin/XKTDefaultDataSource.js +18 -4
- package/src/plugins/ZonesPlugin/index.js +2046 -0
- package/src/plugins/index.js +2 -1
- package/src/plugins/lib/html/Dot.js +19 -1
- package/src/viewer/Viewer.js +3 -1
- package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +9 -0
- package/src/viewer/scene/geometry/builders/buildLineGeometry.js +267 -0
- package/src/viewer/scene/input/Input.js +41 -0
- package/src/viewer/scene/marker/Marker.js +1 -1
- package/src/viewer/scene/mesh/Mesh.js +5 -0
- package/src/viewer/scene/model/SceneModel.js +7 -1
- package/src/viewer/scene/scene/Scene.js +30 -6
- package/src/viewer/scene/sectionPlane/SectionPlane.js +3 -7
- package/src/viewer/scene/webgl/Renderer.js +1 -1
- package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
- package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +8 -4
- package/types/viewer/Viewer.d.ts +2 -0
- package/types/viewer/scene/geometry/builders/buildLineGeometry.d.ts +22 -0
- package/types/viewer/scene/geometry/builders/buildPolylineGeometry.d.ts +2 -2
- package/types/viewer/scene/scene/Scene.d.ts +11 -0
- package/dist/web-ifc.wasm +0 -0
package/dist/xeokit-sdk.cjs.js
CHANGED
|
@@ -1122,8 +1122,8 @@ class PointerLens {
|
|
|
1122
1122
|
);
|
|
1123
1123
|
|
|
1124
1124
|
const centerLensCanvas = [
|
|
1125
|
-
(lensRect.left + lensRect.right) / 2,
|
|
1126
|
-
(lensRect.top + lensRect.bottom) / 2
|
|
1125
|
+
(lensRect.left + lensRect.right) / 2 - canvasRect.left,
|
|
1126
|
+
(lensRect.top + lensRect.bottom) / 2 - canvasRect.top
|
|
1127
1127
|
];
|
|
1128
1128
|
|
|
1129
1129
|
if (this._snappedCanvasPos) {
|
|
@@ -10763,7 +10763,7 @@ class Marker extends Component {
|
|
|
10763
10763
|
this.scene.camera.off(this._onCameraProjMatrix);
|
|
10764
10764
|
if (this._entity) {
|
|
10765
10765
|
if (this._onEntityDestroyed !== null) {
|
|
10766
|
-
this._entity.off(this._onEntityDestroyed);
|
|
10766
|
+
this._entity.model.off(this._onEntityDestroyed);
|
|
10767
10767
|
}
|
|
10768
10768
|
if (this._onEntityModelDestroyed !== null) {
|
|
10769
10769
|
this._entity.model.off(this._onEntityModelDestroyed);
|
|
@@ -11163,7 +11163,25 @@ class Dot {
|
|
|
11163
11163
|
}
|
|
11164
11164
|
|
|
11165
11165
|
}
|
|
11166
|
-
|
|
11166
|
+
|
|
11167
|
+
if (cfg.onTouchstart) {
|
|
11168
|
+
dotClickable.addEventListener('touchstart', (event) => {
|
|
11169
|
+
cfg.onTouchstart(event, this);
|
|
11170
|
+
});
|
|
11171
|
+
}
|
|
11172
|
+
|
|
11173
|
+
if (cfg.onTouchmove) {
|
|
11174
|
+
dotClickable.addEventListener('touchmove', (event) => {
|
|
11175
|
+
cfg.onTouchmove(event, this);
|
|
11176
|
+
});
|
|
11177
|
+
}
|
|
11178
|
+
|
|
11179
|
+
if (cfg.onTouchend) {
|
|
11180
|
+
dotClickable.addEventListener('touchend', (event) => {
|
|
11181
|
+
cfg.onTouchend(event, this);
|
|
11182
|
+
});
|
|
11183
|
+
}
|
|
11184
|
+
|
|
11167
11185
|
this.setPos(cfg.x || 0, cfg.y || 0);
|
|
11168
11186
|
this.setFillColor(cfg.fillColor);
|
|
11169
11187
|
this.setBorderColor(cfg.borderColor);
|
|
@@ -14431,6 +14449,7 @@ class Annotation extends Marker {
|
|
|
14431
14449
|
if (this._marker) {
|
|
14432
14450
|
if (!this._markerExternal) {
|
|
14433
14451
|
this._marker.parentNode.removeChild(this._marker);
|
|
14452
|
+
this._marker = null;
|
|
14434
14453
|
} else {
|
|
14435
14454
|
this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
|
|
14436
14455
|
this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
|
|
@@ -17059,7 +17078,7 @@ class OcclusionLayer {
|
|
|
17059
17078
|
_buildVBOs() {
|
|
17060
17079
|
if (this.positionsBuf) {
|
|
17061
17080
|
if (this.lenPositionsBuf === this.positions.length) { // Just updating buffer elements, don't need to reallocate
|
|
17062
|
-
this.positionsBuf.setData(this.positions); // Indices don't need updating
|
|
17081
|
+
this.positionsBuf.setData(new Float32Array(this.positions)); // Indices don't need updating
|
|
17063
17082
|
return;
|
|
17064
17083
|
}
|
|
17065
17084
|
this.positionsBuf.destroy();
|
|
@@ -17148,7 +17167,6 @@ class OcclusionLayer {
|
|
|
17148
17167
|
|
|
17149
17168
|
const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]);
|
|
17150
17169
|
const POINT_SIZE = 20;
|
|
17151
|
-
const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces
|
|
17152
17170
|
|
|
17153
17171
|
const tempVec3a$J = math.vec3();
|
|
17154
17172
|
|
|
@@ -17229,7 +17247,7 @@ class OcclusionTester {
|
|
|
17229
17247
|
let newOcclusionLayer = this._occlusionLayers[originHash];
|
|
17230
17248
|
if (!newOcclusionLayer) {
|
|
17231
17249
|
newOcclusionLayer = new OcclusionLayer(this._scene, marker.origin);
|
|
17232
|
-
this._occlusionLayers[originHash] =
|
|
17250
|
+
this._occlusionLayers[originHash] = newOcclusionLayer;
|
|
17233
17251
|
this._occlusionLayersListDirty = true;
|
|
17234
17252
|
}
|
|
17235
17253
|
newOcclusionLayer.addMarker(marker);
|
|
@@ -17359,7 +17377,9 @@ class OcclusionTester {
|
|
|
17359
17377
|
if (scene.logarithmicDepthBufferEnabled) {
|
|
17360
17378
|
src.push("vFragDepth = 1.0 + clipPos.w;");
|
|
17361
17379
|
} else {
|
|
17362
|
-
|
|
17380
|
+
if (scene.markerZOffset < 0.000) {
|
|
17381
|
+
src.push("clipPos.z += " + scene.markerZOffset + ";");
|
|
17382
|
+
}
|
|
17363
17383
|
}
|
|
17364
17384
|
src.push(" gl_Position = clipPos;");
|
|
17365
17385
|
src.push("}");
|
|
@@ -17473,7 +17493,10 @@ class OcclusionTester {
|
|
|
17473
17493
|
continue;
|
|
17474
17494
|
}
|
|
17475
17495
|
|
|
17476
|
-
|
|
17496
|
+
// The `origin` has been changed from `occlusionLayer.origin` to `[ 0, 0, 0 ]`
|
|
17497
|
+
// because OcclusionLayer markers' transformation is being applied through the
|
|
17498
|
+
// OcclusionLayer::positions array. See XEOK-33
|
|
17499
|
+
const origin = [ 0, 0, 0 ];
|
|
17477
17500
|
|
|
17478
17501
|
gl.uniformMatrix4fv(this._uViewMatrix, false, createRTCViewMat(camera.viewMatrix, origin));
|
|
17479
17502
|
|
|
@@ -19623,7 +19646,7 @@ const Renderer$1 = function (scene, options) {
|
|
|
19623
19646
|
math.cross3Vec3(worldRayDir, randomVec3, up);
|
|
19624
19647
|
|
|
19625
19648
|
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
19626
|
-
|
|
19649
|
+
// pickProjMatrix = scene.camera.projMatrix;
|
|
19627
19650
|
pickProjMatrix = scene.camera.ortho.matrix;
|
|
19628
19651
|
|
|
19629
19652
|
pickResult.origin = worldRayOrigin;
|
|
@@ -21610,6 +21633,14 @@ class Input extends Component {
|
|
|
21610
21633
|
}
|
|
21611
21634
|
});
|
|
21612
21635
|
|
|
21636
|
+
this.element.addEventListener("contextmenu", this._contextmenuListener = (e) => {
|
|
21637
|
+
if (!this.enabled) {
|
|
21638
|
+
return;
|
|
21639
|
+
}
|
|
21640
|
+
this._getMouseCanvasPos(e);
|
|
21641
|
+
this.fire("contextmenu", this.mouseCanvasPos, true);
|
|
21642
|
+
});
|
|
21643
|
+
|
|
21613
21644
|
const tickifiedMouseWheelFn = this.scene.tickify(
|
|
21614
21645
|
(delta) => { this.fire("mousewheel", delta, true); }
|
|
21615
21646
|
);
|
|
@@ -21643,6 +21674,24 @@ class Input extends Component {
|
|
|
21643
21674
|
});
|
|
21644
21675
|
}
|
|
21645
21676
|
|
|
21677
|
+
this.element.addEventListener("touchstart", this._touchstartListener = (e) => {
|
|
21678
|
+
if (!this.enabled) {
|
|
21679
|
+
return;
|
|
21680
|
+
}
|
|
21681
|
+
[...e.changedTouches].forEach(e => {
|
|
21682
|
+
this.fire("touchstart", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21683
|
+
});
|
|
21684
|
+
});
|
|
21685
|
+
|
|
21686
|
+
this.element.addEventListener("touchend", this._touchendListener = (e) => {
|
|
21687
|
+
if (!this.enabled) {
|
|
21688
|
+
return;
|
|
21689
|
+
}
|
|
21690
|
+
[...e.changedTouches].forEach(e => {
|
|
21691
|
+
this.fire("touchend", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21692
|
+
});
|
|
21693
|
+
});
|
|
21694
|
+
|
|
21646
21695
|
this._eventsBound = true;
|
|
21647
21696
|
}
|
|
21648
21697
|
|
|
@@ -21659,7 +21708,10 @@ class Input extends Component {
|
|
|
21659
21708
|
document.removeEventListener("click", this._clickListener);
|
|
21660
21709
|
document.removeEventListener("dblclick", this._dblClickListener);
|
|
21661
21710
|
this.element.removeEventListener("mousemove", this._mouseMoveListener);
|
|
21711
|
+
this.element.removeEventListener("contextmenu", this._contextmenuListener);
|
|
21662
21712
|
this.element.removeEventListener("wheel", this._mouseWheelListener);
|
|
21713
|
+
this.element.removeEventListener("touchstart", this._touchstartListener);
|
|
21714
|
+
this.element.removeEventListener("touchend", this._touchendListener);
|
|
21663
21715
|
if (window.OrientationChangeEvent) {
|
|
21664
21716
|
window.removeEventListener('orientationchange', this._orientationchangedListener);
|
|
21665
21717
|
}
|
|
@@ -21672,6 +21724,18 @@ class Input extends Component {
|
|
|
21672
21724
|
this._eventsBound = false;
|
|
21673
21725
|
}
|
|
21674
21726
|
|
|
21727
|
+
_getTouchCanvasPos(event) {
|
|
21728
|
+
let element = event.target;
|
|
21729
|
+
let totalOffsetLeft = 0;
|
|
21730
|
+
let totalOffsetTop = 0;
|
|
21731
|
+
while (element.offsetParent) {
|
|
21732
|
+
totalOffsetLeft += element.offsetLeft;
|
|
21733
|
+
totalOffsetTop += element.offsetTop;
|
|
21734
|
+
element = element.offsetParent;
|
|
21735
|
+
}
|
|
21736
|
+
return [ event.pageX - totalOffsetLeft, event.pageY - totalOffsetTop ];
|
|
21737
|
+
}
|
|
21738
|
+
|
|
21675
21739
|
_getMouseCanvasPos(event) {
|
|
21676
21740
|
if (!event) {
|
|
21677
21741
|
event = window.event;
|
|
@@ -30156,6 +30220,7 @@ class Scene extends Component {
|
|
|
30156
30220
|
this._pbrEnabled = !!cfg.pbrEnabled;
|
|
30157
30221
|
this._colorTextureEnabled = (cfg.colorTextureEnabled !== false);
|
|
30158
30222
|
this._dtxEnabled = !!cfg.dtxEnabled;
|
|
30223
|
+
this._markerZOffset = cfg.markerZOffset;
|
|
30159
30224
|
|
|
30160
30225
|
// Register Scene on xeokit
|
|
30161
30226
|
// Do this BEFORE we add components below
|
|
@@ -30676,6 +30741,22 @@ class Scene extends Component {
|
|
|
30676
30741
|
return this._colorTextureEnabled;
|
|
30677
30742
|
}
|
|
30678
30743
|
|
|
30744
|
+
/**
|
|
30745
|
+
* Gets the Z value of offset for Marker's OcclusionTester.
|
|
30746
|
+
* The closest the value is to 0.000 the more precise OcclusionTester will be, but at the same time the less
|
|
30747
|
+
* precise it will behave for Markers that are located exactly on the Surface.
|
|
30748
|
+
*
|
|
30749
|
+
* Default is ````-0.001````.
|
|
30750
|
+
*
|
|
30751
|
+
* @returns {Number} Z offset for Marker
|
|
30752
|
+
*/
|
|
30753
|
+
get markerZOffset() {
|
|
30754
|
+
if (this._markerZOffset == null) {
|
|
30755
|
+
return -0.001;
|
|
30756
|
+
}
|
|
30757
|
+
return this._markerZOffset;
|
|
30758
|
+
}
|
|
30759
|
+
|
|
30679
30760
|
/**
|
|
30680
30761
|
* Performs an occlusion test on all {@link Marker}s in this {@link Scene}.
|
|
30681
30762
|
*
|
|
@@ -31518,11 +31599,9 @@ class Scene extends Component {
|
|
|
31518
31599
|
* @param {Number[]} [params.origin] World-space ray origin when ray-picking. Ignored when canvasPos given.
|
|
31519
31600
|
* @param {Number[]} [params.direction] World-space ray direction when ray-picking. Also indicates the length of the ray. Ignored when canvasPos given.
|
|
31520
31601
|
* @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
|
|
31521
|
-
* @param {
|
|
31522
|
-
* @param {
|
|
31523
|
-
* @param {
|
|
31524
|
-
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31525
|
-
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
31602
|
+
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels.
|
|
31603
|
+
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex. Only works when `canvasPos` given.
|
|
31604
|
+
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge. Only works when `canvasPos` given.
|
|
31526
31605
|
* @param {PickResult} [pickResult] Holds the results of the pick attempt. Will use the Scene's singleton PickResult if you don't supply your own.
|
|
31527
31606
|
* @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
|
|
31528
31607
|
*/
|
|
@@ -31533,6 +31612,11 @@ class Scene extends Component {
|
|
|
31533
31612
|
return null;
|
|
31534
31613
|
}
|
|
31535
31614
|
|
|
31615
|
+
if ((params.snapToVertex || params.snapToEdge) && !params.canvasPos) {
|
|
31616
|
+
this.error("Scene.snapPick() `canvasPos` parameter expected for `snapToVertex:true` or `snapToEdge:true`");
|
|
31617
|
+
return;
|
|
31618
|
+
}
|
|
31619
|
+
|
|
31536
31620
|
params = params || {};
|
|
31537
31621
|
|
|
31538
31622
|
params.pickSurface = params.pickSurface || params.rayPick; // Backwards compatibility
|
|
@@ -31580,7 +31664,7 @@ class Scene extends Component {
|
|
|
31580
31664
|
|
|
31581
31665
|
/**
|
|
31582
31666
|
* @param {Object} params Picking parameters.
|
|
31583
|
-
* @param {Number[]}
|
|
31667
|
+
* @param {Number[]} params.canvasPos Canvas-space coordinates.
|
|
31584
31668
|
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
|
|
31585
31669
|
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31586
31670
|
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
@@ -31591,6 +31675,10 @@ class Scene extends Component {
|
|
|
31591
31675
|
this._warnSnapPickDeprecated = true;
|
|
31592
31676
|
this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead");
|
|
31593
31677
|
}
|
|
31678
|
+
if (!params.canvasPos) {
|
|
31679
|
+
this.error("Scene.snapPick() canvasPos parameter expected");
|
|
31680
|
+
return;
|
|
31681
|
+
}
|
|
31594
31682
|
return this._renderer.snapPick(
|
|
31595
31683
|
params.canvasPos,
|
|
31596
31684
|
params.snapRadius || 30,
|
|
@@ -37653,11 +37741,16 @@ class Mesh extends Component {
|
|
|
37653
37741
|
* @param {EmphasisMaterial} [cfg.highlightMaterial] {@link EmphasisMaterial} to define the xrayed appearance for this Mesh. Inherits {@link Scene#highlightMaterial} by default.
|
|
37654
37742
|
* @param {EmphasisMaterial} [cfg.selectedMaterial] {@link EmphasisMaterial} to define the selected appearance for this Mesh. Inherits {@link Scene#selectedMaterial} by default.
|
|
37655
37743
|
* @param {EmphasisMaterial} [cfg.edgeMaterial] {@link EdgeMaterial} to define the appearance of enhanced edges for this Mesh. Inherits {@link Scene#edgeMaterial} by default.
|
|
37744
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this mESH. This is used to control the order in which
|
|
37745
|
+
* mESHES are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
37746
|
+
* render pass.
|
|
37656
37747
|
*/
|
|
37657
37748
|
constructor(owner, cfg = {}) {
|
|
37658
37749
|
|
|
37659
37750
|
super(owner, cfg);
|
|
37660
37751
|
|
|
37752
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
37753
|
+
|
|
37661
37754
|
/**
|
|
37662
37755
|
* ID of the corresponding object within the originating system, if any.
|
|
37663
37756
|
*
|
|
@@ -42182,6 +42275,7 @@ class SectionPlane extends Component {
|
|
|
42182
42275
|
this._state.active = value !== false;
|
|
42183
42276
|
this.glRedraw();
|
|
42184
42277
|
this.fire("active", this._state.active);
|
|
42278
|
+
this.scene.fire("sectionPlaneUpdated", this);
|
|
42185
42279
|
}
|
|
42186
42280
|
|
|
42187
42281
|
/**
|
|
@@ -42262,13 +42356,8 @@ class SectionPlane extends Component {
|
|
|
42262
42356
|
* Inverts the direction of {@link SectionPlane#dir}.
|
|
42263
42357
|
*/
|
|
42264
42358
|
flipDir() {
|
|
42265
|
-
|
|
42266
|
-
dir
|
|
42267
|
-
dir[1] *= -1.0;
|
|
42268
|
-
dir[2] *= -1.0;
|
|
42269
|
-
this._state.dist = (-math.dotVec3(this._state.pos, this._state.dir));
|
|
42270
|
-
this.fire("dir", this._state.dir);
|
|
42271
|
-
this.glRedraw();
|
|
42359
|
+
math.mulVec3Scalar(this._state.dir, -1.0, this._state.dir);
|
|
42360
|
+
this.dir = this._state.dir;
|
|
42272
42361
|
}
|
|
42273
42362
|
|
|
42274
42363
|
/**
|
|
@@ -82250,11 +82339,16 @@ class SceneModel extends Component {
|
|
|
82250
82339
|
* represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
|
|
82251
82340
|
* to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
|
|
82252
82341
|
* primitives. Only works while {@link DTX#enabled} is also ````true````.
|
|
82342
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this SceneModel. This is used to control the order in which
|
|
82343
|
+
* SceneModels are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
82344
|
+
* render pass.
|
|
82253
82345
|
*/
|
|
82254
82346
|
constructor(owner, cfg = {}) {
|
|
82255
82347
|
|
|
82256
82348
|
super(owner, cfg);
|
|
82257
82349
|
|
|
82350
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
82351
|
+
|
|
82258
82352
|
this._dtxEnabled = this.scene.dtxEnabled && (cfg.dtxEnabled !== false);
|
|
82259
82353
|
|
|
82260
82354
|
this._enableVertexWelding = false; // Not needed for most objects, and very expensive, so disabled
|
|
@@ -84321,6 +84415,7 @@ class SceneModel extends Component {
|
|
|
84321
84415
|
_getVBOBatchingLayer(cfg) {
|
|
84322
84416
|
const model = this;
|
|
84323
84417
|
const origin = cfg.origin;
|
|
84418
|
+
cfg.renderLayer || 0;
|
|
84324
84419
|
const positionsDecodeHash = cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary ?
|
|
84325
84420
|
this._createHashStringFromMatrix(cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary)
|
|
84326
84421
|
: "-";
|
|
@@ -84807,7 +84902,7 @@ class SceneModel extends Component {
|
|
|
84807
84902
|
// -------------- RENDERING ---------------------------------------------------------------------------------------
|
|
84808
84903
|
|
|
84809
84904
|
/** @private */
|
|
84810
|
-
drawColorOpaque(frameCtx) {
|
|
84905
|
+
drawColorOpaque(frameCtx, layerList) {
|
|
84811
84906
|
const renderFlags = this.renderFlags;
|
|
84812
84907
|
for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) {
|
|
84813
84908
|
const layerIndex = renderFlags.visibleLayers[i];
|
|
@@ -86601,7 +86696,7 @@ class DistanceMeasurement extends Component {
|
|
|
86601
86696
|
|
|
86602
86697
|
if (this._wpDirty) {
|
|
86603
86698
|
|
|
86604
|
-
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld,
|
|
86699
|
+
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0);
|
|
86605
86700
|
if(this._measurementOrientation === 'Vertical' && this.useRotationAdjustment){
|
|
86606
86701
|
this._wp[0] = this._originWorld[0];
|
|
86607
86702
|
this._wp[1] = this._originWorld[1];
|
|
@@ -89728,7 +89823,20 @@ class FastNavPlugin extends Plugin {
|
|
|
89728
89823
|
*/
|
|
89729
89824
|
class GLTFDefaultDataSource {
|
|
89730
89825
|
|
|
89731
|
-
constructor() {
|
|
89826
|
+
constructor(cfg = {}) {
|
|
89827
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
89828
|
+
}
|
|
89829
|
+
|
|
89830
|
+
_cacheBusterURL(url) {
|
|
89831
|
+
if (!this.cacheBuster) {
|
|
89832
|
+
return url;
|
|
89833
|
+
}
|
|
89834
|
+
const timestamp = new Date().getTime();
|
|
89835
|
+
if (url.indexOf('?') > -1) {
|
|
89836
|
+
return url + '&_=' + timestamp;
|
|
89837
|
+
} else {
|
|
89838
|
+
return url + '?_=' + timestamp;
|
|
89839
|
+
}
|
|
89732
89840
|
}
|
|
89733
89841
|
|
|
89734
89842
|
/**
|
|
@@ -89739,7 +89847,7 @@ class GLTFDefaultDataSource {
|
|
|
89739
89847
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
89740
89848
|
*/
|
|
89741
89849
|
getMetaModel(metaModelSrc, ok, error) {
|
|
89742
|
-
utils.loadJSON(metaModelSrc,
|
|
89850
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
89743
89851
|
(json) => {
|
|
89744
89852
|
ok(json);
|
|
89745
89853
|
},
|
|
@@ -89756,7 +89864,7 @@ class GLTFDefaultDataSource {
|
|
|
89756
89864
|
* @param {Function} error Fired on error while loading the glTF JSON asset.
|
|
89757
89865
|
*/
|
|
89758
89866
|
getGLTF(glTFSrc, ok, error) {
|
|
89759
|
-
utils.loadArraybuffer(glTFSrc,
|
|
89867
|
+
utils.loadArraybuffer(this._cacheBusterURL(glTFSrc),
|
|
89760
89868
|
(gltf) => {
|
|
89761
89869
|
ok(gltf);
|
|
89762
89870
|
},
|
|
@@ -89773,7 +89881,7 @@ class GLTFDefaultDataSource {
|
|
|
89773
89881
|
* @param {Function} error Fired on error while loading the .glb asset.
|
|
89774
89882
|
*/
|
|
89775
89883
|
getGLB(glbSrc, ok, error) {
|
|
89776
|
-
utils.loadArraybuffer(glbSrc,
|
|
89884
|
+
utils.loadArraybuffer(this._cacheBusterURL(glbSrc),
|
|
89777
89885
|
(arraybuffer) => {
|
|
89778
89886
|
ok(arraybuffer);
|
|
89779
89887
|
},
|
|
@@ -89794,7 +89902,7 @@ class GLTFDefaultDataSource {
|
|
|
89794
89902
|
* @param {Function} error Fired on error while loading the glTF binary asset.
|
|
89795
89903
|
*/
|
|
89796
89904
|
getArrayBuffer(glTFSrc, binarySrc, ok, error) {
|
|
89797
|
-
loadArraybuffer(glTFSrc, binarySrc,
|
|
89905
|
+
loadArraybuffer(this._cacheBusterURL(glTFSrc), binarySrc,
|
|
89798
89906
|
(arrayBuffer) => {
|
|
89799
89907
|
ok(arrayBuffer);
|
|
89800
89908
|
},
|
|
@@ -96110,6 +96218,15 @@ class MousePickHandler {
|
|
|
96110
96218
|
return;
|
|
96111
96219
|
}
|
|
96112
96220
|
|
|
96221
|
+
if (cameraControl.hasSubs("rayMove"))
|
|
96222
|
+
{
|
|
96223
|
+
const origin = math.vec3();
|
|
96224
|
+
const direction = math.vec3();
|
|
96225
|
+
// The origin from math.canvasPosToWorldRay is incorrect for a perspective camera, should be the same as scene.camera.eye
|
|
96226
|
+
math.canvasPosToWorldRay(scene.canvas.canvas, scene.camera.viewMatrix, scene.camera.projMatrix, states.pointerCanvasPos, origin, direction);
|
|
96227
|
+
cameraControl.fire("rayMove", { canvasPos: states.pointerCanvasPos, ray: { origin: origin, direction: direction, canvasPos: states.pointerCanvasPos } }, true);
|
|
96228
|
+
}
|
|
96229
|
+
|
|
96113
96230
|
const hoverSubs = cameraControl.hasSubs("hover");
|
|
96114
96231
|
const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
|
|
96115
96232
|
const hoverOutSubs = cameraControl.hasSubs("hoverOut");
|
|
@@ -108202,6 +108319,7 @@ class Viewer {
|
|
|
108202
108319
|
* store geometry on the GPU for triangle meshes that don't have textures. This gives a much lower memory footprint for these types of model element. This mode may not perform well on low-end GPUs that are optimized
|
|
108203
108320
|
* to use textures to hold geometry data. Works great on most medium/high-end GPUs found in desktop computers, including the nVIDIA and Intel HD chipsets. Set this false to use the default vertex buffer object (VBO)
|
|
108204
108321
|
* mode for storing geometry, which is the standard technique used in most graphics engines, and will work adequately on most low-end GPUs.
|
|
108322
|
+
* @param {Number} [cfg.markerZOffset=-0.001] The Z value of offset for Marker's OcclusionTester. The closest the value is to 0.000 the more precise OcclusionTester will be, but at the same time the less precise it will behave for Markers that are located exactly on the Surface.
|
|
108205
108323
|
* @param {number} [cfg.numCachedSectionPlanes=0] Enhances the efficiency of SectionPlane creation by proactively allocating Viewer resources for a specified quantity
|
|
108206
108324
|
* of SectionPlanes. Introducing this parameter streamlines the initial creation speed of SectionPlanes, particularly up to the designated quantity. This parameter internally
|
|
108207
108325
|
* configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
|
|
@@ -108265,6 +108383,7 @@ class Viewer {
|
|
|
108265
108383
|
pbrEnabled: (!!cfg.pbrEnabled),
|
|
108266
108384
|
colorTextureEnabled: (cfg.colorTextureEnabled !== false),
|
|
108267
108385
|
dtxEnabled: (!!cfg.dtxEnabled),
|
|
108386
|
+
markerZOffset: cfg.markerZOffset,
|
|
108268
108387
|
numCachedSectionPlanes: cfg.numCachedSectionPlanes
|
|
108269
108388
|
});
|
|
108270
108389
|
|
|
@@ -123709,6 +123828,22 @@ class SkyboxesPlugin extends Plugin {
|
|
|
123709
123828
|
*/
|
|
123710
123829
|
class STLDefaultDataSource {
|
|
123711
123830
|
|
|
123831
|
+
constructor(cfg = {}) {
|
|
123832
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
123833
|
+
}
|
|
123834
|
+
|
|
123835
|
+
_cacheBusterURL(url) {
|
|
123836
|
+
if (!this.cacheBuster) {
|
|
123837
|
+
return url;
|
|
123838
|
+
}
|
|
123839
|
+
const timestamp = new Date().getTime();
|
|
123840
|
+
if (url.indexOf('?') > -1) {
|
|
123841
|
+
return url + '&_=' + timestamp;
|
|
123842
|
+
} else {
|
|
123843
|
+
return url + '?_=' + timestamp;
|
|
123844
|
+
}
|
|
123845
|
+
}
|
|
123846
|
+
|
|
123712
123847
|
/**
|
|
123713
123848
|
* Gets STL data.
|
|
123714
123849
|
*
|
|
@@ -123717,6 +123852,7 @@ class STLDefaultDataSource {
|
|
|
123717
123852
|
* @param {Function} error Fired on error while loading the STL file.
|
|
123718
123853
|
*/
|
|
123719
123854
|
getSTL(src, ok, error) {
|
|
123855
|
+
src = this._cacheBusterURL(src);
|
|
123720
123856
|
const request = new XMLHttpRequest();
|
|
123721
123857
|
request.overrideMimeType("application/json");
|
|
123722
123858
|
request.open('GET', src, true);
|
|
@@ -126339,7 +126475,20 @@ class ViewCullPlugin extends Plugin {
|
|
|
126339
126475
|
*/
|
|
126340
126476
|
class XKTDefaultDataSource {
|
|
126341
126477
|
|
|
126342
|
-
constructor() {
|
|
126478
|
+
constructor(cfg = {}) {
|
|
126479
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
126480
|
+
}
|
|
126481
|
+
|
|
126482
|
+
_cacheBusterURL(url) {
|
|
126483
|
+
if (!this.cacheBuster) {
|
|
126484
|
+
return url;
|
|
126485
|
+
}
|
|
126486
|
+
const timestamp = new Date().getTime();
|
|
126487
|
+
if (url.indexOf('?') > -1) {
|
|
126488
|
+
return url + '&_=' + timestamp;
|
|
126489
|
+
} else {
|
|
126490
|
+
return url + '?_=' + timestamp;
|
|
126491
|
+
}
|
|
126343
126492
|
}
|
|
126344
126493
|
|
|
126345
126494
|
/**
|
|
@@ -126350,7 +126499,7 @@ class XKTDefaultDataSource {
|
|
|
126350
126499
|
* @param {Function} error Fired on error while loading the manifest JSON asset.
|
|
126351
126500
|
*/
|
|
126352
126501
|
getManifest(manifestSrc, ok, error) {
|
|
126353
|
-
utils.loadJSON(manifestSrc,
|
|
126502
|
+
utils.loadJSON(this._cacheBusterURL(manifestSrc),
|
|
126354
126503
|
(json) => {
|
|
126355
126504
|
ok(json);
|
|
126356
126505
|
},
|
|
@@ -126367,7 +126516,7 @@ class XKTDefaultDataSource {
|
|
|
126367
126516
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
126368
126517
|
*/
|
|
126369
126518
|
getMetaModel(metaModelSrc, ok, error) {
|
|
126370
|
-
utils.loadJSON(metaModelSrc,
|
|
126519
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
126371
126520
|
(json) => {
|
|
126372
126521
|
ok(json);
|
|
126373
126522
|
},
|
|
@@ -126409,7 +126558,7 @@ class XKTDefaultDataSource {
|
|
|
126409
126558
|
}
|
|
126410
126559
|
} else {
|
|
126411
126560
|
const request = new XMLHttpRequest();
|
|
126412
|
-
request.open('GET', src, true);
|
|
126561
|
+
request.open('GET', this._cacheBusterURL(src), true);
|
|
126413
126562
|
request.responseType = 'arraybuffer';
|
|
126414
126563
|
request.onreadystatechange = function () {
|
|
126415
126564
|
if (request.readyState === 4) {
|
|
@@ -133810,7 +133959,20 @@ class XML3DLoaderPlugin extends Plugin {
|
|
|
133810
133959
|
*/
|
|
133811
133960
|
class WebIFCDefaultDataSource {
|
|
133812
133961
|
|
|
133813
|
-
constructor() {
|
|
133962
|
+
constructor(cfg = {}) {
|
|
133963
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
133964
|
+
}
|
|
133965
|
+
|
|
133966
|
+
_cacheBusterURL(url) {
|
|
133967
|
+
if (!this.cacheBuster) {
|
|
133968
|
+
return url;
|
|
133969
|
+
}
|
|
133970
|
+
const timestamp = new Date().getTime();
|
|
133971
|
+
if (url.indexOf('?') > -1) {
|
|
133972
|
+
return url + '&_=' + timestamp;
|
|
133973
|
+
} else {
|
|
133974
|
+
return url + '?_=' + timestamp;
|
|
133975
|
+
}
|
|
133814
133976
|
}
|
|
133815
133977
|
|
|
133816
133978
|
/**
|
|
@@ -133821,6 +133983,8 @@ class WebIFCDefaultDataSource {
|
|
|
133821
133983
|
* @param {Function} error Callback fired on error.
|
|
133822
133984
|
*/
|
|
133823
133985
|
getIFC(src, ok, error) {
|
|
133986
|
+
src = this._cacheBusterURL(src);
|
|
133987
|
+
|
|
133824
133988
|
var defaultCallback = () => {
|
|
133825
133989
|
};
|
|
133826
133990
|
ok = ok || defaultCallback;
|
|
@@ -134818,7 +134982,20 @@ class WebIFCLoaderPlugin extends Plugin {
|
|
|
134818
134982
|
*/
|
|
134819
134983
|
class LASDefaultDataSource {
|
|
134820
134984
|
|
|
134821
|
-
constructor() {
|
|
134985
|
+
constructor(cfg = {}) {
|
|
134986
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
134987
|
+
}
|
|
134988
|
+
|
|
134989
|
+
_cacheBusterURL(url) {
|
|
134990
|
+
if (!this.cacheBuster) {
|
|
134991
|
+
return url;
|
|
134992
|
+
}
|
|
134993
|
+
const timestamp = new Date().getTime();
|
|
134994
|
+
if (url.indexOf('?') > -1) {
|
|
134995
|
+
return url + '&_=' + timestamp;
|
|
134996
|
+
} else {
|
|
134997
|
+
return url + '?_=' + timestamp;
|
|
134998
|
+
}
|
|
134822
134999
|
}
|
|
134823
135000
|
|
|
134824
135001
|
/**
|
|
@@ -134829,6 +135006,7 @@ class LASDefaultDataSource {
|
|
|
134829
135006
|
* @param {Function} error Callback fired on error.
|
|
134830
135007
|
*/
|
|
134831
135008
|
getLAS(src, ok, error) {
|
|
135009
|
+
src = this._cacheBusterURL(src);
|
|
134832
135010
|
var defaultCallback = () => {
|
|
134833
135011
|
};
|
|
134834
135012
|
ok = ok || defaultCallback;
|
|
@@ -135683,7 +135861,20 @@ function chunkArray(array, chunkSize) {
|
|
|
135683
135861
|
*/
|
|
135684
135862
|
class CityJSONDefaultDataSource {
|
|
135685
135863
|
|
|
135686
|
-
constructor() {
|
|
135864
|
+
constructor(cfg = {}) {
|
|
135865
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
135866
|
+
}
|
|
135867
|
+
|
|
135868
|
+
_cacheBusterURL(url) {
|
|
135869
|
+
if (!this.cacheBuster) {
|
|
135870
|
+
return url;
|
|
135871
|
+
}
|
|
135872
|
+
const timestamp = new Date().getTime();
|
|
135873
|
+
if (url.indexOf('?') > -1) {
|
|
135874
|
+
return url + '&_=' + timestamp;
|
|
135875
|
+
} else {
|
|
135876
|
+
return url + '?_=' + timestamp;
|
|
135877
|
+
}
|
|
135687
135878
|
}
|
|
135688
135879
|
|
|
135689
135880
|
/**
|
|
@@ -135694,7 +135885,7 @@ class CityJSONDefaultDataSource {
|
|
|
135694
135885
|
* @param {Function} error Callback fired on error.
|
|
135695
135886
|
*/
|
|
135696
135887
|
getCityJSON(src, ok, error) {
|
|
135697
|
-
utils.loadJSON(src,
|
|
135888
|
+
utils.loadJSON(this._cacheBusterURL(src),
|
|
135698
135889
|
(json) => {
|
|
135699
135890
|
ok(json);
|
|
135700
135891
|
},
|
|
@@ -137126,7 +137317,20 @@ class CityJSONLoaderPlugin extends Plugin {
|
|
|
137126
137317
|
*/
|
|
137127
137318
|
class DotBIMDefaultDataSource {
|
|
137128
137319
|
|
|
137129
|
-
constructor() {
|
|
137320
|
+
constructor(cfg = {}) {
|
|
137321
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
137322
|
+
}
|
|
137323
|
+
|
|
137324
|
+
_cacheBusterURL(url) {
|
|
137325
|
+
if (!this.cacheBuster) {
|
|
137326
|
+
return url;
|
|
137327
|
+
}
|
|
137328
|
+
const timestamp = new Date().getTime();
|
|
137329
|
+
if (url.indexOf('?') > -1) {
|
|
137330
|
+
return url + '&_=' + timestamp;
|
|
137331
|
+
} else {
|
|
137332
|
+
return url + '?_=' + timestamp;
|
|
137333
|
+
}
|
|
137130
137334
|
}
|
|
137131
137335
|
|
|
137132
137336
|
/**
|
|
@@ -137137,7 +137341,7 @@ class DotBIMDefaultDataSource {
|
|
|
137137
137341
|
* @param {Function} error Fired on error while loading the .BIM JSON asset.
|
|
137138
137342
|
*/
|
|
137139
137343
|
getDotBIM(dotBIMSrc, ok, error) {
|
|
137140
|
-
utils.loadJSON(dotBIMSrc,
|
|
137344
|
+
utils.loadJSON(this._cacheBusterURL(dotBIMSrc),
|
|
137141
137345
|
(json) => {
|
|
137142
137346
|
ok(json);
|
|
137143
137347
|
},
|
|
@@ -137699,6 +137903,2013 @@ class DotBIMLoaderPlugin extends Plugin {
|
|
|
137699
137903
|
}
|
|
137700
137904
|
}
|
|
137701
137905
|
|
|
137906
|
+
const hex2rgb = function(color) {
|
|
137907
|
+
const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
|
|
137908
|
+
return [ rgb(0), rgb(2), rgb(4) ];
|
|
137909
|
+
};
|
|
137910
|
+
|
|
137911
|
+
const transformToNode = function(from, to, vec) {
|
|
137912
|
+
const fromRec = from.getBoundingClientRect();
|
|
137913
|
+
const toRec = to.getBoundingClientRect();
|
|
137914
|
+
vec[0] += fromRec.left - toRec.left;
|
|
137915
|
+
vec[1] += fromRec.top - toRec.top;
|
|
137916
|
+
};
|
|
137917
|
+
|
|
137918
|
+
const triangulateEarClipping = function(planeCoords) {
|
|
137919
|
+
|
|
137920
|
+
const polygonVertices = [ ];
|
|
137921
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
137922
|
+
polygonVertices.push(i);
|
|
137923
|
+
|
|
137924
|
+
const isCCW = (function() {
|
|
137925
|
+
const ba = math.vec2();
|
|
137926
|
+
const bc = math.vec2();
|
|
137927
|
+
|
|
137928
|
+
let anglesSum = 0;
|
|
137929
|
+
|
|
137930
|
+
for (let i = 0; i < polygonVertices.length; ++i)
|
|
137931
|
+
{
|
|
137932
|
+
const a = planeCoords[polygonVertices[i]];
|
|
137933
|
+
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
137934
|
+
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
137935
|
+
|
|
137936
|
+
math.subVec2(a, b, ba);
|
|
137937
|
+
math.subVec2(c, b, bc);
|
|
137938
|
+
|
|
137939
|
+
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
137940
|
+
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
137941
|
+
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
137942
|
+
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
137943
|
+
}
|
|
137944
|
+
|
|
137945
|
+
return anglesSum < (polygonVertices.length * Math.PI);
|
|
137946
|
+
})();
|
|
137947
|
+
|
|
137948
|
+
const pointInTriangle = (function() {
|
|
137949
|
+
const sign = (p1, p2, p3) => {
|
|
137950
|
+
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
137951
|
+
};
|
|
137952
|
+
|
|
137953
|
+
return (pt, v1, v2, v3) => {
|
|
137954
|
+
const d1 = sign(pt, v1, v2);
|
|
137955
|
+
const d2 = sign(pt, v2, v3);
|
|
137956
|
+
const d3 = sign(pt, v3, v1);
|
|
137957
|
+
|
|
137958
|
+
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
137959
|
+
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
137960
|
+
|
|
137961
|
+
return !(has_neg && has_pos);
|
|
137962
|
+
};
|
|
137963
|
+
})();
|
|
137964
|
+
|
|
137965
|
+
const baseTriangles = [ ];
|
|
137966
|
+
|
|
137967
|
+
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
137968
|
+
vertices.forEach((v, i) => {
|
|
137969
|
+
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
137970
|
+
v.next = vertices[(i + 1) % vertices.length];
|
|
137971
|
+
});
|
|
137972
|
+
|
|
137973
|
+
const ba = math.vec2();
|
|
137974
|
+
const bc = math.vec2();
|
|
137975
|
+
|
|
137976
|
+
while (vertices.length > 2) {
|
|
137977
|
+
let earIdx = 0;
|
|
137978
|
+
while (true) {
|
|
137979
|
+
if (earIdx >= vertices.length)
|
|
137980
|
+
{
|
|
137981
|
+
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
137982
|
+
}
|
|
137983
|
+
const v = vertices[earIdx];
|
|
137984
|
+
|
|
137985
|
+
const a = planeCoords[v.prev.idx];
|
|
137986
|
+
const b = planeCoords[v.idx];
|
|
137987
|
+
const c = planeCoords[v.next.idx];
|
|
137988
|
+
|
|
137989
|
+
math.subVec2(a, b, ba);
|
|
137990
|
+
math.subVec2(c, b, bc);
|
|
137991
|
+
|
|
137992
|
+
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
137993
|
+
&&
|
|
137994
|
+
vertices.every( // no other vertices inside
|
|
137995
|
+
vv => ((vv === v)
|
|
137996
|
+
||
|
|
137997
|
+
(vv === v.prev)
|
|
137998
|
+
||
|
|
137999
|
+
(vv === v.next)
|
|
138000
|
+
||
|
|
138001
|
+
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
138002
|
+
break;
|
|
138003
|
+
++earIdx;
|
|
138004
|
+
}
|
|
138005
|
+
|
|
138006
|
+
const ear = vertices[earIdx];
|
|
138007
|
+
vertices.splice(earIdx, 1);
|
|
138008
|
+
|
|
138009
|
+
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
138010
|
+
|
|
138011
|
+
const prev = ear.prev;
|
|
138012
|
+
prev.next = ear.next;
|
|
138013
|
+
const next = ear.next;
|
|
138014
|
+
next.prev = ear.prev;
|
|
138015
|
+
}
|
|
138016
|
+
|
|
138017
|
+
return [ planeCoords, baseTriangles ];
|
|
138018
|
+
};
|
|
138019
|
+
|
|
138020
|
+
const draggableDot3D = function(handleMouseEvents, handleTouchEvents, viewer, worldPos, color, ray2WorldPos, onStart, onMove, onEnd) {
|
|
138021
|
+
const scene = viewer.scene;
|
|
138022
|
+
const canvas = scene.canvas.canvas;
|
|
138023
|
+
|
|
138024
|
+
const marker = new Marker(scene, {});
|
|
138025
|
+
|
|
138026
|
+
const pickWorldPos = canvasPos => {
|
|
138027
|
+
const origin = math.vec3();
|
|
138028
|
+
const direction = math.vec3();
|
|
138029
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138030
|
+
return ray2WorldPos(origin, direction);
|
|
138031
|
+
};
|
|
138032
|
+
|
|
138033
|
+
const onChange = event => {
|
|
138034
|
+
const canvasPos = math.vec2([ event.clientX, event.clientY ]);
|
|
138035
|
+
transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
|
|
138036
|
+
|
|
138037
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
138038
|
+
marker.worldPos = worldPos;
|
|
138039
|
+
updateDotPos();
|
|
138040
|
+
onMove(canvasPos, worldPos);
|
|
138041
|
+
};
|
|
138042
|
+
|
|
138043
|
+
let currentDrag = null;
|
|
138044
|
+
|
|
138045
|
+
const onDragMove = function(event) {
|
|
138046
|
+
const e = currentDrag.matchesEvent(event);
|
|
138047
|
+
if (e)
|
|
138048
|
+
{
|
|
138049
|
+
onChange(e);
|
|
138050
|
+
}
|
|
138051
|
+
};
|
|
138052
|
+
|
|
138053
|
+
const onDragEnd = function(event) {
|
|
138054
|
+
const e = currentDrag.matchesEvent(event);
|
|
138055
|
+
if (e)
|
|
138056
|
+
{
|
|
138057
|
+
dot.setOpacity(idleOpacity);
|
|
138058
|
+
currentDrag.cleanup();
|
|
138059
|
+
onChange(e);
|
|
138060
|
+
onEnd();
|
|
138061
|
+
}
|
|
138062
|
+
};
|
|
138063
|
+
|
|
138064
|
+
const startDrag = function(matchesEvent, cleanupHandlers) {
|
|
138065
|
+
if (currentDrag) {
|
|
138066
|
+
currentDrag.cleanup();
|
|
138067
|
+
}
|
|
138068
|
+
|
|
138069
|
+
dot.setOpacity(1.0);
|
|
138070
|
+
dot.setClickable(false);
|
|
138071
|
+
viewer.cameraControl.active = false;
|
|
138072
|
+
|
|
138073
|
+
currentDrag = {
|
|
138074
|
+
matchesEvent: matchesEvent,
|
|
138075
|
+
cleanup: function() {
|
|
138076
|
+
currentDrag = null;
|
|
138077
|
+
dot.setClickable(true);
|
|
138078
|
+
viewer.cameraControl.active = true;
|
|
138079
|
+
cleanupHandlers();
|
|
138080
|
+
}
|
|
138081
|
+
};
|
|
138082
|
+
|
|
138083
|
+
onStart();
|
|
138084
|
+
};
|
|
138085
|
+
|
|
138086
|
+
const dotCfg = { fillColor: color };
|
|
138087
|
+
|
|
138088
|
+
if (handleMouseEvents)
|
|
138089
|
+
{
|
|
138090
|
+
dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
|
|
138091
|
+
dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
|
|
138092
|
+
dotCfg.onMouseDown = event => {
|
|
138093
|
+
if (event.which === 1)
|
|
138094
|
+
{
|
|
138095
|
+
canvas.addEventListener("mousemove", onDragMove);
|
|
138096
|
+
canvas.addEventListener("mouseup", onDragEnd);
|
|
138097
|
+
startDrag(
|
|
138098
|
+
event => (event.which === 1) && event,
|
|
138099
|
+
() => {
|
|
138100
|
+
canvas.removeEventListener("mousemove", onDragMove);
|
|
138101
|
+
canvas.removeEventListener("mouseup", onDragEnd);
|
|
138102
|
+
});
|
|
138103
|
+
}
|
|
138104
|
+
};
|
|
138105
|
+
}
|
|
138106
|
+
|
|
138107
|
+
if (handleTouchEvents)
|
|
138108
|
+
{
|
|
138109
|
+
let touchStartId;
|
|
138110
|
+
dotCfg.onTouchstart = event => {
|
|
138111
|
+
event.preventDefault();
|
|
138112
|
+
if (event.touches.length === 1)
|
|
138113
|
+
{
|
|
138114
|
+
touchStartId = event.touches[0].identifier;
|
|
138115
|
+
startDrag(
|
|
138116
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId),
|
|
138117
|
+
() => { touchStartId = null; });
|
|
138118
|
+
}
|
|
138119
|
+
};
|
|
138120
|
+
dotCfg.onTouchmove = event => {
|
|
138121
|
+
event.preventDefault();
|
|
138122
|
+
onDragMove(event);
|
|
138123
|
+
};
|
|
138124
|
+
dotCfg.onTouchend = event => {
|
|
138125
|
+
event.preventDefault();
|
|
138126
|
+
onDragEnd(event);
|
|
138127
|
+
};
|
|
138128
|
+
}
|
|
138129
|
+
|
|
138130
|
+
const dotParent = canvas.ownerDocument.body;
|
|
138131
|
+
const dot = new Dot(dotParent, dotCfg);
|
|
138132
|
+
|
|
138133
|
+
const idleOpacity = 0.5;
|
|
138134
|
+
dot.setOpacity(idleOpacity);
|
|
138135
|
+
|
|
138136
|
+
const updateDotPos = function() {
|
|
138137
|
+
const pos = marker.canvasPos.slice();
|
|
138138
|
+
transformToNode(canvas, dotParent, pos);
|
|
138139
|
+
dot.setPos(pos[0], pos[1]);
|
|
138140
|
+
};
|
|
138141
|
+
|
|
138142
|
+
marker.worldPos = worldPos;
|
|
138143
|
+
updateDotPos();
|
|
138144
|
+
|
|
138145
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
|
|
138146
|
+
const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
|
|
138147
|
+
|
|
138148
|
+
return {
|
|
138149
|
+
setActive: value => dot.setClickable(value),
|
|
138150
|
+
getWorldPos: () => marker.worldPos,
|
|
138151
|
+
setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
|
|
138152
|
+
destroy: function() {
|
|
138153
|
+
currentDrag && currentDrag.cleanup();
|
|
138154
|
+
scene.camera.off(onViewMatrix);
|
|
138155
|
+
scene.camera.off(onProjMatrix);
|
|
138156
|
+
marker.destroy();
|
|
138157
|
+
dot.destroy();
|
|
138158
|
+
}
|
|
138159
|
+
};
|
|
138160
|
+
};
|
|
138161
|
+
|
|
138162
|
+
const marker3D = function(scene, color) {
|
|
138163
|
+
const canvas = scene.canvas.canvas;
|
|
138164
|
+
|
|
138165
|
+
const markerParent = canvas.parentNode;
|
|
138166
|
+
const markerDiv = document.createElement("div");
|
|
138167
|
+
markerParent.insertBefore(markerDiv, canvas);
|
|
138168
|
+
|
|
138169
|
+
let size = 5;
|
|
138170
|
+
markerDiv.style.background = color;
|
|
138171
|
+
markerDiv.style.border = "2px solid white";
|
|
138172
|
+
markerDiv.style.margin = "0 0";
|
|
138173
|
+
markerDiv.style.zIndex = "100";
|
|
138174
|
+
markerDiv.style.position = "absolute";
|
|
138175
|
+
markerDiv.style.pointerEvents = "none";
|
|
138176
|
+
markerDiv.style.display = "none";
|
|
138177
|
+
|
|
138178
|
+
const marker = new Marker(scene, {});
|
|
138179
|
+
|
|
138180
|
+
const px = x => x + "px";
|
|
138181
|
+
const update = function() {
|
|
138182
|
+
const pos = marker.canvasPos.slice();
|
|
138183
|
+
transformToNode(canvas, markerParent, pos);
|
|
138184
|
+
markerDiv.style.left = px(pos[0] - 3 - size / 2);
|
|
138185
|
+
markerDiv.style.top = px(pos[1] - 3 - size / 2);
|
|
138186
|
+
markerDiv.style.borderRadius = px(size * 2);
|
|
138187
|
+
markerDiv.style.width = px(size);
|
|
138188
|
+
markerDiv.style.height = px(size);
|
|
138189
|
+
};
|
|
138190
|
+
const onViewMatrix = scene.camera.on("viewMatrix", update);
|
|
138191
|
+
const onProjMatrix = scene.camera.on("projMatrix", update);
|
|
138192
|
+
|
|
138193
|
+
return {
|
|
138194
|
+
update: function(worldPos) {
|
|
138195
|
+
if (worldPos)
|
|
138196
|
+
{
|
|
138197
|
+
marker.worldPos = worldPos;
|
|
138198
|
+
update();
|
|
138199
|
+
}
|
|
138200
|
+
markerDiv.style.display = worldPos ? "" : "none";
|
|
138201
|
+
},
|
|
138202
|
+
|
|
138203
|
+
setHighlighted: function(h) {
|
|
138204
|
+
size = h ? 10 : 5;
|
|
138205
|
+
update();
|
|
138206
|
+
},
|
|
138207
|
+
|
|
138208
|
+
getCanvasPos: () => marker.canvasPos,
|
|
138209
|
+
|
|
138210
|
+
getWorldPos: () => marker.worldPos,
|
|
138211
|
+
|
|
138212
|
+
destroy: function() {
|
|
138213
|
+
markerDiv.parentNode.removeChild(markerDiv);
|
|
138214
|
+
scene.camera.off(onViewMatrix);
|
|
138215
|
+
scene.camera.off(onProjMatrix);
|
|
138216
|
+
marker.destroy();
|
|
138217
|
+
}
|
|
138218
|
+
};
|
|
138219
|
+
};
|
|
138220
|
+
|
|
138221
|
+
const wire3D = function(scene, color, startWorldPos) {
|
|
138222
|
+
const canvas = scene.canvas.canvas;
|
|
138223
|
+
|
|
138224
|
+
const startMarker = new Marker(scene, {});
|
|
138225
|
+
startMarker.worldPos = startWorldPos;
|
|
138226
|
+
const endMarker = new Marker(scene, {});
|
|
138227
|
+
const wireParent = canvas.ownerDocument.body;
|
|
138228
|
+
const wire = new Wire(wireParent, {
|
|
138229
|
+
color: color,
|
|
138230
|
+
thickness: 1,
|
|
138231
|
+
thicknessClickable: 6
|
|
138232
|
+
});
|
|
138233
|
+
wire.setVisible(false);
|
|
138234
|
+
|
|
138235
|
+
const updatePos = function() {
|
|
138236
|
+
const p0 = startMarker.canvasPos.slice();
|
|
138237
|
+
const p1 = endMarker.canvasPos.slice();
|
|
138238
|
+
transformToNode(canvas, wireParent, p0);
|
|
138239
|
+
transformToNode(canvas, wireParent, p1);
|
|
138240
|
+
wire.setStartAndEnd(p0[0], p0[1], p1[0], p1[1]);
|
|
138241
|
+
};
|
|
138242
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updatePos);
|
|
138243
|
+
const onProjMatrix = scene.camera.on("projMatrix", updatePos);
|
|
138244
|
+
|
|
138245
|
+
return {
|
|
138246
|
+
update: function(endWorldPos) {
|
|
138247
|
+
if (endWorldPos)
|
|
138248
|
+
{
|
|
138249
|
+
endMarker.worldPos = endWorldPos;
|
|
138250
|
+
updatePos();
|
|
138251
|
+
}
|
|
138252
|
+
wire.setVisible(!!endWorldPos);
|
|
138253
|
+
},
|
|
138254
|
+
|
|
138255
|
+
destroy: function() {
|
|
138256
|
+
scene.camera.off(onViewMatrix);
|
|
138257
|
+
scene.camera.off(onProjMatrix);
|
|
138258
|
+
startMarker.destroy();
|
|
138259
|
+
endMarker.destroy();
|
|
138260
|
+
wire.destroy();
|
|
138261
|
+
}
|
|
138262
|
+
};
|
|
138263
|
+
};
|
|
138264
|
+
|
|
138265
|
+
const basePolygon3D = function(scene, color, alpha) {
|
|
138266
|
+
let mesh = null;
|
|
138267
|
+
|
|
138268
|
+
const updateBase = points => {
|
|
138269
|
+
if (points)
|
|
138270
|
+
{
|
|
138271
|
+
if (mesh)
|
|
138272
|
+
{
|
|
138273
|
+
mesh.destroy();
|
|
138274
|
+
}
|
|
138275
|
+
|
|
138276
|
+
try {
|
|
138277
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(points.map(p => [ p[0], p[2] ]));
|
|
138278
|
+
|
|
138279
|
+
const positions = [ ].concat(...baseVertices.map(p => [p[0], points[0][1], p[1]])); // To convert from Float64Array into an Array
|
|
138280
|
+
const ind = [ ].concat(...baseTriangles);
|
|
138281
|
+
mesh = new Mesh(scene, {
|
|
138282
|
+
pickable: false, // otherwise there's a WebGL error inside PickMeshRenderer.prototype.drawMesh
|
|
138283
|
+
geometry: new ReadableGeometry(
|
|
138284
|
+
scene,
|
|
138285
|
+
{
|
|
138286
|
+
positions: positions,
|
|
138287
|
+
indices: ind,
|
|
138288
|
+
normals: math.buildNormals(positions, ind)
|
|
138289
|
+
}),
|
|
138290
|
+
material: new PhongMaterial(scene, {
|
|
138291
|
+
alpha: (alpha !== undefined) ? alpha : 0.5,
|
|
138292
|
+
backfaces: true,
|
|
138293
|
+
diffuse: hex2rgb(color)
|
|
138294
|
+
})
|
|
138295
|
+
});
|
|
138296
|
+
} catch (e) {
|
|
138297
|
+
mesh = null;
|
|
138298
|
+
}
|
|
138299
|
+
}
|
|
138300
|
+
|
|
138301
|
+
if (mesh)
|
|
138302
|
+
{
|
|
138303
|
+
mesh.visible = !!points;
|
|
138304
|
+
}
|
|
138305
|
+
};
|
|
138306
|
+
updateBase(null);
|
|
138307
|
+
|
|
138308
|
+
return {
|
|
138309
|
+
updateBase: updateBase,
|
|
138310
|
+
destroy: () => mesh && mesh.destroy()
|
|
138311
|
+
};
|
|
138312
|
+
};
|
|
138313
|
+
|
|
138314
|
+
const startAAZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
138315
|
+
const marker1 = marker3D(scene, zoneColor);
|
|
138316
|
+
const marker2 = marker3D(scene, zoneColor);
|
|
138317
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
138318
|
+
|
|
138319
|
+
const updatePointerLens = (pointerLens
|
|
138320
|
+
? function(canvasPos) {
|
|
138321
|
+
pointerLens.visible = !! canvasPos;
|
|
138322
|
+
if (canvasPos)
|
|
138323
|
+
{
|
|
138324
|
+
pointerLens.canvasPos = canvasPos;
|
|
138325
|
+
}
|
|
138326
|
+
}
|
|
138327
|
+
: () => { });
|
|
138328
|
+
|
|
138329
|
+
let deactivatePointSelection = select3dPoint(
|
|
138330
|
+
() => {
|
|
138331
|
+
updatePointerLens(null);
|
|
138332
|
+
marker1.update(null);
|
|
138333
|
+
},
|
|
138334
|
+
(canvasPos, worldPos) => {
|
|
138335
|
+
updatePointerLens(canvasPos);
|
|
138336
|
+
marker1.update(worldPos);
|
|
138337
|
+
},
|
|
138338
|
+
function(point1CanvasPos, point1WorldPos) {
|
|
138339
|
+
marker1.update(point1WorldPos);
|
|
138340
|
+
|
|
138341
|
+
deactivatePointSelection = select3dPoint(
|
|
138342
|
+
function() {
|
|
138343
|
+
updatePointerLens(null);
|
|
138344
|
+
marker2.update(null);
|
|
138345
|
+
basePolygon.updateBase(null);
|
|
138346
|
+
},
|
|
138347
|
+
function(canvasPos, point2WorldPos) {
|
|
138348
|
+
updatePointerLens(canvasPos);
|
|
138349
|
+
marker2.update(point2WorldPos);
|
|
138350
|
+
|
|
138351
|
+
if (math.distVec3(point1WorldPos, point2WorldPos) > 0.01)
|
|
138352
|
+
{
|
|
138353
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138354
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138355
|
+
|
|
138356
|
+
const xmin = min(0);
|
|
138357
|
+
const ymin = min(1);
|
|
138358
|
+
const zmin = min(2);
|
|
138359
|
+
const xmax = max(0);
|
|
138360
|
+
max(1);
|
|
138361
|
+
const zmax = max(2);
|
|
138362
|
+
|
|
138363
|
+
basePolygon.updateBase([ [ xmin, ymin, zmax ], [ xmax, ymin, zmax ],
|
|
138364
|
+
[ xmax, ymin, zmin ], [ xmin, ymin, zmin ] ]);
|
|
138365
|
+
}
|
|
138366
|
+
else
|
|
138367
|
+
basePolygon.updateBase(null);
|
|
138368
|
+
},
|
|
138369
|
+
function(point2CanvasPos, point2WorldPos) {
|
|
138370
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
138371
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
138372
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
138373
|
+
marker2.update(point2WorldPos);
|
|
138374
|
+
|
|
138375
|
+
marker1.destroy();
|
|
138376
|
+
marker2.destroy();
|
|
138377
|
+
basePolygon.destroy();
|
|
138378
|
+
updatePointerLens(null);
|
|
138379
|
+
|
|
138380
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138381
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138382
|
+
|
|
138383
|
+
const xmin = min(0);
|
|
138384
|
+
const zmin = min(2);
|
|
138385
|
+
const xmax = max(0);
|
|
138386
|
+
const zmax = max(2);
|
|
138387
|
+
|
|
138388
|
+
const zone = zonesPlugin.createZone(
|
|
138389
|
+
{
|
|
138390
|
+
id: math.createUUID(),
|
|
138391
|
+
geometry: {
|
|
138392
|
+
planeCoordinates: [
|
|
138393
|
+
[ xmin, zmax ],
|
|
138394
|
+
[ xmax, zmax ],
|
|
138395
|
+
[ xmax, zmin ],
|
|
138396
|
+
[ xmin, zmin ]
|
|
138397
|
+
],
|
|
138398
|
+
altitude: zoneAltitude,
|
|
138399
|
+
height: zoneHeight
|
|
138400
|
+
},
|
|
138401
|
+
alpha: zoneAlpha,
|
|
138402
|
+
color: zoneColor
|
|
138403
|
+
});
|
|
138404
|
+
|
|
138405
|
+
onZoneCreated(zone);
|
|
138406
|
+
});
|
|
138407
|
+
});
|
|
138408
|
+
|
|
138409
|
+
return {
|
|
138410
|
+
deactivate: function() {
|
|
138411
|
+
deactivatePointSelection();
|
|
138412
|
+
marker1.destroy();
|
|
138413
|
+
marker2.destroy();
|
|
138414
|
+
basePolygon.destroy();
|
|
138415
|
+
updatePointerLens(null);
|
|
138416
|
+
}
|
|
138417
|
+
};
|
|
138418
|
+
};
|
|
138419
|
+
|
|
138420
|
+
const mousePointSelector = function(viewer, ray2WorldPos) {
|
|
138421
|
+
return function(onCancel, onChange, onCommit) {
|
|
138422
|
+
const scene = viewer.scene;
|
|
138423
|
+
const canvas = scene.canvas.canvas;
|
|
138424
|
+
const moveTolerance = 20;
|
|
138425
|
+
|
|
138426
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138427
|
+
vec2[0] = event.clientX;
|
|
138428
|
+
vec2[1] = event.clientY;
|
|
138429
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138430
|
+
return vec2;
|
|
138431
|
+
};
|
|
138432
|
+
|
|
138433
|
+
const pickWorldPos = canvasPos => {
|
|
138434
|
+
const origin = math.vec3();
|
|
138435
|
+
const direction = math.vec3();
|
|
138436
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138437
|
+
return ray2WorldPos(origin, direction);
|
|
138438
|
+
};
|
|
138439
|
+
|
|
138440
|
+
let buttonDown = false;
|
|
138441
|
+
const resetAction = function() {
|
|
138442
|
+
buttonDown = false;
|
|
138443
|
+
};
|
|
138444
|
+
|
|
138445
|
+
const cleanup = function() {
|
|
138446
|
+
resetAction();
|
|
138447
|
+
canvas.removeEventListener("mousedown", onMouseDown);
|
|
138448
|
+
canvas.removeEventListener("mousemove", onMouseMove);
|
|
138449
|
+
viewer.cameraControl.off(onCameraControlRayMove);
|
|
138450
|
+
canvas.removeEventListener("mouseup", onMouseUp);
|
|
138451
|
+
};
|
|
138452
|
+
|
|
138453
|
+
const startCanvasPos = math.vec2();
|
|
138454
|
+
const onMouseDown = function(event) {
|
|
138455
|
+
if (event.which === 1)
|
|
138456
|
+
{
|
|
138457
|
+
copyCanvasPos(event, startCanvasPos);
|
|
138458
|
+
buttonDown = true;
|
|
138459
|
+
}
|
|
138460
|
+
};
|
|
138461
|
+
canvas.addEventListener("mousedown", onMouseDown);
|
|
138462
|
+
|
|
138463
|
+
const onMouseMove = function(event) {
|
|
138464
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138465
|
+
if (buttonDown && math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138466
|
+
{
|
|
138467
|
+
resetAction();
|
|
138468
|
+
onCancel();
|
|
138469
|
+
}
|
|
138470
|
+
};
|
|
138471
|
+
canvas.addEventListener("mousemove", onMouseMove);
|
|
138472
|
+
|
|
138473
|
+
const onCameraControlRayMove = viewer.cameraControl.on(
|
|
138474
|
+
"rayMove",
|
|
138475
|
+
event => {
|
|
138476
|
+
const canvasPos = event.canvasPos;
|
|
138477
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138478
|
+
});
|
|
138479
|
+
|
|
138480
|
+
const onMouseUp = function(event) {
|
|
138481
|
+
if ((event.which === 1) && buttonDown)
|
|
138482
|
+
{
|
|
138483
|
+
cleanup();
|
|
138484
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138485
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138486
|
+
}
|
|
138487
|
+
};
|
|
138488
|
+
canvas.addEventListener("mouseup", onMouseUp);
|
|
138489
|
+
|
|
138490
|
+
return cleanup;
|
|
138491
|
+
};
|
|
138492
|
+
};
|
|
138493
|
+
|
|
138494
|
+
const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
138495
|
+
return function(onCancel, onChange, onCommit) {
|
|
138496
|
+
const scene = viewer.scene;
|
|
138497
|
+
const canvas = scene.canvas.canvas;
|
|
138498
|
+
const longTouchTimeoutMs = 300;
|
|
138499
|
+
const moveTolerance = 20;
|
|
138500
|
+
|
|
138501
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138502
|
+
vec2[0] = event.clientX;
|
|
138503
|
+
vec2[1] = event.clientY;
|
|
138504
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138505
|
+
return vec2;
|
|
138506
|
+
};
|
|
138507
|
+
|
|
138508
|
+
const pickWorldPos = canvasPos => {
|
|
138509
|
+
const origin = math.vec3();
|
|
138510
|
+
const direction = math.vec3();
|
|
138511
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138512
|
+
return ray2WorldPos(origin, direction);
|
|
138513
|
+
};
|
|
138514
|
+
|
|
138515
|
+
let longTouchTimeout = null;
|
|
138516
|
+
const nop = () => { };
|
|
138517
|
+
let onSingleTouchMove = nop;
|
|
138518
|
+
let startTouchIdentifier;
|
|
138519
|
+
|
|
138520
|
+
const resetAction = function() {
|
|
138521
|
+
pointerCircle.stop();
|
|
138522
|
+
clearTimeout(longTouchTimeout);
|
|
138523
|
+
viewer.cameraControl.active = true;
|
|
138524
|
+
onSingleTouchMove = nop;
|
|
138525
|
+
startTouchIdentifier = null;
|
|
138526
|
+
};
|
|
138527
|
+
|
|
138528
|
+
const cleanup = function() {
|
|
138529
|
+
resetAction();
|
|
138530
|
+
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
138531
|
+
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
138532
|
+
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
138533
|
+
};
|
|
138534
|
+
|
|
138535
|
+
const onCanvasTouchStart = function(event) {
|
|
138536
|
+
const touches = event.touches;
|
|
138537
|
+
|
|
138538
|
+
if (touches.length !== 1)
|
|
138539
|
+
{
|
|
138540
|
+
resetAction();
|
|
138541
|
+
onCancel();
|
|
138542
|
+
}
|
|
138543
|
+
else
|
|
138544
|
+
{
|
|
138545
|
+
const startTouch = touches[0];
|
|
138546
|
+
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
138547
|
+
|
|
138548
|
+
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
138549
|
+
if (startWorldPos)
|
|
138550
|
+
{
|
|
138551
|
+
startTouchIdentifier = startTouch.identifier;
|
|
138552
|
+
|
|
138553
|
+
onSingleTouchMove = canvasPos => {
|
|
138554
|
+
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138555
|
+
{
|
|
138556
|
+
resetAction();
|
|
138557
|
+
}
|
|
138558
|
+
};
|
|
138559
|
+
|
|
138560
|
+
longTouchTimeout = setTimeout(
|
|
138561
|
+
function() {
|
|
138562
|
+
pointerCircle.start(startCanvasPos);
|
|
138563
|
+
|
|
138564
|
+
longTouchTimeout = setTimeout(
|
|
138565
|
+
function() {
|
|
138566
|
+
pointerCircle.stop();
|
|
138567
|
+
|
|
138568
|
+
viewer.cameraControl.active = false;
|
|
138569
|
+
|
|
138570
|
+
onSingleTouchMove = canvasPos => {
|
|
138571
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138572
|
+
};
|
|
138573
|
+
|
|
138574
|
+
onSingleTouchMove(startCanvasPos);
|
|
138575
|
+
},
|
|
138576
|
+
longTouchTimeoutMs);
|
|
138577
|
+
},
|
|
138578
|
+
250);
|
|
138579
|
+
}
|
|
138580
|
+
}
|
|
138581
|
+
};
|
|
138582
|
+
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
138583
|
+
|
|
138584
|
+
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
138585
|
+
|
|
138586
|
+
const onCanvasTouchMove = function(event) {
|
|
138587
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138588
|
+
if (touch)
|
|
138589
|
+
{
|
|
138590
|
+
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
138591
|
+
}
|
|
138592
|
+
};
|
|
138593
|
+
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
138594
|
+
|
|
138595
|
+
const onCanvasTouchEnd = function(event) {
|
|
138596
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138597
|
+
if (touch)
|
|
138598
|
+
{
|
|
138599
|
+
cleanup();
|
|
138600
|
+
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
138601
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138602
|
+
}
|
|
138603
|
+
};
|
|
138604
|
+
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
138605
|
+
|
|
138606
|
+
return cleanup;
|
|
138607
|
+
};
|
|
138608
|
+
};
|
|
138609
|
+
|
|
138610
|
+
const planeIntersect = function(p0, n, origin, direction) {
|
|
138611
|
+
const t = - (math.dotVec3(origin, n) - p0) / math.dotVec3(direction, n);
|
|
138612
|
+
{
|
|
138613
|
+
const worldPos = math.vec3();
|
|
138614
|
+
math.mulVec3Scalar(direction, t, worldPos);
|
|
138615
|
+
math.addVec3(origin, worldPos, worldPos);
|
|
138616
|
+
return worldPos;
|
|
138617
|
+
}
|
|
138618
|
+
};
|
|
138619
|
+
|
|
138620
|
+
/**
|
|
138621
|
+
* @desc Renders a transparent box between two 3D points.
|
|
138622
|
+
*
|
|
138623
|
+
* See {@link ZonesPlugin} for more info.
|
|
138624
|
+
*/
|
|
138625
|
+
|
|
138626
|
+
class Zone extends Component {
|
|
138627
|
+
|
|
138628
|
+
/**
|
|
138629
|
+
* @private
|
|
138630
|
+
*/
|
|
138631
|
+
constructor(plugin, cfg = {}) {
|
|
138632
|
+
|
|
138633
|
+
super(plugin.viewer.scene, cfg);
|
|
138634
|
+
|
|
138635
|
+
/**
|
|
138636
|
+
* The {@link ZonesPlugin} that owns this Zone.
|
|
138637
|
+
* @type {ZonesPlugin}
|
|
138638
|
+
*/
|
|
138639
|
+
this.plugin = plugin;
|
|
138640
|
+
|
|
138641
|
+
this._container = cfg.container;
|
|
138642
|
+
if (!this._container) {
|
|
138643
|
+
throw "config missing: container";
|
|
138644
|
+
}
|
|
138645
|
+
|
|
138646
|
+
this._eventSubs = {};
|
|
138647
|
+
|
|
138648
|
+
this.plugin.viewer.scene;
|
|
138649
|
+
|
|
138650
|
+
this._geometry = cfg.geometry;
|
|
138651
|
+
|
|
138652
|
+
cfg.onMouseOver ? (event) => {
|
|
138653
|
+
cfg.onMouseOver(event, this);
|
|
138654
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event));
|
|
138655
|
+
} : null;
|
|
138656
|
+
|
|
138657
|
+
cfg.onMouseLeave ? (event) => {
|
|
138658
|
+
cfg.onMouseLeave(event, this);
|
|
138659
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event));
|
|
138660
|
+
} : null;
|
|
138661
|
+
|
|
138662
|
+
cfg.onContextMenu ? (event) => {
|
|
138663
|
+
cfg.onContextMenu(event, this);
|
|
138664
|
+
} : null;
|
|
138665
|
+
|
|
138666
|
+
this._alpha = (("alpha" in cfg) && (cfg.alpha !== undefined)) ? cfg.alpha : 0.5;
|
|
138667
|
+
this.color = cfg.color;
|
|
138668
|
+
|
|
138669
|
+
this._visible = true;
|
|
138670
|
+
|
|
138671
|
+
this._rebuildMesh();
|
|
138672
|
+
}
|
|
138673
|
+
|
|
138674
|
+
_rebuildMesh() {
|
|
138675
|
+
const scene = this.plugin.viewer.scene;
|
|
138676
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138677
|
+
const downward = this._geometry.height < 0;
|
|
138678
|
+
const altitude = this._geometry.altitude + (downward ? this._geometry.height : 0);
|
|
138679
|
+
const height = this._geometry.height * (downward ? -1 : 1);
|
|
138680
|
+
|
|
138681
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
|
|
138682
|
+
|
|
138683
|
+
const pos = [ ];
|
|
138684
|
+
const ind = [ ];
|
|
138685
|
+
|
|
138686
|
+
|
|
138687
|
+
const addPlane = (isCeiling) => {
|
|
138688
|
+
const baseIdx = pos.length;
|
|
138689
|
+
|
|
138690
|
+
for (let c of baseVertices) {
|
|
138691
|
+
pos.push([ c[0], altitude + (isCeiling ? height : 0), c[1] ]);
|
|
138692
|
+
}
|
|
138693
|
+
|
|
138694
|
+
for (let t of baseTriangles) {
|
|
138695
|
+
ind.push(...(isCeiling ? t : t.slice(0).reverse()).map(i => i + baseIdx));
|
|
138696
|
+
}
|
|
138697
|
+
};
|
|
138698
|
+
addPlane(false); // floor
|
|
138699
|
+
addPlane(true); // ceiling
|
|
138700
|
+
|
|
138701
|
+
|
|
138702
|
+
// sides
|
|
138703
|
+
for (let i = 0; i < baseVertices.length; ++i) {
|
|
138704
|
+
const a = baseVertices[i];
|
|
138705
|
+
const b = baseVertices[(i+1) % baseVertices.length];
|
|
138706
|
+
const f = altitude;
|
|
138707
|
+
const c = altitude + height;
|
|
138708
|
+
|
|
138709
|
+
const baseIdx = pos.length;
|
|
138710
|
+
|
|
138711
|
+
pos.push(
|
|
138712
|
+
[ a[0], f, a[1] ],
|
|
138713
|
+
[ b[0], f, b[1] ],
|
|
138714
|
+
[ b[0], c, b[1] ],
|
|
138715
|
+
[ a[0], c, a[1] ]
|
|
138716
|
+
);
|
|
138717
|
+
|
|
138718
|
+
ind.push(...[ 0, 1, 2, 0, 2, 3 ].map(i => i + baseIdx));
|
|
138719
|
+
}
|
|
138720
|
+
|
|
138721
|
+
|
|
138722
|
+
if (this._zoneMesh) {
|
|
138723
|
+
this._zoneMesh.destroy();
|
|
138724
|
+
}
|
|
138725
|
+
|
|
138726
|
+
|
|
138727
|
+
const positions = [].concat(...pos);
|
|
138728
|
+
this._zoneMesh = new Mesh(scene, {
|
|
138729
|
+
edges: this._edges,
|
|
138730
|
+
geometry: new ReadableGeometry(
|
|
138731
|
+
scene,
|
|
138732
|
+
{
|
|
138733
|
+
positions: positions,
|
|
138734
|
+
indices: ind,
|
|
138735
|
+
normals: math.buildNormals(positions, ind)
|
|
138736
|
+
}),
|
|
138737
|
+
material: new PhongMaterial(scene, {
|
|
138738
|
+
alpha: this._alpha,
|
|
138739
|
+
backfaces: true,
|
|
138740
|
+
diffuse: hex2rgb(this._color)
|
|
138741
|
+
}),
|
|
138742
|
+
visible: this._visible
|
|
138743
|
+
});
|
|
138744
|
+
this._zoneMesh.highlighted = this._highlighted;
|
|
138745
|
+
|
|
138746
|
+
this._zoneMesh.zone = this;
|
|
138747
|
+
|
|
138748
|
+
|
|
138749
|
+
const min = idx => Math.min(...pos.map(p => p[idx]));
|
|
138750
|
+
const max = idx => Math.max(...pos.map(p => p[idx]));
|
|
138751
|
+
|
|
138752
|
+
const xmin = min(0);
|
|
138753
|
+
const ymin = min(1);
|
|
138754
|
+
const zmin = min(2);
|
|
138755
|
+
const xmax = max(0);
|
|
138756
|
+
const ymax = max(1);
|
|
138757
|
+
const zmax = max(2);
|
|
138758
|
+
|
|
138759
|
+
this._center = math.vec3([ (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2 ]);
|
|
138760
|
+
}
|
|
138761
|
+
|
|
138762
|
+
sectionedAverage(sectionPlanes) {
|
|
138763
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138764
|
+
|
|
138765
|
+
let faces = [ ];
|
|
138766
|
+
{
|
|
138767
|
+
const h = this._geometry.height;
|
|
138768
|
+
const a = this._geometry.altitude;
|
|
138769
|
+
const c = a + Math.max(0, h);
|
|
138770
|
+
const f = a + Math.min(0, h);
|
|
138771
|
+
|
|
138772
|
+
const addPlane = (isCeiling) => {
|
|
138773
|
+
const face = planeCoords.map(p => [ p[0], isCeiling ? c : f, p[1] ]);
|
|
138774
|
+
faces.push(isCeiling ? face : face.slice(0).reverse());
|
|
138775
|
+
};
|
|
138776
|
+
addPlane(true); // ceiling
|
|
138777
|
+
addPlane(false); // floor
|
|
138778
|
+
|
|
138779
|
+
// sides
|
|
138780
|
+
const p = (idx, y) => [ planeCoords[idx][0], y, planeCoords[idx][1] ];
|
|
138781
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
138782
|
+
{
|
|
138783
|
+
const j = (i + 1) % planeCoords.length;
|
|
138784
|
+
faces.push([ p(i, f), p(j, f), p(j, c), p(i, c) ]);
|
|
138785
|
+
}
|
|
138786
|
+
}
|
|
138787
|
+
|
|
138788
|
+
for (const s of sectionPlanes)
|
|
138789
|
+
{
|
|
138790
|
+
const dir = s.dir;
|
|
138791
|
+
const dist = s.dist;
|
|
138792
|
+
const newFaces = [ ];
|
|
138793
|
+
|
|
138794
|
+
for (const face of faces)
|
|
138795
|
+
{
|
|
138796
|
+
const EPSILON = 1e-5;
|
|
138797
|
+
const COPLANAR = 0;
|
|
138798
|
+
const FRONT = 1;
|
|
138799
|
+
const BACK = 2;
|
|
138800
|
+
const SPANNING = 3;
|
|
138801
|
+
|
|
138802
|
+
// Classify each point as well as the entire polygon into one of the above four classes.
|
|
138803
|
+
let polygonType = 0;
|
|
138804
|
+
const types = [ ];
|
|
138805
|
+
for (let i = 0; i < face.length; i++) {
|
|
138806
|
+
const t = math.dotVec3(dir, face[i]) + dist;
|
|
138807
|
+
const type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR;
|
|
138808
|
+
polygonType |= type;
|
|
138809
|
+
types.push(type);
|
|
138810
|
+
}
|
|
138811
|
+
|
|
138812
|
+
// Put the polygon in the correct list, splitting it when necessary.
|
|
138813
|
+
switch (polygonType) {
|
|
138814
|
+
case COPLANAR:
|
|
138815
|
+
newFaces.push(face);
|
|
138816
|
+
break;
|
|
138817
|
+
case FRONT:
|
|
138818
|
+
newFaces.push(face);
|
|
138819
|
+
break;
|
|
138820
|
+
case BACK:
|
|
138821
|
+
break;
|
|
138822
|
+
case SPANNING:
|
|
138823
|
+
const f = [ ];
|
|
138824
|
+
for (let i = 0; i < face.length; i++)
|
|
138825
|
+
{
|
|
138826
|
+
var j = (i + 1) % face.length;
|
|
138827
|
+
const ti = types[i];
|
|
138828
|
+
const tj = types[j];
|
|
138829
|
+
const vi = face[i];
|
|
138830
|
+
const vj = face[j];
|
|
138831
|
+
if (ti !== BACK)
|
|
138832
|
+
{
|
|
138833
|
+
f.push(vi);
|
|
138834
|
+
}
|
|
138835
|
+
|
|
138836
|
+
if ((ti | tj) === SPANNING)
|
|
138837
|
+
{
|
|
138838
|
+
const diff = math.vec3();
|
|
138839
|
+
math.subVec3(vj, vi, diff);
|
|
138840
|
+
const t = - (dist + math.dotVec3(dir, vi)) / math.dotVec3(dir, diff);
|
|
138841
|
+
const v = [0,0,0];
|
|
138842
|
+
math.lerpVec3(t, 0, 1, vi, vj, v);
|
|
138843
|
+
f.push(v);
|
|
138844
|
+
}
|
|
138845
|
+
}
|
|
138846
|
+
if (f.length >= 3)
|
|
138847
|
+
{
|
|
138848
|
+
newFaces.push(f);
|
|
138849
|
+
}
|
|
138850
|
+
break;
|
|
138851
|
+
}
|
|
138852
|
+
}
|
|
138853
|
+
|
|
138854
|
+
faces = newFaces;
|
|
138855
|
+
}
|
|
138856
|
+
|
|
138857
|
+
if (faces.length === 0)
|
|
138858
|
+
{
|
|
138859
|
+
return null;
|
|
138860
|
+
}
|
|
138861
|
+
else
|
|
138862
|
+
{
|
|
138863
|
+
const avg = math.vec3([ 0, 0, 0 ]);
|
|
138864
|
+
const unique = new Set();
|
|
138865
|
+
|
|
138866
|
+
for (const f of faces)
|
|
138867
|
+
{
|
|
138868
|
+
for (const p of f)
|
|
138869
|
+
{
|
|
138870
|
+
const id = p.map(x => x.toFixed(3)).join(":");
|
|
138871
|
+
if (! (unique.has(id)))
|
|
138872
|
+
{
|
|
138873
|
+
unique.add(id);
|
|
138874
|
+
math.addVec3(avg, p, avg);
|
|
138875
|
+
}
|
|
138876
|
+
}
|
|
138877
|
+
}
|
|
138878
|
+
|
|
138879
|
+
math.mulVec3Scalar(avg, 1 / unique.size, avg);
|
|
138880
|
+
|
|
138881
|
+
return avg;
|
|
138882
|
+
}
|
|
138883
|
+
}
|
|
138884
|
+
|
|
138885
|
+
get center() {
|
|
138886
|
+
return this._center;
|
|
138887
|
+
}
|
|
138888
|
+
|
|
138889
|
+
get altitude() {
|
|
138890
|
+
return this._geometry.altitude;
|
|
138891
|
+
}
|
|
138892
|
+
|
|
138893
|
+
set altitude(value) {
|
|
138894
|
+
this._geometry.altitude = value;
|
|
138895
|
+
this._rebuildMesh();
|
|
138896
|
+
}
|
|
138897
|
+
|
|
138898
|
+
get height() {
|
|
138899
|
+
return this._geometry.height;
|
|
138900
|
+
}
|
|
138901
|
+
|
|
138902
|
+
set height(value) {
|
|
138903
|
+
this._geometry.height = value;
|
|
138904
|
+
this._rebuildMesh();
|
|
138905
|
+
}
|
|
138906
|
+
|
|
138907
|
+
get highlighted() {
|
|
138908
|
+
return this._highlighted;
|
|
138909
|
+
}
|
|
138910
|
+
|
|
138911
|
+
set highlighted(value)
|
|
138912
|
+
{
|
|
138913
|
+
this._highlighted = value;
|
|
138914
|
+
if (this._zoneMesh) {
|
|
138915
|
+
this._zoneMesh.highlighted = value;
|
|
138916
|
+
}
|
|
138917
|
+
}
|
|
138918
|
+
|
|
138919
|
+
set color(value) {
|
|
138920
|
+
this._color = value;
|
|
138921
|
+
if (this._zoneMesh) {
|
|
138922
|
+
this._zoneMesh.material.diffuse = hex2rgb(this._color);
|
|
138923
|
+
}
|
|
138924
|
+
}
|
|
138925
|
+
|
|
138926
|
+
get color() {
|
|
138927
|
+
return this._color;
|
|
138928
|
+
}
|
|
138929
|
+
|
|
138930
|
+
set alpha(value) {
|
|
138931
|
+
this._alpha = value;
|
|
138932
|
+
if (this._zoneMesh) {
|
|
138933
|
+
this._zoneMesh.material.alpha = this._alpha;
|
|
138934
|
+
}
|
|
138935
|
+
}
|
|
138936
|
+
|
|
138937
|
+
get alpha() {
|
|
138938
|
+
return this._alpha;
|
|
138939
|
+
}
|
|
138940
|
+
|
|
138941
|
+
get edges() {
|
|
138942
|
+
return this._edges;
|
|
138943
|
+
}
|
|
138944
|
+
|
|
138945
|
+
set edges(edges) {
|
|
138946
|
+
this._edges = edges;
|
|
138947
|
+
if (this._zoneMesh) {
|
|
138948
|
+
this._zoneMesh.edges = this._edges;
|
|
138949
|
+
}
|
|
138950
|
+
}
|
|
138951
|
+
|
|
138952
|
+
/**
|
|
138953
|
+
* Sets whether this Zone is visible or not.
|
|
138954
|
+
*
|
|
138955
|
+
* @type {Boolean}
|
|
138956
|
+
*/
|
|
138957
|
+
set visible(value) {
|
|
138958
|
+
this._visible = !!value;
|
|
138959
|
+
this._zoneMesh.visible = this._visible;
|
|
138960
|
+
this._needUpdate();
|
|
138961
|
+
}
|
|
138962
|
+
|
|
138963
|
+
/**
|
|
138964
|
+
* Gets whether this Zone is visible or not.
|
|
138965
|
+
*
|
|
138966
|
+
* @type {Boolean}
|
|
138967
|
+
*/
|
|
138968
|
+
get visible() {
|
|
138969
|
+
return this._visible;
|
|
138970
|
+
}
|
|
138971
|
+
|
|
138972
|
+
/**
|
|
138973
|
+
* Gets this Zone as JSON.
|
|
138974
|
+
*
|
|
138975
|
+
* @returns {JSON}
|
|
138976
|
+
*/
|
|
138977
|
+
|
|
138978
|
+
getJSON() {
|
|
138979
|
+
return {
|
|
138980
|
+
id: this.id,
|
|
138981
|
+
geometry: this._geometry,
|
|
138982
|
+
alpha: this._alpha,
|
|
138983
|
+
color: this._color
|
|
138984
|
+
};
|
|
138985
|
+
}
|
|
138986
|
+
|
|
138987
|
+
duplicate() {
|
|
138988
|
+
return this.plugin.createZone(
|
|
138989
|
+
{
|
|
138990
|
+
id: math.createUUID(),
|
|
138991
|
+
geometry: {
|
|
138992
|
+
planeCoordinates: this._geometry.planeCoordinates.map(c => c.slice()),
|
|
138993
|
+
altitude: this._geometry.altitude,
|
|
138994
|
+
height: this._geometry.height
|
|
138995
|
+
},
|
|
138996
|
+
alpha: this._alpha,
|
|
138997
|
+
color: this._color
|
|
138998
|
+
});
|
|
138999
|
+
}
|
|
139000
|
+
|
|
139001
|
+
/**
|
|
139002
|
+
* @private
|
|
139003
|
+
*/
|
|
139004
|
+
destroy() {
|
|
139005
|
+
this._zoneMesh.destroy();
|
|
139006
|
+
super.destroy();
|
|
139007
|
+
}
|
|
139008
|
+
}
|
|
139009
|
+
|
|
139010
|
+
/**
|
|
139011
|
+
* Creates {@link Zone}s in a {@link ZonesPlugin} from mouse input.
|
|
139012
|
+
*
|
|
139013
|
+
* ## Usage
|
|
139014
|
+
*
|
|
139015
|
+
* [[Run example](/examples/measurement/#distance_createWithMouse_snapping)]
|
|
139016
|
+
*
|
|
139017
|
+
* ````javascript
|
|
139018
|
+
* import {Viewer, XKTLoaderPlugin, ZonesPlugin, ZonesMouseControl} from "xeokit-sdk.es.js";
|
|
139019
|
+
*
|
|
139020
|
+
* const viewer = new Viewer({
|
|
139021
|
+
* canvasId: "myCanvas",
|
|
139022
|
+
* });
|
|
139023
|
+
*
|
|
139024
|
+
* viewer.camera.eye = [-3.93, 2.85, 27.01];
|
|
139025
|
+
* viewer.camera.look = [4.40, 3.72, 8.89];
|
|
139026
|
+
* viewer.camera.up = [-0.01, 0.99, 0.039];
|
|
139027
|
+
*
|
|
139028
|
+
* const xktLoader = new XKTLoaderPlugin(viewer);
|
|
139029
|
+
*
|
|
139030
|
+
* const sceneModel = xktLoader.load({
|
|
139031
|
+
* id: "myModel",
|
|
139032
|
+
* src: "Duplex.xkt"
|
|
139033
|
+
* });
|
|
139034
|
+
*
|
|
139035
|
+
* const zones = new ZonesPlugin(viewer);
|
|
139036
|
+
*
|
|
139037
|
+
* const zonesControl = new ZonesMouseControl(Zones)
|
|
139038
|
+
* ````
|
|
139039
|
+
*/
|
|
139040
|
+
class ZonesMouseControl extends Component {
|
|
139041
|
+
|
|
139042
|
+
/**
|
|
139043
|
+
* Creates a ZonesMouseControl bound to the given ZonesPlugin.
|
|
139044
|
+
*
|
|
139045
|
+
* @param {ZonesPlugin} zonesPlugin The ZonesPlugin to control.
|
|
139046
|
+
* @param [cfg] Configuration
|
|
139047
|
+
* @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor when snapping is enabled.
|
|
139048
|
+
*/
|
|
139049
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139050
|
+
super(zonesPlugin.viewer.scene);
|
|
139051
|
+
|
|
139052
|
+
this.zonesPlugin = zonesPlugin;
|
|
139053
|
+
this.pointerLens = cfg.pointerLens;
|
|
139054
|
+
this._deactivate = null;
|
|
139055
|
+
}
|
|
139056
|
+
|
|
139057
|
+
get active() {
|
|
139058
|
+
return !! this._deactivate;
|
|
139059
|
+
}
|
|
139060
|
+
|
|
139061
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139062
|
+
|
|
139063
|
+
if (this._deactivate) {
|
|
139064
|
+
return;
|
|
139065
|
+
}
|
|
139066
|
+
|
|
139067
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139068
|
+
const params = zoneAltitude;
|
|
139069
|
+
const param = (name, defaultValue) => {
|
|
139070
|
+
if (name in params) {
|
|
139071
|
+
return params[name];
|
|
139072
|
+
} else if (defaultValue !== undefined) {
|
|
139073
|
+
return defaultValue;
|
|
139074
|
+
} else {
|
|
139075
|
+
throw "config missing: " + name;
|
|
139076
|
+
}
|
|
139077
|
+
};
|
|
139078
|
+
|
|
139079
|
+
zoneAltitude = param("altitude");
|
|
139080
|
+
zoneHeight = param("height");
|
|
139081
|
+
zoneColor = param("color", "#008000");
|
|
139082
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139083
|
+
}
|
|
139084
|
+
|
|
139085
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139086
|
+
const viewer = zonesPlugin.viewer;
|
|
139087
|
+
const scene = viewer.scene;
|
|
139088
|
+
const self = this;
|
|
139089
|
+
|
|
139090
|
+
const select3dPoint = mousePointSelector(
|
|
139091
|
+
viewer,
|
|
139092
|
+
function(origin, direction) {
|
|
139093
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139094
|
+
});
|
|
139095
|
+
|
|
139096
|
+
(function rec() {
|
|
139097
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139098
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139099
|
+
zone => {
|
|
139100
|
+
let reactivate = true;
|
|
139101
|
+
self._deactivate = () => { reactivate = false; };
|
|
139102
|
+
self.fire("zoneEnd", zone);
|
|
139103
|
+
if (reactivate)
|
|
139104
|
+
{
|
|
139105
|
+
rec();
|
|
139106
|
+
}
|
|
139107
|
+
}).deactivate;
|
|
139108
|
+
})();
|
|
139109
|
+
}
|
|
139110
|
+
|
|
139111
|
+
deactivate() {
|
|
139112
|
+
if (this._deactivate)
|
|
139113
|
+
{
|
|
139114
|
+
this._deactivate();
|
|
139115
|
+
this._deactivate = null;
|
|
139116
|
+
}
|
|
139117
|
+
}
|
|
139118
|
+
|
|
139119
|
+
/**
|
|
139120
|
+
* Destroys this ZonesMouseControl.
|
|
139121
|
+
*
|
|
139122
|
+
* Destroys any {@link Zone} under construction by this ZonesMouseControl.
|
|
139123
|
+
*/
|
|
139124
|
+
destroy() {
|
|
139125
|
+
this.deactivate();
|
|
139126
|
+
super.destroy();
|
|
139127
|
+
}
|
|
139128
|
+
}
|
|
139129
|
+
|
|
139130
|
+
/**
|
|
139131
|
+
* ZonesPlugin documentation to be added, mostly compatible with DistanceMeasurementsPlugin.
|
|
139132
|
+
*/
|
|
139133
|
+
class ZonesPlugin extends Plugin {
|
|
139134
|
+
|
|
139135
|
+
/**
|
|
139136
|
+
* @constructor
|
|
139137
|
+
* @param {Viewer} viewer The Viewer.
|
|
139138
|
+
* @param {Object} [cfg] Plugin configuration.
|
|
139139
|
+
* @param {String} [cfg.id="Zones"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
|
|
139140
|
+
* @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
|
|
139141
|
+
* @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label.
|
|
139142
|
+
* @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels).
|
|
139143
|
+
* @param {PointerCircle} [cfg.pointerLens] A PointerLens to help the user position the pointer. This can be shared with other plugins.
|
|
139144
|
+
*/
|
|
139145
|
+
constructor(viewer, cfg = {}) {
|
|
139146
|
+
|
|
139147
|
+
super("Zones", viewer);
|
|
139148
|
+
|
|
139149
|
+
this._pointerLens = cfg.pointerLens;
|
|
139150
|
+
|
|
139151
|
+
this._container = cfg.container || document.body;
|
|
139152
|
+
|
|
139153
|
+
this._zones = [ ];
|
|
139154
|
+
|
|
139155
|
+
this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF";
|
|
139156
|
+
this.zIndex = cfg.zIndex || 10000;
|
|
139157
|
+
|
|
139158
|
+
this._onMouseOver = (event, zone) => {
|
|
139159
|
+
this.fire("mouseOver", {
|
|
139160
|
+
plugin: this,
|
|
139161
|
+
zone,
|
|
139162
|
+
event
|
|
139163
|
+
});
|
|
139164
|
+
};
|
|
139165
|
+
|
|
139166
|
+
this._onMouseLeave = (event, zone) => {
|
|
139167
|
+
this.fire("mouseLeave", {
|
|
139168
|
+
plugin: this,
|
|
139169
|
+
zone,
|
|
139170
|
+
event
|
|
139171
|
+
});
|
|
139172
|
+
};
|
|
139173
|
+
|
|
139174
|
+
this._onContextMenu = (event, zone) => {
|
|
139175
|
+
this.fire("contextMenu", {
|
|
139176
|
+
plugin: this,
|
|
139177
|
+
zone,
|
|
139178
|
+
event
|
|
139179
|
+
});
|
|
139180
|
+
};
|
|
139181
|
+
}
|
|
139182
|
+
|
|
139183
|
+
/**
|
|
139184
|
+
* Creates a {@link Zone}.
|
|
139185
|
+
*
|
|
139186
|
+
* The Zone is then registered by {@link Zone#id} in {@link ZonesPlugin#zones}.
|
|
139187
|
+
*
|
|
139188
|
+
* @param {Object} params {@link Zone} configuration.
|
|
139189
|
+
* @param {String} params.id Unique ID to assign to {@link Zone#id}. The Zone will be registered by this in {@link ZonesPlugin#zones} and {@link Scene.components}. Must be unique among all components in the {@link Viewer}.
|
|
139190
|
+
* @param {Number[]} params.origin.worldPos Origin World-space 3D position.
|
|
139191
|
+
* @param {Entity} params.origin.entity Origin Entity.
|
|
139192
|
+
* @param {Number[]} params.target.worldPos Target World-space 3D position.
|
|
139193
|
+
* @param {Entity} params.target.entity Target Entity.
|
|
139194
|
+
* @param {string} [params.color] The color of the length dot, wire and label.
|
|
139195
|
+
* @returns {Zone} The new {@link Zone}.
|
|
139196
|
+
*/
|
|
139197
|
+
createZone(params = {}) {
|
|
139198
|
+
if (this.viewer.scene.components[params.id]) {
|
|
139199
|
+
this.error("Viewer scene component with this ID already exists: " + params.id);
|
|
139200
|
+
delete params.id;
|
|
139201
|
+
}
|
|
139202
|
+
|
|
139203
|
+
const zone = new Zone(this, {
|
|
139204
|
+
id: params.id,
|
|
139205
|
+
plugin: this,
|
|
139206
|
+
container: this._container,
|
|
139207
|
+
geometry: params.geometry,
|
|
139208
|
+
alpha: params.alpha,
|
|
139209
|
+
color: params.color,
|
|
139210
|
+
onMouseOver: this._onMouseOver,
|
|
139211
|
+
onMouseLeave: this._onMouseLeave,
|
|
139212
|
+
onContextMenu: this._onContextMenu
|
|
139213
|
+
});
|
|
139214
|
+
this._zones.push(zone);
|
|
139215
|
+
zone.on("destroyed", () => {
|
|
139216
|
+
const idx = this._zones.indexOf(zone);
|
|
139217
|
+
if (idx >= 0) {
|
|
139218
|
+
this._zones.splice(idx, 1);
|
|
139219
|
+
}
|
|
139220
|
+
});
|
|
139221
|
+
this.fire("zoneCreated", zone);
|
|
139222
|
+
return zone;
|
|
139223
|
+
}
|
|
139224
|
+
|
|
139225
|
+
/**
|
|
139226
|
+
* Gets the existing {@link Zone}s, each mapped to its {@link Zone#id}.
|
|
139227
|
+
*
|
|
139228
|
+
* @type {{String:Zone}}
|
|
139229
|
+
*/
|
|
139230
|
+
get zones() {
|
|
139231
|
+
return this._zones;
|
|
139232
|
+
}
|
|
139233
|
+
|
|
139234
|
+
/**
|
|
139235
|
+
* Destroys this ZonesPlugin.
|
|
139236
|
+
*
|
|
139237
|
+
* Destroys all {@link Zone}s first.
|
|
139238
|
+
*/
|
|
139239
|
+
destroy() {
|
|
139240
|
+
super.destroy();
|
|
139241
|
+
}
|
|
139242
|
+
}
|
|
139243
|
+
|
|
139244
|
+
class ZonesTouchControl extends Component {
|
|
139245
|
+
|
|
139246
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139247
|
+
super(zonesPlugin.viewer.scene);
|
|
139248
|
+
|
|
139249
|
+
this.zonesPlugin = zonesPlugin;
|
|
139250
|
+
this.pointerLens = cfg.pointerLens;
|
|
139251
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139252
|
+
this._deactivate = null;
|
|
139253
|
+
}
|
|
139254
|
+
|
|
139255
|
+
get active() {
|
|
139256
|
+
return !! this._deactivate;
|
|
139257
|
+
}
|
|
139258
|
+
|
|
139259
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139260
|
+
|
|
139261
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139262
|
+
const params = zoneAltitude;
|
|
139263
|
+
const param = (name, defaultValue) => {
|
|
139264
|
+
if (name in params) {
|
|
139265
|
+
return params[name];
|
|
139266
|
+
} else if (defaultValue !== undefined) {
|
|
139267
|
+
return defaultValue;
|
|
139268
|
+
} else {
|
|
139269
|
+
throw "config missing: " + name;
|
|
139270
|
+
}
|
|
139271
|
+
};
|
|
139272
|
+
|
|
139273
|
+
zoneAltitude = param("altitude");
|
|
139274
|
+
zoneHeight = param("height");
|
|
139275
|
+
zoneColor = param("color", "#008000");
|
|
139276
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139277
|
+
}
|
|
139278
|
+
|
|
139279
|
+
if (this._deactivate) {
|
|
139280
|
+
return;
|
|
139281
|
+
}
|
|
139282
|
+
|
|
139283
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139284
|
+
const viewer = zonesPlugin.viewer;
|
|
139285
|
+
const scene = viewer.scene;
|
|
139286
|
+
const self = this;
|
|
139287
|
+
|
|
139288
|
+
const select3dPoint = touchPointSelector(
|
|
139289
|
+
viewer,
|
|
139290
|
+
this.pointerCircle,
|
|
139291
|
+
function(origin, direction) {
|
|
139292
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139293
|
+
});
|
|
139294
|
+
|
|
139295
|
+
(function rec() {
|
|
139296
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139297
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139298
|
+
zone => {
|
|
139299
|
+
let reactivate = true;
|
|
139300
|
+
self._deactivate = () => { reactivate = false; };
|
|
139301
|
+
self.fire("zoneEnd", zone);
|
|
139302
|
+
if (reactivate)
|
|
139303
|
+
{
|
|
139304
|
+
rec();
|
|
139305
|
+
}
|
|
139306
|
+
}).deactivate;
|
|
139307
|
+
})();
|
|
139308
|
+
}
|
|
139309
|
+
|
|
139310
|
+
deactivate() {
|
|
139311
|
+
if (this._deactivate)
|
|
139312
|
+
{
|
|
139313
|
+
this._deactivate();
|
|
139314
|
+
this._deactivate = null;
|
|
139315
|
+
}
|
|
139316
|
+
}
|
|
139317
|
+
|
|
139318
|
+
destroy() {
|
|
139319
|
+
this.deactivate();
|
|
139320
|
+
super.destroy();
|
|
139321
|
+
}
|
|
139322
|
+
}
|
|
139323
|
+
|
|
139324
|
+
const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
139325
|
+
const updatePointerLens = (pointerLens
|
|
139326
|
+
? function(canvasPos) {
|
|
139327
|
+
pointerLens.visible = !! canvasPos;
|
|
139328
|
+
if (canvasPos)
|
|
139329
|
+
{
|
|
139330
|
+
pointerLens.canvasPos = canvasPos;
|
|
139331
|
+
}
|
|
139332
|
+
}
|
|
139333
|
+
: () => { });
|
|
139334
|
+
|
|
139335
|
+
let deactivatePointSelection;
|
|
139336
|
+
const cleanups = [ () => updatePointerLens(null) ];
|
|
139337
|
+
|
|
139338
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
139339
|
+
cleanups.push(() => basePolygon.destroy());
|
|
139340
|
+
|
|
139341
|
+
(function selectNextPoint(markers) {
|
|
139342
|
+
const marker = marker3D(scene, zoneColor);
|
|
139343
|
+
const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
|
|
139344
|
+
|
|
139345
|
+
cleanups.push(() => {
|
|
139346
|
+
marker.destroy();
|
|
139347
|
+
wire && wire.destroy();
|
|
139348
|
+
});
|
|
139349
|
+
|
|
139350
|
+
const firstMarker = (markers.length > 0) && markers[0];
|
|
139351
|
+
const getSnappedFirst = function(canvasPos) {
|
|
139352
|
+
const firstCanvasPos = firstMarker && firstMarker.getCanvasPos();
|
|
139353
|
+
const snapToFirst = firstCanvasPos && (math.distVec2(firstCanvasPos, canvasPos) < 10);
|
|
139354
|
+
return snapToFirst && { canvasPos: firstCanvasPos, worldPos: firstMarker.getWorldPos() };
|
|
139355
|
+
};
|
|
139356
|
+
|
|
139357
|
+
const lastSegmentIntersects = (function() {
|
|
139358
|
+
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
139359
|
+
(q[0] >= Math.min(p[0], r[0])) &&
|
|
139360
|
+
(q[1] <= Math.max(p[1], r[1])) &&
|
|
139361
|
+
(q[1] >= Math.min(p[1], r[1])));
|
|
139362
|
+
|
|
139363
|
+
const orient = (p, q, r) => {
|
|
139364
|
+
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
139365
|
+
// collinear
|
|
139366
|
+
// clockwise
|
|
139367
|
+
// counterclockwise
|
|
139368
|
+
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
139369
|
+
};
|
|
139370
|
+
|
|
139371
|
+
return function(pos2D, excludeFirstSegment) {
|
|
139372
|
+
const a = pos2D[pos2D.length - 2];
|
|
139373
|
+
const b = pos2D[pos2D.length - 1];
|
|
139374
|
+
|
|
139375
|
+
for (let i = excludeFirstSegment ? 1 : 0; i < pos2D.length - 2 - 1; ++i)
|
|
139376
|
+
{
|
|
139377
|
+
const c = pos2D[i];
|
|
139378
|
+
const d = pos2D[i + 1];
|
|
139379
|
+
|
|
139380
|
+
const o1 = orient(a, b, c);
|
|
139381
|
+
const o2 = orient(a, b, d);
|
|
139382
|
+
const o3 = orient(c, d, a);
|
|
139383
|
+
const o4 = orient(c, d, b);
|
|
139384
|
+
|
|
139385
|
+
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
139386
|
+
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
139387
|
+
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
139388
|
+
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
139389
|
+
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
139390
|
+
{
|
|
139391
|
+
return true;
|
|
139392
|
+
}
|
|
139393
|
+
}
|
|
139394
|
+
|
|
139395
|
+
return false;
|
|
139396
|
+
};
|
|
139397
|
+
})();
|
|
139398
|
+
|
|
139399
|
+
deactivatePointSelection = select3dPoint(
|
|
139400
|
+
() => {
|
|
139401
|
+
updatePointerLens(null);
|
|
139402
|
+
marker.update(null);
|
|
139403
|
+
wire && wire.update(null);
|
|
139404
|
+
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
139405
|
+
},
|
|
139406
|
+
(canvasPos, worldPos) => {
|
|
139407
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139408
|
+
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
139409
|
+
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
139410
|
+
marker.update((! snappedFirst) && worldPos);
|
|
139411
|
+
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
139412
|
+
if ((markers.length >= 2))
|
|
139413
|
+
{
|
|
139414
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139415
|
+
const inter = lastSegmentIntersects(pos.map(p => [ p[0], p[2] ]), snappedFirst);
|
|
139416
|
+
basePolygon.updateBase(inter ? null : pos);
|
|
139417
|
+
}
|
|
139418
|
+
else
|
|
139419
|
+
basePolygon.updateBase(null);
|
|
139420
|
+
},
|
|
139421
|
+
function(canvasPos, worldPos) {
|
|
139422
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139423
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139424
|
+
basePolygon.updateBase(pos);
|
|
139425
|
+
const pos2D = pos.map(p => [ p[0], p[2] ]);
|
|
139426
|
+
if ((markers.length > 2) && lastSegmentIntersects(pos2D, snappedFirst))
|
|
139427
|
+
{
|
|
139428
|
+
cleanups.pop()();
|
|
139429
|
+
selectNextPoint(markers);
|
|
139430
|
+
}
|
|
139431
|
+
else if (snappedFirst)
|
|
139432
|
+
{
|
|
139433
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
139434
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
139435
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
139436
|
+
marker.update(worldPos);
|
|
139437
|
+
|
|
139438
|
+
cleanups.forEach(c => c());
|
|
139439
|
+
onZoneCreated(
|
|
139440
|
+
zonesPlugin.createZone(
|
|
139441
|
+
{
|
|
139442
|
+
id: math.createUUID(),
|
|
139443
|
+
geometry: {
|
|
139444
|
+
planeCoordinates: pos2D,
|
|
139445
|
+
altitude: zoneAltitude,
|
|
139446
|
+
height: zoneHeight
|
|
139447
|
+
},
|
|
139448
|
+
alpha: zoneAlpha,
|
|
139449
|
+
color: zoneColor
|
|
139450
|
+
}));
|
|
139451
|
+
}
|
|
139452
|
+
else
|
|
139453
|
+
{
|
|
139454
|
+
marker.update(worldPos);
|
|
139455
|
+
wire && wire.update(worldPos);
|
|
139456
|
+
selectNextPoint(markers.concat(marker));
|
|
139457
|
+
}
|
|
139458
|
+
});
|
|
139459
|
+
})([ ]);
|
|
139460
|
+
|
|
139461
|
+
return {
|
|
139462
|
+
closeSurface: function() {
|
|
139463
|
+
throw "TODO";
|
|
139464
|
+
},
|
|
139465
|
+
deactivate: function() {
|
|
139466
|
+
deactivatePointSelection();
|
|
139467
|
+
cleanups.forEach(c => c());
|
|
139468
|
+
}
|
|
139469
|
+
};
|
|
139470
|
+
};
|
|
139471
|
+
|
|
139472
|
+
class ZonesPolysurfaceMouseControl extends Component {
|
|
139473
|
+
|
|
139474
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139475
|
+
super(zonesPlugin.viewer.scene);
|
|
139476
|
+
|
|
139477
|
+
this.zonesPlugin = zonesPlugin;
|
|
139478
|
+
this.pointerLens = cfg.pointerLens;
|
|
139479
|
+
this._action = null;
|
|
139480
|
+
}
|
|
139481
|
+
|
|
139482
|
+
get active() {
|
|
139483
|
+
return !! this._action;
|
|
139484
|
+
}
|
|
139485
|
+
|
|
139486
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139487
|
+
|
|
139488
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139489
|
+
const params = zoneAltitude;
|
|
139490
|
+
const param = (name, defaultValue) => {
|
|
139491
|
+
if (name in params) {
|
|
139492
|
+
return params[name];
|
|
139493
|
+
} else if (defaultValue !== undefined) {
|
|
139494
|
+
return defaultValue;
|
|
139495
|
+
} else {
|
|
139496
|
+
throw "config missing: " + name;
|
|
139497
|
+
}
|
|
139498
|
+
};
|
|
139499
|
+
|
|
139500
|
+
zoneAltitude = param("altitude");
|
|
139501
|
+
zoneHeight = param("height");
|
|
139502
|
+
zoneColor = param("color", "#008000");
|
|
139503
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139504
|
+
}
|
|
139505
|
+
|
|
139506
|
+
if (this._action) {
|
|
139507
|
+
return;
|
|
139508
|
+
}
|
|
139509
|
+
|
|
139510
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139511
|
+
const viewer = zonesPlugin.viewer;
|
|
139512
|
+
const scene = viewer.scene;
|
|
139513
|
+
const self = this;
|
|
139514
|
+
|
|
139515
|
+
const select3dPoint = mousePointSelector(
|
|
139516
|
+
viewer,
|
|
139517
|
+
function(origin, direction) {
|
|
139518
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139519
|
+
});
|
|
139520
|
+
|
|
139521
|
+
(function rec() {
|
|
139522
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139523
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139524
|
+
zone => {
|
|
139525
|
+
let reactivate = true;
|
|
139526
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139527
|
+
self.fire("zoneEnd", zone);
|
|
139528
|
+
if (reactivate)
|
|
139529
|
+
{
|
|
139530
|
+
rec();
|
|
139531
|
+
}
|
|
139532
|
+
});
|
|
139533
|
+
})();
|
|
139534
|
+
}
|
|
139535
|
+
|
|
139536
|
+
deactivate() {
|
|
139537
|
+
if (this._action)
|
|
139538
|
+
{
|
|
139539
|
+
this._action.deactivate();
|
|
139540
|
+
this._action = null;
|
|
139541
|
+
}
|
|
139542
|
+
}
|
|
139543
|
+
|
|
139544
|
+
destroy() {
|
|
139545
|
+
this.deactivate();
|
|
139546
|
+
super.destroy();
|
|
139547
|
+
}
|
|
139548
|
+
}
|
|
139549
|
+
|
|
139550
|
+
class ZonesPolysurfaceTouchControl extends Component {
|
|
139551
|
+
|
|
139552
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139553
|
+
super(zonesPlugin.viewer.scene);
|
|
139554
|
+
|
|
139555
|
+
this.zonesPlugin = zonesPlugin;
|
|
139556
|
+
this.pointerLens = cfg.pointerLens;
|
|
139557
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139558
|
+
this._action = null;
|
|
139559
|
+
}
|
|
139560
|
+
|
|
139561
|
+
get active() {
|
|
139562
|
+
return !! this._action;
|
|
139563
|
+
}
|
|
139564
|
+
|
|
139565
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139566
|
+
|
|
139567
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139568
|
+
const params = zoneAltitude;
|
|
139569
|
+
const param = (name, defaultValue) => {
|
|
139570
|
+
if (name in params) {
|
|
139571
|
+
return params[name];
|
|
139572
|
+
} else if (defaultValue !== undefined) {
|
|
139573
|
+
return defaultValue;
|
|
139574
|
+
} else {
|
|
139575
|
+
throw "config missing: " + name;
|
|
139576
|
+
}
|
|
139577
|
+
};
|
|
139578
|
+
|
|
139579
|
+
zoneAltitude = param("altitude");
|
|
139580
|
+
zoneHeight = param("height");
|
|
139581
|
+
zoneColor = param("color", "#008000");
|
|
139582
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139583
|
+
}
|
|
139584
|
+
|
|
139585
|
+
if (this._action) {
|
|
139586
|
+
return;
|
|
139587
|
+
}
|
|
139588
|
+
|
|
139589
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139590
|
+
const viewer = zonesPlugin.viewer;
|
|
139591
|
+
const scene = viewer.scene;
|
|
139592
|
+
const self = this;
|
|
139593
|
+
|
|
139594
|
+
const select3dPoint = touchPointSelector(
|
|
139595
|
+
viewer,
|
|
139596
|
+
this.pointerCircle,
|
|
139597
|
+
function(origin, direction) {
|
|
139598
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139599
|
+
});
|
|
139600
|
+
|
|
139601
|
+
(function rec() {
|
|
139602
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139603
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139604
|
+
zone => {
|
|
139605
|
+
let reactivate = true;
|
|
139606
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139607
|
+
self.fire("zoneEnd", zone);
|
|
139608
|
+
if (reactivate)
|
|
139609
|
+
{
|
|
139610
|
+
rec();
|
|
139611
|
+
}
|
|
139612
|
+
});
|
|
139613
|
+
})();
|
|
139614
|
+
}
|
|
139615
|
+
|
|
139616
|
+
deactivate() {
|
|
139617
|
+
if (this._action)
|
|
139618
|
+
{
|
|
139619
|
+
this._action.deactivate();
|
|
139620
|
+
this._action = null;
|
|
139621
|
+
}
|
|
139622
|
+
}
|
|
139623
|
+
|
|
139624
|
+
destroy() {
|
|
139625
|
+
this.deactivate();
|
|
139626
|
+
super.destroy();
|
|
139627
|
+
}
|
|
139628
|
+
}
|
|
139629
|
+
|
|
139630
|
+
class ZoneEditControl extends Component {
|
|
139631
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139632
|
+
super(zone.plugin.viewer.scene);
|
|
139633
|
+
const self = this;
|
|
139634
|
+
|
|
139635
|
+
const altitude = zone._geometry.altitude;
|
|
139636
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139637
|
+
const updatePointerLens = (pointerLens
|
|
139638
|
+
? function(canvasPos) {
|
|
139639
|
+
pointerLens.visible = !! canvasPos;
|
|
139640
|
+
if (canvasPos)
|
|
139641
|
+
{
|
|
139642
|
+
pointerLens.canvasPos = canvasPos;
|
|
139643
|
+
}
|
|
139644
|
+
}
|
|
139645
|
+
: () => { });
|
|
139646
|
+
|
|
139647
|
+
const dots = zone._geometry.planeCoordinates.map(planeCoord => {
|
|
139648
|
+
let initWorldPos, initPlaneCoord;
|
|
139649
|
+
const setPlaneCoord = function(coord) {
|
|
139650
|
+
planeCoord[0] = coord[0];
|
|
139651
|
+
planeCoord[1] = coord[1];
|
|
139652
|
+
try {
|
|
139653
|
+
zone._rebuildMesh();
|
|
139654
|
+
} catch (e) {
|
|
139655
|
+
if (zone._zoneMesh) {
|
|
139656
|
+
zone._zoneMesh.destroy();
|
|
139657
|
+
zone._zoneMesh = null;
|
|
139658
|
+
}
|
|
139659
|
+
}
|
|
139660
|
+
};
|
|
139661
|
+
|
|
139662
|
+
const dot = draggableDot3D(
|
|
139663
|
+
handleMouseEvents,
|
|
139664
|
+
handleTouchEvents,
|
|
139665
|
+
zone.plugin.viewer,
|
|
139666
|
+
math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
|
|
139667
|
+
zone._color,
|
|
139668
|
+
(orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
|
|
139669
|
+
() => {
|
|
139670
|
+
initWorldPos = dot.getWorldPos().slice();
|
|
139671
|
+
initPlaneCoord = planeCoord.slice();
|
|
139672
|
+
set_other_dots_active(false, dot);
|
|
139673
|
+
},
|
|
139674
|
+
(canvasPos, worldPos) => {
|
|
139675
|
+
updatePointerLens(canvasPos);
|
|
139676
|
+
setPlaneCoord([ worldPos[0], worldPos[2] ]);
|
|
139677
|
+
},
|
|
139678
|
+
() => {
|
|
139679
|
+
if (zone._zoneMesh)
|
|
139680
|
+
{
|
|
139681
|
+
self.fire("edited");
|
|
139682
|
+
}
|
|
139683
|
+
else
|
|
139684
|
+
{
|
|
139685
|
+
dot.setWorldPos(initWorldPos);
|
|
139686
|
+
setPlaneCoord(initPlaneCoord);
|
|
139687
|
+
}
|
|
139688
|
+
updatePointerLens(null);
|
|
139689
|
+
set_other_dots_active(true, dot);
|
|
139690
|
+
});
|
|
139691
|
+
return dot;
|
|
139692
|
+
});
|
|
139693
|
+
const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
|
|
139694
|
+
set_other_dots_active(true);
|
|
139695
|
+
|
|
139696
|
+
const cleanup = function() {
|
|
139697
|
+
dots.forEach(m => m.destroy());
|
|
139698
|
+
updatePointerLens(null);
|
|
139699
|
+
};
|
|
139700
|
+
|
|
139701
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139702
|
+
|
|
139703
|
+
this._deactivate = function() {
|
|
139704
|
+
zone.off("destroyed", destroyCb);
|
|
139705
|
+
cleanup();
|
|
139706
|
+
};
|
|
139707
|
+
}
|
|
139708
|
+
|
|
139709
|
+
deactivate() {
|
|
139710
|
+
this._deactivate();
|
|
139711
|
+
super.destroy();
|
|
139712
|
+
}
|
|
139713
|
+
}
|
|
139714
|
+
|
|
139715
|
+
class ZoneEditMouseControl extends ZoneEditControl {
|
|
139716
|
+
constructor(zone, cfg) {
|
|
139717
|
+
super(zone, cfg, true, false);
|
|
139718
|
+
}
|
|
139719
|
+
}
|
|
139720
|
+
|
|
139721
|
+
class ZoneEditTouchControl extends ZoneEditControl {
|
|
139722
|
+
constructor(zone, cfg) {
|
|
139723
|
+
super(zone, cfg, false, true);
|
|
139724
|
+
}
|
|
139725
|
+
}
|
|
139726
|
+
|
|
139727
|
+
|
|
139728
|
+
class ZoneTranslateControl extends Component {
|
|
139729
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139730
|
+
const viewer = zone.plugin.viewer;
|
|
139731
|
+
const scene = viewer.scene;
|
|
139732
|
+
const canvas = scene.canvas.canvas;
|
|
139733
|
+
|
|
139734
|
+
super(scene);
|
|
139735
|
+
const self = this;
|
|
139736
|
+
|
|
139737
|
+
const altitude = zone._geometry.altitude;
|
|
139738
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139739
|
+
const updatePointerLens = (pointerLens
|
|
139740
|
+
? function(canvasPos) {
|
|
139741
|
+
pointerLens.visible = !! canvasPos;
|
|
139742
|
+
if (canvasPos)
|
|
139743
|
+
{
|
|
139744
|
+
pointerLens.canvasPos = canvasPos;
|
|
139745
|
+
}
|
|
139746
|
+
}
|
|
139747
|
+
: () => { });
|
|
139748
|
+
|
|
139749
|
+
const ray2WorldPos = (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir);
|
|
139750
|
+
|
|
139751
|
+
const pickWorldPos = canvasPos => {
|
|
139752
|
+
const origin = math.vec3();
|
|
139753
|
+
const direction = math.vec3();
|
|
139754
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
139755
|
+
return ray2WorldPos(origin, direction);
|
|
139756
|
+
};
|
|
139757
|
+
|
|
139758
|
+
const copyCanvasPos = (event, vec2) => {
|
|
139759
|
+
vec2[0] = event.clientX;
|
|
139760
|
+
vec2[1] = event.clientY;
|
|
139761
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
139762
|
+
return vec2;
|
|
139763
|
+
};
|
|
139764
|
+
|
|
139765
|
+
const canvasHandle = function(type, cb) {
|
|
139766
|
+
const callback = event => {
|
|
139767
|
+
event.preventDefault();
|
|
139768
|
+
cb(event);
|
|
139769
|
+
};
|
|
139770
|
+
canvas.addEventListener(type, callback);
|
|
139771
|
+
return () => canvas.removeEventListener(type, callback);
|
|
139772
|
+
};
|
|
139773
|
+
|
|
139774
|
+
let cleanupCurrentDrag = () => { };
|
|
139775
|
+
|
|
139776
|
+
const startDrag = function(event, onMoveType, onEndType, matchesEvent) {
|
|
139777
|
+
const e = matchesEvent(event);
|
|
139778
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139779
|
+
const pickRecord = viewer.scene.pick({ canvasPos: canvasPos, includeEntities: [ zone._zoneMesh.id ] });
|
|
139780
|
+
const pickZone = pickRecord && pickRecord.entity && pickRecord.entity.zone;
|
|
139781
|
+
|
|
139782
|
+
if (pickZone === zone)
|
|
139783
|
+
{
|
|
139784
|
+
cleanupCurrentDrag();
|
|
139785
|
+
|
|
139786
|
+
canvas.style.cursor = "move";
|
|
139787
|
+
viewer.cameraControl.active = false;
|
|
139788
|
+
|
|
139789
|
+
const onChange = (function() {
|
|
139790
|
+
const initCoords = zone._geometry.planeCoordinates.map(c => c.slice());
|
|
139791
|
+
const initWorldPos = pickWorldPos(canvasPos);
|
|
139792
|
+
const initDragCoord = math.vec2([ initWorldPos[0], initWorldPos[2] ]);
|
|
139793
|
+
const dPos = math.vec2();
|
|
139794
|
+
|
|
139795
|
+
return function(canvasPos) {
|
|
139796
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
139797
|
+
dPos[0] = worldPos[0];
|
|
139798
|
+
dPos[1] = worldPos[2];
|
|
139799
|
+
math.subVec2(initDragCoord, dPos, dPos);
|
|
139800
|
+
|
|
139801
|
+
zone._geometry.planeCoordinates.forEach((planeCoord, idx) => {
|
|
139802
|
+
math.subVec2(initCoords[idx], dPos, planeCoord);
|
|
139803
|
+
});
|
|
139804
|
+
|
|
139805
|
+
try {
|
|
139806
|
+
zone._rebuildMesh();
|
|
139807
|
+
} catch (e) {
|
|
139808
|
+
if (zone._zoneMesh) {
|
|
139809
|
+
zone._zoneMesh.destroy();
|
|
139810
|
+
zone._zoneMesh = null;
|
|
139811
|
+
}
|
|
139812
|
+
}
|
|
139813
|
+
};
|
|
139814
|
+
})();
|
|
139815
|
+
|
|
139816
|
+
const cleanupMove = canvasHandle(
|
|
139817
|
+
onMoveType,
|
|
139818
|
+
function(event) {
|
|
139819
|
+
const e = matchesEvent(event);
|
|
139820
|
+
if (e)
|
|
139821
|
+
{
|
|
139822
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139823
|
+
onChange(canvasPos);
|
|
139824
|
+
updatePointerLens(canvasPos);
|
|
139825
|
+
}
|
|
139826
|
+
});
|
|
139827
|
+
|
|
139828
|
+
const cleanupEnd = canvasHandle(
|
|
139829
|
+
onEndType,
|
|
139830
|
+
function(event) {
|
|
139831
|
+
const e = matchesEvent(event);
|
|
139832
|
+
if (e)
|
|
139833
|
+
{
|
|
139834
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139835
|
+
onChange(canvasPos);
|
|
139836
|
+
updatePointerLens(null);
|
|
139837
|
+
cleanupCurrentDrag();
|
|
139838
|
+
self.fire("translated");
|
|
139839
|
+
}
|
|
139840
|
+
});
|
|
139841
|
+
|
|
139842
|
+
cleanupCurrentDrag = function() {
|
|
139843
|
+
cleanupCurrentDrag = () => { };
|
|
139844
|
+
canvas.style.cursor = "default";
|
|
139845
|
+
viewer.cameraControl.active = true;
|
|
139846
|
+
cleanupMove();
|
|
139847
|
+
cleanupEnd();
|
|
139848
|
+
};
|
|
139849
|
+
}
|
|
139850
|
+
};
|
|
139851
|
+
|
|
139852
|
+
const startDragCbs = [ ];
|
|
139853
|
+
|
|
139854
|
+
if (handleMouseEvents) {
|
|
139855
|
+
startDragCbs.push(
|
|
139856
|
+
canvasHandle("mousedown", event => {
|
|
139857
|
+
if (event.which === 1) {
|
|
139858
|
+
startDrag(
|
|
139859
|
+
event,
|
|
139860
|
+
"mousemove",
|
|
139861
|
+
"mouseup",
|
|
139862
|
+
event => (event.which === 1) && event);
|
|
139863
|
+
}
|
|
139864
|
+
}));
|
|
139865
|
+
}
|
|
139866
|
+
|
|
139867
|
+
if (handleTouchEvents) {
|
|
139868
|
+
startDragCbs.push(
|
|
139869
|
+
canvasHandle("touchstart", event => {
|
|
139870
|
+
if (event.touches.length === 1) {
|
|
139871
|
+
const touchStartId = event.touches[0].identifier;
|
|
139872
|
+
startDrag(
|
|
139873
|
+
event,
|
|
139874
|
+
"touchmove",
|
|
139875
|
+
"touchend",
|
|
139876
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId));
|
|
139877
|
+
}
|
|
139878
|
+
}));
|
|
139879
|
+
}
|
|
139880
|
+
|
|
139881
|
+
const cleanup = function() {
|
|
139882
|
+
cleanupCurrentDrag();
|
|
139883
|
+
startDragCbs.forEach(cb => cb());
|
|
139884
|
+
updatePointerLens(null);
|
|
139885
|
+
};
|
|
139886
|
+
|
|
139887
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139888
|
+
|
|
139889
|
+
this._deactivate = function() {
|
|
139890
|
+
zone.off("destroyed", destroyCb);
|
|
139891
|
+
cleanup();
|
|
139892
|
+
};
|
|
139893
|
+
}
|
|
139894
|
+
|
|
139895
|
+
deactivate() {
|
|
139896
|
+
this._deactivate();
|
|
139897
|
+
super.destroy();
|
|
139898
|
+
}
|
|
139899
|
+
}
|
|
139900
|
+
|
|
139901
|
+
class ZoneTranslateMouseControl extends ZoneTranslateControl {
|
|
139902
|
+
constructor(zone, cfg) {
|
|
139903
|
+
super(zone, cfg, true, false);
|
|
139904
|
+
}
|
|
139905
|
+
}
|
|
139906
|
+
|
|
139907
|
+
class ZoneTranslateTouchControl extends ZoneTranslateControl {
|
|
139908
|
+
constructor(zone, cfg) {
|
|
139909
|
+
super(zone, cfg, false, true);
|
|
139910
|
+
}
|
|
139911
|
+
}
|
|
139912
|
+
|
|
137702
139913
|
exports.AlphaFormat = AlphaFormat;
|
|
137703
139914
|
exports.AmbientLight = AmbientLight;
|
|
137704
139915
|
exports.AngleMeasurementsControl = AngleMeasurementsControl;
|
|
@@ -137858,6 +140069,17 @@ exports.WorkerPool = WorkerPool$1;
|
|
|
137858
140069
|
exports.XKTDefaultDataSource = XKTDefaultDataSource;
|
|
137859
140070
|
exports.XKTLoaderPlugin = XKTLoaderPlugin;
|
|
137860
140071
|
exports.XML3DLoaderPlugin = XML3DLoaderPlugin;
|
|
140072
|
+
exports.ZoneEditControl = ZoneEditControl;
|
|
140073
|
+
exports.ZoneEditMouseControl = ZoneEditMouseControl;
|
|
140074
|
+
exports.ZoneEditTouchControl = ZoneEditTouchControl;
|
|
140075
|
+
exports.ZoneTranslateControl = ZoneTranslateControl;
|
|
140076
|
+
exports.ZoneTranslateMouseControl = ZoneTranslateMouseControl;
|
|
140077
|
+
exports.ZoneTranslateTouchControl = ZoneTranslateTouchControl;
|
|
140078
|
+
exports.ZonesMouseControl = ZonesMouseControl;
|
|
140079
|
+
exports.ZonesPlugin = ZonesPlugin;
|
|
140080
|
+
exports.ZonesPolysurfaceMouseControl = ZonesPolysurfaceMouseControl;
|
|
140081
|
+
exports.ZonesPolysurfaceTouchControl = ZonesPolysurfaceTouchControl;
|
|
140082
|
+
exports.ZonesTouchControl = ZonesTouchControl;
|
|
137861
140083
|
exports.buildBoxGeometry = buildBoxGeometry;
|
|
137862
140084
|
exports.buildBoxLinesGeometry = buildBoxLinesGeometry;
|
|
137863
140085
|
exports.buildBoxLinesGeometryFromAABB = buildBoxLinesGeometryFromAABB;
|