@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.es.js
CHANGED
|
@@ -1118,8 +1118,8 @@ class PointerLens {
|
|
|
1118
1118
|
);
|
|
1119
1119
|
|
|
1120
1120
|
const centerLensCanvas = [
|
|
1121
|
-
(lensRect.left + lensRect.right) / 2,
|
|
1122
|
-
(lensRect.top + lensRect.bottom) / 2
|
|
1121
|
+
(lensRect.left + lensRect.right) / 2 - canvasRect.left,
|
|
1122
|
+
(lensRect.top + lensRect.bottom) / 2 - canvasRect.top
|
|
1123
1123
|
];
|
|
1124
1124
|
|
|
1125
1125
|
if (this._snappedCanvasPos) {
|
|
@@ -10759,7 +10759,7 @@ class Marker extends Component {
|
|
|
10759
10759
|
this.scene.camera.off(this._onCameraProjMatrix);
|
|
10760
10760
|
if (this._entity) {
|
|
10761
10761
|
if (this._onEntityDestroyed !== null) {
|
|
10762
|
-
this._entity.off(this._onEntityDestroyed);
|
|
10762
|
+
this._entity.model.off(this._onEntityDestroyed);
|
|
10763
10763
|
}
|
|
10764
10764
|
if (this._onEntityModelDestroyed !== null) {
|
|
10765
10765
|
this._entity.model.off(this._onEntityModelDestroyed);
|
|
@@ -11159,7 +11159,25 @@ class Dot {
|
|
|
11159
11159
|
}
|
|
11160
11160
|
|
|
11161
11161
|
}
|
|
11162
|
-
|
|
11162
|
+
|
|
11163
|
+
if (cfg.onTouchstart) {
|
|
11164
|
+
dotClickable.addEventListener('touchstart', (event) => {
|
|
11165
|
+
cfg.onTouchstart(event, this);
|
|
11166
|
+
});
|
|
11167
|
+
}
|
|
11168
|
+
|
|
11169
|
+
if (cfg.onTouchmove) {
|
|
11170
|
+
dotClickable.addEventListener('touchmove', (event) => {
|
|
11171
|
+
cfg.onTouchmove(event, this);
|
|
11172
|
+
});
|
|
11173
|
+
}
|
|
11174
|
+
|
|
11175
|
+
if (cfg.onTouchend) {
|
|
11176
|
+
dotClickable.addEventListener('touchend', (event) => {
|
|
11177
|
+
cfg.onTouchend(event, this);
|
|
11178
|
+
});
|
|
11179
|
+
}
|
|
11180
|
+
|
|
11163
11181
|
this.setPos(cfg.x || 0, cfg.y || 0);
|
|
11164
11182
|
this.setFillColor(cfg.fillColor);
|
|
11165
11183
|
this.setBorderColor(cfg.borderColor);
|
|
@@ -14427,6 +14445,7 @@ class Annotation extends Marker {
|
|
|
14427
14445
|
if (this._marker) {
|
|
14428
14446
|
if (!this._markerExternal) {
|
|
14429
14447
|
this._marker.parentNode.removeChild(this._marker);
|
|
14448
|
+
this._marker = null;
|
|
14430
14449
|
} else {
|
|
14431
14450
|
this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
|
|
14432
14451
|
this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
|
|
@@ -17055,7 +17074,7 @@ class OcclusionLayer {
|
|
|
17055
17074
|
_buildVBOs() {
|
|
17056
17075
|
if (this.positionsBuf) {
|
|
17057
17076
|
if (this.lenPositionsBuf === this.positions.length) { // Just updating buffer elements, don't need to reallocate
|
|
17058
|
-
this.positionsBuf.setData(this.positions); // Indices don't need updating
|
|
17077
|
+
this.positionsBuf.setData(new Float32Array(this.positions)); // Indices don't need updating
|
|
17059
17078
|
return;
|
|
17060
17079
|
}
|
|
17061
17080
|
this.positionsBuf.destroy();
|
|
@@ -17144,7 +17163,6 @@ class OcclusionLayer {
|
|
|
17144
17163
|
|
|
17145
17164
|
const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]);
|
|
17146
17165
|
const POINT_SIZE = 20;
|
|
17147
|
-
const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces
|
|
17148
17166
|
|
|
17149
17167
|
const tempVec3a$J = math.vec3();
|
|
17150
17168
|
|
|
@@ -17225,7 +17243,7 @@ class OcclusionTester {
|
|
|
17225
17243
|
let newOcclusionLayer = this._occlusionLayers[originHash];
|
|
17226
17244
|
if (!newOcclusionLayer) {
|
|
17227
17245
|
newOcclusionLayer = new OcclusionLayer(this._scene, marker.origin);
|
|
17228
|
-
this._occlusionLayers[originHash] =
|
|
17246
|
+
this._occlusionLayers[originHash] = newOcclusionLayer;
|
|
17229
17247
|
this._occlusionLayersListDirty = true;
|
|
17230
17248
|
}
|
|
17231
17249
|
newOcclusionLayer.addMarker(marker);
|
|
@@ -17355,7 +17373,9 @@ class OcclusionTester {
|
|
|
17355
17373
|
if (scene.logarithmicDepthBufferEnabled) {
|
|
17356
17374
|
src.push("vFragDepth = 1.0 + clipPos.w;");
|
|
17357
17375
|
} else {
|
|
17358
|
-
|
|
17376
|
+
if (scene.markerZOffset < 0.000) {
|
|
17377
|
+
src.push("clipPos.z += " + scene.markerZOffset + ";");
|
|
17378
|
+
}
|
|
17359
17379
|
}
|
|
17360
17380
|
src.push(" gl_Position = clipPos;");
|
|
17361
17381
|
src.push("}");
|
|
@@ -17469,7 +17489,10 @@ class OcclusionTester {
|
|
|
17469
17489
|
continue;
|
|
17470
17490
|
}
|
|
17471
17491
|
|
|
17472
|
-
|
|
17492
|
+
// The `origin` has been changed from `occlusionLayer.origin` to `[ 0, 0, 0 ]`
|
|
17493
|
+
// because OcclusionLayer markers' transformation is being applied through the
|
|
17494
|
+
// OcclusionLayer::positions array. See XEOK-33
|
|
17495
|
+
const origin = [ 0, 0, 0 ];
|
|
17473
17496
|
|
|
17474
17497
|
gl.uniformMatrix4fv(this._uViewMatrix, false, createRTCViewMat(camera.viewMatrix, origin));
|
|
17475
17498
|
|
|
@@ -19619,7 +19642,7 @@ const Renderer$1 = function (scene, options) {
|
|
|
19619
19642
|
math.cross3Vec3(worldRayDir, randomVec3, up);
|
|
19620
19643
|
|
|
19621
19644
|
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
19622
|
-
|
|
19645
|
+
// pickProjMatrix = scene.camera.projMatrix;
|
|
19623
19646
|
pickProjMatrix = scene.camera.ortho.matrix;
|
|
19624
19647
|
|
|
19625
19648
|
pickResult.origin = worldRayOrigin;
|
|
@@ -21606,6 +21629,14 @@ class Input extends Component {
|
|
|
21606
21629
|
}
|
|
21607
21630
|
});
|
|
21608
21631
|
|
|
21632
|
+
this.element.addEventListener("contextmenu", this._contextmenuListener = (e) => {
|
|
21633
|
+
if (!this.enabled) {
|
|
21634
|
+
return;
|
|
21635
|
+
}
|
|
21636
|
+
this._getMouseCanvasPos(e);
|
|
21637
|
+
this.fire("contextmenu", this.mouseCanvasPos, true);
|
|
21638
|
+
});
|
|
21639
|
+
|
|
21609
21640
|
const tickifiedMouseWheelFn = this.scene.tickify(
|
|
21610
21641
|
(delta) => { this.fire("mousewheel", delta, true); }
|
|
21611
21642
|
);
|
|
@@ -21639,6 +21670,24 @@ class Input extends Component {
|
|
|
21639
21670
|
});
|
|
21640
21671
|
}
|
|
21641
21672
|
|
|
21673
|
+
this.element.addEventListener("touchstart", this._touchstartListener = (e) => {
|
|
21674
|
+
if (!this.enabled) {
|
|
21675
|
+
return;
|
|
21676
|
+
}
|
|
21677
|
+
[...e.changedTouches].forEach(e => {
|
|
21678
|
+
this.fire("touchstart", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21679
|
+
});
|
|
21680
|
+
});
|
|
21681
|
+
|
|
21682
|
+
this.element.addEventListener("touchend", this._touchendListener = (e) => {
|
|
21683
|
+
if (!this.enabled) {
|
|
21684
|
+
return;
|
|
21685
|
+
}
|
|
21686
|
+
[...e.changedTouches].forEach(e => {
|
|
21687
|
+
this.fire("touchend", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21688
|
+
});
|
|
21689
|
+
});
|
|
21690
|
+
|
|
21642
21691
|
this._eventsBound = true;
|
|
21643
21692
|
}
|
|
21644
21693
|
|
|
@@ -21655,7 +21704,10 @@ class Input extends Component {
|
|
|
21655
21704
|
document.removeEventListener("click", this._clickListener);
|
|
21656
21705
|
document.removeEventListener("dblclick", this._dblClickListener);
|
|
21657
21706
|
this.element.removeEventListener("mousemove", this._mouseMoveListener);
|
|
21707
|
+
this.element.removeEventListener("contextmenu", this._contextmenuListener);
|
|
21658
21708
|
this.element.removeEventListener("wheel", this._mouseWheelListener);
|
|
21709
|
+
this.element.removeEventListener("touchstart", this._touchstartListener);
|
|
21710
|
+
this.element.removeEventListener("touchend", this._touchendListener);
|
|
21659
21711
|
if (window.OrientationChangeEvent) {
|
|
21660
21712
|
window.removeEventListener('orientationchange', this._orientationchangedListener);
|
|
21661
21713
|
}
|
|
@@ -21668,6 +21720,18 @@ class Input extends Component {
|
|
|
21668
21720
|
this._eventsBound = false;
|
|
21669
21721
|
}
|
|
21670
21722
|
|
|
21723
|
+
_getTouchCanvasPos(event) {
|
|
21724
|
+
let element = event.target;
|
|
21725
|
+
let totalOffsetLeft = 0;
|
|
21726
|
+
let totalOffsetTop = 0;
|
|
21727
|
+
while (element.offsetParent) {
|
|
21728
|
+
totalOffsetLeft += element.offsetLeft;
|
|
21729
|
+
totalOffsetTop += element.offsetTop;
|
|
21730
|
+
element = element.offsetParent;
|
|
21731
|
+
}
|
|
21732
|
+
return [ event.pageX - totalOffsetLeft, event.pageY - totalOffsetTop ];
|
|
21733
|
+
}
|
|
21734
|
+
|
|
21671
21735
|
_getMouseCanvasPos(event) {
|
|
21672
21736
|
if (!event) {
|
|
21673
21737
|
event = window.event;
|
|
@@ -30152,6 +30216,7 @@ class Scene extends Component {
|
|
|
30152
30216
|
this._pbrEnabled = !!cfg.pbrEnabled;
|
|
30153
30217
|
this._colorTextureEnabled = (cfg.colorTextureEnabled !== false);
|
|
30154
30218
|
this._dtxEnabled = !!cfg.dtxEnabled;
|
|
30219
|
+
this._markerZOffset = cfg.markerZOffset;
|
|
30155
30220
|
|
|
30156
30221
|
// Register Scene on xeokit
|
|
30157
30222
|
// Do this BEFORE we add components below
|
|
@@ -30672,6 +30737,22 @@ class Scene extends Component {
|
|
|
30672
30737
|
return this._colorTextureEnabled;
|
|
30673
30738
|
}
|
|
30674
30739
|
|
|
30740
|
+
/**
|
|
30741
|
+
* Gets the Z value of offset for Marker's OcclusionTester.
|
|
30742
|
+
* The closest the value is to 0.000 the more precise OcclusionTester will be, but at the same time the less
|
|
30743
|
+
* precise it will behave for Markers that are located exactly on the Surface.
|
|
30744
|
+
*
|
|
30745
|
+
* Default is ````-0.001````.
|
|
30746
|
+
*
|
|
30747
|
+
* @returns {Number} Z offset for Marker
|
|
30748
|
+
*/
|
|
30749
|
+
get markerZOffset() {
|
|
30750
|
+
if (this._markerZOffset == null) {
|
|
30751
|
+
return -0.001;
|
|
30752
|
+
}
|
|
30753
|
+
return this._markerZOffset;
|
|
30754
|
+
}
|
|
30755
|
+
|
|
30675
30756
|
/**
|
|
30676
30757
|
* Performs an occlusion test on all {@link Marker}s in this {@link Scene}.
|
|
30677
30758
|
*
|
|
@@ -31514,11 +31595,9 @@ class Scene extends Component {
|
|
|
31514
31595
|
* @param {Number[]} [params.origin] World-space ray origin when ray-picking. Ignored when canvasPos given.
|
|
31515
31596
|
* @param {Number[]} [params.direction] World-space ray direction when ray-picking. Also indicates the length of the ray. Ignored when canvasPos given.
|
|
31516
31597
|
* @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
|
|
31517
|
-
* @param {
|
|
31518
|
-
* @param {
|
|
31519
|
-
* @param {
|
|
31520
|
-
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31521
|
-
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
31598
|
+
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels.
|
|
31599
|
+
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex. Only works when `canvasPos` given.
|
|
31600
|
+
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge. Only works when `canvasPos` given.
|
|
31522
31601
|
* @param {PickResult} [pickResult] Holds the results of the pick attempt. Will use the Scene's singleton PickResult if you don't supply your own.
|
|
31523
31602
|
* @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
|
|
31524
31603
|
*/
|
|
@@ -31529,6 +31608,11 @@ class Scene extends Component {
|
|
|
31529
31608
|
return null;
|
|
31530
31609
|
}
|
|
31531
31610
|
|
|
31611
|
+
if ((params.snapToVertex || params.snapToEdge) && !params.canvasPos) {
|
|
31612
|
+
this.error("Scene.snapPick() `canvasPos` parameter expected for `snapToVertex:true` or `snapToEdge:true`");
|
|
31613
|
+
return;
|
|
31614
|
+
}
|
|
31615
|
+
|
|
31532
31616
|
params = params || {};
|
|
31533
31617
|
|
|
31534
31618
|
params.pickSurface = params.pickSurface || params.rayPick; // Backwards compatibility
|
|
@@ -31576,7 +31660,7 @@ class Scene extends Component {
|
|
|
31576
31660
|
|
|
31577
31661
|
/**
|
|
31578
31662
|
* @param {Object} params Picking parameters.
|
|
31579
|
-
* @param {Number[]}
|
|
31663
|
+
* @param {Number[]} params.canvasPos Canvas-space coordinates.
|
|
31580
31664
|
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
|
|
31581
31665
|
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31582
31666
|
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
@@ -31587,6 +31671,10 @@ class Scene extends Component {
|
|
|
31587
31671
|
this._warnSnapPickDeprecated = true;
|
|
31588
31672
|
this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead");
|
|
31589
31673
|
}
|
|
31674
|
+
if (!params.canvasPos) {
|
|
31675
|
+
this.error("Scene.snapPick() canvasPos parameter expected");
|
|
31676
|
+
return;
|
|
31677
|
+
}
|
|
31590
31678
|
return this._renderer.snapPick(
|
|
31591
31679
|
params.canvasPos,
|
|
31592
31680
|
params.snapRadius || 30,
|
|
@@ -37649,11 +37737,16 @@ class Mesh extends Component {
|
|
|
37649
37737
|
* @param {EmphasisMaterial} [cfg.highlightMaterial] {@link EmphasisMaterial} to define the xrayed appearance for this Mesh. Inherits {@link Scene#highlightMaterial} by default.
|
|
37650
37738
|
* @param {EmphasisMaterial} [cfg.selectedMaterial] {@link EmphasisMaterial} to define the selected appearance for this Mesh. Inherits {@link Scene#selectedMaterial} by default.
|
|
37651
37739
|
* @param {EmphasisMaterial} [cfg.edgeMaterial] {@link EdgeMaterial} to define the appearance of enhanced edges for this Mesh. Inherits {@link Scene#edgeMaterial} by default.
|
|
37740
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this mESH. This is used to control the order in which
|
|
37741
|
+
* mESHES are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
37742
|
+
* render pass.
|
|
37652
37743
|
*/
|
|
37653
37744
|
constructor(owner, cfg = {}) {
|
|
37654
37745
|
|
|
37655
37746
|
super(owner, cfg);
|
|
37656
37747
|
|
|
37748
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
37749
|
+
|
|
37657
37750
|
/**
|
|
37658
37751
|
* ID of the corresponding object within the originating system, if any.
|
|
37659
37752
|
*
|
|
@@ -42178,6 +42271,7 @@ class SectionPlane extends Component {
|
|
|
42178
42271
|
this._state.active = value !== false;
|
|
42179
42272
|
this.glRedraw();
|
|
42180
42273
|
this.fire("active", this._state.active);
|
|
42274
|
+
this.scene.fire("sectionPlaneUpdated", this);
|
|
42181
42275
|
}
|
|
42182
42276
|
|
|
42183
42277
|
/**
|
|
@@ -42258,13 +42352,8 @@ class SectionPlane extends Component {
|
|
|
42258
42352
|
* Inverts the direction of {@link SectionPlane#dir}.
|
|
42259
42353
|
*/
|
|
42260
42354
|
flipDir() {
|
|
42261
|
-
|
|
42262
|
-
dir
|
|
42263
|
-
dir[1] *= -1.0;
|
|
42264
|
-
dir[2] *= -1.0;
|
|
42265
|
-
this._state.dist = (-math.dotVec3(this._state.pos, this._state.dir));
|
|
42266
|
-
this.fire("dir", this._state.dir);
|
|
42267
|
-
this.glRedraw();
|
|
42355
|
+
math.mulVec3Scalar(this._state.dir, -1.0, this._state.dir);
|
|
42356
|
+
this.dir = this._state.dir;
|
|
42268
42357
|
}
|
|
42269
42358
|
|
|
42270
42359
|
/**
|
|
@@ -82246,11 +82335,16 @@ class SceneModel extends Component {
|
|
|
82246
82335
|
* represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
|
|
82247
82336
|
* to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
|
|
82248
82337
|
* primitives. Only works while {@link DTX#enabled} is also ````true````.
|
|
82338
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this SceneModel. This is used to control the order in which
|
|
82339
|
+
* SceneModels are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
82340
|
+
* render pass.
|
|
82249
82341
|
*/
|
|
82250
82342
|
constructor(owner, cfg = {}) {
|
|
82251
82343
|
|
|
82252
82344
|
super(owner, cfg);
|
|
82253
82345
|
|
|
82346
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
82347
|
+
|
|
82254
82348
|
this._dtxEnabled = this.scene.dtxEnabled && (cfg.dtxEnabled !== false);
|
|
82255
82349
|
|
|
82256
82350
|
this._enableVertexWelding = false; // Not needed for most objects, and very expensive, so disabled
|
|
@@ -84317,6 +84411,7 @@ class SceneModel extends Component {
|
|
|
84317
84411
|
_getVBOBatchingLayer(cfg) {
|
|
84318
84412
|
const model = this;
|
|
84319
84413
|
const origin = cfg.origin;
|
|
84414
|
+
cfg.renderLayer || 0;
|
|
84320
84415
|
const positionsDecodeHash = cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary ?
|
|
84321
84416
|
this._createHashStringFromMatrix(cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary)
|
|
84322
84417
|
: "-";
|
|
@@ -84803,7 +84898,7 @@ class SceneModel extends Component {
|
|
|
84803
84898
|
// -------------- RENDERING ---------------------------------------------------------------------------------------
|
|
84804
84899
|
|
|
84805
84900
|
/** @private */
|
|
84806
|
-
drawColorOpaque(frameCtx) {
|
|
84901
|
+
drawColorOpaque(frameCtx, layerList) {
|
|
84807
84902
|
const renderFlags = this.renderFlags;
|
|
84808
84903
|
for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) {
|
|
84809
84904
|
const layerIndex = renderFlags.visibleLayers[i];
|
|
@@ -86597,7 +86692,7 @@ class DistanceMeasurement extends Component {
|
|
|
86597
86692
|
|
|
86598
86693
|
if (this._wpDirty) {
|
|
86599
86694
|
|
|
86600
|
-
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld,
|
|
86695
|
+
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0);
|
|
86601
86696
|
if(this._measurementOrientation === 'Vertical' && this.useRotationAdjustment){
|
|
86602
86697
|
this._wp[0] = this._originWorld[0];
|
|
86603
86698
|
this._wp[1] = this._originWorld[1];
|
|
@@ -89724,7 +89819,20 @@ class FastNavPlugin extends Plugin {
|
|
|
89724
89819
|
*/
|
|
89725
89820
|
class GLTFDefaultDataSource {
|
|
89726
89821
|
|
|
89727
|
-
constructor() {
|
|
89822
|
+
constructor(cfg = {}) {
|
|
89823
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
89824
|
+
}
|
|
89825
|
+
|
|
89826
|
+
_cacheBusterURL(url) {
|
|
89827
|
+
if (!this.cacheBuster) {
|
|
89828
|
+
return url;
|
|
89829
|
+
}
|
|
89830
|
+
const timestamp = new Date().getTime();
|
|
89831
|
+
if (url.indexOf('?') > -1) {
|
|
89832
|
+
return url + '&_=' + timestamp;
|
|
89833
|
+
} else {
|
|
89834
|
+
return url + '?_=' + timestamp;
|
|
89835
|
+
}
|
|
89728
89836
|
}
|
|
89729
89837
|
|
|
89730
89838
|
/**
|
|
@@ -89735,7 +89843,7 @@ class GLTFDefaultDataSource {
|
|
|
89735
89843
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
89736
89844
|
*/
|
|
89737
89845
|
getMetaModel(metaModelSrc, ok, error) {
|
|
89738
|
-
utils.loadJSON(metaModelSrc,
|
|
89846
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
89739
89847
|
(json) => {
|
|
89740
89848
|
ok(json);
|
|
89741
89849
|
},
|
|
@@ -89752,7 +89860,7 @@ class GLTFDefaultDataSource {
|
|
|
89752
89860
|
* @param {Function} error Fired on error while loading the glTF JSON asset.
|
|
89753
89861
|
*/
|
|
89754
89862
|
getGLTF(glTFSrc, ok, error) {
|
|
89755
|
-
utils.loadArraybuffer(glTFSrc,
|
|
89863
|
+
utils.loadArraybuffer(this._cacheBusterURL(glTFSrc),
|
|
89756
89864
|
(gltf) => {
|
|
89757
89865
|
ok(gltf);
|
|
89758
89866
|
},
|
|
@@ -89769,7 +89877,7 @@ class GLTFDefaultDataSource {
|
|
|
89769
89877
|
* @param {Function} error Fired on error while loading the .glb asset.
|
|
89770
89878
|
*/
|
|
89771
89879
|
getGLB(glbSrc, ok, error) {
|
|
89772
|
-
utils.loadArraybuffer(glbSrc,
|
|
89880
|
+
utils.loadArraybuffer(this._cacheBusterURL(glbSrc),
|
|
89773
89881
|
(arraybuffer) => {
|
|
89774
89882
|
ok(arraybuffer);
|
|
89775
89883
|
},
|
|
@@ -89790,7 +89898,7 @@ class GLTFDefaultDataSource {
|
|
|
89790
89898
|
* @param {Function} error Fired on error while loading the glTF binary asset.
|
|
89791
89899
|
*/
|
|
89792
89900
|
getArrayBuffer(glTFSrc, binarySrc, ok, error) {
|
|
89793
|
-
loadArraybuffer(glTFSrc, binarySrc,
|
|
89901
|
+
loadArraybuffer(this._cacheBusterURL(glTFSrc), binarySrc,
|
|
89794
89902
|
(arrayBuffer) => {
|
|
89795
89903
|
ok(arrayBuffer);
|
|
89796
89904
|
},
|
|
@@ -96106,6 +96214,15 @@ class MousePickHandler {
|
|
|
96106
96214
|
return;
|
|
96107
96215
|
}
|
|
96108
96216
|
|
|
96217
|
+
if (cameraControl.hasSubs("rayMove"))
|
|
96218
|
+
{
|
|
96219
|
+
const origin = math.vec3();
|
|
96220
|
+
const direction = math.vec3();
|
|
96221
|
+
// The origin from math.canvasPosToWorldRay is incorrect for a perspective camera, should be the same as scene.camera.eye
|
|
96222
|
+
math.canvasPosToWorldRay(scene.canvas.canvas, scene.camera.viewMatrix, scene.camera.projMatrix, states.pointerCanvasPos, origin, direction);
|
|
96223
|
+
cameraControl.fire("rayMove", { canvasPos: states.pointerCanvasPos, ray: { origin: origin, direction: direction, canvasPos: states.pointerCanvasPos } }, true);
|
|
96224
|
+
}
|
|
96225
|
+
|
|
96109
96226
|
const hoverSubs = cameraControl.hasSubs("hover");
|
|
96110
96227
|
const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
|
|
96111
96228
|
const hoverOutSubs = cameraControl.hasSubs("hoverOut");
|
|
@@ -108198,6 +108315,7 @@ class Viewer {
|
|
|
108198
108315
|
* 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
|
|
108199
108316
|
* 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)
|
|
108200
108317
|
* mode for storing geometry, which is the standard technique used in most graphics engines, and will work adequately on most low-end GPUs.
|
|
108318
|
+
* @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.
|
|
108201
108319
|
* @param {number} [cfg.numCachedSectionPlanes=0] Enhances the efficiency of SectionPlane creation by proactively allocating Viewer resources for a specified quantity
|
|
108202
108320
|
* of SectionPlanes. Introducing this parameter streamlines the initial creation speed of SectionPlanes, particularly up to the designated quantity. This parameter internally
|
|
108203
108321
|
* configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
|
|
@@ -108261,6 +108379,7 @@ class Viewer {
|
|
|
108261
108379
|
pbrEnabled: (!!cfg.pbrEnabled),
|
|
108262
108380
|
colorTextureEnabled: (cfg.colorTextureEnabled !== false),
|
|
108263
108381
|
dtxEnabled: (!!cfg.dtxEnabled),
|
|
108382
|
+
markerZOffset: cfg.markerZOffset,
|
|
108264
108383
|
numCachedSectionPlanes: cfg.numCachedSectionPlanes
|
|
108265
108384
|
});
|
|
108266
108385
|
|
|
@@ -123705,6 +123824,22 @@ class SkyboxesPlugin extends Plugin {
|
|
|
123705
123824
|
*/
|
|
123706
123825
|
class STLDefaultDataSource {
|
|
123707
123826
|
|
|
123827
|
+
constructor(cfg = {}) {
|
|
123828
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
123829
|
+
}
|
|
123830
|
+
|
|
123831
|
+
_cacheBusterURL(url) {
|
|
123832
|
+
if (!this.cacheBuster) {
|
|
123833
|
+
return url;
|
|
123834
|
+
}
|
|
123835
|
+
const timestamp = new Date().getTime();
|
|
123836
|
+
if (url.indexOf('?') > -1) {
|
|
123837
|
+
return url + '&_=' + timestamp;
|
|
123838
|
+
} else {
|
|
123839
|
+
return url + '?_=' + timestamp;
|
|
123840
|
+
}
|
|
123841
|
+
}
|
|
123842
|
+
|
|
123708
123843
|
/**
|
|
123709
123844
|
* Gets STL data.
|
|
123710
123845
|
*
|
|
@@ -123713,6 +123848,7 @@ class STLDefaultDataSource {
|
|
|
123713
123848
|
* @param {Function} error Fired on error while loading the STL file.
|
|
123714
123849
|
*/
|
|
123715
123850
|
getSTL(src, ok, error) {
|
|
123851
|
+
src = this._cacheBusterURL(src);
|
|
123716
123852
|
const request = new XMLHttpRequest();
|
|
123717
123853
|
request.overrideMimeType("application/json");
|
|
123718
123854
|
request.open('GET', src, true);
|
|
@@ -126335,7 +126471,20 @@ class ViewCullPlugin extends Plugin {
|
|
|
126335
126471
|
*/
|
|
126336
126472
|
class XKTDefaultDataSource {
|
|
126337
126473
|
|
|
126338
|
-
constructor() {
|
|
126474
|
+
constructor(cfg = {}) {
|
|
126475
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
126476
|
+
}
|
|
126477
|
+
|
|
126478
|
+
_cacheBusterURL(url) {
|
|
126479
|
+
if (!this.cacheBuster) {
|
|
126480
|
+
return url;
|
|
126481
|
+
}
|
|
126482
|
+
const timestamp = new Date().getTime();
|
|
126483
|
+
if (url.indexOf('?') > -1) {
|
|
126484
|
+
return url + '&_=' + timestamp;
|
|
126485
|
+
} else {
|
|
126486
|
+
return url + '?_=' + timestamp;
|
|
126487
|
+
}
|
|
126339
126488
|
}
|
|
126340
126489
|
|
|
126341
126490
|
/**
|
|
@@ -126346,7 +126495,7 @@ class XKTDefaultDataSource {
|
|
|
126346
126495
|
* @param {Function} error Fired on error while loading the manifest JSON asset.
|
|
126347
126496
|
*/
|
|
126348
126497
|
getManifest(manifestSrc, ok, error) {
|
|
126349
|
-
utils.loadJSON(manifestSrc,
|
|
126498
|
+
utils.loadJSON(this._cacheBusterURL(manifestSrc),
|
|
126350
126499
|
(json) => {
|
|
126351
126500
|
ok(json);
|
|
126352
126501
|
},
|
|
@@ -126363,7 +126512,7 @@ class XKTDefaultDataSource {
|
|
|
126363
126512
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
126364
126513
|
*/
|
|
126365
126514
|
getMetaModel(metaModelSrc, ok, error) {
|
|
126366
|
-
utils.loadJSON(metaModelSrc,
|
|
126515
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
126367
126516
|
(json) => {
|
|
126368
126517
|
ok(json);
|
|
126369
126518
|
},
|
|
@@ -126405,7 +126554,7 @@ class XKTDefaultDataSource {
|
|
|
126405
126554
|
}
|
|
126406
126555
|
} else {
|
|
126407
126556
|
const request = new XMLHttpRequest();
|
|
126408
|
-
request.open('GET', src, true);
|
|
126557
|
+
request.open('GET', this._cacheBusterURL(src), true);
|
|
126409
126558
|
request.responseType = 'arraybuffer';
|
|
126410
126559
|
request.onreadystatechange = function () {
|
|
126411
126560
|
if (request.readyState === 4) {
|
|
@@ -133806,7 +133955,20 @@ class XML3DLoaderPlugin extends Plugin {
|
|
|
133806
133955
|
*/
|
|
133807
133956
|
class WebIFCDefaultDataSource {
|
|
133808
133957
|
|
|
133809
|
-
constructor() {
|
|
133958
|
+
constructor(cfg = {}) {
|
|
133959
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
133960
|
+
}
|
|
133961
|
+
|
|
133962
|
+
_cacheBusterURL(url) {
|
|
133963
|
+
if (!this.cacheBuster) {
|
|
133964
|
+
return url;
|
|
133965
|
+
}
|
|
133966
|
+
const timestamp = new Date().getTime();
|
|
133967
|
+
if (url.indexOf('?') > -1) {
|
|
133968
|
+
return url + '&_=' + timestamp;
|
|
133969
|
+
} else {
|
|
133970
|
+
return url + '?_=' + timestamp;
|
|
133971
|
+
}
|
|
133810
133972
|
}
|
|
133811
133973
|
|
|
133812
133974
|
/**
|
|
@@ -133817,6 +133979,8 @@ class WebIFCDefaultDataSource {
|
|
|
133817
133979
|
* @param {Function} error Callback fired on error.
|
|
133818
133980
|
*/
|
|
133819
133981
|
getIFC(src, ok, error) {
|
|
133982
|
+
src = this._cacheBusterURL(src);
|
|
133983
|
+
|
|
133820
133984
|
var defaultCallback = () => {
|
|
133821
133985
|
};
|
|
133822
133986
|
ok = ok || defaultCallback;
|
|
@@ -134814,7 +134978,20 @@ class WebIFCLoaderPlugin extends Plugin {
|
|
|
134814
134978
|
*/
|
|
134815
134979
|
class LASDefaultDataSource {
|
|
134816
134980
|
|
|
134817
|
-
constructor() {
|
|
134981
|
+
constructor(cfg = {}) {
|
|
134982
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
134983
|
+
}
|
|
134984
|
+
|
|
134985
|
+
_cacheBusterURL(url) {
|
|
134986
|
+
if (!this.cacheBuster) {
|
|
134987
|
+
return url;
|
|
134988
|
+
}
|
|
134989
|
+
const timestamp = new Date().getTime();
|
|
134990
|
+
if (url.indexOf('?') > -1) {
|
|
134991
|
+
return url + '&_=' + timestamp;
|
|
134992
|
+
} else {
|
|
134993
|
+
return url + '?_=' + timestamp;
|
|
134994
|
+
}
|
|
134818
134995
|
}
|
|
134819
134996
|
|
|
134820
134997
|
/**
|
|
@@ -134825,6 +135002,7 @@ class LASDefaultDataSource {
|
|
|
134825
135002
|
* @param {Function} error Callback fired on error.
|
|
134826
135003
|
*/
|
|
134827
135004
|
getLAS(src, ok, error) {
|
|
135005
|
+
src = this._cacheBusterURL(src);
|
|
134828
135006
|
var defaultCallback = () => {
|
|
134829
135007
|
};
|
|
134830
135008
|
ok = ok || defaultCallback;
|
|
@@ -135679,7 +135857,20 @@ function chunkArray(array, chunkSize) {
|
|
|
135679
135857
|
*/
|
|
135680
135858
|
class CityJSONDefaultDataSource {
|
|
135681
135859
|
|
|
135682
|
-
constructor() {
|
|
135860
|
+
constructor(cfg = {}) {
|
|
135861
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
135862
|
+
}
|
|
135863
|
+
|
|
135864
|
+
_cacheBusterURL(url) {
|
|
135865
|
+
if (!this.cacheBuster) {
|
|
135866
|
+
return url;
|
|
135867
|
+
}
|
|
135868
|
+
const timestamp = new Date().getTime();
|
|
135869
|
+
if (url.indexOf('?') > -1) {
|
|
135870
|
+
return url + '&_=' + timestamp;
|
|
135871
|
+
} else {
|
|
135872
|
+
return url + '?_=' + timestamp;
|
|
135873
|
+
}
|
|
135683
135874
|
}
|
|
135684
135875
|
|
|
135685
135876
|
/**
|
|
@@ -135690,7 +135881,7 @@ class CityJSONDefaultDataSource {
|
|
|
135690
135881
|
* @param {Function} error Callback fired on error.
|
|
135691
135882
|
*/
|
|
135692
135883
|
getCityJSON(src, ok, error) {
|
|
135693
|
-
utils.loadJSON(src,
|
|
135884
|
+
utils.loadJSON(this._cacheBusterURL(src),
|
|
135694
135885
|
(json) => {
|
|
135695
135886
|
ok(json);
|
|
135696
135887
|
},
|
|
@@ -137122,7 +137313,20 @@ class CityJSONLoaderPlugin extends Plugin {
|
|
|
137122
137313
|
*/
|
|
137123
137314
|
class DotBIMDefaultDataSource {
|
|
137124
137315
|
|
|
137125
|
-
constructor() {
|
|
137316
|
+
constructor(cfg = {}) {
|
|
137317
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
137318
|
+
}
|
|
137319
|
+
|
|
137320
|
+
_cacheBusterURL(url) {
|
|
137321
|
+
if (!this.cacheBuster) {
|
|
137322
|
+
return url;
|
|
137323
|
+
}
|
|
137324
|
+
const timestamp = new Date().getTime();
|
|
137325
|
+
if (url.indexOf('?') > -1) {
|
|
137326
|
+
return url + '&_=' + timestamp;
|
|
137327
|
+
} else {
|
|
137328
|
+
return url + '?_=' + timestamp;
|
|
137329
|
+
}
|
|
137126
137330
|
}
|
|
137127
137331
|
|
|
137128
137332
|
/**
|
|
@@ -137133,7 +137337,7 @@ class DotBIMDefaultDataSource {
|
|
|
137133
137337
|
* @param {Function} error Fired on error while loading the .BIM JSON asset.
|
|
137134
137338
|
*/
|
|
137135
137339
|
getDotBIM(dotBIMSrc, ok, error) {
|
|
137136
|
-
utils.loadJSON(dotBIMSrc,
|
|
137340
|
+
utils.loadJSON(this._cacheBusterURL(dotBIMSrc),
|
|
137137
137341
|
(json) => {
|
|
137138
137342
|
ok(json);
|
|
137139
137343
|
},
|
|
@@ -137695,4 +137899,2011 @@ class DotBIMLoaderPlugin extends Plugin {
|
|
|
137695
137899
|
}
|
|
137696
137900
|
}
|
|
137697
137901
|
|
|
137698
|
-
|
|
137902
|
+
const hex2rgb = function(color) {
|
|
137903
|
+
const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
|
|
137904
|
+
return [ rgb(0), rgb(2), rgb(4) ];
|
|
137905
|
+
};
|
|
137906
|
+
|
|
137907
|
+
const transformToNode = function(from, to, vec) {
|
|
137908
|
+
const fromRec = from.getBoundingClientRect();
|
|
137909
|
+
const toRec = to.getBoundingClientRect();
|
|
137910
|
+
vec[0] += fromRec.left - toRec.left;
|
|
137911
|
+
vec[1] += fromRec.top - toRec.top;
|
|
137912
|
+
};
|
|
137913
|
+
|
|
137914
|
+
const triangulateEarClipping = function(planeCoords) {
|
|
137915
|
+
|
|
137916
|
+
const polygonVertices = [ ];
|
|
137917
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
137918
|
+
polygonVertices.push(i);
|
|
137919
|
+
|
|
137920
|
+
const isCCW = (function() {
|
|
137921
|
+
const ba = math.vec2();
|
|
137922
|
+
const bc = math.vec2();
|
|
137923
|
+
|
|
137924
|
+
let anglesSum = 0;
|
|
137925
|
+
|
|
137926
|
+
for (let i = 0; i < polygonVertices.length; ++i)
|
|
137927
|
+
{
|
|
137928
|
+
const a = planeCoords[polygonVertices[i]];
|
|
137929
|
+
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
137930
|
+
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
137931
|
+
|
|
137932
|
+
math.subVec2(a, b, ba);
|
|
137933
|
+
math.subVec2(c, b, bc);
|
|
137934
|
+
|
|
137935
|
+
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
137936
|
+
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
137937
|
+
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
137938
|
+
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
137939
|
+
}
|
|
137940
|
+
|
|
137941
|
+
return anglesSum < (polygonVertices.length * Math.PI);
|
|
137942
|
+
})();
|
|
137943
|
+
|
|
137944
|
+
const pointInTriangle = (function() {
|
|
137945
|
+
const sign = (p1, p2, p3) => {
|
|
137946
|
+
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
137947
|
+
};
|
|
137948
|
+
|
|
137949
|
+
return (pt, v1, v2, v3) => {
|
|
137950
|
+
const d1 = sign(pt, v1, v2);
|
|
137951
|
+
const d2 = sign(pt, v2, v3);
|
|
137952
|
+
const d3 = sign(pt, v3, v1);
|
|
137953
|
+
|
|
137954
|
+
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
137955
|
+
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
137956
|
+
|
|
137957
|
+
return !(has_neg && has_pos);
|
|
137958
|
+
};
|
|
137959
|
+
})();
|
|
137960
|
+
|
|
137961
|
+
const baseTriangles = [ ];
|
|
137962
|
+
|
|
137963
|
+
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
137964
|
+
vertices.forEach((v, i) => {
|
|
137965
|
+
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
137966
|
+
v.next = vertices[(i + 1) % vertices.length];
|
|
137967
|
+
});
|
|
137968
|
+
|
|
137969
|
+
const ba = math.vec2();
|
|
137970
|
+
const bc = math.vec2();
|
|
137971
|
+
|
|
137972
|
+
while (vertices.length > 2) {
|
|
137973
|
+
let earIdx = 0;
|
|
137974
|
+
while (true) {
|
|
137975
|
+
if (earIdx >= vertices.length)
|
|
137976
|
+
{
|
|
137977
|
+
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
137978
|
+
}
|
|
137979
|
+
const v = vertices[earIdx];
|
|
137980
|
+
|
|
137981
|
+
const a = planeCoords[v.prev.idx];
|
|
137982
|
+
const b = planeCoords[v.idx];
|
|
137983
|
+
const c = planeCoords[v.next.idx];
|
|
137984
|
+
|
|
137985
|
+
math.subVec2(a, b, ba);
|
|
137986
|
+
math.subVec2(c, b, bc);
|
|
137987
|
+
|
|
137988
|
+
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
137989
|
+
&&
|
|
137990
|
+
vertices.every( // no other vertices inside
|
|
137991
|
+
vv => ((vv === v)
|
|
137992
|
+
||
|
|
137993
|
+
(vv === v.prev)
|
|
137994
|
+
||
|
|
137995
|
+
(vv === v.next)
|
|
137996
|
+
||
|
|
137997
|
+
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
137998
|
+
break;
|
|
137999
|
+
++earIdx;
|
|
138000
|
+
}
|
|
138001
|
+
|
|
138002
|
+
const ear = vertices[earIdx];
|
|
138003
|
+
vertices.splice(earIdx, 1);
|
|
138004
|
+
|
|
138005
|
+
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
138006
|
+
|
|
138007
|
+
const prev = ear.prev;
|
|
138008
|
+
prev.next = ear.next;
|
|
138009
|
+
const next = ear.next;
|
|
138010
|
+
next.prev = ear.prev;
|
|
138011
|
+
}
|
|
138012
|
+
|
|
138013
|
+
return [ planeCoords, baseTriangles ];
|
|
138014
|
+
};
|
|
138015
|
+
|
|
138016
|
+
const draggableDot3D = function(handleMouseEvents, handleTouchEvents, viewer, worldPos, color, ray2WorldPos, onStart, onMove, onEnd) {
|
|
138017
|
+
const scene = viewer.scene;
|
|
138018
|
+
const canvas = scene.canvas.canvas;
|
|
138019
|
+
|
|
138020
|
+
const marker = new Marker(scene, {});
|
|
138021
|
+
|
|
138022
|
+
const pickWorldPos = canvasPos => {
|
|
138023
|
+
const origin = math.vec3();
|
|
138024
|
+
const direction = math.vec3();
|
|
138025
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138026
|
+
return ray2WorldPos(origin, direction);
|
|
138027
|
+
};
|
|
138028
|
+
|
|
138029
|
+
const onChange = event => {
|
|
138030
|
+
const canvasPos = math.vec2([ event.clientX, event.clientY ]);
|
|
138031
|
+
transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
|
|
138032
|
+
|
|
138033
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
138034
|
+
marker.worldPos = worldPos;
|
|
138035
|
+
updateDotPos();
|
|
138036
|
+
onMove(canvasPos, worldPos);
|
|
138037
|
+
};
|
|
138038
|
+
|
|
138039
|
+
let currentDrag = null;
|
|
138040
|
+
|
|
138041
|
+
const onDragMove = function(event) {
|
|
138042
|
+
const e = currentDrag.matchesEvent(event);
|
|
138043
|
+
if (e)
|
|
138044
|
+
{
|
|
138045
|
+
onChange(e);
|
|
138046
|
+
}
|
|
138047
|
+
};
|
|
138048
|
+
|
|
138049
|
+
const onDragEnd = function(event) {
|
|
138050
|
+
const e = currentDrag.matchesEvent(event);
|
|
138051
|
+
if (e)
|
|
138052
|
+
{
|
|
138053
|
+
dot.setOpacity(idleOpacity);
|
|
138054
|
+
currentDrag.cleanup();
|
|
138055
|
+
onChange(e);
|
|
138056
|
+
onEnd();
|
|
138057
|
+
}
|
|
138058
|
+
};
|
|
138059
|
+
|
|
138060
|
+
const startDrag = function(matchesEvent, cleanupHandlers) {
|
|
138061
|
+
if (currentDrag) {
|
|
138062
|
+
currentDrag.cleanup();
|
|
138063
|
+
}
|
|
138064
|
+
|
|
138065
|
+
dot.setOpacity(1.0);
|
|
138066
|
+
dot.setClickable(false);
|
|
138067
|
+
viewer.cameraControl.active = false;
|
|
138068
|
+
|
|
138069
|
+
currentDrag = {
|
|
138070
|
+
matchesEvent: matchesEvent,
|
|
138071
|
+
cleanup: function() {
|
|
138072
|
+
currentDrag = null;
|
|
138073
|
+
dot.setClickable(true);
|
|
138074
|
+
viewer.cameraControl.active = true;
|
|
138075
|
+
cleanupHandlers();
|
|
138076
|
+
}
|
|
138077
|
+
};
|
|
138078
|
+
|
|
138079
|
+
onStart();
|
|
138080
|
+
};
|
|
138081
|
+
|
|
138082
|
+
const dotCfg = { fillColor: color };
|
|
138083
|
+
|
|
138084
|
+
if (handleMouseEvents)
|
|
138085
|
+
{
|
|
138086
|
+
dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
|
|
138087
|
+
dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
|
|
138088
|
+
dotCfg.onMouseDown = event => {
|
|
138089
|
+
if (event.which === 1)
|
|
138090
|
+
{
|
|
138091
|
+
canvas.addEventListener("mousemove", onDragMove);
|
|
138092
|
+
canvas.addEventListener("mouseup", onDragEnd);
|
|
138093
|
+
startDrag(
|
|
138094
|
+
event => (event.which === 1) && event,
|
|
138095
|
+
() => {
|
|
138096
|
+
canvas.removeEventListener("mousemove", onDragMove);
|
|
138097
|
+
canvas.removeEventListener("mouseup", onDragEnd);
|
|
138098
|
+
});
|
|
138099
|
+
}
|
|
138100
|
+
};
|
|
138101
|
+
}
|
|
138102
|
+
|
|
138103
|
+
if (handleTouchEvents)
|
|
138104
|
+
{
|
|
138105
|
+
let touchStartId;
|
|
138106
|
+
dotCfg.onTouchstart = event => {
|
|
138107
|
+
event.preventDefault();
|
|
138108
|
+
if (event.touches.length === 1)
|
|
138109
|
+
{
|
|
138110
|
+
touchStartId = event.touches[0].identifier;
|
|
138111
|
+
startDrag(
|
|
138112
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId),
|
|
138113
|
+
() => { touchStartId = null; });
|
|
138114
|
+
}
|
|
138115
|
+
};
|
|
138116
|
+
dotCfg.onTouchmove = event => {
|
|
138117
|
+
event.preventDefault();
|
|
138118
|
+
onDragMove(event);
|
|
138119
|
+
};
|
|
138120
|
+
dotCfg.onTouchend = event => {
|
|
138121
|
+
event.preventDefault();
|
|
138122
|
+
onDragEnd(event);
|
|
138123
|
+
};
|
|
138124
|
+
}
|
|
138125
|
+
|
|
138126
|
+
const dotParent = canvas.ownerDocument.body;
|
|
138127
|
+
const dot = new Dot(dotParent, dotCfg);
|
|
138128
|
+
|
|
138129
|
+
const idleOpacity = 0.5;
|
|
138130
|
+
dot.setOpacity(idleOpacity);
|
|
138131
|
+
|
|
138132
|
+
const updateDotPos = function() {
|
|
138133
|
+
const pos = marker.canvasPos.slice();
|
|
138134
|
+
transformToNode(canvas, dotParent, pos);
|
|
138135
|
+
dot.setPos(pos[0], pos[1]);
|
|
138136
|
+
};
|
|
138137
|
+
|
|
138138
|
+
marker.worldPos = worldPos;
|
|
138139
|
+
updateDotPos();
|
|
138140
|
+
|
|
138141
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
|
|
138142
|
+
const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
|
|
138143
|
+
|
|
138144
|
+
return {
|
|
138145
|
+
setActive: value => dot.setClickable(value),
|
|
138146
|
+
getWorldPos: () => marker.worldPos,
|
|
138147
|
+
setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
|
|
138148
|
+
destroy: function() {
|
|
138149
|
+
currentDrag && currentDrag.cleanup();
|
|
138150
|
+
scene.camera.off(onViewMatrix);
|
|
138151
|
+
scene.camera.off(onProjMatrix);
|
|
138152
|
+
marker.destroy();
|
|
138153
|
+
dot.destroy();
|
|
138154
|
+
}
|
|
138155
|
+
};
|
|
138156
|
+
};
|
|
138157
|
+
|
|
138158
|
+
const marker3D = function(scene, color) {
|
|
138159
|
+
const canvas = scene.canvas.canvas;
|
|
138160
|
+
|
|
138161
|
+
const markerParent = canvas.parentNode;
|
|
138162
|
+
const markerDiv = document.createElement("div");
|
|
138163
|
+
markerParent.insertBefore(markerDiv, canvas);
|
|
138164
|
+
|
|
138165
|
+
let size = 5;
|
|
138166
|
+
markerDiv.style.background = color;
|
|
138167
|
+
markerDiv.style.border = "2px solid white";
|
|
138168
|
+
markerDiv.style.margin = "0 0";
|
|
138169
|
+
markerDiv.style.zIndex = "100";
|
|
138170
|
+
markerDiv.style.position = "absolute";
|
|
138171
|
+
markerDiv.style.pointerEvents = "none";
|
|
138172
|
+
markerDiv.style.display = "none";
|
|
138173
|
+
|
|
138174
|
+
const marker = new Marker(scene, {});
|
|
138175
|
+
|
|
138176
|
+
const px = x => x + "px";
|
|
138177
|
+
const update = function() {
|
|
138178
|
+
const pos = marker.canvasPos.slice();
|
|
138179
|
+
transformToNode(canvas, markerParent, pos);
|
|
138180
|
+
markerDiv.style.left = px(pos[0] - 3 - size / 2);
|
|
138181
|
+
markerDiv.style.top = px(pos[1] - 3 - size / 2);
|
|
138182
|
+
markerDiv.style.borderRadius = px(size * 2);
|
|
138183
|
+
markerDiv.style.width = px(size);
|
|
138184
|
+
markerDiv.style.height = px(size);
|
|
138185
|
+
};
|
|
138186
|
+
const onViewMatrix = scene.camera.on("viewMatrix", update);
|
|
138187
|
+
const onProjMatrix = scene.camera.on("projMatrix", update);
|
|
138188
|
+
|
|
138189
|
+
return {
|
|
138190
|
+
update: function(worldPos) {
|
|
138191
|
+
if (worldPos)
|
|
138192
|
+
{
|
|
138193
|
+
marker.worldPos = worldPos;
|
|
138194
|
+
update();
|
|
138195
|
+
}
|
|
138196
|
+
markerDiv.style.display = worldPos ? "" : "none";
|
|
138197
|
+
},
|
|
138198
|
+
|
|
138199
|
+
setHighlighted: function(h) {
|
|
138200
|
+
size = h ? 10 : 5;
|
|
138201
|
+
update();
|
|
138202
|
+
},
|
|
138203
|
+
|
|
138204
|
+
getCanvasPos: () => marker.canvasPos,
|
|
138205
|
+
|
|
138206
|
+
getWorldPos: () => marker.worldPos,
|
|
138207
|
+
|
|
138208
|
+
destroy: function() {
|
|
138209
|
+
markerDiv.parentNode.removeChild(markerDiv);
|
|
138210
|
+
scene.camera.off(onViewMatrix);
|
|
138211
|
+
scene.camera.off(onProjMatrix);
|
|
138212
|
+
marker.destroy();
|
|
138213
|
+
}
|
|
138214
|
+
};
|
|
138215
|
+
};
|
|
138216
|
+
|
|
138217
|
+
const wire3D = function(scene, color, startWorldPos) {
|
|
138218
|
+
const canvas = scene.canvas.canvas;
|
|
138219
|
+
|
|
138220
|
+
const startMarker = new Marker(scene, {});
|
|
138221
|
+
startMarker.worldPos = startWorldPos;
|
|
138222
|
+
const endMarker = new Marker(scene, {});
|
|
138223
|
+
const wireParent = canvas.ownerDocument.body;
|
|
138224
|
+
const wire = new Wire(wireParent, {
|
|
138225
|
+
color: color,
|
|
138226
|
+
thickness: 1,
|
|
138227
|
+
thicknessClickable: 6
|
|
138228
|
+
});
|
|
138229
|
+
wire.setVisible(false);
|
|
138230
|
+
|
|
138231
|
+
const updatePos = function() {
|
|
138232
|
+
const p0 = startMarker.canvasPos.slice();
|
|
138233
|
+
const p1 = endMarker.canvasPos.slice();
|
|
138234
|
+
transformToNode(canvas, wireParent, p0);
|
|
138235
|
+
transformToNode(canvas, wireParent, p1);
|
|
138236
|
+
wire.setStartAndEnd(p0[0], p0[1], p1[0], p1[1]);
|
|
138237
|
+
};
|
|
138238
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updatePos);
|
|
138239
|
+
const onProjMatrix = scene.camera.on("projMatrix", updatePos);
|
|
138240
|
+
|
|
138241
|
+
return {
|
|
138242
|
+
update: function(endWorldPos) {
|
|
138243
|
+
if (endWorldPos)
|
|
138244
|
+
{
|
|
138245
|
+
endMarker.worldPos = endWorldPos;
|
|
138246
|
+
updatePos();
|
|
138247
|
+
}
|
|
138248
|
+
wire.setVisible(!!endWorldPos);
|
|
138249
|
+
},
|
|
138250
|
+
|
|
138251
|
+
destroy: function() {
|
|
138252
|
+
scene.camera.off(onViewMatrix);
|
|
138253
|
+
scene.camera.off(onProjMatrix);
|
|
138254
|
+
startMarker.destroy();
|
|
138255
|
+
endMarker.destroy();
|
|
138256
|
+
wire.destroy();
|
|
138257
|
+
}
|
|
138258
|
+
};
|
|
138259
|
+
};
|
|
138260
|
+
|
|
138261
|
+
const basePolygon3D = function(scene, color, alpha) {
|
|
138262
|
+
let mesh = null;
|
|
138263
|
+
|
|
138264
|
+
const updateBase = points => {
|
|
138265
|
+
if (points)
|
|
138266
|
+
{
|
|
138267
|
+
if (mesh)
|
|
138268
|
+
{
|
|
138269
|
+
mesh.destroy();
|
|
138270
|
+
}
|
|
138271
|
+
|
|
138272
|
+
try {
|
|
138273
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(points.map(p => [ p[0], p[2] ]));
|
|
138274
|
+
|
|
138275
|
+
const positions = [ ].concat(...baseVertices.map(p => [p[0], points[0][1], p[1]])); // To convert from Float64Array into an Array
|
|
138276
|
+
const ind = [ ].concat(...baseTriangles);
|
|
138277
|
+
mesh = new Mesh(scene, {
|
|
138278
|
+
pickable: false, // otherwise there's a WebGL error inside PickMeshRenderer.prototype.drawMesh
|
|
138279
|
+
geometry: new ReadableGeometry(
|
|
138280
|
+
scene,
|
|
138281
|
+
{
|
|
138282
|
+
positions: positions,
|
|
138283
|
+
indices: ind,
|
|
138284
|
+
normals: math.buildNormals(positions, ind)
|
|
138285
|
+
}),
|
|
138286
|
+
material: new PhongMaterial(scene, {
|
|
138287
|
+
alpha: (alpha !== undefined) ? alpha : 0.5,
|
|
138288
|
+
backfaces: true,
|
|
138289
|
+
diffuse: hex2rgb(color)
|
|
138290
|
+
})
|
|
138291
|
+
});
|
|
138292
|
+
} catch (e) {
|
|
138293
|
+
mesh = null;
|
|
138294
|
+
}
|
|
138295
|
+
}
|
|
138296
|
+
|
|
138297
|
+
if (mesh)
|
|
138298
|
+
{
|
|
138299
|
+
mesh.visible = !!points;
|
|
138300
|
+
}
|
|
138301
|
+
};
|
|
138302
|
+
updateBase(null);
|
|
138303
|
+
|
|
138304
|
+
return {
|
|
138305
|
+
updateBase: updateBase,
|
|
138306
|
+
destroy: () => mesh && mesh.destroy()
|
|
138307
|
+
};
|
|
138308
|
+
};
|
|
138309
|
+
|
|
138310
|
+
const startAAZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
138311
|
+
const marker1 = marker3D(scene, zoneColor);
|
|
138312
|
+
const marker2 = marker3D(scene, zoneColor);
|
|
138313
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
138314
|
+
|
|
138315
|
+
const updatePointerLens = (pointerLens
|
|
138316
|
+
? function(canvasPos) {
|
|
138317
|
+
pointerLens.visible = !! canvasPos;
|
|
138318
|
+
if (canvasPos)
|
|
138319
|
+
{
|
|
138320
|
+
pointerLens.canvasPos = canvasPos;
|
|
138321
|
+
}
|
|
138322
|
+
}
|
|
138323
|
+
: () => { });
|
|
138324
|
+
|
|
138325
|
+
let deactivatePointSelection = select3dPoint(
|
|
138326
|
+
() => {
|
|
138327
|
+
updatePointerLens(null);
|
|
138328
|
+
marker1.update(null);
|
|
138329
|
+
},
|
|
138330
|
+
(canvasPos, worldPos) => {
|
|
138331
|
+
updatePointerLens(canvasPos);
|
|
138332
|
+
marker1.update(worldPos);
|
|
138333
|
+
},
|
|
138334
|
+
function(point1CanvasPos, point1WorldPos) {
|
|
138335
|
+
marker1.update(point1WorldPos);
|
|
138336
|
+
|
|
138337
|
+
deactivatePointSelection = select3dPoint(
|
|
138338
|
+
function() {
|
|
138339
|
+
updatePointerLens(null);
|
|
138340
|
+
marker2.update(null);
|
|
138341
|
+
basePolygon.updateBase(null);
|
|
138342
|
+
},
|
|
138343
|
+
function(canvasPos, point2WorldPos) {
|
|
138344
|
+
updatePointerLens(canvasPos);
|
|
138345
|
+
marker2.update(point2WorldPos);
|
|
138346
|
+
|
|
138347
|
+
if (math.distVec3(point1WorldPos, point2WorldPos) > 0.01)
|
|
138348
|
+
{
|
|
138349
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138350
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138351
|
+
|
|
138352
|
+
const xmin = min(0);
|
|
138353
|
+
const ymin = min(1);
|
|
138354
|
+
const zmin = min(2);
|
|
138355
|
+
const xmax = max(0);
|
|
138356
|
+
max(1);
|
|
138357
|
+
const zmax = max(2);
|
|
138358
|
+
|
|
138359
|
+
basePolygon.updateBase([ [ xmin, ymin, zmax ], [ xmax, ymin, zmax ],
|
|
138360
|
+
[ xmax, ymin, zmin ], [ xmin, ymin, zmin ] ]);
|
|
138361
|
+
}
|
|
138362
|
+
else
|
|
138363
|
+
basePolygon.updateBase(null);
|
|
138364
|
+
},
|
|
138365
|
+
function(point2CanvasPos, point2WorldPos) {
|
|
138366
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
138367
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
138368
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
138369
|
+
marker2.update(point2WorldPos);
|
|
138370
|
+
|
|
138371
|
+
marker1.destroy();
|
|
138372
|
+
marker2.destroy();
|
|
138373
|
+
basePolygon.destroy();
|
|
138374
|
+
updatePointerLens(null);
|
|
138375
|
+
|
|
138376
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138377
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138378
|
+
|
|
138379
|
+
const xmin = min(0);
|
|
138380
|
+
const zmin = min(2);
|
|
138381
|
+
const xmax = max(0);
|
|
138382
|
+
const zmax = max(2);
|
|
138383
|
+
|
|
138384
|
+
const zone = zonesPlugin.createZone(
|
|
138385
|
+
{
|
|
138386
|
+
id: math.createUUID(),
|
|
138387
|
+
geometry: {
|
|
138388
|
+
planeCoordinates: [
|
|
138389
|
+
[ xmin, zmax ],
|
|
138390
|
+
[ xmax, zmax ],
|
|
138391
|
+
[ xmax, zmin ],
|
|
138392
|
+
[ xmin, zmin ]
|
|
138393
|
+
],
|
|
138394
|
+
altitude: zoneAltitude,
|
|
138395
|
+
height: zoneHeight
|
|
138396
|
+
},
|
|
138397
|
+
alpha: zoneAlpha,
|
|
138398
|
+
color: zoneColor
|
|
138399
|
+
});
|
|
138400
|
+
|
|
138401
|
+
onZoneCreated(zone);
|
|
138402
|
+
});
|
|
138403
|
+
});
|
|
138404
|
+
|
|
138405
|
+
return {
|
|
138406
|
+
deactivate: function() {
|
|
138407
|
+
deactivatePointSelection();
|
|
138408
|
+
marker1.destroy();
|
|
138409
|
+
marker2.destroy();
|
|
138410
|
+
basePolygon.destroy();
|
|
138411
|
+
updatePointerLens(null);
|
|
138412
|
+
}
|
|
138413
|
+
};
|
|
138414
|
+
};
|
|
138415
|
+
|
|
138416
|
+
const mousePointSelector = function(viewer, ray2WorldPos) {
|
|
138417
|
+
return function(onCancel, onChange, onCommit) {
|
|
138418
|
+
const scene = viewer.scene;
|
|
138419
|
+
const canvas = scene.canvas.canvas;
|
|
138420
|
+
const moveTolerance = 20;
|
|
138421
|
+
|
|
138422
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138423
|
+
vec2[0] = event.clientX;
|
|
138424
|
+
vec2[1] = event.clientY;
|
|
138425
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138426
|
+
return vec2;
|
|
138427
|
+
};
|
|
138428
|
+
|
|
138429
|
+
const pickWorldPos = canvasPos => {
|
|
138430
|
+
const origin = math.vec3();
|
|
138431
|
+
const direction = math.vec3();
|
|
138432
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138433
|
+
return ray2WorldPos(origin, direction);
|
|
138434
|
+
};
|
|
138435
|
+
|
|
138436
|
+
let buttonDown = false;
|
|
138437
|
+
const resetAction = function() {
|
|
138438
|
+
buttonDown = false;
|
|
138439
|
+
};
|
|
138440
|
+
|
|
138441
|
+
const cleanup = function() {
|
|
138442
|
+
resetAction();
|
|
138443
|
+
canvas.removeEventListener("mousedown", onMouseDown);
|
|
138444
|
+
canvas.removeEventListener("mousemove", onMouseMove);
|
|
138445
|
+
viewer.cameraControl.off(onCameraControlRayMove);
|
|
138446
|
+
canvas.removeEventListener("mouseup", onMouseUp);
|
|
138447
|
+
};
|
|
138448
|
+
|
|
138449
|
+
const startCanvasPos = math.vec2();
|
|
138450
|
+
const onMouseDown = function(event) {
|
|
138451
|
+
if (event.which === 1)
|
|
138452
|
+
{
|
|
138453
|
+
copyCanvasPos(event, startCanvasPos);
|
|
138454
|
+
buttonDown = true;
|
|
138455
|
+
}
|
|
138456
|
+
};
|
|
138457
|
+
canvas.addEventListener("mousedown", onMouseDown);
|
|
138458
|
+
|
|
138459
|
+
const onMouseMove = function(event) {
|
|
138460
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138461
|
+
if (buttonDown && math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138462
|
+
{
|
|
138463
|
+
resetAction();
|
|
138464
|
+
onCancel();
|
|
138465
|
+
}
|
|
138466
|
+
};
|
|
138467
|
+
canvas.addEventListener("mousemove", onMouseMove);
|
|
138468
|
+
|
|
138469
|
+
const onCameraControlRayMove = viewer.cameraControl.on(
|
|
138470
|
+
"rayMove",
|
|
138471
|
+
event => {
|
|
138472
|
+
const canvasPos = event.canvasPos;
|
|
138473
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138474
|
+
});
|
|
138475
|
+
|
|
138476
|
+
const onMouseUp = function(event) {
|
|
138477
|
+
if ((event.which === 1) && buttonDown)
|
|
138478
|
+
{
|
|
138479
|
+
cleanup();
|
|
138480
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138481
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138482
|
+
}
|
|
138483
|
+
};
|
|
138484
|
+
canvas.addEventListener("mouseup", onMouseUp);
|
|
138485
|
+
|
|
138486
|
+
return cleanup;
|
|
138487
|
+
};
|
|
138488
|
+
};
|
|
138489
|
+
|
|
138490
|
+
const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
138491
|
+
return function(onCancel, onChange, onCommit) {
|
|
138492
|
+
const scene = viewer.scene;
|
|
138493
|
+
const canvas = scene.canvas.canvas;
|
|
138494
|
+
const longTouchTimeoutMs = 300;
|
|
138495
|
+
const moveTolerance = 20;
|
|
138496
|
+
|
|
138497
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138498
|
+
vec2[0] = event.clientX;
|
|
138499
|
+
vec2[1] = event.clientY;
|
|
138500
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138501
|
+
return vec2;
|
|
138502
|
+
};
|
|
138503
|
+
|
|
138504
|
+
const pickWorldPos = canvasPos => {
|
|
138505
|
+
const origin = math.vec3();
|
|
138506
|
+
const direction = math.vec3();
|
|
138507
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138508
|
+
return ray2WorldPos(origin, direction);
|
|
138509
|
+
};
|
|
138510
|
+
|
|
138511
|
+
let longTouchTimeout = null;
|
|
138512
|
+
const nop = () => { };
|
|
138513
|
+
let onSingleTouchMove = nop;
|
|
138514
|
+
let startTouchIdentifier;
|
|
138515
|
+
|
|
138516
|
+
const resetAction = function() {
|
|
138517
|
+
pointerCircle.stop();
|
|
138518
|
+
clearTimeout(longTouchTimeout);
|
|
138519
|
+
viewer.cameraControl.active = true;
|
|
138520
|
+
onSingleTouchMove = nop;
|
|
138521
|
+
startTouchIdentifier = null;
|
|
138522
|
+
};
|
|
138523
|
+
|
|
138524
|
+
const cleanup = function() {
|
|
138525
|
+
resetAction();
|
|
138526
|
+
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
138527
|
+
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
138528
|
+
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
138529
|
+
};
|
|
138530
|
+
|
|
138531
|
+
const onCanvasTouchStart = function(event) {
|
|
138532
|
+
const touches = event.touches;
|
|
138533
|
+
|
|
138534
|
+
if (touches.length !== 1)
|
|
138535
|
+
{
|
|
138536
|
+
resetAction();
|
|
138537
|
+
onCancel();
|
|
138538
|
+
}
|
|
138539
|
+
else
|
|
138540
|
+
{
|
|
138541
|
+
const startTouch = touches[0];
|
|
138542
|
+
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
138543
|
+
|
|
138544
|
+
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
138545
|
+
if (startWorldPos)
|
|
138546
|
+
{
|
|
138547
|
+
startTouchIdentifier = startTouch.identifier;
|
|
138548
|
+
|
|
138549
|
+
onSingleTouchMove = canvasPos => {
|
|
138550
|
+
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138551
|
+
{
|
|
138552
|
+
resetAction();
|
|
138553
|
+
}
|
|
138554
|
+
};
|
|
138555
|
+
|
|
138556
|
+
longTouchTimeout = setTimeout(
|
|
138557
|
+
function() {
|
|
138558
|
+
pointerCircle.start(startCanvasPos);
|
|
138559
|
+
|
|
138560
|
+
longTouchTimeout = setTimeout(
|
|
138561
|
+
function() {
|
|
138562
|
+
pointerCircle.stop();
|
|
138563
|
+
|
|
138564
|
+
viewer.cameraControl.active = false;
|
|
138565
|
+
|
|
138566
|
+
onSingleTouchMove = canvasPos => {
|
|
138567
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138568
|
+
};
|
|
138569
|
+
|
|
138570
|
+
onSingleTouchMove(startCanvasPos);
|
|
138571
|
+
},
|
|
138572
|
+
longTouchTimeoutMs);
|
|
138573
|
+
},
|
|
138574
|
+
250);
|
|
138575
|
+
}
|
|
138576
|
+
}
|
|
138577
|
+
};
|
|
138578
|
+
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
138579
|
+
|
|
138580
|
+
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
138581
|
+
|
|
138582
|
+
const onCanvasTouchMove = function(event) {
|
|
138583
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138584
|
+
if (touch)
|
|
138585
|
+
{
|
|
138586
|
+
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
138587
|
+
}
|
|
138588
|
+
};
|
|
138589
|
+
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
138590
|
+
|
|
138591
|
+
const onCanvasTouchEnd = function(event) {
|
|
138592
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138593
|
+
if (touch)
|
|
138594
|
+
{
|
|
138595
|
+
cleanup();
|
|
138596
|
+
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
138597
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138598
|
+
}
|
|
138599
|
+
};
|
|
138600
|
+
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
138601
|
+
|
|
138602
|
+
return cleanup;
|
|
138603
|
+
};
|
|
138604
|
+
};
|
|
138605
|
+
|
|
138606
|
+
const planeIntersect = function(p0, n, origin, direction) {
|
|
138607
|
+
const t = - (math.dotVec3(origin, n) - p0) / math.dotVec3(direction, n);
|
|
138608
|
+
{
|
|
138609
|
+
const worldPos = math.vec3();
|
|
138610
|
+
math.mulVec3Scalar(direction, t, worldPos);
|
|
138611
|
+
math.addVec3(origin, worldPos, worldPos);
|
|
138612
|
+
return worldPos;
|
|
138613
|
+
}
|
|
138614
|
+
};
|
|
138615
|
+
|
|
138616
|
+
/**
|
|
138617
|
+
* @desc Renders a transparent box between two 3D points.
|
|
138618
|
+
*
|
|
138619
|
+
* See {@link ZonesPlugin} for more info.
|
|
138620
|
+
*/
|
|
138621
|
+
|
|
138622
|
+
class Zone extends Component {
|
|
138623
|
+
|
|
138624
|
+
/**
|
|
138625
|
+
* @private
|
|
138626
|
+
*/
|
|
138627
|
+
constructor(plugin, cfg = {}) {
|
|
138628
|
+
|
|
138629
|
+
super(plugin.viewer.scene, cfg);
|
|
138630
|
+
|
|
138631
|
+
/**
|
|
138632
|
+
* The {@link ZonesPlugin} that owns this Zone.
|
|
138633
|
+
* @type {ZonesPlugin}
|
|
138634
|
+
*/
|
|
138635
|
+
this.plugin = plugin;
|
|
138636
|
+
|
|
138637
|
+
this._container = cfg.container;
|
|
138638
|
+
if (!this._container) {
|
|
138639
|
+
throw "config missing: container";
|
|
138640
|
+
}
|
|
138641
|
+
|
|
138642
|
+
this._eventSubs = {};
|
|
138643
|
+
|
|
138644
|
+
this.plugin.viewer.scene;
|
|
138645
|
+
|
|
138646
|
+
this._geometry = cfg.geometry;
|
|
138647
|
+
|
|
138648
|
+
cfg.onMouseOver ? (event) => {
|
|
138649
|
+
cfg.onMouseOver(event, this);
|
|
138650
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event));
|
|
138651
|
+
} : null;
|
|
138652
|
+
|
|
138653
|
+
cfg.onMouseLeave ? (event) => {
|
|
138654
|
+
cfg.onMouseLeave(event, this);
|
|
138655
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event));
|
|
138656
|
+
} : null;
|
|
138657
|
+
|
|
138658
|
+
cfg.onContextMenu ? (event) => {
|
|
138659
|
+
cfg.onContextMenu(event, this);
|
|
138660
|
+
} : null;
|
|
138661
|
+
|
|
138662
|
+
this._alpha = (("alpha" in cfg) && (cfg.alpha !== undefined)) ? cfg.alpha : 0.5;
|
|
138663
|
+
this.color = cfg.color;
|
|
138664
|
+
|
|
138665
|
+
this._visible = true;
|
|
138666
|
+
|
|
138667
|
+
this._rebuildMesh();
|
|
138668
|
+
}
|
|
138669
|
+
|
|
138670
|
+
_rebuildMesh() {
|
|
138671
|
+
const scene = this.plugin.viewer.scene;
|
|
138672
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138673
|
+
const downward = this._geometry.height < 0;
|
|
138674
|
+
const altitude = this._geometry.altitude + (downward ? this._geometry.height : 0);
|
|
138675
|
+
const height = this._geometry.height * (downward ? -1 : 1);
|
|
138676
|
+
|
|
138677
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
|
|
138678
|
+
|
|
138679
|
+
const pos = [ ];
|
|
138680
|
+
const ind = [ ];
|
|
138681
|
+
|
|
138682
|
+
|
|
138683
|
+
const addPlane = (isCeiling) => {
|
|
138684
|
+
const baseIdx = pos.length;
|
|
138685
|
+
|
|
138686
|
+
for (let c of baseVertices) {
|
|
138687
|
+
pos.push([ c[0], altitude + (isCeiling ? height : 0), c[1] ]);
|
|
138688
|
+
}
|
|
138689
|
+
|
|
138690
|
+
for (let t of baseTriangles) {
|
|
138691
|
+
ind.push(...(isCeiling ? t : t.slice(0).reverse()).map(i => i + baseIdx));
|
|
138692
|
+
}
|
|
138693
|
+
};
|
|
138694
|
+
addPlane(false); // floor
|
|
138695
|
+
addPlane(true); // ceiling
|
|
138696
|
+
|
|
138697
|
+
|
|
138698
|
+
// sides
|
|
138699
|
+
for (let i = 0; i < baseVertices.length; ++i) {
|
|
138700
|
+
const a = baseVertices[i];
|
|
138701
|
+
const b = baseVertices[(i+1) % baseVertices.length];
|
|
138702
|
+
const f = altitude;
|
|
138703
|
+
const c = altitude + height;
|
|
138704
|
+
|
|
138705
|
+
const baseIdx = pos.length;
|
|
138706
|
+
|
|
138707
|
+
pos.push(
|
|
138708
|
+
[ a[0], f, a[1] ],
|
|
138709
|
+
[ b[0], f, b[1] ],
|
|
138710
|
+
[ b[0], c, b[1] ],
|
|
138711
|
+
[ a[0], c, a[1] ]
|
|
138712
|
+
);
|
|
138713
|
+
|
|
138714
|
+
ind.push(...[ 0, 1, 2, 0, 2, 3 ].map(i => i + baseIdx));
|
|
138715
|
+
}
|
|
138716
|
+
|
|
138717
|
+
|
|
138718
|
+
if (this._zoneMesh) {
|
|
138719
|
+
this._zoneMesh.destroy();
|
|
138720
|
+
}
|
|
138721
|
+
|
|
138722
|
+
|
|
138723
|
+
const positions = [].concat(...pos);
|
|
138724
|
+
this._zoneMesh = new Mesh(scene, {
|
|
138725
|
+
edges: this._edges,
|
|
138726
|
+
geometry: new ReadableGeometry(
|
|
138727
|
+
scene,
|
|
138728
|
+
{
|
|
138729
|
+
positions: positions,
|
|
138730
|
+
indices: ind,
|
|
138731
|
+
normals: math.buildNormals(positions, ind)
|
|
138732
|
+
}),
|
|
138733
|
+
material: new PhongMaterial(scene, {
|
|
138734
|
+
alpha: this._alpha,
|
|
138735
|
+
backfaces: true,
|
|
138736
|
+
diffuse: hex2rgb(this._color)
|
|
138737
|
+
}),
|
|
138738
|
+
visible: this._visible
|
|
138739
|
+
});
|
|
138740
|
+
this._zoneMesh.highlighted = this._highlighted;
|
|
138741
|
+
|
|
138742
|
+
this._zoneMesh.zone = this;
|
|
138743
|
+
|
|
138744
|
+
|
|
138745
|
+
const min = idx => Math.min(...pos.map(p => p[idx]));
|
|
138746
|
+
const max = idx => Math.max(...pos.map(p => p[idx]));
|
|
138747
|
+
|
|
138748
|
+
const xmin = min(0);
|
|
138749
|
+
const ymin = min(1);
|
|
138750
|
+
const zmin = min(2);
|
|
138751
|
+
const xmax = max(0);
|
|
138752
|
+
const ymax = max(1);
|
|
138753
|
+
const zmax = max(2);
|
|
138754
|
+
|
|
138755
|
+
this._center = math.vec3([ (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2 ]);
|
|
138756
|
+
}
|
|
138757
|
+
|
|
138758
|
+
sectionedAverage(sectionPlanes) {
|
|
138759
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138760
|
+
|
|
138761
|
+
let faces = [ ];
|
|
138762
|
+
{
|
|
138763
|
+
const h = this._geometry.height;
|
|
138764
|
+
const a = this._geometry.altitude;
|
|
138765
|
+
const c = a + Math.max(0, h);
|
|
138766
|
+
const f = a + Math.min(0, h);
|
|
138767
|
+
|
|
138768
|
+
const addPlane = (isCeiling) => {
|
|
138769
|
+
const face = planeCoords.map(p => [ p[0], isCeiling ? c : f, p[1] ]);
|
|
138770
|
+
faces.push(isCeiling ? face : face.slice(0).reverse());
|
|
138771
|
+
};
|
|
138772
|
+
addPlane(true); // ceiling
|
|
138773
|
+
addPlane(false); // floor
|
|
138774
|
+
|
|
138775
|
+
// sides
|
|
138776
|
+
const p = (idx, y) => [ planeCoords[idx][0], y, planeCoords[idx][1] ];
|
|
138777
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
138778
|
+
{
|
|
138779
|
+
const j = (i + 1) % planeCoords.length;
|
|
138780
|
+
faces.push([ p(i, f), p(j, f), p(j, c), p(i, c) ]);
|
|
138781
|
+
}
|
|
138782
|
+
}
|
|
138783
|
+
|
|
138784
|
+
for (const s of sectionPlanes)
|
|
138785
|
+
{
|
|
138786
|
+
const dir = s.dir;
|
|
138787
|
+
const dist = s.dist;
|
|
138788
|
+
const newFaces = [ ];
|
|
138789
|
+
|
|
138790
|
+
for (const face of faces)
|
|
138791
|
+
{
|
|
138792
|
+
const EPSILON = 1e-5;
|
|
138793
|
+
const COPLANAR = 0;
|
|
138794
|
+
const FRONT = 1;
|
|
138795
|
+
const BACK = 2;
|
|
138796
|
+
const SPANNING = 3;
|
|
138797
|
+
|
|
138798
|
+
// Classify each point as well as the entire polygon into one of the above four classes.
|
|
138799
|
+
let polygonType = 0;
|
|
138800
|
+
const types = [ ];
|
|
138801
|
+
for (let i = 0; i < face.length; i++) {
|
|
138802
|
+
const t = math.dotVec3(dir, face[i]) + dist;
|
|
138803
|
+
const type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR;
|
|
138804
|
+
polygonType |= type;
|
|
138805
|
+
types.push(type);
|
|
138806
|
+
}
|
|
138807
|
+
|
|
138808
|
+
// Put the polygon in the correct list, splitting it when necessary.
|
|
138809
|
+
switch (polygonType) {
|
|
138810
|
+
case COPLANAR:
|
|
138811
|
+
newFaces.push(face);
|
|
138812
|
+
break;
|
|
138813
|
+
case FRONT:
|
|
138814
|
+
newFaces.push(face);
|
|
138815
|
+
break;
|
|
138816
|
+
case BACK:
|
|
138817
|
+
break;
|
|
138818
|
+
case SPANNING:
|
|
138819
|
+
const f = [ ];
|
|
138820
|
+
for (let i = 0; i < face.length; i++)
|
|
138821
|
+
{
|
|
138822
|
+
var j = (i + 1) % face.length;
|
|
138823
|
+
const ti = types[i];
|
|
138824
|
+
const tj = types[j];
|
|
138825
|
+
const vi = face[i];
|
|
138826
|
+
const vj = face[j];
|
|
138827
|
+
if (ti !== BACK)
|
|
138828
|
+
{
|
|
138829
|
+
f.push(vi);
|
|
138830
|
+
}
|
|
138831
|
+
|
|
138832
|
+
if ((ti | tj) === SPANNING)
|
|
138833
|
+
{
|
|
138834
|
+
const diff = math.vec3();
|
|
138835
|
+
math.subVec3(vj, vi, diff);
|
|
138836
|
+
const t = - (dist + math.dotVec3(dir, vi)) / math.dotVec3(dir, diff);
|
|
138837
|
+
const v = [0,0,0];
|
|
138838
|
+
math.lerpVec3(t, 0, 1, vi, vj, v);
|
|
138839
|
+
f.push(v);
|
|
138840
|
+
}
|
|
138841
|
+
}
|
|
138842
|
+
if (f.length >= 3)
|
|
138843
|
+
{
|
|
138844
|
+
newFaces.push(f);
|
|
138845
|
+
}
|
|
138846
|
+
break;
|
|
138847
|
+
}
|
|
138848
|
+
}
|
|
138849
|
+
|
|
138850
|
+
faces = newFaces;
|
|
138851
|
+
}
|
|
138852
|
+
|
|
138853
|
+
if (faces.length === 0)
|
|
138854
|
+
{
|
|
138855
|
+
return null;
|
|
138856
|
+
}
|
|
138857
|
+
else
|
|
138858
|
+
{
|
|
138859
|
+
const avg = math.vec3([ 0, 0, 0 ]);
|
|
138860
|
+
const unique = new Set();
|
|
138861
|
+
|
|
138862
|
+
for (const f of faces)
|
|
138863
|
+
{
|
|
138864
|
+
for (const p of f)
|
|
138865
|
+
{
|
|
138866
|
+
const id = p.map(x => x.toFixed(3)).join(":");
|
|
138867
|
+
if (! (unique.has(id)))
|
|
138868
|
+
{
|
|
138869
|
+
unique.add(id);
|
|
138870
|
+
math.addVec3(avg, p, avg);
|
|
138871
|
+
}
|
|
138872
|
+
}
|
|
138873
|
+
}
|
|
138874
|
+
|
|
138875
|
+
math.mulVec3Scalar(avg, 1 / unique.size, avg);
|
|
138876
|
+
|
|
138877
|
+
return avg;
|
|
138878
|
+
}
|
|
138879
|
+
}
|
|
138880
|
+
|
|
138881
|
+
get center() {
|
|
138882
|
+
return this._center;
|
|
138883
|
+
}
|
|
138884
|
+
|
|
138885
|
+
get altitude() {
|
|
138886
|
+
return this._geometry.altitude;
|
|
138887
|
+
}
|
|
138888
|
+
|
|
138889
|
+
set altitude(value) {
|
|
138890
|
+
this._geometry.altitude = value;
|
|
138891
|
+
this._rebuildMesh();
|
|
138892
|
+
}
|
|
138893
|
+
|
|
138894
|
+
get height() {
|
|
138895
|
+
return this._geometry.height;
|
|
138896
|
+
}
|
|
138897
|
+
|
|
138898
|
+
set height(value) {
|
|
138899
|
+
this._geometry.height = value;
|
|
138900
|
+
this._rebuildMesh();
|
|
138901
|
+
}
|
|
138902
|
+
|
|
138903
|
+
get highlighted() {
|
|
138904
|
+
return this._highlighted;
|
|
138905
|
+
}
|
|
138906
|
+
|
|
138907
|
+
set highlighted(value)
|
|
138908
|
+
{
|
|
138909
|
+
this._highlighted = value;
|
|
138910
|
+
if (this._zoneMesh) {
|
|
138911
|
+
this._zoneMesh.highlighted = value;
|
|
138912
|
+
}
|
|
138913
|
+
}
|
|
138914
|
+
|
|
138915
|
+
set color(value) {
|
|
138916
|
+
this._color = value;
|
|
138917
|
+
if (this._zoneMesh) {
|
|
138918
|
+
this._zoneMesh.material.diffuse = hex2rgb(this._color);
|
|
138919
|
+
}
|
|
138920
|
+
}
|
|
138921
|
+
|
|
138922
|
+
get color() {
|
|
138923
|
+
return this._color;
|
|
138924
|
+
}
|
|
138925
|
+
|
|
138926
|
+
set alpha(value) {
|
|
138927
|
+
this._alpha = value;
|
|
138928
|
+
if (this._zoneMesh) {
|
|
138929
|
+
this._zoneMesh.material.alpha = this._alpha;
|
|
138930
|
+
}
|
|
138931
|
+
}
|
|
138932
|
+
|
|
138933
|
+
get alpha() {
|
|
138934
|
+
return this._alpha;
|
|
138935
|
+
}
|
|
138936
|
+
|
|
138937
|
+
get edges() {
|
|
138938
|
+
return this._edges;
|
|
138939
|
+
}
|
|
138940
|
+
|
|
138941
|
+
set edges(edges) {
|
|
138942
|
+
this._edges = edges;
|
|
138943
|
+
if (this._zoneMesh) {
|
|
138944
|
+
this._zoneMesh.edges = this._edges;
|
|
138945
|
+
}
|
|
138946
|
+
}
|
|
138947
|
+
|
|
138948
|
+
/**
|
|
138949
|
+
* Sets whether this Zone is visible or not.
|
|
138950
|
+
*
|
|
138951
|
+
* @type {Boolean}
|
|
138952
|
+
*/
|
|
138953
|
+
set visible(value) {
|
|
138954
|
+
this._visible = !!value;
|
|
138955
|
+
this._zoneMesh.visible = this._visible;
|
|
138956
|
+
this._needUpdate();
|
|
138957
|
+
}
|
|
138958
|
+
|
|
138959
|
+
/**
|
|
138960
|
+
* Gets whether this Zone is visible or not.
|
|
138961
|
+
*
|
|
138962
|
+
* @type {Boolean}
|
|
138963
|
+
*/
|
|
138964
|
+
get visible() {
|
|
138965
|
+
return this._visible;
|
|
138966
|
+
}
|
|
138967
|
+
|
|
138968
|
+
/**
|
|
138969
|
+
* Gets this Zone as JSON.
|
|
138970
|
+
*
|
|
138971
|
+
* @returns {JSON}
|
|
138972
|
+
*/
|
|
138973
|
+
|
|
138974
|
+
getJSON() {
|
|
138975
|
+
return {
|
|
138976
|
+
id: this.id,
|
|
138977
|
+
geometry: this._geometry,
|
|
138978
|
+
alpha: this._alpha,
|
|
138979
|
+
color: this._color
|
|
138980
|
+
};
|
|
138981
|
+
}
|
|
138982
|
+
|
|
138983
|
+
duplicate() {
|
|
138984
|
+
return this.plugin.createZone(
|
|
138985
|
+
{
|
|
138986
|
+
id: math.createUUID(),
|
|
138987
|
+
geometry: {
|
|
138988
|
+
planeCoordinates: this._geometry.planeCoordinates.map(c => c.slice()),
|
|
138989
|
+
altitude: this._geometry.altitude,
|
|
138990
|
+
height: this._geometry.height
|
|
138991
|
+
},
|
|
138992
|
+
alpha: this._alpha,
|
|
138993
|
+
color: this._color
|
|
138994
|
+
});
|
|
138995
|
+
}
|
|
138996
|
+
|
|
138997
|
+
/**
|
|
138998
|
+
* @private
|
|
138999
|
+
*/
|
|
139000
|
+
destroy() {
|
|
139001
|
+
this._zoneMesh.destroy();
|
|
139002
|
+
super.destroy();
|
|
139003
|
+
}
|
|
139004
|
+
}
|
|
139005
|
+
|
|
139006
|
+
/**
|
|
139007
|
+
* Creates {@link Zone}s in a {@link ZonesPlugin} from mouse input.
|
|
139008
|
+
*
|
|
139009
|
+
* ## Usage
|
|
139010
|
+
*
|
|
139011
|
+
* [[Run example](/examples/measurement/#distance_createWithMouse_snapping)]
|
|
139012
|
+
*
|
|
139013
|
+
* ````javascript
|
|
139014
|
+
* import {Viewer, XKTLoaderPlugin, ZonesPlugin, ZonesMouseControl} from "xeokit-sdk.es.js";
|
|
139015
|
+
*
|
|
139016
|
+
* const viewer = new Viewer({
|
|
139017
|
+
* canvasId: "myCanvas",
|
|
139018
|
+
* });
|
|
139019
|
+
*
|
|
139020
|
+
* viewer.camera.eye = [-3.93, 2.85, 27.01];
|
|
139021
|
+
* viewer.camera.look = [4.40, 3.72, 8.89];
|
|
139022
|
+
* viewer.camera.up = [-0.01, 0.99, 0.039];
|
|
139023
|
+
*
|
|
139024
|
+
* const xktLoader = new XKTLoaderPlugin(viewer);
|
|
139025
|
+
*
|
|
139026
|
+
* const sceneModel = xktLoader.load({
|
|
139027
|
+
* id: "myModel",
|
|
139028
|
+
* src: "Duplex.xkt"
|
|
139029
|
+
* });
|
|
139030
|
+
*
|
|
139031
|
+
* const zones = new ZonesPlugin(viewer);
|
|
139032
|
+
*
|
|
139033
|
+
* const zonesControl = new ZonesMouseControl(Zones)
|
|
139034
|
+
* ````
|
|
139035
|
+
*/
|
|
139036
|
+
class ZonesMouseControl extends Component {
|
|
139037
|
+
|
|
139038
|
+
/**
|
|
139039
|
+
* Creates a ZonesMouseControl bound to the given ZonesPlugin.
|
|
139040
|
+
*
|
|
139041
|
+
* @param {ZonesPlugin} zonesPlugin The ZonesPlugin to control.
|
|
139042
|
+
* @param [cfg] Configuration
|
|
139043
|
+
* @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor when snapping is enabled.
|
|
139044
|
+
*/
|
|
139045
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139046
|
+
super(zonesPlugin.viewer.scene);
|
|
139047
|
+
|
|
139048
|
+
this.zonesPlugin = zonesPlugin;
|
|
139049
|
+
this.pointerLens = cfg.pointerLens;
|
|
139050
|
+
this._deactivate = null;
|
|
139051
|
+
}
|
|
139052
|
+
|
|
139053
|
+
get active() {
|
|
139054
|
+
return !! this._deactivate;
|
|
139055
|
+
}
|
|
139056
|
+
|
|
139057
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139058
|
+
|
|
139059
|
+
if (this._deactivate) {
|
|
139060
|
+
return;
|
|
139061
|
+
}
|
|
139062
|
+
|
|
139063
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139064
|
+
const params = zoneAltitude;
|
|
139065
|
+
const param = (name, defaultValue) => {
|
|
139066
|
+
if (name in params) {
|
|
139067
|
+
return params[name];
|
|
139068
|
+
} else if (defaultValue !== undefined) {
|
|
139069
|
+
return defaultValue;
|
|
139070
|
+
} else {
|
|
139071
|
+
throw "config missing: " + name;
|
|
139072
|
+
}
|
|
139073
|
+
};
|
|
139074
|
+
|
|
139075
|
+
zoneAltitude = param("altitude");
|
|
139076
|
+
zoneHeight = param("height");
|
|
139077
|
+
zoneColor = param("color", "#008000");
|
|
139078
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139079
|
+
}
|
|
139080
|
+
|
|
139081
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139082
|
+
const viewer = zonesPlugin.viewer;
|
|
139083
|
+
const scene = viewer.scene;
|
|
139084
|
+
const self = this;
|
|
139085
|
+
|
|
139086
|
+
const select3dPoint = mousePointSelector(
|
|
139087
|
+
viewer,
|
|
139088
|
+
function(origin, direction) {
|
|
139089
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139090
|
+
});
|
|
139091
|
+
|
|
139092
|
+
(function rec() {
|
|
139093
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139094
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139095
|
+
zone => {
|
|
139096
|
+
let reactivate = true;
|
|
139097
|
+
self._deactivate = () => { reactivate = false; };
|
|
139098
|
+
self.fire("zoneEnd", zone);
|
|
139099
|
+
if (reactivate)
|
|
139100
|
+
{
|
|
139101
|
+
rec();
|
|
139102
|
+
}
|
|
139103
|
+
}).deactivate;
|
|
139104
|
+
})();
|
|
139105
|
+
}
|
|
139106
|
+
|
|
139107
|
+
deactivate() {
|
|
139108
|
+
if (this._deactivate)
|
|
139109
|
+
{
|
|
139110
|
+
this._deactivate();
|
|
139111
|
+
this._deactivate = null;
|
|
139112
|
+
}
|
|
139113
|
+
}
|
|
139114
|
+
|
|
139115
|
+
/**
|
|
139116
|
+
* Destroys this ZonesMouseControl.
|
|
139117
|
+
*
|
|
139118
|
+
* Destroys any {@link Zone} under construction by this ZonesMouseControl.
|
|
139119
|
+
*/
|
|
139120
|
+
destroy() {
|
|
139121
|
+
this.deactivate();
|
|
139122
|
+
super.destroy();
|
|
139123
|
+
}
|
|
139124
|
+
}
|
|
139125
|
+
|
|
139126
|
+
/**
|
|
139127
|
+
* ZonesPlugin documentation to be added, mostly compatible with DistanceMeasurementsPlugin.
|
|
139128
|
+
*/
|
|
139129
|
+
class ZonesPlugin extends Plugin {
|
|
139130
|
+
|
|
139131
|
+
/**
|
|
139132
|
+
* @constructor
|
|
139133
|
+
* @param {Viewer} viewer The Viewer.
|
|
139134
|
+
* @param {Object} [cfg] Plugin configuration.
|
|
139135
|
+
* @param {String} [cfg.id="Zones"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
|
|
139136
|
+
* @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
|
|
139137
|
+
* @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label.
|
|
139138
|
+
* @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels).
|
|
139139
|
+
* @param {PointerCircle} [cfg.pointerLens] A PointerLens to help the user position the pointer. This can be shared with other plugins.
|
|
139140
|
+
*/
|
|
139141
|
+
constructor(viewer, cfg = {}) {
|
|
139142
|
+
|
|
139143
|
+
super("Zones", viewer);
|
|
139144
|
+
|
|
139145
|
+
this._pointerLens = cfg.pointerLens;
|
|
139146
|
+
|
|
139147
|
+
this._container = cfg.container || document.body;
|
|
139148
|
+
|
|
139149
|
+
this._zones = [ ];
|
|
139150
|
+
|
|
139151
|
+
this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF";
|
|
139152
|
+
this.zIndex = cfg.zIndex || 10000;
|
|
139153
|
+
|
|
139154
|
+
this._onMouseOver = (event, zone) => {
|
|
139155
|
+
this.fire("mouseOver", {
|
|
139156
|
+
plugin: this,
|
|
139157
|
+
zone,
|
|
139158
|
+
event
|
|
139159
|
+
});
|
|
139160
|
+
};
|
|
139161
|
+
|
|
139162
|
+
this._onMouseLeave = (event, zone) => {
|
|
139163
|
+
this.fire("mouseLeave", {
|
|
139164
|
+
plugin: this,
|
|
139165
|
+
zone,
|
|
139166
|
+
event
|
|
139167
|
+
});
|
|
139168
|
+
};
|
|
139169
|
+
|
|
139170
|
+
this._onContextMenu = (event, zone) => {
|
|
139171
|
+
this.fire("contextMenu", {
|
|
139172
|
+
plugin: this,
|
|
139173
|
+
zone,
|
|
139174
|
+
event
|
|
139175
|
+
});
|
|
139176
|
+
};
|
|
139177
|
+
}
|
|
139178
|
+
|
|
139179
|
+
/**
|
|
139180
|
+
* Creates a {@link Zone}.
|
|
139181
|
+
*
|
|
139182
|
+
* The Zone is then registered by {@link Zone#id} in {@link ZonesPlugin#zones}.
|
|
139183
|
+
*
|
|
139184
|
+
* @param {Object} params {@link Zone} configuration.
|
|
139185
|
+
* @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}.
|
|
139186
|
+
* @param {Number[]} params.origin.worldPos Origin World-space 3D position.
|
|
139187
|
+
* @param {Entity} params.origin.entity Origin Entity.
|
|
139188
|
+
* @param {Number[]} params.target.worldPos Target World-space 3D position.
|
|
139189
|
+
* @param {Entity} params.target.entity Target Entity.
|
|
139190
|
+
* @param {string} [params.color] The color of the length dot, wire and label.
|
|
139191
|
+
* @returns {Zone} The new {@link Zone}.
|
|
139192
|
+
*/
|
|
139193
|
+
createZone(params = {}) {
|
|
139194
|
+
if (this.viewer.scene.components[params.id]) {
|
|
139195
|
+
this.error("Viewer scene component with this ID already exists: " + params.id);
|
|
139196
|
+
delete params.id;
|
|
139197
|
+
}
|
|
139198
|
+
|
|
139199
|
+
const zone = new Zone(this, {
|
|
139200
|
+
id: params.id,
|
|
139201
|
+
plugin: this,
|
|
139202
|
+
container: this._container,
|
|
139203
|
+
geometry: params.geometry,
|
|
139204
|
+
alpha: params.alpha,
|
|
139205
|
+
color: params.color,
|
|
139206
|
+
onMouseOver: this._onMouseOver,
|
|
139207
|
+
onMouseLeave: this._onMouseLeave,
|
|
139208
|
+
onContextMenu: this._onContextMenu
|
|
139209
|
+
});
|
|
139210
|
+
this._zones.push(zone);
|
|
139211
|
+
zone.on("destroyed", () => {
|
|
139212
|
+
const idx = this._zones.indexOf(zone);
|
|
139213
|
+
if (idx >= 0) {
|
|
139214
|
+
this._zones.splice(idx, 1);
|
|
139215
|
+
}
|
|
139216
|
+
});
|
|
139217
|
+
this.fire("zoneCreated", zone);
|
|
139218
|
+
return zone;
|
|
139219
|
+
}
|
|
139220
|
+
|
|
139221
|
+
/**
|
|
139222
|
+
* Gets the existing {@link Zone}s, each mapped to its {@link Zone#id}.
|
|
139223
|
+
*
|
|
139224
|
+
* @type {{String:Zone}}
|
|
139225
|
+
*/
|
|
139226
|
+
get zones() {
|
|
139227
|
+
return this._zones;
|
|
139228
|
+
}
|
|
139229
|
+
|
|
139230
|
+
/**
|
|
139231
|
+
* Destroys this ZonesPlugin.
|
|
139232
|
+
*
|
|
139233
|
+
* Destroys all {@link Zone}s first.
|
|
139234
|
+
*/
|
|
139235
|
+
destroy() {
|
|
139236
|
+
super.destroy();
|
|
139237
|
+
}
|
|
139238
|
+
}
|
|
139239
|
+
|
|
139240
|
+
class ZonesTouchControl extends Component {
|
|
139241
|
+
|
|
139242
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139243
|
+
super(zonesPlugin.viewer.scene);
|
|
139244
|
+
|
|
139245
|
+
this.zonesPlugin = zonesPlugin;
|
|
139246
|
+
this.pointerLens = cfg.pointerLens;
|
|
139247
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139248
|
+
this._deactivate = null;
|
|
139249
|
+
}
|
|
139250
|
+
|
|
139251
|
+
get active() {
|
|
139252
|
+
return !! this._deactivate;
|
|
139253
|
+
}
|
|
139254
|
+
|
|
139255
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139256
|
+
|
|
139257
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139258
|
+
const params = zoneAltitude;
|
|
139259
|
+
const param = (name, defaultValue) => {
|
|
139260
|
+
if (name in params) {
|
|
139261
|
+
return params[name];
|
|
139262
|
+
} else if (defaultValue !== undefined) {
|
|
139263
|
+
return defaultValue;
|
|
139264
|
+
} else {
|
|
139265
|
+
throw "config missing: " + name;
|
|
139266
|
+
}
|
|
139267
|
+
};
|
|
139268
|
+
|
|
139269
|
+
zoneAltitude = param("altitude");
|
|
139270
|
+
zoneHeight = param("height");
|
|
139271
|
+
zoneColor = param("color", "#008000");
|
|
139272
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139273
|
+
}
|
|
139274
|
+
|
|
139275
|
+
if (this._deactivate) {
|
|
139276
|
+
return;
|
|
139277
|
+
}
|
|
139278
|
+
|
|
139279
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139280
|
+
const viewer = zonesPlugin.viewer;
|
|
139281
|
+
const scene = viewer.scene;
|
|
139282
|
+
const self = this;
|
|
139283
|
+
|
|
139284
|
+
const select3dPoint = touchPointSelector(
|
|
139285
|
+
viewer,
|
|
139286
|
+
this.pointerCircle,
|
|
139287
|
+
function(origin, direction) {
|
|
139288
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139289
|
+
});
|
|
139290
|
+
|
|
139291
|
+
(function rec() {
|
|
139292
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139293
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139294
|
+
zone => {
|
|
139295
|
+
let reactivate = true;
|
|
139296
|
+
self._deactivate = () => { reactivate = false; };
|
|
139297
|
+
self.fire("zoneEnd", zone);
|
|
139298
|
+
if (reactivate)
|
|
139299
|
+
{
|
|
139300
|
+
rec();
|
|
139301
|
+
}
|
|
139302
|
+
}).deactivate;
|
|
139303
|
+
})();
|
|
139304
|
+
}
|
|
139305
|
+
|
|
139306
|
+
deactivate() {
|
|
139307
|
+
if (this._deactivate)
|
|
139308
|
+
{
|
|
139309
|
+
this._deactivate();
|
|
139310
|
+
this._deactivate = null;
|
|
139311
|
+
}
|
|
139312
|
+
}
|
|
139313
|
+
|
|
139314
|
+
destroy() {
|
|
139315
|
+
this.deactivate();
|
|
139316
|
+
super.destroy();
|
|
139317
|
+
}
|
|
139318
|
+
}
|
|
139319
|
+
|
|
139320
|
+
const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
139321
|
+
const updatePointerLens = (pointerLens
|
|
139322
|
+
? function(canvasPos) {
|
|
139323
|
+
pointerLens.visible = !! canvasPos;
|
|
139324
|
+
if (canvasPos)
|
|
139325
|
+
{
|
|
139326
|
+
pointerLens.canvasPos = canvasPos;
|
|
139327
|
+
}
|
|
139328
|
+
}
|
|
139329
|
+
: () => { });
|
|
139330
|
+
|
|
139331
|
+
let deactivatePointSelection;
|
|
139332
|
+
const cleanups = [ () => updatePointerLens(null) ];
|
|
139333
|
+
|
|
139334
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
139335
|
+
cleanups.push(() => basePolygon.destroy());
|
|
139336
|
+
|
|
139337
|
+
(function selectNextPoint(markers) {
|
|
139338
|
+
const marker = marker3D(scene, zoneColor);
|
|
139339
|
+
const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
|
|
139340
|
+
|
|
139341
|
+
cleanups.push(() => {
|
|
139342
|
+
marker.destroy();
|
|
139343
|
+
wire && wire.destroy();
|
|
139344
|
+
});
|
|
139345
|
+
|
|
139346
|
+
const firstMarker = (markers.length > 0) && markers[0];
|
|
139347
|
+
const getSnappedFirst = function(canvasPos) {
|
|
139348
|
+
const firstCanvasPos = firstMarker && firstMarker.getCanvasPos();
|
|
139349
|
+
const snapToFirst = firstCanvasPos && (math.distVec2(firstCanvasPos, canvasPos) < 10);
|
|
139350
|
+
return snapToFirst && { canvasPos: firstCanvasPos, worldPos: firstMarker.getWorldPos() };
|
|
139351
|
+
};
|
|
139352
|
+
|
|
139353
|
+
const lastSegmentIntersects = (function() {
|
|
139354
|
+
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
139355
|
+
(q[0] >= Math.min(p[0], r[0])) &&
|
|
139356
|
+
(q[1] <= Math.max(p[1], r[1])) &&
|
|
139357
|
+
(q[1] >= Math.min(p[1], r[1])));
|
|
139358
|
+
|
|
139359
|
+
const orient = (p, q, r) => {
|
|
139360
|
+
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
139361
|
+
// collinear
|
|
139362
|
+
// clockwise
|
|
139363
|
+
// counterclockwise
|
|
139364
|
+
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
139365
|
+
};
|
|
139366
|
+
|
|
139367
|
+
return function(pos2D, excludeFirstSegment) {
|
|
139368
|
+
const a = pos2D[pos2D.length - 2];
|
|
139369
|
+
const b = pos2D[pos2D.length - 1];
|
|
139370
|
+
|
|
139371
|
+
for (let i = excludeFirstSegment ? 1 : 0; i < pos2D.length - 2 - 1; ++i)
|
|
139372
|
+
{
|
|
139373
|
+
const c = pos2D[i];
|
|
139374
|
+
const d = pos2D[i + 1];
|
|
139375
|
+
|
|
139376
|
+
const o1 = orient(a, b, c);
|
|
139377
|
+
const o2 = orient(a, b, d);
|
|
139378
|
+
const o3 = orient(c, d, a);
|
|
139379
|
+
const o4 = orient(c, d, b);
|
|
139380
|
+
|
|
139381
|
+
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
139382
|
+
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
139383
|
+
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
139384
|
+
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
139385
|
+
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
139386
|
+
{
|
|
139387
|
+
return true;
|
|
139388
|
+
}
|
|
139389
|
+
}
|
|
139390
|
+
|
|
139391
|
+
return false;
|
|
139392
|
+
};
|
|
139393
|
+
})();
|
|
139394
|
+
|
|
139395
|
+
deactivatePointSelection = select3dPoint(
|
|
139396
|
+
() => {
|
|
139397
|
+
updatePointerLens(null);
|
|
139398
|
+
marker.update(null);
|
|
139399
|
+
wire && wire.update(null);
|
|
139400
|
+
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
139401
|
+
},
|
|
139402
|
+
(canvasPos, worldPos) => {
|
|
139403
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139404
|
+
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
139405
|
+
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
139406
|
+
marker.update((! snappedFirst) && worldPos);
|
|
139407
|
+
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
139408
|
+
if ((markers.length >= 2))
|
|
139409
|
+
{
|
|
139410
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139411
|
+
const inter = lastSegmentIntersects(pos.map(p => [ p[0], p[2] ]), snappedFirst);
|
|
139412
|
+
basePolygon.updateBase(inter ? null : pos);
|
|
139413
|
+
}
|
|
139414
|
+
else
|
|
139415
|
+
basePolygon.updateBase(null);
|
|
139416
|
+
},
|
|
139417
|
+
function(canvasPos, worldPos) {
|
|
139418
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139419
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139420
|
+
basePolygon.updateBase(pos);
|
|
139421
|
+
const pos2D = pos.map(p => [ p[0], p[2] ]);
|
|
139422
|
+
if ((markers.length > 2) && lastSegmentIntersects(pos2D, snappedFirst))
|
|
139423
|
+
{
|
|
139424
|
+
cleanups.pop()();
|
|
139425
|
+
selectNextPoint(markers);
|
|
139426
|
+
}
|
|
139427
|
+
else if (snappedFirst)
|
|
139428
|
+
{
|
|
139429
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
139430
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
139431
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
139432
|
+
marker.update(worldPos);
|
|
139433
|
+
|
|
139434
|
+
cleanups.forEach(c => c());
|
|
139435
|
+
onZoneCreated(
|
|
139436
|
+
zonesPlugin.createZone(
|
|
139437
|
+
{
|
|
139438
|
+
id: math.createUUID(),
|
|
139439
|
+
geometry: {
|
|
139440
|
+
planeCoordinates: pos2D,
|
|
139441
|
+
altitude: zoneAltitude,
|
|
139442
|
+
height: zoneHeight
|
|
139443
|
+
},
|
|
139444
|
+
alpha: zoneAlpha,
|
|
139445
|
+
color: zoneColor
|
|
139446
|
+
}));
|
|
139447
|
+
}
|
|
139448
|
+
else
|
|
139449
|
+
{
|
|
139450
|
+
marker.update(worldPos);
|
|
139451
|
+
wire && wire.update(worldPos);
|
|
139452
|
+
selectNextPoint(markers.concat(marker));
|
|
139453
|
+
}
|
|
139454
|
+
});
|
|
139455
|
+
})([ ]);
|
|
139456
|
+
|
|
139457
|
+
return {
|
|
139458
|
+
closeSurface: function() {
|
|
139459
|
+
throw "TODO";
|
|
139460
|
+
},
|
|
139461
|
+
deactivate: function() {
|
|
139462
|
+
deactivatePointSelection();
|
|
139463
|
+
cleanups.forEach(c => c());
|
|
139464
|
+
}
|
|
139465
|
+
};
|
|
139466
|
+
};
|
|
139467
|
+
|
|
139468
|
+
class ZonesPolysurfaceMouseControl extends Component {
|
|
139469
|
+
|
|
139470
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139471
|
+
super(zonesPlugin.viewer.scene);
|
|
139472
|
+
|
|
139473
|
+
this.zonesPlugin = zonesPlugin;
|
|
139474
|
+
this.pointerLens = cfg.pointerLens;
|
|
139475
|
+
this._action = null;
|
|
139476
|
+
}
|
|
139477
|
+
|
|
139478
|
+
get active() {
|
|
139479
|
+
return !! this._action;
|
|
139480
|
+
}
|
|
139481
|
+
|
|
139482
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139483
|
+
|
|
139484
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139485
|
+
const params = zoneAltitude;
|
|
139486
|
+
const param = (name, defaultValue) => {
|
|
139487
|
+
if (name in params) {
|
|
139488
|
+
return params[name];
|
|
139489
|
+
} else if (defaultValue !== undefined) {
|
|
139490
|
+
return defaultValue;
|
|
139491
|
+
} else {
|
|
139492
|
+
throw "config missing: " + name;
|
|
139493
|
+
}
|
|
139494
|
+
};
|
|
139495
|
+
|
|
139496
|
+
zoneAltitude = param("altitude");
|
|
139497
|
+
zoneHeight = param("height");
|
|
139498
|
+
zoneColor = param("color", "#008000");
|
|
139499
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139500
|
+
}
|
|
139501
|
+
|
|
139502
|
+
if (this._action) {
|
|
139503
|
+
return;
|
|
139504
|
+
}
|
|
139505
|
+
|
|
139506
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139507
|
+
const viewer = zonesPlugin.viewer;
|
|
139508
|
+
const scene = viewer.scene;
|
|
139509
|
+
const self = this;
|
|
139510
|
+
|
|
139511
|
+
const select3dPoint = mousePointSelector(
|
|
139512
|
+
viewer,
|
|
139513
|
+
function(origin, direction) {
|
|
139514
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139515
|
+
});
|
|
139516
|
+
|
|
139517
|
+
(function rec() {
|
|
139518
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139519
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139520
|
+
zone => {
|
|
139521
|
+
let reactivate = true;
|
|
139522
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139523
|
+
self.fire("zoneEnd", zone);
|
|
139524
|
+
if (reactivate)
|
|
139525
|
+
{
|
|
139526
|
+
rec();
|
|
139527
|
+
}
|
|
139528
|
+
});
|
|
139529
|
+
})();
|
|
139530
|
+
}
|
|
139531
|
+
|
|
139532
|
+
deactivate() {
|
|
139533
|
+
if (this._action)
|
|
139534
|
+
{
|
|
139535
|
+
this._action.deactivate();
|
|
139536
|
+
this._action = null;
|
|
139537
|
+
}
|
|
139538
|
+
}
|
|
139539
|
+
|
|
139540
|
+
destroy() {
|
|
139541
|
+
this.deactivate();
|
|
139542
|
+
super.destroy();
|
|
139543
|
+
}
|
|
139544
|
+
}
|
|
139545
|
+
|
|
139546
|
+
class ZonesPolysurfaceTouchControl extends Component {
|
|
139547
|
+
|
|
139548
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139549
|
+
super(zonesPlugin.viewer.scene);
|
|
139550
|
+
|
|
139551
|
+
this.zonesPlugin = zonesPlugin;
|
|
139552
|
+
this.pointerLens = cfg.pointerLens;
|
|
139553
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139554
|
+
this._action = null;
|
|
139555
|
+
}
|
|
139556
|
+
|
|
139557
|
+
get active() {
|
|
139558
|
+
return !! this._action;
|
|
139559
|
+
}
|
|
139560
|
+
|
|
139561
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139562
|
+
|
|
139563
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139564
|
+
const params = zoneAltitude;
|
|
139565
|
+
const param = (name, defaultValue) => {
|
|
139566
|
+
if (name in params) {
|
|
139567
|
+
return params[name];
|
|
139568
|
+
} else if (defaultValue !== undefined) {
|
|
139569
|
+
return defaultValue;
|
|
139570
|
+
} else {
|
|
139571
|
+
throw "config missing: " + name;
|
|
139572
|
+
}
|
|
139573
|
+
};
|
|
139574
|
+
|
|
139575
|
+
zoneAltitude = param("altitude");
|
|
139576
|
+
zoneHeight = param("height");
|
|
139577
|
+
zoneColor = param("color", "#008000");
|
|
139578
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139579
|
+
}
|
|
139580
|
+
|
|
139581
|
+
if (this._action) {
|
|
139582
|
+
return;
|
|
139583
|
+
}
|
|
139584
|
+
|
|
139585
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139586
|
+
const viewer = zonesPlugin.viewer;
|
|
139587
|
+
const scene = viewer.scene;
|
|
139588
|
+
const self = this;
|
|
139589
|
+
|
|
139590
|
+
const select3dPoint = touchPointSelector(
|
|
139591
|
+
viewer,
|
|
139592
|
+
this.pointerCircle,
|
|
139593
|
+
function(origin, direction) {
|
|
139594
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139595
|
+
});
|
|
139596
|
+
|
|
139597
|
+
(function rec() {
|
|
139598
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139599
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139600
|
+
zone => {
|
|
139601
|
+
let reactivate = true;
|
|
139602
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139603
|
+
self.fire("zoneEnd", zone);
|
|
139604
|
+
if (reactivate)
|
|
139605
|
+
{
|
|
139606
|
+
rec();
|
|
139607
|
+
}
|
|
139608
|
+
});
|
|
139609
|
+
})();
|
|
139610
|
+
}
|
|
139611
|
+
|
|
139612
|
+
deactivate() {
|
|
139613
|
+
if (this._action)
|
|
139614
|
+
{
|
|
139615
|
+
this._action.deactivate();
|
|
139616
|
+
this._action = null;
|
|
139617
|
+
}
|
|
139618
|
+
}
|
|
139619
|
+
|
|
139620
|
+
destroy() {
|
|
139621
|
+
this.deactivate();
|
|
139622
|
+
super.destroy();
|
|
139623
|
+
}
|
|
139624
|
+
}
|
|
139625
|
+
|
|
139626
|
+
class ZoneEditControl extends Component {
|
|
139627
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139628
|
+
super(zone.plugin.viewer.scene);
|
|
139629
|
+
const self = this;
|
|
139630
|
+
|
|
139631
|
+
const altitude = zone._geometry.altitude;
|
|
139632
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139633
|
+
const updatePointerLens = (pointerLens
|
|
139634
|
+
? function(canvasPos) {
|
|
139635
|
+
pointerLens.visible = !! canvasPos;
|
|
139636
|
+
if (canvasPos)
|
|
139637
|
+
{
|
|
139638
|
+
pointerLens.canvasPos = canvasPos;
|
|
139639
|
+
}
|
|
139640
|
+
}
|
|
139641
|
+
: () => { });
|
|
139642
|
+
|
|
139643
|
+
const dots = zone._geometry.planeCoordinates.map(planeCoord => {
|
|
139644
|
+
let initWorldPos, initPlaneCoord;
|
|
139645
|
+
const setPlaneCoord = function(coord) {
|
|
139646
|
+
planeCoord[0] = coord[0];
|
|
139647
|
+
planeCoord[1] = coord[1];
|
|
139648
|
+
try {
|
|
139649
|
+
zone._rebuildMesh();
|
|
139650
|
+
} catch (e) {
|
|
139651
|
+
if (zone._zoneMesh) {
|
|
139652
|
+
zone._zoneMesh.destroy();
|
|
139653
|
+
zone._zoneMesh = null;
|
|
139654
|
+
}
|
|
139655
|
+
}
|
|
139656
|
+
};
|
|
139657
|
+
|
|
139658
|
+
const dot = draggableDot3D(
|
|
139659
|
+
handleMouseEvents,
|
|
139660
|
+
handleTouchEvents,
|
|
139661
|
+
zone.plugin.viewer,
|
|
139662
|
+
math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
|
|
139663
|
+
zone._color,
|
|
139664
|
+
(orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
|
|
139665
|
+
() => {
|
|
139666
|
+
initWorldPos = dot.getWorldPos().slice();
|
|
139667
|
+
initPlaneCoord = planeCoord.slice();
|
|
139668
|
+
set_other_dots_active(false, dot);
|
|
139669
|
+
},
|
|
139670
|
+
(canvasPos, worldPos) => {
|
|
139671
|
+
updatePointerLens(canvasPos);
|
|
139672
|
+
setPlaneCoord([ worldPos[0], worldPos[2] ]);
|
|
139673
|
+
},
|
|
139674
|
+
() => {
|
|
139675
|
+
if (zone._zoneMesh)
|
|
139676
|
+
{
|
|
139677
|
+
self.fire("edited");
|
|
139678
|
+
}
|
|
139679
|
+
else
|
|
139680
|
+
{
|
|
139681
|
+
dot.setWorldPos(initWorldPos);
|
|
139682
|
+
setPlaneCoord(initPlaneCoord);
|
|
139683
|
+
}
|
|
139684
|
+
updatePointerLens(null);
|
|
139685
|
+
set_other_dots_active(true, dot);
|
|
139686
|
+
});
|
|
139687
|
+
return dot;
|
|
139688
|
+
});
|
|
139689
|
+
const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
|
|
139690
|
+
set_other_dots_active(true);
|
|
139691
|
+
|
|
139692
|
+
const cleanup = function() {
|
|
139693
|
+
dots.forEach(m => m.destroy());
|
|
139694
|
+
updatePointerLens(null);
|
|
139695
|
+
};
|
|
139696
|
+
|
|
139697
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139698
|
+
|
|
139699
|
+
this._deactivate = function() {
|
|
139700
|
+
zone.off("destroyed", destroyCb);
|
|
139701
|
+
cleanup();
|
|
139702
|
+
};
|
|
139703
|
+
}
|
|
139704
|
+
|
|
139705
|
+
deactivate() {
|
|
139706
|
+
this._deactivate();
|
|
139707
|
+
super.destroy();
|
|
139708
|
+
}
|
|
139709
|
+
}
|
|
139710
|
+
|
|
139711
|
+
class ZoneEditMouseControl extends ZoneEditControl {
|
|
139712
|
+
constructor(zone, cfg) {
|
|
139713
|
+
super(zone, cfg, true, false);
|
|
139714
|
+
}
|
|
139715
|
+
}
|
|
139716
|
+
|
|
139717
|
+
class ZoneEditTouchControl extends ZoneEditControl {
|
|
139718
|
+
constructor(zone, cfg) {
|
|
139719
|
+
super(zone, cfg, false, true);
|
|
139720
|
+
}
|
|
139721
|
+
}
|
|
139722
|
+
|
|
139723
|
+
|
|
139724
|
+
class ZoneTranslateControl extends Component {
|
|
139725
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139726
|
+
const viewer = zone.plugin.viewer;
|
|
139727
|
+
const scene = viewer.scene;
|
|
139728
|
+
const canvas = scene.canvas.canvas;
|
|
139729
|
+
|
|
139730
|
+
super(scene);
|
|
139731
|
+
const self = this;
|
|
139732
|
+
|
|
139733
|
+
const altitude = zone._geometry.altitude;
|
|
139734
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139735
|
+
const updatePointerLens = (pointerLens
|
|
139736
|
+
? function(canvasPos) {
|
|
139737
|
+
pointerLens.visible = !! canvasPos;
|
|
139738
|
+
if (canvasPos)
|
|
139739
|
+
{
|
|
139740
|
+
pointerLens.canvasPos = canvasPos;
|
|
139741
|
+
}
|
|
139742
|
+
}
|
|
139743
|
+
: () => { });
|
|
139744
|
+
|
|
139745
|
+
const ray2WorldPos = (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir);
|
|
139746
|
+
|
|
139747
|
+
const pickWorldPos = canvasPos => {
|
|
139748
|
+
const origin = math.vec3();
|
|
139749
|
+
const direction = math.vec3();
|
|
139750
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
139751
|
+
return ray2WorldPos(origin, direction);
|
|
139752
|
+
};
|
|
139753
|
+
|
|
139754
|
+
const copyCanvasPos = (event, vec2) => {
|
|
139755
|
+
vec2[0] = event.clientX;
|
|
139756
|
+
vec2[1] = event.clientY;
|
|
139757
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
139758
|
+
return vec2;
|
|
139759
|
+
};
|
|
139760
|
+
|
|
139761
|
+
const canvasHandle = function(type, cb) {
|
|
139762
|
+
const callback = event => {
|
|
139763
|
+
event.preventDefault();
|
|
139764
|
+
cb(event);
|
|
139765
|
+
};
|
|
139766
|
+
canvas.addEventListener(type, callback);
|
|
139767
|
+
return () => canvas.removeEventListener(type, callback);
|
|
139768
|
+
};
|
|
139769
|
+
|
|
139770
|
+
let cleanupCurrentDrag = () => { };
|
|
139771
|
+
|
|
139772
|
+
const startDrag = function(event, onMoveType, onEndType, matchesEvent) {
|
|
139773
|
+
const e = matchesEvent(event);
|
|
139774
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139775
|
+
const pickRecord = viewer.scene.pick({ canvasPos: canvasPos, includeEntities: [ zone._zoneMesh.id ] });
|
|
139776
|
+
const pickZone = pickRecord && pickRecord.entity && pickRecord.entity.zone;
|
|
139777
|
+
|
|
139778
|
+
if (pickZone === zone)
|
|
139779
|
+
{
|
|
139780
|
+
cleanupCurrentDrag();
|
|
139781
|
+
|
|
139782
|
+
canvas.style.cursor = "move";
|
|
139783
|
+
viewer.cameraControl.active = false;
|
|
139784
|
+
|
|
139785
|
+
const onChange = (function() {
|
|
139786
|
+
const initCoords = zone._geometry.planeCoordinates.map(c => c.slice());
|
|
139787
|
+
const initWorldPos = pickWorldPos(canvasPos);
|
|
139788
|
+
const initDragCoord = math.vec2([ initWorldPos[0], initWorldPos[2] ]);
|
|
139789
|
+
const dPos = math.vec2();
|
|
139790
|
+
|
|
139791
|
+
return function(canvasPos) {
|
|
139792
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
139793
|
+
dPos[0] = worldPos[0];
|
|
139794
|
+
dPos[1] = worldPos[2];
|
|
139795
|
+
math.subVec2(initDragCoord, dPos, dPos);
|
|
139796
|
+
|
|
139797
|
+
zone._geometry.planeCoordinates.forEach((planeCoord, idx) => {
|
|
139798
|
+
math.subVec2(initCoords[idx], dPos, planeCoord);
|
|
139799
|
+
});
|
|
139800
|
+
|
|
139801
|
+
try {
|
|
139802
|
+
zone._rebuildMesh();
|
|
139803
|
+
} catch (e) {
|
|
139804
|
+
if (zone._zoneMesh) {
|
|
139805
|
+
zone._zoneMesh.destroy();
|
|
139806
|
+
zone._zoneMesh = null;
|
|
139807
|
+
}
|
|
139808
|
+
}
|
|
139809
|
+
};
|
|
139810
|
+
})();
|
|
139811
|
+
|
|
139812
|
+
const cleanupMove = canvasHandle(
|
|
139813
|
+
onMoveType,
|
|
139814
|
+
function(event) {
|
|
139815
|
+
const e = matchesEvent(event);
|
|
139816
|
+
if (e)
|
|
139817
|
+
{
|
|
139818
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139819
|
+
onChange(canvasPos);
|
|
139820
|
+
updatePointerLens(canvasPos);
|
|
139821
|
+
}
|
|
139822
|
+
});
|
|
139823
|
+
|
|
139824
|
+
const cleanupEnd = canvasHandle(
|
|
139825
|
+
onEndType,
|
|
139826
|
+
function(event) {
|
|
139827
|
+
const e = matchesEvent(event);
|
|
139828
|
+
if (e)
|
|
139829
|
+
{
|
|
139830
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139831
|
+
onChange(canvasPos);
|
|
139832
|
+
updatePointerLens(null);
|
|
139833
|
+
cleanupCurrentDrag();
|
|
139834
|
+
self.fire("translated");
|
|
139835
|
+
}
|
|
139836
|
+
});
|
|
139837
|
+
|
|
139838
|
+
cleanupCurrentDrag = function() {
|
|
139839
|
+
cleanupCurrentDrag = () => { };
|
|
139840
|
+
canvas.style.cursor = "default";
|
|
139841
|
+
viewer.cameraControl.active = true;
|
|
139842
|
+
cleanupMove();
|
|
139843
|
+
cleanupEnd();
|
|
139844
|
+
};
|
|
139845
|
+
}
|
|
139846
|
+
};
|
|
139847
|
+
|
|
139848
|
+
const startDragCbs = [ ];
|
|
139849
|
+
|
|
139850
|
+
if (handleMouseEvents) {
|
|
139851
|
+
startDragCbs.push(
|
|
139852
|
+
canvasHandle("mousedown", event => {
|
|
139853
|
+
if (event.which === 1) {
|
|
139854
|
+
startDrag(
|
|
139855
|
+
event,
|
|
139856
|
+
"mousemove",
|
|
139857
|
+
"mouseup",
|
|
139858
|
+
event => (event.which === 1) && event);
|
|
139859
|
+
}
|
|
139860
|
+
}));
|
|
139861
|
+
}
|
|
139862
|
+
|
|
139863
|
+
if (handleTouchEvents) {
|
|
139864
|
+
startDragCbs.push(
|
|
139865
|
+
canvasHandle("touchstart", event => {
|
|
139866
|
+
if (event.touches.length === 1) {
|
|
139867
|
+
const touchStartId = event.touches[0].identifier;
|
|
139868
|
+
startDrag(
|
|
139869
|
+
event,
|
|
139870
|
+
"touchmove",
|
|
139871
|
+
"touchend",
|
|
139872
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId));
|
|
139873
|
+
}
|
|
139874
|
+
}));
|
|
139875
|
+
}
|
|
139876
|
+
|
|
139877
|
+
const cleanup = function() {
|
|
139878
|
+
cleanupCurrentDrag();
|
|
139879
|
+
startDragCbs.forEach(cb => cb());
|
|
139880
|
+
updatePointerLens(null);
|
|
139881
|
+
};
|
|
139882
|
+
|
|
139883
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139884
|
+
|
|
139885
|
+
this._deactivate = function() {
|
|
139886
|
+
zone.off("destroyed", destroyCb);
|
|
139887
|
+
cleanup();
|
|
139888
|
+
};
|
|
139889
|
+
}
|
|
139890
|
+
|
|
139891
|
+
deactivate() {
|
|
139892
|
+
this._deactivate();
|
|
139893
|
+
super.destroy();
|
|
139894
|
+
}
|
|
139895
|
+
}
|
|
139896
|
+
|
|
139897
|
+
class ZoneTranslateMouseControl extends ZoneTranslateControl {
|
|
139898
|
+
constructor(zone, cfg) {
|
|
139899
|
+
super(zone, cfg, true, false);
|
|
139900
|
+
}
|
|
139901
|
+
}
|
|
139902
|
+
|
|
139903
|
+
class ZoneTranslateTouchControl extends ZoneTranslateControl {
|
|
139904
|
+
constructor(zone, cfg) {
|
|
139905
|
+
super(zone, cfg, false, true);
|
|
139906
|
+
}
|
|
139907
|
+
}
|
|
139908
|
+
|
|
139909
|
+
export { AlphaFormat, AmbientLight, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$2 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createRTCViewMat, frustumIntersectsAABB3, getKTX2TextureTranscoder, getPlaneRTCPos, load3DSGeometry, loadOBJGeometry, math, rtcToWorldPos, sRGBEncoding, setFrustum, stats, utils, worldToRTCPos, worldToRTCPositions };
|