@xeokit/xeokit-sdk 2.6.16 → 2.6.19
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 +2348 -118
- package/dist/xeokit-sdk.es.js +2338 -119
- package/dist/xeokit-sdk.es5.js +559 -419
- 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 +4 -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 -4
- package/src/viewer/scene/sectionPlane/SectionPlane.js +3 -7
- package/src/viewer/scene/webgl/Renderer.js +84 -79
- package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
- package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +8 -5
- package/types/viewer/Viewer.d.ts +2 -0
- package/types/viewer/scene/geometry/builders/buildLineGeometry.d.ts +22 -0
- package/types/viewer/scene/geometry/builders/buildPolylineGeometry.d.ts +2 -2
- package/types/viewer/scene/scene/Scene.d.ts +11 -0
- package/dist/web-ifc.wasm +0 -0
package/dist/xeokit-sdk.cjs.js
CHANGED
|
@@ -1122,8 +1122,8 @@ class PointerLens {
|
|
|
1122
1122
|
);
|
|
1123
1123
|
|
|
1124
1124
|
const centerLensCanvas = [
|
|
1125
|
-
(lensRect.left + lensRect.right) / 2,
|
|
1126
|
-
(lensRect.top + lensRect.bottom) / 2
|
|
1125
|
+
(lensRect.left + lensRect.right) / 2 - canvasRect.left,
|
|
1126
|
+
(lensRect.top + lensRect.bottom) / 2 - canvasRect.top
|
|
1127
1127
|
];
|
|
1128
1128
|
|
|
1129
1129
|
if (this._snappedCanvasPos) {
|
|
@@ -10639,6 +10639,9 @@ class Marker extends Component {
|
|
|
10639
10639
|
return;
|
|
10640
10640
|
}
|
|
10641
10641
|
this._occludable = occludable;
|
|
10642
|
+
if (this._occludable) {
|
|
10643
|
+
this._renderer.markerWorldPosUpdated(this);
|
|
10644
|
+
}
|
|
10642
10645
|
}
|
|
10643
10646
|
|
|
10644
10647
|
/**
|
|
@@ -10760,7 +10763,7 @@ class Marker extends Component {
|
|
|
10760
10763
|
this.scene.camera.off(this._onCameraProjMatrix);
|
|
10761
10764
|
if (this._entity) {
|
|
10762
10765
|
if (this._onEntityDestroyed !== null) {
|
|
10763
|
-
this._entity.off(this._onEntityDestroyed);
|
|
10766
|
+
this._entity.model.off(this._onEntityDestroyed);
|
|
10764
10767
|
}
|
|
10765
10768
|
if (this._onEntityModelDestroyed !== null) {
|
|
10766
10769
|
this._entity.model.off(this._onEntityModelDestroyed);
|
|
@@ -11160,7 +11163,25 @@ class Dot {
|
|
|
11160
11163
|
}
|
|
11161
11164
|
|
|
11162
11165
|
}
|
|
11163
|
-
|
|
11166
|
+
|
|
11167
|
+
if (cfg.onTouchstart) {
|
|
11168
|
+
dotClickable.addEventListener('touchstart', (event) => {
|
|
11169
|
+
cfg.onTouchstart(event, this);
|
|
11170
|
+
});
|
|
11171
|
+
}
|
|
11172
|
+
|
|
11173
|
+
if (cfg.onTouchmove) {
|
|
11174
|
+
dotClickable.addEventListener('touchmove', (event) => {
|
|
11175
|
+
cfg.onTouchmove(event, this);
|
|
11176
|
+
});
|
|
11177
|
+
}
|
|
11178
|
+
|
|
11179
|
+
if (cfg.onTouchend) {
|
|
11180
|
+
dotClickable.addEventListener('touchend', (event) => {
|
|
11181
|
+
cfg.onTouchend(event, this);
|
|
11182
|
+
});
|
|
11183
|
+
}
|
|
11184
|
+
|
|
11164
11185
|
this.setPos(cfg.x || 0, cfg.y || 0);
|
|
11165
11186
|
this.setFillColor(cfg.fillColor);
|
|
11166
11187
|
this.setBorderColor(cfg.borderColor);
|
|
@@ -14428,6 +14449,7 @@ class Annotation extends Marker {
|
|
|
14428
14449
|
if (this._marker) {
|
|
14429
14450
|
if (!this._markerExternal) {
|
|
14430
14451
|
this._marker.parentNode.removeChild(this._marker);
|
|
14452
|
+
this._marker = null;
|
|
14431
14453
|
} else {
|
|
14432
14454
|
this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
|
|
14433
14455
|
this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
|
|
@@ -17056,7 +17078,7 @@ class OcclusionLayer {
|
|
|
17056
17078
|
_buildVBOs() {
|
|
17057
17079
|
if (this.positionsBuf) {
|
|
17058
17080
|
if (this.lenPositionsBuf === this.positions.length) { // Just updating buffer elements, don't need to reallocate
|
|
17059
|
-
this.positionsBuf.setData(this.positions); // Indices don't need updating
|
|
17081
|
+
this.positionsBuf.setData(new Float32Array(this.positions)); // Indices don't need updating
|
|
17060
17082
|
return;
|
|
17061
17083
|
}
|
|
17062
17084
|
this.positionsBuf.destroy();
|
|
@@ -17145,7 +17167,6 @@ class OcclusionLayer {
|
|
|
17145
17167
|
|
|
17146
17168
|
const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]);
|
|
17147
17169
|
const POINT_SIZE = 20;
|
|
17148
|
-
const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces
|
|
17149
17170
|
|
|
17150
17171
|
const tempVec3a$J = math.vec3();
|
|
17151
17172
|
|
|
@@ -17212,7 +17233,6 @@ class OcclusionTester {
|
|
|
17212
17233
|
markerWorldPosUpdated(marker) {
|
|
17213
17234
|
const occlusionLayer = this._markersToOcclusionLayersMap[marker.id];
|
|
17214
17235
|
if (!occlusionLayer) {
|
|
17215
|
-
marker.error("Marker has not been added to OcclusionTester");
|
|
17216
17236
|
return;
|
|
17217
17237
|
}
|
|
17218
17238
|
const originHash = marker.origin.join();
|
|
@@ -17227,7 +17247,7 @@ class OcclusionTester {
|
|
|
17227
17247
|
let newOcclusionLayer = this._occlusionLayers[originHash];
|
|
17228
17248
|
if (!newOcclusionLayer) {
|
|
17229
17249
|
newOcclusionLayer = new OcclusionLayer(this._scene, marker.origin);
|
|
17230
|
-
this._occlusionLayers[originHash] =
|
|
17250
|
+
this._occlusionLayers[originHash] = newOcclusionLayer;
|
|
17231
17251
|
this._occlusionLayersListDirty = true;
|
|
17232
17252
|
}
|
|
17233
17253
|
newOcclusionLayer.addMarker(marker);
|
|
@@ -17357,7 +17377,9 @@ class OcclusionTester {
|
|
|
17357
17377
|
if (scene.logarithmicDepthBufferEnabled) {
|
|
17358
17378
|
src.push("vFragDepth = 1.0 + clipPos.w;");
|
|
17359
17379
|
} else {
|
|
17360
|
-
|
|
17380
|
+
if (scene.markerZOffset < 0.000) {
|
|
17381
|
+
src.push("clipPos.z += " + scene.markerZOffset + ";");
|
|
17382
|
+
}
|
|
17361
17383
|
}
|
|
17362
17384
|
src.push(" gl_Position = clipPos;");
|
|
17363
17385
|
src.push("}");
|
|
@@ -17471,7 +17493,10 @@ class OcclusionTester {
|
|
|
17471
17493
|
continue;
|
|
17472
17494
|
}
|
|
17473
17495
|
|
|
17474
|
-
|
|
17496
|
+
// The `origin` has been changed from `occlusionLayer.origin` to `[ 0, 0, 0 ]`
|
|
17497
|
+
// because OcclusionLayer markers' transformation is being applied through the
|
|
17498
|
+
// OcclusionLayer::positions array. See XEOK-33
|
|
17499
|
+
const origin = [ 0, 0, 0 ];
|
|
17475
17500
|
|
|
17476
17501
|
gl.uniformMatrix4fv(this._uViewMatrix, false, createRTCViewMat(camera.viewMatrix, origin));
|
|
17477
17502
|
|
|
@@ -18710,6 +18735,9 @@ const Renderer$1 = function (scene, options) {
|
|
|
18710
18735
|
let drawableTypeInfo = {};
|
|
18711
18736
|
let drawables = {};
|
|
18712
18737
|
|
|
18738
|
+
let postSortDrawableList = [];
|
|
18739
|
+
let postCullDrawableList = [];
|
|
18740
|
+
|
|
18713
18741
|
let drawableListDirty = true;
|
|
18714
18742
|
let stateSortDirty = true;
|
|
18715
18743
|
let imageDirty = true;
|
|
@@ -18935,28 +18963,38 @@ const Renderer$1 = function (scene, options) {
|
|
|
18935
18963
|
const drawableInfo = drawableTypeInfo[type];
|
|
18936
18964
|
if (drawableInfo.isStateSortable) {
|
|
18937
18965
|
drawableInfo.drawableListPreCull.sort(drawableInfo.stateSortCompare);
|
|
18966
|
+
|
|
18967
|
+
drawableInfo.drawableList = drawableInfo.drawableListPreCull;
|
|
18938
18968
|
}
|
|
18939
18969
|
}
|
|
18940
18970
|
}
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
function cullDrawableList() {
|
|
18971
|
+
let lenDrawableList = 0;
|
|
18944
18972
|
for (let type in drawableTypeInfo) {
|
|
18945
18973
|
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
18946
18974
|
const drawableInfo = drawableTypeInfo[type];
|
|
18947
18975
|
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
18948
|
-
const drawableList = drawableInfo.drawableList;
|
|
18949
|
-
let lenDrawableList = 0;
|
|
18950
18976
|
for (let i = 0, len = drawableListPreCull.length; i < len; i++) {
|
|
18951
18977
|
const drawable = drawableListPreCull[i];
|
|
18952
|
-
drawable
|
|
18953
|
-
if (!drawable.renderFlags.culled) {
|
|
18954
|
-
drawableList[lenDrawableList++] = drawable;
|
|
18955
|
-
}
|
|
18978
|
+
postSortDrawableList[lenDrawableList++] = drawable;
|
|
18956
18979
|
}
|
|
18957
|
-
drawableList.length = lenDrawableList;
|
|
18958
18980
|
}
|
|
18959
18981
|
}
|
|
18982
|
+
postSortDrawableList.length = lenDrawableList;
|
|
18983
|
+
postSortDrawableList.sort((a, b) => {
|
|
18984
|
+
return a.renderOrder - b.renderOrder;
|
|
18985
|
+
});
|
|
18986
|
+
}
|
|
18987
|
+
|
|
18988
|
+
function cullDrawableList() {
|
|
18989
|
+
let lenDrawableList = 0;
|
|
18990
|
+
for (let i = 0, len = postSortDrawableList.length; i < len; i++) {
|
|
18991
|
+
const drawable = postSortDrawableList[i];
|
|
18992
|
+
drawable.rebuildRenderFlags();
|
|
18993
|
+
if (!drawable.renderFlags.culled) {
|
|
18994
|
+
postCullDrawableList[lenDrawableList++] = drawable;
|
|
18995
|
+
}
|
|
18996
|
+
}
|
|
18997
|
+
postCullDrawableList.length = lenDrawableList;
|
|
18960
18998
|
}
|
|
18961
18999
|
|
|
18962
19000
|
function draw(params) {
|
|
@@ -19189,7 +19227,6 @@ const Renderer$1 = function (scene, options) {
|
|
|
19189
19227
|
}
|
|
19190
19228
|
|
|
19191
19229
|
let i;
|
|
19192
|
-
let len;
|
|
19193
19230
|
let drawable;
|
|
19194
19231
|
|
|
19195
19232
|
const startTime = Date.now();
|
|
@@ -19222,93 +19259,85 @@ const Renderer$1 = function (scene, options) {
|
|
|
19222
19259
|
// Render normal opaque solids, defer others to bins to render after
|
|
19223
19260
|
//------------------------------------------------------------------------------------------------------
|
|
19224
19261
|
|
|
19225
|
-
for (let
|
|
19226
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
19227
|
-
|
|
19228
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
19229
|
-
const drawableList = drawableInfo.drawableList;
|
|
19230
|
-
|
|
19231
|
-
for (i = 0, len = drawableList.length; i < len; i++) {
|
|
19262
|
+
for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
|
|
19232
19263
|
|
|
19233
|
-
|
|
19264
|
+
drawable = postCullDrawableList[i];
|
|
19234
19265
|
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19266
|
+
if (drawable.culled === true || drawable.visible === false) {
|
|
19267
|
+
continue;
|
|
19268
|
+
}
|
|
19238
19269
|
|
|
19239
|
-
|
|
19270
|
+
const renderFlags = drawable.renderFlags;
|
|
19240
19271
|
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19272
|
+
if (renderFlags.colorOpaque) {
|
|
19273
|
+
if (saoEnabled && saoPossible && drawable.saoEnabled) {
|
|
19274
|
+
normalDrawSAOBin[normalDrawSAOBinLen++] = drawable;
|
|
19275
|
+
} else {
|
|
19276
|
+
drawable.drawColorOpaque(frameCtx);
|
|
19277
|
+
}
|
|
19278
|
+
}
|
|
19248
19279
|
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19252
|
-
|
|
19253
|
-
|
|
19280
|
+
if (transparentEnabled) {
|
|
19281
|
+
if (renderFlags.colorTransparent) {
|
|
19282
|
+
normalFillTransparentBin[normalFillTransparentBinLen++] = drawable;
|
|
19283
|
+
}
|
|
19284
|
+
}
|
|
19254
19285
|
|
|
19255
|
-
|
|
19256
|
-
|
|
19257
|
-
|
|
19286
|
+
if (renderFlags.xrayedSilhouetteTransparent) {
|
|
19287
|
+
xrayedFillTransparentBin[xrayedFillTransparentBinLen++] = drawable;
|
|
19288
|
+
}
|
|
19258
19289
|
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19290
|
+
if (renderFlags.xrayedSilhouetteOpaque) {
|
|
19291
|
+
xrayedFillOpaqueBin[xrayedFillOpaqueBinLen++] = drawable;
|
|
19292
|
+
}
|
|
19262
19293
|
|
|
19263
|
-
|
|
19264
|
-
|
|
19265
|
-
|
|
19294
|
+
if (renderFlags.highlightedSilhouetteTransparent) {
|
|
19295
|
+
highlightedFillTransparentBin[highlightedFillTransparentBinLen++] = drawable;
|
|
19296
|
+
}
|
|
19266
19297
|
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19298
|
+
if (renderFlags.highlightedSilhouetteOpaque) {
|
|
19299
|
+
highlightedFillOpaqueBin[highlightedFillOpaqueBinLen++] = drawable;
|
|
19300
|
+
}
|
|
19270
19301
|
|
|
19271
|
-
|
|
19272
|
-
|
|
19273
|
-
|
|
19302
|
+
if (renderFlags.selectedSilhouetteTransparent) {
|
|
19303
|
+
selectedFillTransparentBin[selectedFillTransparentBinLen++] = drawable;
|
|
19304
|
+
}
|
|
19274
19305
|
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19306
|
+
if (renderFlags.selectedSilhouetteOpaque) {
|
|
19307
|
+
selectedFillOpaqueBin[selectedFillOpaqueBinLen++] = drawable;
|
|
19308
|
+
}
|
|
19278
19309
|
|
|
19279
|
-
|
|
19280
|
-
|
|
19281
|
-
|
|
19282
|
-
|
|
19310
|
+
if (drawable.edges && edgesEnabled) {
|
|
19311
|
+
if (renderFlags.edgesOpaque) {
|
|
19312
|
+
normalEdgesOpaqueBin[normalEdgesOpaqueBinLen++] = drawable;
|
|
19313
|
+
}
|
|
19283
19314
|
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19315
|
+
if (renderFlags.edgesTransparent) {
|
|
19316
|
+
normalEdgesTransparentBin[normalEdgesTransparentBinLen++] = drawable;
|
|
19317
|
+
}
|
|
19287
19318
|
|
|
19288
|
-
|
|
19289
|
-
|
|
19290
|
-
|
|
19319
|
+
if (renderFlags.selectedEdgesTransparent) {
|
|
19320
|
+
selectedEdgesTransparentBin[selectedEdgesTransparentBinLen++] = drawable;
|
|
19321
|
+
}
|
|
19291
19322
|
|
|
19292
|
-
|
|
19293
|
-
|
|
19294
|
-
|
|
19323
|
+
if (renderFlags.selectedEdgesOpaque) {
|
|
19324
|
+
selectedEdgesOpaqueBin[selectedEdgesOpaqueBinLen++] = drawable;
|
|
19325
|
+
}
|
|
19295
19326
|
|
|
19296
|
-
|
|
19297
|
-
|
|
19298
|
-
|
|
19327
|
+
if (renderFlags.xrayedEdgesTransparent) {
|
|
19328
|
+
xrayEdgesTransparentBin[xrayEdgesTransparentBinLen++] = drawable;
|
|
19329
|
+
}
|
|
19299
19330
|
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19331
|
+
if (renderFlags.xrayedEdgesOpaque) {
|
|
19332
|
+
xrayEdgesOpaqueBin[xrayEdgesOpaqueBinLen++] = drawable;
|
|
19333
|
+
}
|
|
19303
19334
|
|
|
19304
|
-
|
|
19305
|
-
|
|
19306
|
-
|
|
19335
|
+
if (renderFlags.highlightedEdgesTransparent) {
|
|
19336
|
+
highlightedEdgesTransparentBin[highlightedEdgesTransparentBinLen++] = drawable;
|
|
19337
|
+
}
|
|
19307
19338
|
|
|
19308
|
-
|
|
19309
|
-
|
|
19310
|
-
}
|
|
19311
|
-
}
|
|
19339
|
+
if (renderFlags.highlightedEdgesOpaque) {
|
|
19340
|
+
highlightedEdgesOpaqueBin[highlightedEdgesOpaqueBinLen++] = drawable;
|
|
19312
19341
|
}
|
|
19313
19342
|
}
|
|
19314
19343
|
}
|
|
@@ -19621,7 +19650,7 @@ const Renderer$1 = function (scene, options) {
|
|
|
19621
19650
|
math.cross3Vec3(worldRayDir, randomVec3, up);
|
|
19622
19651
|
|
|
19623
19652
|
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
19624
|
-
|
|
19653
|
+
// pickProjMatrix = scene.camera.projMatrix;
|
|
19625
19654
|
pickProjMatrix = scene.camera.ortho.matrix;
|
|
19626
19655
|
|
|
19627
19656
|
pickResult.origin = worldRayOrigin;
|
|
@@ -21608,6 +21637,14 @@ class Input extends Component {
|
|
|
21608
21637
|
}
|
|
21609
21638
|
});
|
|
21610
21639
|
|
|
21640
|
+
this.element.addEventListener("contextmenu", this._contextmenuListener = (e) => {
|
|
21641
|
+
if (!this.enabled) {
|
|
21642
|
+
return;
|
|
21643
|
+
}
|
|
21644
|
+
this._getMouseCanvasPos(e);
|
|
21645
|
+
this.fire("contextmenu", this.mouseCanvasPos, true);
|
|
21646
|
+
});
|
|
21647
|
+
|
|
21611
21648
|
const tickifiedMouseWheelFn = this.scene.tickify(
|
|
21612
21649
|
(delta) => { this.fire("mousewheel", delta, true); }
|
|
21613
21650
|
);
|
|
@@ -21641,6 +21678,24 @@ class Input extends Component {
|
|
|
21641
21678
|
});
|
|
21642
21679
|
}
|
|
21643
21680
|
|
|
21681
|
+
this.element.addEventListener("touchstart", this._touchstartListener = (e) => {
|
|
21682
|
+
if (!this.enabled) {
|
|
21683
|
+
return;
|
|
21684
|
+
}
|
|
21685
|
+
[...e.changedTouches].forEach(e => {
|
|
21686
|
+
this.fire("touchstart", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21687
|
+
});
|
|
21688
|
+
});
|
|
21689
|
+
|
|
21690
|
+
this.element.addEventListener("touchend", this._touchendListener = (e) => {
|
|
21691
|
+
if (!this.enabled) {
|
|
21692
|
+
return;
|
|
21693
|
+
}
|
|
21694
|
+
[...e.changedTouches].forEach(e => {
|
|
21695
|
+
this.fire("touchend", [ e.identifier, this._getTouchCanvasPos(e) ], true);
|
|
21696
|
+
});
|
|
21697
|
+
});
|
|
21698
|
+
|
|
21644
21699
|
this._eventsBound = true;
|
|
21645
21700
|
}
|
|
21646
21701
|
|
|
@@ -21657,7 +21712,10 @@ class Input extends Component {
|
|
|
21657
21712
|
document.removeEventListener("click", this._clickListener);
|
|
21658
21713
|
document.removeEventListener("dblclick", this._dblClickListener);
|
|
21659
21714
|
this.element.removeEventListener("mousemove", this._mouseMoveListener);
|
|
21715
|
+
this.element.removeEventListener("contextmenu", this._contextmenuListener);
|
|
21660
21716
|
this.element.removeEventListener("wheel", this._mouseWheelListener);
|
|
21717
|
+
this.element.removeEventListener("touchstart", this._touchstartListener);
|
|
21718
|
+
this.element.removeEventListener("touchend", this._touchendListener);
|
|
21661
21719
|
if (window.OrientationChangeEvent) {
|
|
21662
21720
|
window.removeEventListener('orientationchange', this._orientationchangedListener);
|
|
21663
21721
|
}
|
|
@@ -21670,6 +21728,18 @@ class Input extends Component {
|
|
|
21670
21728
|
this._eventsBound = false;
|
|
21671
21729
|
}
|
|
21672
21730
|
|
|
21731
|
+
_getTouchCanvasPos(event) {
|
|
21732
|
+
let element = event.target;
|
|
21733
|
+
let totalOffsetLeft = 0;
|
|
21734
|
+
let totalOffsetTop = 0;
|
|
21735
|
+
while (element.offsetParent) {
|
|
21736
|
+
totalOffsetLeft += element.offsetLeft;
|
|
21737
|
+
totalOffsetTop += element.offsetTop;
|
|
21738
|
+
element = element.offsetParent;
|
|
21739
|
+
}
|
|
21740
|
+
return [ event.pageX - totalOffsetLeft, event.pageY - totalOffsetTop ];
|
|
21741
|
+
}
|
|
21742
|
+
|
|
21673
21743
|
_getMouseCanvasPos(event) {
|
|
21674
21744
|
if (!event) {
|
|
21675
21745
|
event = window.event;
|
|
@@ -30154,6 +30224,7 @@ class Scene extends Component {
|
|
|
30154
30224
|
this._pbrEnabled = !!cfg.pbrEnabled;
|
|
30155
30225
|
this._colorTextureEnabled = (cfg.colorTextureEnabled !== false);
|
|
30156
30226
|
this._dtxEnabled = !!cfg.dtxEnabled;
|
|
30227
|
+
this._markerZOffset = cfg.markerZOffset;
|
|
30157
30228
|
|
|
30158
30229
|
// Register Scene on xeokit
|
|
30159
30230
|
// Do this BEFORE we add components below
|
|
@@ -30674,6 +30745,22 @@ class Scene extends Component {
|
|
|
30674
30745
|
return this._colorTextureEnabled;
|
|
30675
30746
|
}
|
|
30676
30747
|
|
|
30748
|
+
/**
|
|
30749
|
+
* Gets the Z value of offset for Marker's OcclusionTester.
|
|
30750
|
+
* The closest the value is to 0.000 the more precise OcclusionTester will be, but at the same time the less
|
|
30751
|
+
* precise it will behave for Markers that are located exactly on the Surface.
|
|
30752
|
+
*
|
|
30753
|
+
* Default is ````-0.001````.
|
|
30754
|
+
*
|
|
30755
|
+
* @returns {Number} Z offset for Marker
|
|
30756
|
+
*/
|
|
30757
|
+
get markerZOffset() {
|
|
30758
|
+
if (this._markerZOffset == null) {
|
|
30759
|
+
return -0.001;
|
|
30760
|
+
}
|
|
30761
|
+
return this._markerZOffset;
|
|
30762
|
+
}
|
|
30763
|
+
|
|
30677
30764
|
/**
|
|
30678
30765
|
* Performs an occlusion test on all {@link Marker}s in this {@link Scene}.
|
|
30679
30766
|
*
|
|
@@ -31518,9 +31605,9 @@ class Scene extends Component {
|
|
|
31518
31605
|
* @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
|
|
31519
31606
|
* @param {String[]} [params.includeEntities] IDs of {@link Entity}s to restrict picking to. When given, ignores {@link Entity}s whose IDs are not in this list.
|
|
31520
31607
|
* @param {String[]} [params.excludeEntities] IDs of {@link Entity}s to ignore. When given, will pick *through* these {@link Entity}s, as if they were not there.
|
|
31521
|
-
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
|
|
31522
|
-
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31523
|
-
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
31608
|
+
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels.
|
|
31609
|
+
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex. Only works when `canvasPos` given.
|
|
31610
|
+
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge. Only works when `canvasPos` given.
|
|
31524
31611
|
* @param {PickResult} [pickResult] Holds the results of the pick attempt. Will use the Scene's singleton PickResult if you don't supply your own.
|
|
31525
31612
|
* @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
|
|
31526
31613
|
*/
|
|
@@ -31531,6 +31618,11 @@ class Scene extends Component {
|
|
|
31531
31618
|
return null;
|
|
31532
31619
|
}
|
|
31533
31620
|
|
|
31621
|
+
if ((params.snapToVertex || params.snapToEdge) && !params.canvasPos) {
|
|
31622
|
+
this.error("Scene.snapPick() `canvasPos` parameter expected for `snapToVertex:true` or `snapToEdge:true`");
|
|
31623
|
+
return;
|
|
31624
|
+
}
|
|
31625
|
+
|
|
31534
31626
|
params = params || {};
|
|
31535
31627
|
|
|
31536
31628
|
params.pickSurface = params.pickSurface || params.rayPick; // Backwards compatibility
|
|
@@ -31578,7 +31670,7 @@ class Scene extends Component {
|
|
|
31578
31670
|
|
|
31579
31671
|
/**
|
|
31580
31672
|
* @param {Object} params Picking parameters.
|
|
31581
|
-
* @param {Number[]}
|
|
31673
|
+
* @param {Number[]} params.canvasPos Canvas-space coordinates.
|
|
31582
31674
|
* @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
|
|
31583
31675
|
* @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
|
|
31584
31676
|
* @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
|
|
@@ -31589,6 +31681,10 @@ class Scene extends Component {
|
|
|
31589
31681
|
this._warnSnapPickDeprecated = true;
|
|
31590
31682
|
this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead");
|
|
31591
31683
|
}
|
|
31684
|
+
if (!params.canvasPos) {
|
|
31685
|
+
this.error("Scene.snapPick() canvasPos parameter expected");
|
|
31686
|
+
return;
|
|
31687
|
+
}
|
|
31592
31688
|
return this._renderer.snapPick(
|
|
31593
31689
|
params.canvasPos,
|
|
31594
31690
|
params.snapRadius || 30,
|
|
@@ -37651,11 +37747,16 @@ class Mesh extends Component {
|
|
|
37651
37747
|
* @param {EmphasisMaterial} [cfg.highlightMaterial] {@link EmphasisMaterial} to define the xrayed appearance for this Mesh. Inherits {@link Scene#highlightMaterial} by default.
|
|
37652
37748
|
* @param {EmphasisMaterial} [cfg.selectedMaterial] {@link EmphasisMaterial} to define the selected appearance for this Mesh. Inherits {@link Scene#selectedMaterial} by default.
|
|
37653
37749
|
* @param {EmphasisMaterial} [cfg.edgeMaterial] {@link EdgeMaterial} to define the appearance of enhanced edges for this Mesh. Inherits {@link Scene#edgeMaterial} by default.
|
|
37750
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this mESH. This is used to control the order in which
|
|
37751
|
+
* mESHES are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
37752
|
+
* render pass.
|
|
37654
37753
|
*/
|
|
37655
37754
|
constructor(owner, cfg = {}) {
|
|
37656
37755
|
|
|
37657
37756
|
super(owner, cfg);
|
|
37658
37757
|
|
|
37758
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
37759
|
+
|
|
37659
37760
|
/**
|
|
37660
37761
|
* ID of the corresponding object within the originating system, if any.
|
|
37661
37762
|
*
|
|
@@ -42180,6 +42281,7 @@ class SectionPlane extends Component {
|
|
|
42180
42281
|
this._state.active = value !== false;
|
|
42181
42282
|
this.glRedraw();
|
|
42182
42283
|
this.fire("active", this._state.active);
|
|
42284
|
+
this.scene.fire("sectionPlaneUpdated", this);
|
|
42183
42285
|
}
|
|
42184
42286
|
|
|
42185
42287
|
/**
|
|
@@ -42260,13 +42362,8 @@ class SectionPlane extends Component {
|
|
|
42260
42362
|
* Inverts the direction of {@link SectionPlane#dir}.
|
|
42261
42363
|
*/
|
|
42262
42364
|
flipDir() {
|
|
42263
|
-
|
|
42264
|
-
dir
|
|
42265
|
-
dir[1] *= -1.0;
|
|
42266
|
-
dir[2] *= -1.0;
|
|
42267
|
-
this._state.dist = (-math.dotVec3(this._state.pos, this._state.dir));
|
|
42268
|
-
this.fire("dir", this._state.dir);
|
|
42269
|
-
this.glRedraw();
|
|
42365
|
+
math.mulVec3Scalar(this._state.dir, -1.0, this._state.dir);
|
|
42366
|
+
this.dir = this._state.dir;
|
|
42270
42367
|
}
|
|
42271
42368
|
|
|
42272
42369
|
/**
|
|
@@ -82248,11 +82345,16 @@ class SceneModel extends Component {
|
|
|
82248
82345
|
* represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
|
|
82249
82346
|
* to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
|
|
82250
82347
|
* primitives. Only works while {@link DTX#enabled} is also ````true````.
|
|
82348
|
+
* @param {Number} [cfg.renderOrder=0] Specifies the rendering order for this SceneModel. This is used to control the order in which
|
|
82349
|
+
* SceneModels are drawn when they have transparent objects, to give control over the order in which those objects are blended within the transparent
|
|
82350
|
+
* render pass.
|
|
82251
82351
|
*/
|
|
82252
82352
|
constructor(owner, cfg = {}) {
|
|
82253
82353
|
|
|
82254
82354
|
super(owner, cfg);
|
|
82255
82355
|
|
|
82356
|
+
this.renderOrder = cfg.renderOrder || 0;
|
|
82357
|
+
|
|
82256
82358
|
this._dtxEnabled = this.scene.dtxEnabled && (cfg.dtxEnabled !== false);
|
|
82257
82359
|
|
|
82258
82360
|
this._enableVertexWelding = false; // Not needed for most objects, and very expensive, so disabled
|
|
@@ -84319,6 +84421,7 @@ class SceneModel extends Component {
|
|
|
84319
84421
|
_getVBOBatchingLayer(cfg) {
|
|
84320
84422
|
const model = this;
|
|
84321
84423
|
const origin = cfg.origin;
|
|
84424
|
+
cfg.renderLayer || 0;
|
|
84322
84425
|
const positionsDecodeHash = cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary ?
|
|
84323
84426
|
this._createHashStringFromMatrix(cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary)
|
|
84324
84427
|
: "-";
|
|
@@ -84805,7 +84908,7 @@ class SceneModel extends Component {
|
|
|
84805
84908
|
// -------------- RENDERING ---------------------------------------------------------------------------------------
|
|
84806
84909
|
|
|
84807
84910
|
/** @private */
|
|
84808
|
-
drawColorOpaque(frameCtx) {
|
|
84911
|
+
drawColorOpaque(frameCtx, layerList) {
|
|
84809
84912
|
const renderFlags = this.renderFlags;
|
|
84810
84913
|
for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) {
|
|
84811
84914
|
const layerIndex = renderFlags.visibleLayers[i];
|
|
@@ -86599,7 +86702,7 @@ class DistanceMeasurement extends Component {
|
|
|
86599
86702
|
|
|
86600
86703
|
if (this._wpDirty) {
|
|
86601
86704
|
|
|
86602
|
-
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld,
|
|
86705
|
+
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0);
|
|
86603
86706
|
if(this._measurementOrientation === 'Vertical' && this.useRotationAdjustment){
|
|
86604
86707
|
this._wp[0] = this._originWorld[0];
|
|
86605
86708
|
this._wp[1] = this._originWorld[1];
|
|
@@ -89726,7 +89829,20 @@ class FastNavPlugin extends Plugin {
|
|
|
89726
89829
|
*/
|
|
89727
89830
|
class GLTFDefaultDataSource {
|
|
89728
89831
|
|
|
89729
|
-
constructor() {
|
|
89832
|
+
constructor(cfg = {}) {
|
|
89833
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
89834
|
+
}
|
|
89835
|
+
|
|
89836
|
+
_cacheBusterURL(url) {
|
|
89837
|
+
if (!this.cacheBuster) {
|
|
89838
|
+
return url;
|
|
89839
|
+
}
|
|
89840
|
+
const timestamp = new Date().getTime();
|
|
89841
|
+
if (url.indexOf('?') > -1) {
|
|
89842
|
+
return url + '&_=' + timestamp;
|
|
89843
|
+
} else {
|
|
89844
|
+
return url + '?_=' + timestamp;
|
|
89845
|
+
}
|
|
89730
89846
|
}
|
|
89731
89847
|
|
|
89732
89848
|
/**
|
|
@@ -89737,7 +89853,7 @@ class GLTFDefaultDataSource {
|
|
|
89737
89853
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
89738
89854
|
*/
|
|
89739
89855
|
getMetaModel(metaModelSrc, ok, error) {
|
|
89740
|
-
utils.loadJSON(metaModelSrc,
|
|
89856
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
89741
89857
|
(json) => {
|
|
89742
89858
|
ok(json);
|
|
89743
89859
|
},
|
|
@@ -89754,7 +89870,7 @@ class GLTFDefaultDataSource {
|
|
|
89754
89870
|
* @param {Function} error Fired on error while loading the glTF JSON asset.
|
|
89755
89871
|
*/
|
|
89756
89872
|
getGLTF(glTFSrc, ok, error) {
|
|
89757
|
-
utils.loadArraybuffer(glTFSrc,
|
|
89873
|
+
utils.loadArraybuffer(this._cacheBusterURL(glTFSrc),
|
|
89758
89874
|
(gltf) => {
|
|
89759
89875
|
ok(gltf);
|
|
89760
89876
|
},
|
|
@@ -89771,7 +89887,7 @@ class GLTFDefaultDataSource {
|
|
|
89771
89887
|
* @param {Function} error Fired on error while loading the .glb asset.
|
|
89772
89888
|
*/
|
|
89773
89889
|
getGLB(glbSrc, ok, error) {
|
|
89774
|
-
utils.loadArraybuffer(glbSrc,
|
|
89890
|
+
utils.loadArraybuffer(this._cacheBusterURL(glbSrc),
|
|
89775
89891
|
(arraybuffer) => {
|
|
89776
89892
|
ok(arraybuffer);
|
|
89777
89893
|
},
|
|
@@ -89792,7 +89908,7 @@ class GLTFDefaultDataSource {
|
|
|
89792
89908
|
* @param {Function} error Fired on error while loading the glTF binary asset.
|
|
89793
89909
|
*/
|
|
89794
89910
|
getArrayBuffer(glTFSrc, binarySrc, ok, error) {
|
|
89795
|
-
loadArraybuffer(glTFSrc, binarySrc,
|
|
89911
|
+
loadArraybuffer(this._cacheBusterURL(glTFSrc), binarySrc,
|
|
89796
89912
|
(arrayBuffer) => {
|
|
89797
89913
|
ok(arrayBuffer);
|
|
89798
89914
|
},
|
|
@@ -96108,6 +96224,15 @@ class MousePickHandler {
|
|
|
96108
96224
|
return;
|
|
96109
96225
|
}
|
|
96110
96226
|
|
|
96227
|
+
if (cameraControl.hasSubs("rayMove"))
|
|
96228
|
+
{
|
|
96229
|
+
const origin = math.vec3();
|
|
96230
|
+
const direction = math.vec3();
|
|
96231
|
+
// The origin from math.canvasPosToWorldRay is incorrect for a perspective camera, should be the same as scene.camera.eye
|
|
96232
|
+
math.canvasPosToWorldRay(scene.canvas.canvas, scene.camera.viewMatrix, scene.camera.projMatrix, states.pointerCanvasPos, origin, direction);
|
|
96233
|
+
cameraControl.fire("rayMove", { canvasPos: states.pointerCanvasPos, ray: { origin: origin, direction: direction, canvasPos: states.pointerCanvasPos } }, true);
|
|
96234
|
+
}
|
|
96235
|
+
|
|
96111
96236
|
const hoverSubs = cameraControl.hasSubs("hover");
|
|
96112
96237
|
const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
|
|
96113
96238
|
const hoverOutSubs = cameraControl.hasSubs("hoverOut");
|
|
@@ -108200,6 +108325,7 @@ class Viewer {
|
|
|
108200
108325
|
* 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
|
|
108201
108326
|
* 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)
|
|
108202
108327
|
* mode for storing geometry, which is the standard technique used in most graphics engines, and will work adequately on most low-end GPUs.
|
|
108328
|
+
* @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.
|
|
108203
108329
|
* @param {number} [cfg.numCachedSectionPlanes=0] Enhances the efficiency of SectionPlane creation by proactively allocating Viewer resources for a specified quantity
|
|
108204
108330
|
* of SectionPlanes. Introducing this parameter streamlines the initial creation speed of SectionPlanes, particularly up to the designated quantity. This parameter internally
|
|
108205
108331
|
* configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
|
|
@@ -108263,6 +108389,7 @@ class Viewer {
|
|
|
108263
108389
|
pbrEnabled: (!!cfg.pbrEnabled),
|
|
108264
108390
|
colorTextureEnabled: (cfg.colorTextureEnabled !== false),
|
|
108265
108391
|
dtxEnabled: (!!cfg.dtxEnabled),
|
|
108392
|
+
markerZOffset: cfg.markerZOffset,
|
|
108266
108393
|
numCachedSectionPlanes: cfg.numCachedSectionPlanes
|
|
108267
108394
|
});
|
|
108268
108395
|
|
|
@@ -123707,6 +123834,22 @@ class SkyboxesPlugin extends Plugin {
|
|
|
123707
123834
|
*/
|
|
123708
123835
|
class STLDefaultDataSource {
|
|
123709
123836
|
|
|
123837
|
+
constructor(cfg = {}) {
|
|
123838
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
123839
|
+
}
|
|
123840
|
+
|
|
123841
|
+
_cacheBusterURL(url) {
|
|
123842
|
+
if (!this.cacheBuster) {
|
|
123843
|
+
return url;
|
|
123844
|
+
}
|
|
123845
|
+
const timestamp = new Date().getTime();
|
|
123846
|
+
if (url.indexOf('?') > -1) {
|
|
123847
|
+
return url + '&_=' + timestamp;
|
|
123848
|
+
} else {
|
|
123849
|
+
return url + '?_=' + timestamp;
|
|
123850
|
+
}
|
|
123851
|
+
}
|
|
123852
|
+
|
|
123710
123853
|
/**
|
|
123711
123854
|
* Gets STL data.
|
|
123712
123855
|
*
|
|
@@ -123715,6 +123858,7 @@ class STLDefaultDataSource {
|
|
|
123715
123858
|
* @param {Function} error Fired on error while loading the STL file.
|
|
123716
123859
|
*/
|
|
123717
123860
|
getSTL(src, ok, error) {
|
|
123861
|
+
src = this._cacheBusterURL(src);
|
|
123718
123862
|
const request = new XMLHttpRequest();
|
|
123719
123863
|
request.overrideMimeType("application/json");
|
|
123720
123864
|
request.open('GET', src, true);
|
|
@@ -126337,7 +126481,20 @@ class ViewCullPlugin extends Plugin {
|
|
|
126337
126481
|
*/
|
|
126338
126482
|
class XKTDefaultDataSource {
|
|
126339
126483
|
|
|
126340
|
-
constructor() {
|
|
126484
|
+
constructor(cfg = {}) {
|
|
126485
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
126486
|
+
}
|
|
126487
|
+
|
|
126488
|
+
_cacheBusterURL(url) {
|
|
126489
|
+
if (!this.cacheBuster) {
|
|
126490
|
+
return url;
|
|
126491
|
+
}
|
|
126492
|
+
const timestamp = new Date().getTime();
|
|
126493
|
+
if (url.indexOf('?') > -1) {
|
|
126494
|
+
return url + '&_=' + timestamp;
|
|
126495
|
+
} else {
|
|
126496
|
+
return url + '?_=' + timestamp;
|
|
126497
|
+
}
|
|
126341
126498
|
}
|
|
126342
126499
|
|
|
126343
126500
|
/**
|
|
@@ -126348,7 +126505,7 @@ class XKTDefaultDataSource {
|
|
|
126348
126505
|
* @param {Function} error Fired on error while loading the manifest JSON asset.
|
|
126349
126506
|
*/
|
|
126350
126507
|
getManifest(manifestSrc, ok, error) {
|
|
126351
|
-
utils.loadJSON(manifestSrc,
|
|
126508
|
+
utils.loadJSON(this._cacheBusterURL(manifestSrc),
|
|
126352
126509
|
(json) => {
|
|
126353
126510
|
ok(json);
|
|
126354
126511
|
},
|
|
@@ -126365,7 +126522,7 @@ class XKTDefaultDataSource {
|
|
|
126365
126522
|
* @param {Function} error Fired on error while loading the metamodel JSON asset.
|
|
126366
126523
|
*/
|
|
126367
126524
|
getMetaModel(metaModelSrc, ok, error) {
|
|
126368
|
-
utils.loadJSON(metaModelSrc,
|
|
126525
|
+
utils.loadJSON(this._cacheBusterURL(metaModelSrc),
|
|
126369
126526
|
(json) => {
|
|
126370
126527
|
ok(json);
|
|
126371
126528
|
},
|
|
@@ -126407,7 +126564,7 @@ class XKTDefaultDataSource {
|
|
|
126407
126564
|
}
|
|
126408
126565
|
} else {
|
|
126409
126566
|
const request = new XMLHttpRequest();
|
|
126410
|
-
request.open('GET', src, true);
|
|
126567
|
+
request.open('GET', this._cacheBusterURL(src), true);
|
|
126411
126568
|
request.responseType = 'arraybuffer';
|
|
126412
126569
|
request.onreadystatechange = function () {
|
|
126413
126570
|
if (request.readyState === 4) {
|
|
@@ -133808,7 +133965,20 @@ class XML3DLoaderPlugin extends Plugin {
|
|
|
133808
133965
|
*/
|
|
133809
133966
|
class WebIFCDefaultDataSource {
|
|
133810
133967
|
|
|
133811
|
-
constructor() {
|
|
133968
|
+
constructor(cfg = {}) {
|
|
133969
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
133970
|
+
}
|
|
133971
|
+
|
|
133972
|
+
_cacheBusterURL(url) {
|
|
133973
|
+
if (!this.cacheBuster) {
|
|
133974
|
+
return url;
|
|
133975
|
+
}
|
|
133976
|
+
const timestamp = new Date().getTime();
|
|
133977
|
+
if (url.indexOf('?') > -1) {
|
|
133978
|
+
return url + '&_=' + timestamp;
|
|
133979
|
+
} else {
|
|
133980
|
+
return url + '?_=' + timestamp;
|
|
133981
|
+
}
|
|
133812
133982
|
}
|
|
133813
133983
|
|
|
133814
133984
|
/**
|
|
@@ -133819,6 +133989,8 @@ class WebIFCDefaultDataSource {
|
|
|
133819
133989
|
* @param {Function} error Callback fired on error.
|
|
133820
133990
|
*/
|
|
133821
133991
|
getIFC(src, ok, error) {
|
|
133992
|
+
src = this._cacheBusterURL(src);
|
|
133993
|
+
|
|
133822
133994
|
var defaultCallback = () => {
|
|
133823
133995
|
};
|
|
133824
133996
|
ok = ok || defaultCallback;
|
|
@@ -134816,7 +134988,20 @@ class WebIFCLoaderPlugin extends Plugin {
|
|
|
134816
134988
|
*/
|
|
134817
134989
|
class LASDefaultDataSource {
|
|
134818
134990
|
|
|
134819
|
-
constructor() {
|
|
134991
|
+
constructor(cfg = {}) {
|
|
134992
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
134993
|
+
}
|
|
134994
|
+
|
|
134995
|
+
_cacheBusterURL(url) {
|
|
134996
|
+
if (!this.cacheBuster) {
|
|
134997
|
+
return url;
|
|
134998
|
+
}
|
|
134999
|
+
const timestamp = new Date().getTime();
|
|
135000
|
+
if (url.indexOf('?') > -1) {
|
|
135001
|
+
return url + '&_=' + timestamp;
|
|
135002
|
+
} else {
|
|
135003
|
+
return url + '?_=' + timestamp;
|
|
135004
|
+
}
|
|
134820
135005
|
}
|
|
134821
135006
|
|
|
134822
135007
|
/**
|
|
@@ -134827,6 +135012,7 @@ class LASDefaultDataSource {
|
|
|
134827
135012
|
* @param {Function} error Callback fired on error.
|
|
134828
135013
|
*/
|
|
134829
135014
|
getLAS(src, ok, error) {
|
|
135015
|
+
src = this._cacheBusterURL(src);
|
|
134830
135016
|
var defaultCallback = () => {
|
|
134831
135017
|
};
|
|
134832
135018
|
ok = ok || defaultCallback;
|
|
@@ -135681,7 +135867,20 @@ function chunkArray(array, chunkSize) {
|
|
|
135681
135867
|
*/
|
|
135682
135868
|
class CityJSONDefaultDataSource {
|
|
135683
135869
|
|
|
135684
|
-
constructor() {
|
|
135870
|
+
constructor(cfg = {}) {
|
|
135871
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
135872
|
+
}
|
|
135873
|
+
|
|
135874
|
+
_cacheBusterURL(url) {
|
|
135875
|
+
if (!this.cacheBuster) {
|
|
135876
|
+
return url;
|
|
135877
|
+
}
|
|
135878
|
+
const timestamp = new Date().getTime();
|
|
135879
|
+
if (url.indexOf('?') > -1) {
|
|
135880
|
+
return url + '&_=' + timestamp;
|
|
135881
|
+
} else {
|
|
135882
|
+
return url + '?_=' + timestamp;
|
|
135883
|
+
}
|
|
135685
135884
|
}
|
|
135686
135885
|
|
|
135687
135886
|
/**
|
|
@@ -135692,7 +135891,7 @@ class CityJSONDefaultDataSource {
|
|
|
135692
135891
|
* @param {Function} error Callback fired on error.
|
|
135693
135892
|
*/
|
|
135694
135893
|
getCityJSON(src, ok, error) {
|
|
135695
|
-
utils.loadJSON(src,
|
|
135894
|
+
utils.loadJSON(this._cacheBusterURL(src),
|
|
135696
135895
|
(json) => {
|
|
135697
135896
|
ok(json);
|
|
135698
135897
|
},
|
|
@@ -137124,7 +137323,20 @@ class CityJSONLoaderPlugin extends Plugin {
|
|
|
137124
137323
|
*/
|
|
137125
137324
|
class DotBIMDefaultDataSource {
|
|
137126
137325
|
|
|
137127
|
-
constructor() {
|
|
137326
|
+
constructor(cfg = {}) {
|
|
137327
|
+
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
137328
|
+
}
|
|
137329
|
+
|
|
137330
|
+
_cacheBusterURL(url) {
|
|
137331
|
+
if (!this.cacheBuster) {
|
|
137332
|
+
return url;
|
|
137333
|
+
}
|
|
137334
|
+
const timestamp = new Date().getTime();
|
|
137335
|
+
if (url.indexOf('?') > -1) {
|
|
137336
|
+
return url + '&_=' + timestamp;
|
|
137337
|
+
} else {
|
|
137338
|
+
return url + '?_=' + timestamp;
|
|
137339
|
+
}
|
|
137128
137340
|
}
|
|
137129
137341
|
|
|
137130
137342
|
/**
|
|
@@ -137135,7 +137347,7 @@ class DotBIMDefaultDataSource {
|
|
|
137135
137347
|
* @param {Function} error Fired on error while loading the .BIM JSON asset.
|
|
137136
137348
|
*/
|
|
137137
137349
|
getDotBIM(dotBIMSrc, ok, error) {
|
|
137138
|
-
utils.loadJSON(dotBIMSrc,
|
|
137350
|
+
utils.loadJSON(this._cacheBusterURL(dotBIMSrc),
|
|
137139
137351
|
(json) => {
|
|
137140
137352
|
ok(json);
|
|
137141
137353
|
},
|
|
@@ -137697,6 +137909,2013 @@ class DotBIMLoaderPlugin extends Plugin {
|
|
|
137697
137909
|
}
|
|
137698
137910
|
}
|
|
137699
137911
|
|
|
137912
|
+
const hex2rgb = function(color) {
|
|
137913
|
+
const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
|
|
137914
|
+
return [ rgb(0), rgb(2), rgb(4) ];
|
|
137915
|
+
};
|
|
137916
|
+
|
|
137917
|
+
const transformToNode = function(from, to, vec) {
|
|
137918
|
+
const fromRec = from.getBoundingClientRect();
|
|
137919
|
+
const toRec = to.getBoundingClientRect();
|
|
137920
|
+
vec[0] += fromRec.left - toRec.left;
|
|
137921
|
+
vec[1] += fromRec.top - toRec.top;
|
|
137922
|
+
};
|
|
137923
|
+
|
|
137924
|
+
const triangulateEarClipping = function(planeCoords) {
|
|
137925
|
+
|
|
137926
|
+
const polygonVertices = [ ];
|
|
137927
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
137928
|
+
polygonVertices.push(i);
|
|
137929
|
+
|
|
137930
|
+
const isCCW = (function() {
|
|
137931
|
+
const ba = math.vec2();
|
|
137932
|
+
const bc = math.vec2();
|
|
137933
|
+
|
|
137934
|
+
let anglesSum = 0;
|
|
137935
|
+
|
|
137936
|
+
for (let i = 0; i < polygonVertices.length; ++i)
|
|
137937
|
+
{
|
|
137938
|
+
const a = planeCoords[polygonVertices[i]];
|
|
137939
|
+
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
137940
|
+
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
137941
|
+
|
|
137942
|
+
math.subVec2(a, b, ba);
|
|
137943
|
+
math.subVec2(c, b, bc);
|
|
137944
|
+
|
|
137945
|
+
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
137946
|
+
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
137947
|
+
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
137948
|
+
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
137949
|
+
}
|
|
137950
|
+
|
|
137951
|
+
return anglesSum < (polygonVertices.length * Math.PI);
|
|
137952
|
+
})();
|
|
137953
|
+
|
|
137954
|
+
const pointInTriangle = (function() {
|
|
137955
|
+
const sign = (p1, p2, p3) => {
|
|
137956
|
+
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
137957
|
+
};
|
|
137958
|
+
|
|
137959
|
+
return (pt, v1, v2, v3) => {
|
|
137960
|
+
const d1 = sign(pt, v1, v2);
|
|
137961
|
+
const d2 = sign(pt, v2, v3);
|
|
137962
|
+
const d3 = sign(pt, v3, v1);
|
|
137963
|
+
|
|
137964
|
+
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
137965
|
+
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
137966
|
+
|
|
137967
|
+
return !(has_neg && has_pos);
|
|
137968
|
+
};
|
|
137969
|
+
})();
|
|
137970
|
+
|
|
137971
|
+
const baseTriangles = [ ];
|
|
137972
|
+
|
|
137973
|
+
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
137974
|
+
vertices.forEach((v, i) => {
|
|
137975
|
+
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
137976
|
+
v.next = vertices[(i + 1) % vertices.length];
|
|
137977
|
+
});
|
|
137978
|
+
|
|
137979
|
+
const ba = math.vec2();
|
|
137980
|
+
const bc = math.vec2();
|
|
137981
|
+
|
|
137982
|
+
while (vertices.length > 2) {
|
|
137983
|
+
let earIdx = 0;
|
|
137984
|
+
while (true) {
|
|
137985
|
+
if (earIdx >= vertices.length)
|
|
137986
|
+
{
|
|
137987
|
+
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
137988
|
+
}
|
|
137989
|
+
const v = vertices[earIdx];
|
|
137990
|
+
|
|
137991
|
+
const a = planeCoords[v.prev.idx];
|
|
137992
|
+
const b = planeCoords[v.idx];
|
|
137993
|
+
const c = planeCoords[v.next.idx];
|
|
137994
|
+
|
|
137995
|
+
math.subVec2(a, b, ba);
|
|
137996
|
+
math.subVec2(c, b, bc);
|
|
137997
|
+
|
|
137998
|
+
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
137999
|
+
&&
|
|
138000
|
+
vertices.every( // no other vertices inside
|
|
138001
|
+
vv => ((vv === v)
|
|
138002
|
+
||
|
|
138003
|
+
(vv === v.prev)
|
|
138004
|
+
||
|
|
138005
|
+
(vv === v.next)
|
|
138006
|
+
||
|
|
138007
|
+
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
138008
|
+
break;
|
|
138009
|
+
++earIdx;
|
|
138010
|
+
}
|
|
138011
|
+
|
|
138012
|
+
const ear = vertices[earIdx];
|
|
138013
|
+
vertices.splice(earIdx, 1);
|
|
138014
|
+
|
|
138015
|
+
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
138016
|
+
|
|
138017
|
+
const prev = ear.prev;
|
|
138018
|
+
prev.next = ear.next;
|
|
138019
|
+
const next = ear.next;
|
|
138020
|
+
next.prev = ear.prev;
|
|
138021
|
+
}
|
|
138022
|
+
|
|
138023
|
+
return [ planeCoords, baseTriangles ];
|
|
138024
|
+
};
|
|
138025
|
+
|
|
138026
|
+
const draggableDot3D = function(handleMouseEvents, handleTouchEvents, viewer, worldPos, color, ray2WorldPos, onStart, onMove, onEnd) {
|
|
138027
|
+
const scene = viewer.scene;
|
|
138028
|
+
const canvas = scene.canvas.canvas;
|
|
138029
|
+
|
|
138030
|
+
const marker = new Marker(scene, {});
|
|
138031
|
+
|
|
138032
|
+
const pickWorldPos = canvasPos => {
|
|
138033
|
+
const origin = math.vec3();
|
|
138034
|
+
const direction = math.vec3();
|
|
138035
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138036
|
+
return ray2WorldPos(origin, direction);
|
|
138037
|
+
};
|
|
138038
|
+
|
|
138039
|
+
const onChange = event => {
|
|
138040
|
+
const canvasPos = math.vec2([ event.clientX, event.clientY ]);
|
|
138041
|
+
transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
|
|
138042
|
+
|
|
138043
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
138044
|
+
marker.worldPos = worldPos;
|
|
138045
|
+
updateDotPos();
|
|
138046
|
+
onMove(canvasPos, worldPos);
|
|
138047
|
+
};
|
|
138048
|
+
|
|
138049
|
+
let currentDrag = null;
|
|
138050
|
+
|
|
138051
|
+
const onDragMove = function(event) {
|
|
138052
|
+
const e = currentDrag.matchesEvent(event);
|
|
138053
|
+
if (e)
|
|
138054
|
+
{
|
|
138055
|
+
onChange(e);
|
|
138056
|
+
}
|
|
138057
|
+
};
|
|
138058
|
+
|
|
138059
|
+
const onDragEnd = function(event) {
|
|
138060
|
+
const e = currentDrag.matchesEvent(event);
|
|
138061
|
+
if (e)
|
|
138062
|
+
{
|
|
138063
|
+
dot.setOpacity(idleOpacity);
|
|
138064
|
+
currentDrag.cleanup();
|
|
138065
|
+
onChange(e);
|
|
138066
|
+
onEnd();
|
|
138067
|
+
}
|
|
138068
|
+
};
|
|
138069
|
+
|
|
138070
|
+
const startDrag = function(matchesEvent, cleanupHandlers) {
|
|
138071
|
+
if (currentDrag) {
|
|
138072
|
+
currentDrag.cleanup();
|
|
138073
|
+
}
|
|
138074
|
+
|
|
138075
|
+
dot.setOpacity(1.0);
|
|
138076
|
+
dot.setClickable(false);
|
|
138077
|
+
viewer.cameraControl.active = false;
|
|
138078
|
+
|
|
138079
|
+
currentDrag = {
|
|
138080
|
+
matchesEvent: matchesEvent,
|
|
138081
|
+
cleanup: function() {
|
|
138082
|
+
currentDrag = null;
|
|
138083
|
+
dot.setClickable(true);
|
|
138084
|
+
viewer.cameraControl.active = true;
|
|
138085
|
+
cleanupHandlers();
|
|
138086
|
+
}
|
|
138087
|
+
};
|
|
138088
|
+
|
|
138089
|
+
onStart();
|
|
138090
|
+
};
|
|
138091
|
+
|
|
138092
|
+
const dotCfg = { fillColor: color };
|
|
138093
|
+
|
|
138094
|
+
if (handleMouseEvents)
|
|
138095
|
+
{
|
|
138096
|
+
dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
|
|
138097
|
+
dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
|
|
138098
|
+
dotCfg.onMouseDown = event => {
|
|
138099
|
+
if (event.which === 1)
|
|
138100
|
+
{
|
|
138101
|
+
canvas.addEventListener("mousemove", onDragMove);
|
|
138102
|
+
canvas.addEventListener("mouseup", onDragEnd);
|
|
138103
|
+
startDrag(
|
|
138104
|
+
event => (event.which === 1) && event,
|
|
138105
|
+
() => {
|
|
138106
|
+
canvas.removeEventListener("mousemove", onDragMove);
|
|
138107
|
+
canvas.removeEventListener("mouseup", onDragEnd);
|
|
138108
|
+
});
|
|
138109
|
+
}
|
|
138110
|
+
};
|
|
138111
|
+
}
|
|
138112
|
+
|
|
138113
|
+
if (handleTouchEvents)
|
|
138114
|
+
{
|
|
138115
|
+
let touchStartId;
|
|
138116
|
+
dotCfg.onTouchstart = event => {
|
|
138117
|
+
event.preventDefault();
|
|
138118
|
+
if (event.touches.length === 1)
|
|
138119
|
+
{
|
|
138120
|
+
touchStartId = event.touches[0].identifier;
|
|
138121
|
+
startDrag(
|
|
138122
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId),
|
|
138123
|
+
() => { touchStartId = null; });
|
|
138124
|
+
}
|
|
138125
|
+
};
|
|
138126
|
+
dotCfg.onTouchmove = event => {
|
|
138127
|
+
event.preventDefault();
|
|
138128
|
+
onDragMove(event);
|
|
138129
|
+
};
|
|
138130
|
+
dotCfg.onTouchend = event => {
|
|
138131
|
+
event.preventDefault();
|
|
138132
|
+
onDragEnd(event);
|
|
138133
|
+
};
|
|
138134
|
+
}
|
|
138135
|
+
|
|
138136
|
+
const dotParent = canvas.ownerDocument.body;
|
|
138137
|
+
const dot = new Dot(dotParent, dotCfg);
|
|
138138
|
+
|
|
138139
|
+
const idleOpacity = 0.5;
|
|
138140
|
+
dot.setOpacity(idleOpacity);
|
|
138141
|
+
|
|
138142
|
+
const updateDotPos = function() {
|
|
138143
|
+
const pos = marker.canvasPos.slice();
|
|
138144
|
+
transformToNode(canvas, dotParent, pos);
|
|
138145
|
+
dot.setPos(pos[0], pos[1]);
|
|
138146
|
+
};
|
|
138147
|
+
|
|
138148
|
+
marker.worldPos = worldPos;
|
|
138149
|
+
updateDotPos();
|
|
138150
|
+
|
|
138151
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
|
|
138152
|
+
const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
|
|
138153
|
+
|
|
138154
|
+
return {
|
|
138155
|
+
setActive: value => dot.setClickable(value),
|
|
138156
|
+
getWorldPos: () => marker.worldPos,
|
|
138157
|
+
setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
|
|
138158
|
+
destroy: function() {
|
|
138159
|
+
currentDrag && currentDrag.cleanup();
|
|
138160
|
+
scene.camera.off(onViewMatrix);
|
|
138161
|
+
scene.camera.off(onProjMatrix);
|
|
138162
|
+
marker.destroy();
|
|
138163
|
+
dot.destroy();
|
|
138164
|
+
}
|
|
138165
|
+
};
|
|
138166
|
+
};
|
|
138167
|
+
|
|
138168
|
+
const marker3D = function(scene, color) {
|
|
138169
|
+
const canvas = scene.canvas.canvas;
|
|
138170
|
+
|
|
138171
|
+
const markerParent = canvas.parentNode;
|
|
138172
|
+
const markerDiv = document.createElement("div");
|
|
138173
|
+
markerParent.insertBefore(markerDiv, canvas);
|
|
138174
|
+
|
|
138175
|
+
let size = 5;
|
|
138176
|
+
markerDiv.style.background = color;
|
|
138177
|
+
markerDiv.style.border = "2px solid white";
|
|
138178
|
+
markerDiv.style.margin = "0 0";
|
|
138179
|
+
markerDiv.style.zIndex = "100";
|
|
138180
|
+
markerDiv.style.position = "absolute";
|
|
138181
|
+
markerDiv.style.pointerEvents = "none";
|
|
138182
|
+
markerDiv.style.display = "none";
|
|
138183
|
+
|
|
138184
|
+
const marker = new Marker(scene, {});
|
|
138185
|
+
|
|
138186
|
+
const px = x => x + "px";
|
|
138187
|
+
const update = function() {
|
|
138188
|
+
const pos = marker.canvasPos.slice();
|
|
138189
|
+
transformToNode(canvas, markerParent, pos);
|
|
138190
|
+
markerDiv.style.left = px(pos[0] - 3 - size / 2);
|
|
138191
|
+
markerDiv.style.top = px(pos[1] - 3 - size / 2);
|
|
138192
|
+
markerDiv.style.borderRadius = px(size * 2);
|
|
138193
|
+
markerDiv.style.width = px(size);
|
|
138194
|
+
markerDiv.style.height = px(size);
|
|
138195
|
+
};
|
|
138196
|
+
const onViewMatrix = scene.camera.on("viewMatrix", update);
|
|
138197
|
+
const onProjMatrix = scene.camera.on("projMatrix", update);
|
|
138198
|
+
|
|
138199
|
+
return {
|
|
138200
|
+
update: function(worldPos) {
|
|
138201
|
+
if (worldPos)
|
|
138202
|
+
{
|
|
138203
|
+
marker.worldPos = worldPos;
|
|
138204
|
+
update();
|
|
138205
|
+
}
|
|
138206
|
+
markerDiv.style.display = worldPos ? "" : "none";
|
|
138207
|
+
},
|
|
138208
|
+
|
|
138209
|
+
setHighlighted: function(h) {
|
|
138210
|
+
size = h ? 10 : 5;
|
|
138211
|
+
update();
|
|
138212
|
+
},
|
|
138213
|
+
|
|
138214
|
+
getCanvasPos: () => marker.canvasPos,
|
|
138215
|
+
|
|
138216
|
+
getWorldPos: () => marker.worldPos,
|
|
138217
|
+
|
|
138218
|
+
destroy: function() {
|
|
138219
|
+
markerDiv.parentNode.removeChild(markerDiv);
|
|
138220
|
+
scene.camera.off(onViewMatrix);
|
|
138221
|
+
scene.camera.off(onProjMatrix);
|
|
138222
|
+
marker.destroy();
|
|
138223
|
+
}
|
|
138224
|
+
};
|
|
138225
|
+
};
|
|
138226
|
+
|
|
138227
|
+
const wire3D = function(scene, color, startWorldPos) {
|
|
138228
|
+
const canvas = scene.canvas.canvas;
|
|
138229
|
+
|
|
138230
|
+
const startMarker = new Marker(scene, {});
|
|
138231
|
+
startMarker.worldPos = startWorldPos;
|
|
138232
|
+
const endMarker = new Marker(scene, {});
|
|
138233
|
+
const wireParent = canvas.ownerDocument.body;
|
|
138234
|
+
const wire = new Wire(wireParent, {
|
|
138235
|
+
color: color,
|
|
138236
|
+
thickness: 1,
|
|
138237
|
+
thicknessClickable: 6
|
|
138238
|
+
});
|
|
138239
|
+
wire.setVisible(false);
|
|
138240
|
+
|
|
138241
|
+
const updatePos = function() {
|
|
138242
|
+
const p0 = startMarker.canvasPos.slice();
|
|
138243
|
+
const p1 = endMarker.canvasPos.slice();
|
|
138244
|
+
transformToNode(canvas, wireParent, p0);
|
|
138245
|
+
transformToNode(canvas, wireParent, p1);
|
|
138246
|
+
wire.setStartAndEnd(p0[0], p0[1], p1[0], p1[1]);
|
|
138247
|
+
};
|
|
138248
|
+
const onViewMatrix = scene.camera.on("viewMatrix", updatePos);
|
|
138249
|
+
const onProjMatrix = scene.camera.on("projMatrix", updatePos);
|
|
138250
|
+
|
|
138251
|
+
return {
|
|
138252
|
+
update: function(endWorldPos) {
|
|
138253
|
+
if (endWorldPos)
|
|
138254
|
+
{
|
|
138255
|
+
endMarker.worldPos = endWorldPos;
|
|
138256
|
+
updatePos();
|
|
138257
|
+
}
|
|
138258
|
+
wire.setVisible(!!endWorldPos);
|
|
138259
|
+
},
|
|
138260
|
+
|
|
138261
|
+
destroy: function() {
|
|
138262
|
+
scene.camera.off(onViewMatrix);
|
|
138263
|
+
scene.camera.off(onProjMatrix);
|
|
138264
|
+
startMarker.destroy();
|
|
138265
|
+
endMarker.destroy();
|
|
138266
|
+
wire.destroy();
|
|
138267
|
+
}
|
|
138268
|
+
};
|
|
138269
|
+
};
|
|
138270
|
+
|
|
138271
|
+
const basePolygon3D = function(scene, color, alpha) {
|
|
138272
|
+
let mesh = null;
|
|
138273
|
+
|
|
138274
|
+
const updateBase = points => {
|
|
138275
|
+
if (points)
|
|
138276
|
+
{
|
|
138277
|
+
if (mesh)
|
|
138278
|
+
{
|
|
138279
|
+
mesh.destroy();
|
|
138280
|
+
}
|
|
138281
|
+
|
|
138282
|
+
try {
|
|
138283
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(points.map(p => [ p[0], p[2] ]));
|
|
138284
|
+
|
|
138285
|
+
const positions = [ ].concat(...baseVertices.map(p => [p[0], points[0][1], p[1]])); // To convert from Float64Array into an Array
|
|
138286
|
+
const ind = [ ].concat(...baseTriangles);
|
|
138287
|
+
mesh = new Mesh(scene, {
|
|
138288
|
+
pickable: false, // otherwise there's a WebGL error inside PickMeshRenderer.prototype.drawMesh
|
|
138289
|
+
geometry: new ReadableGeometry(
|
|
138290
|
+
scene,
|
|
138291
|
+
{
|
|
138292
|
+
positions: positions,
|
|
138293
|
+
indices: ind,
|
|
138294
|
+
normals: math.buildNormals(positions, ind)
|
|
138295
|
+
}),
|
|
138296
|
+
material: new PhongMaterial(scene, {
|
|
138297
|
+
alpha: (alpha !== undefined) ? alpha : 0.5,
|
|
138298
|
+
backfaces: true,
|
|
138299
|
+
diffuse: hex2rgb(color)
|
|
138300
|
+
})
|
|
138301
|
+
});
|
|
138302
|
+
} catch (e) {
|
|
138303
|
+
mesh = null;
|
|
138304
|
+
}
|
|
138305
|
+
}
|
|
138306
|
+
|
|
138307
|
+
if (mesh)
|
|
138308
|
+
{
|
|
138309
|
+
mesh.visible = !!points;
|
|
138310
|
+
}
|
|
138311
|
+
};
|
|
138312
|
+
updateBase(null);
|
|
138313
|
+
|
|
138314
|
+
return {
|
|
138315
|
+
updateBase: updateBase,
|
|
138316
|
+
destroy: () => mesh && mesh.destroy()
|
|
138317
|
+
};
|
|
138318
|
+
};
|
|
138319
|
+
|
|
138320
|
+
const startAAZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
138321
|
+
const marker1 = marker3D(scene, zoneColor);
|
|
138322
|
+
const marker2 = marker3D(scene, zoneColor);
|
|
138323
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
138324
|
+
|
|
138325
|
+
const updatePointerLens = (pointerLens
|
|
138326
|
+
? function(canvasPos) {
|
|
138327
|
+
pointerLens.visible = !! canvasPos;
|
|
138328
|
+
if (canvasPos)
|
|
138329
|
+
{
|
|
138330
|
+
pointerLens.canvasPos = canvasPos;
|
|
138331
|
+
}
|
|
138332
|
+
}
|
|
138333
|
+
: () => { });
|
|
138334
|
+
|
|
138335
|
+
let deactivatePointSelection = select3dPoint(
|
|
138336
|
+
() => {
|
|
138337
|
+
updatePointerLens(null);
|
|
138338
|
+
marker1.update(null);
|
|
138339
|
+
},
|
|
138340
|
+
(canvasPos, worldPos) => {
|
|
138341
|
+
updatePointerLens(canvasPos);
|
|
138342
|
+
marker1.update(worldPos);
|
|
138343
|
+
},
|
|
138344
|
+
function(point1CanvasPos, point1WorldPos) {
|
|
138345
|
+
marker1.update(point1WorldPos);
|
|
138346
|
+
|
|
138347
|
+
deactivatePointSelection = select3dPoint(
|
|
138348
|
+
function() {
|
|
138349
|
+
updatePointerLens(null);
|
|
138350
|
+
marker2.update(null);
|
|
138351
|
+
basePolygon.updateBase(null);
|
|
138352
|
+
},
|
|
138353
|
+
function(canvasPos, point2WorldPos) {
|
|
138354
|
+
updatePointerLens(canvasPos);
|
|
138355
|
+
marker2.update(point2WorldPos);
|
|
138356
|
+
|
|
138357
|
+
if (math.distVec3(point1WorldPos, point2WorldPos) > 0.01)
|
|
138358
|
+
{
|
|
138359
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138360
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138361
|
+
|
|
138362
|
+
const xmin = min(0);
|
|
138363
|
+
const ymin = min(1);
|
|
138364
|
+
const zmin = min(2);
|
|
138365
|
+
const xmax = max(0);
|
|
138366
|
+
max(1);
|
|
138367
|
+
const zmax = max(2);
|
|
138368
|
+
|
|
138369
|
+
basePolygon.updateBase([ [ xmin, ymin, zmax ], [ xmax, ymin, zmax ],
|
|
138370
|
+
[ xmax, ymin, zmin ], [ xmin, ymin, zmin ] ]);
|
|
138371
|
+
}
|
|
138372
|
+
else
|
|
138373
|
+
basePolygon.updateBase(null);
|
|
138374
|
+
},
|
|
138375
|
+
function(point2CanvasPos, point2WorldPos) {
|
|
138376
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
138377
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
138378
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
138379
|
+
marker2.update(point2WorldPos);
|
|
138380
|
+
|
|
138381
|
+
marker1.destroy();
|
|
138382
|
+
marker2.destroy();
|
|
138383
|
+
basePolygon.destroy();
|
|
138384
|
+
updatePointerLens(null);
|
|
138385
|
+
|
|
138386
|
+
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138387
|
+
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
138388
|
+
|
|
138389
|
+
const xmin = min(0);
|
|
138390
|
+
const zmin = min(2);
|
|
138391
|
+
const xmax = max(0);
|
|
138392
|
+
const zmax = max(2);
|
|
138393
|
+
|
|
138394
|
+
const zone = zonesPlugin.createZone(
|
|
138395
|
+
{
|
|
138396
|
+
id: math.createUUID(),
|
|
138397
|
+
geometry: {
|
|
138398
|
+
planeCoordinates: [
|
|
138399
|
+
[ xmin, zmax ],
|
|
138400
|
+
[ xmax, zmax ],
|
|
138401
|
+
[ xmax, zmin ],
|
|
138402
|
+
[ xmin, zmin ]
|
|
138403
|
+
],
|
|
138404
|
+
altitude: zoneAltitude,
|
|
138405
|
+
height: zoneHeight
|
|
138406
|
+
},
|
|
138407
|
+
alpha: zoneAlpha,
|
|
138408
|
+
color: zoneColor
|
|
138409
|
+
});
|
|
138410
|
+
|
|
138411
|
+
onZoneCreated(zone);
|
|
138412
|
+
});
|
|
138413
|
+
});
|
|
138414
|
+
|
|
138415
|
+
return {
|
|
138416
|
+
deactivate: function() {
|
|
138417
|
+
deactivatePointSelection();
|
|
138418
|
+
marker1.destroy();
|
|
138419
|
+
marker2.destroy();
|
|
138420
|
+
basePolygon.destroy();
|
|
138421
|
+
updatePointerLens(null);
|
|
138422
|
+
}
|
|
138423
|
+
};
|
|
138424
|
+
};
|
|
138425
|
+
|
|
138426
|
+
const mousePointSelector = function(viewer, ray2WorldPos) {
|
|
138427
|
+
return function(onCancel, onChange, onCommit) {
|
|
138428
|
+
const scene = viewer.scene;
|
|
138429
|
+
const canvas = scene.canvas.canvas;
|
|
138430
|
+
const moveTolerance = 20;
|
|
138431
|
+
|
|
138432
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138433
|
+
vec2[0] = event.clientX;
|
|
138434
|
+
vec2[1] = event.clientY;
|
|
138435
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138436
|
+
return vec2;
|
|
138437
|
+
};
|
|
138438
|
+
|
|
138439
|
+
const pickWorldPos = canvasPos => {
|
|
138440
|
+
const origin = math.vec3();
|
|
138441
|
+
const direction = math.vec3();
|
|
138442
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138443
|
+
return ray2WorldPos(origin, direction);
|
|
138444
|
+
};
|
|
138445
|
+
|
|
138446
|
+
let buttonDown = false;
|
|
138447
|
+
const resetAction = function() {
|
|
138448
|
+
buttonDown = false;
|
|
138449
|
+
};
|
|
138450
|
+
|
|
138451
|
+
const cleanup = function() {
|
|
138452
|
+
resetAction();
|
|
138453
|
+
canvas.removeEventListener("mousedown", onMouseDown);
|
|
138454
|
+
canvas.removeEventListener("mousemove", onMouseMove);
|
|
138455
|
+
viewer.cameraControl.off(onCameraControlRayMove);
|
|
138456
|
+
canvas.removeEventListener("mouseup", onMouseUp);
|
|
138457
|
+
};
|
|
138458
|
+
|
|
138459
|
+
const startCanvasPos = math.vec2();
|
|
138460
|
+
const onMouseDown = function(event) {
|
|
138461
|
+
if (event.which === 1)
|
|
138462
|
+
{
|
|
138463
|
+
copyCanvasPos(event, startCanvasPos);
|
|
138464
|
+
buttonDown = true;
|
|
138465
|
+
}
|
|
138466
|
+
};
|
|
138467
|
+
canvas.addEventListener("mousedown", onMouseDown);
|
|
138468
|
+
|
|
138469
|
+
const onMouseMove = function(event) {
|
|
138470
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138471
|
+
if (buttonDown && math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138472
|
+
{
|
|
138473
|
+
resetAction();
|
|
138474
|
+
onCancel();
|
|
138475
|
+
}
|
|
138476
|
+
};
|
|
138477
|
+
canvas.addEventListener("mousemove", onMouseMove);
|
|
138478
|
+
|
|
138479
|
+
const onCameraControlRayMove = viewer.cameraControl.on(
|
|
138480
|
+
"rayMove",
|
|
138481
|
+
event => {
|
|
138482
|
+
const canvasPos = event.canvasPos;
|
|
138483
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138484
|
+
});
|
|
138485
|
+
|
|
138486
|
+
const onMouseUp = function(event) {
|
|
138487
|
+
if ((event.which === 1) && buttonDown)
|
|
138488
|
+
{
|
|
138489
|
+
cleanup();
|
|
138490
|
+
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
138491
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138492
|
+
}
|
|
138493
|
+
};
|
|
138494
|
+
canvas.addEventListener("mouseup", onMouseUp);
|
|
138495
|
+
|
|
138496
|
+
return cleanup;
|
|
138497
|
+
};
|
|
138498
|
+
};
|
|
138499
|
+
|
|
138500
|
+
const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
138501
|
+
return function(onCancel, onChange, onCommit) {
|
|
138502
|
+
const scene = viewer.scene;
|
|
138503
|
+
const canvas = scene.canvas.canvas;
|
|
138504
|
+
const longTouchTimeoutMs = 300;
|
|
138505
|
+
const moveTolerance = 20;
|
|
138506
|
+
|
|
138507
|
+
const copyCanvasPos = (event, vec2) => {
|
|
138508
|
+
vec2[0] = event.clientX;
|
|
138509
|
+
vec2[1] = event.clientY;
|
|
138510
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
138511
|
+
return vec2;
|
|
138512
|
+
};
|
|
138513
|
+
|
|
138514
|
+
const pickWorldPos = canvasPos => {
|
|
138515
|
+
const origin = math.vec3();
|
|
138516
|
+
const direction = math.vec3();
|
|
138517
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
138518
|
+
return ray2WorldPos(origin, direction);
|
|
138519
|
+
};
|
|
138520
|
+
|
|
138521
|
+
let longTouchTimeout = null;
|
|
138522
|
+
const nop = () => { };
|
|
138523
|
+
let onSingleTouchMove = nop;
|
|
138524
|
+
let startTouchIdentifier;
|
|
138525
|
+
|
|
138526
|
+
const resetAction = function() {
|
|
138527
|
+
pointerCircle.stop();
|
|
138528
|
+
clearTimeout(longTouchTimeout);
|
|
138529
|
+
viewer.cameraControl.active = true;
|
|
138530
|
+
onSingleTouchMove = nop;
|
|
138531
|
+
startTouchIdentifier = null;
|
|
138532
|
+
};
|
|
138533
|
+
|
|
138534
|
+
const cleanup = function() {
|
|
138535
|
+
resetAction();
|
|
138536
|
+
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
138537
|
+
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
138538
|
+
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
138539
|
+
};
|
|
138540
|
+
|
|
138541
|
+
const onCanvasTouchStart = function(event) {
|
|
138542
|
+
const touches = event.touches;
|
|
138543
|
+
|
|
138544
|
+
if (touches.length !== 1)
|
|
138545
|
+
{
|
|
138546
|
+
resetAction();
|
|
138547
|
+
onCancel();
|
|
138548
|
+
}
|
|
138549
|
+
else
|
|
138550
|
+
{
|
|
138551
|
+
const startTouch = touches[0];
|
|
138552
|
+
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
138553
|
+
|
|
138554
|
+
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
138555
|
+
if (startWorldPos)
|
|
138556
|
+
{
|
|
138557
|
+
startTouchIdentifier = startTouch.identifier;
|
|
138558
|
+
|
|
138559
|
+
onSingleTouchMove = canvasPos => {
|
|
138560
|
+
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
138561
|
+
{
|
|
138562
|
+
resetAction();
|
|
138563
|
+
}
|
|
138564
|
+
};
|
|
138565
|
+
|
|
138566
|
+
longTouchTimeout = setTimeout(
|
|
138567
|
+
function() {
|
|
138568
|
+
pointerCircle.start(startCanvasPos);
|
|
138569
|
+
|
|
138570
|
+
longTouchTimeout = setTimeout(
|
|
138571
|
+
function() {
|
|
138572
|
+
pointerCircle.stop();
|
|
138573
|
+
|
|
138574
|
+
viewer.cameraControl.active = false;
|
|
138575
|
+
|
|
138576
|
+
onSingleTouchMove = canvasPos => {
|
|
138577
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
138578
|
+
};
|
|
138579
|
+
|
|
138580
|
+
onSingleTouchMove(startCanvasPos);
|
|
138581
|
+
},
|
|
138582
|
+
longTouchTimeoutMs);
|
|
138583
|
+
},
|
|
138584
|
+
250);
|
|
138585
|
+
}
|
|
138586
|
+
}
|
|
138587
|
+
};
|
|
138588
|
+
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
138589
|
+
|
|
138590
|
+
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
138591
|
+
|
|
138592
|
+
const onCanvasTouchMove = function(event) {
|
|
138593
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138594
|
+
if (touch)
|
|
138595
|
+
{
|
|
138596
|
+
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
138597
|
+
}
|
|
138598
|
+
};
|
|
138599
|
+
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
138600
|
+
|
|
138601
|
+
const onCanvasTouchEnd = function(event) {
|
|
138602
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
138603
|
+
if (touch)
|
|
138604
|
+
{
|
|
138605
|
+
cleanup();
|
|
138606
|
+
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
138607
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
138608
|
+
}
|
|
138609
|
+
};
|
|
138610
|
+
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
138611
|
+
|
|
138612
|
+
return cleanup;
|
|
138613
|
+
};
|
|
138614
|
+
};
|
|
138615
|
+
|
|
138616
|
+
const planeIntersect = function(p0, n, origin, direction) {
|
|
138617
|
+
const t = - (math.dotVec3(origin, n) - p0) / math.dotVec3(direction, n);
|
|
138618
|
+
{
|
|
138619
|
+
const worldPos = math.vec3();
|
|
138620
|
+
math.mulVec3Scalar(direction, t, worldPos);
|
|
138621
|
+
math.addVec3(origin, worldPos, worldPos);
|
|
138622
|
+
return worldPos;
|
|
138623
|
+
}
|
|
138624
|
+
};
|
|
138625
|
+
|
|
138626
|
+
/**
|
|
138627
|
+
* @desc Renders a transparent box between two 3D points.
|
|
138628
|
+
*
|
|
138629
|
+
* See {@link ZonesPlugin} for more info.
|
|
138630
|
+
*/
|
|
138631
|
+
|
|
138632
|
+
class Zone extends Component {
|
|
138633
|
+
|
|
138634
|
+
/**
|
|
138635
|
+
* @private
|
|
138636
|
+
*/
|
|
138637
|
+
constructor(plugin, cfg = {}) {
|
|
138638
|
+
|
|
138639
|
+
super(plugin.viewer.scene, cfg);
|
|
138640
|
+
|
|
138641
|
+
/**
|
|
138642
|
+
* The {@link ZonesPlugin} that owns this Zone.
|
|
138643
|
+
* @type {ZonesPlugin}
|
|
138644
|
+
*/
|
|
138645
|
+
this.plugin = plugin;
|
|
138646
|
+
|
|
138647
|
+
this._container = cfg.container;
|
|
138648
|
+
if (!this._container) {
|
|
138649
|
+
throw "config missing: container";
|
|
138650
|
+
}
|
|
138651
|
+
|
|
138652
|
+
this._eventSubs = {};
|
|
138653
|
+
|
|
138654
|
+
this.plugin.viewer.scene;
|
|
138655
|
+
|
|
138656
|
+
this._geometry = cfg.geometry;
|
|
138657
|
+
|
|
138658
|
+
cfg.onMouseOver ? (event) => {
|
|
138659
|
+
cfg.onMouseOver(event, this);
|
|
138660
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event));
|
|
138661
|
+
} : null;
|
|
138662
|
+
|
|
138663
|
+
cfg.onMouseLeave ? (event) => {
|
|
138664
|
+
cfg.onMouseLeave(event, this);
|
|
138665
|
+
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event));
|
|
138666
|
+
} : null;
|
|
138667
|
+
|
|
138668
|
+
cfg.onContextMenu ? (event) => {
|
|
138669
|
+
cfg.onContextMenu(event, this);
|
|
138670
|
+
} : null;
|
|
138671
|
+
|
|
138672
|
+
this._alpha = (("alpha" in cfg) && (cfg.alpha !== undefined)) ? cfg.alpha : 0.5;
|
|
138673
|
+
this.color = cfg.color;
|
|
138674
|
+
|
|
138675
|
+
this._visible = true;
|
|
138676
|
+
|
|
138677
|
+
this._rebuildMesh();
|
|
138678
|
+
}
|
|
138679
|
+
|
|
138680
|
+
_rebuildMesh() {
|
|
138681
|
+
const scene = this.plugin.viewer.scene;
|
|
138682
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138683
|
+
const downward = this._geometry.height < 0;
|
|
138684
|
+
const altitude = this._geometry.altitude + (downward ? this._geometry.height : 0);
|
|
138685
|
+
const height = this._geometry.height * (downward ? -1 : 1);
|
|
138686
|
+
|
|
138687
|
+
const [ baseVertices, baseTriangles ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
|
|
138688
|
+
|
|
138689
|
+
const pos = [ ];
|
|
138690
|
+
const ind = [ ];
|
|
138691
|
+
|
|
138692
|
+
|
|
138693
|
+
const addPlane = (isCeiling) => {
|
|
138694
|
+
const baseIdx = pos.length;
|
|
138695
|
+
|
|
138696
|
+
for (let c of baseVertices) {
|
|
138697
|
+
pos.push([ c[0], altitude + (isCeiling ? height : 0), c[1] ]);
|
|
138698
|
+
}
|
|
138699
|
+
|
|
138700
|
+
for (let t of baseTriangles) {
|
|
138701
|
+
ind.push(...(isCeiling ? t : t.slice(0).reverse()).map(i => i + baseIdx));
|
|
138702
|
+
}
|
|
138703
|
+
};
|
|
138704
|
+
addPlane(false); // floor
|
|
138705
|
+
addPlane(true); // ceiling
|
|
138706
|
+
|
|
138707
|
+
|
|
138708
|
+
// sides
|
|
138709
|
+
for (let i = 0; i < baseVertices.length; ++i) {
|
|
138710
|
+
const a = baseVertices[i];
|
|
138711
|
+
const b = baseVertices[(i+1) % baseVertices.length];
|
|
138712
|
+
const f = altitude;
|
|
138713
|
+
const c = altitude + height;
|
|
138714
|
+
|
|
138715
|
+
const baseIdx = pos.length;
|
|
138716
|
+
|
|
138717
|
+
pos.push(
|
|
138718
|
+
[ a[0], f, a[1] ],
|
|
138719
|
+
[ b[0], f, b[1] ],
|
|
138720
|
+
[ b[0], c, b[1] ],
|
|
138721
|
+
[ a[0], c, a[1] ]
|
|
138722
|
+
);
|
|
138723
|
+
|
|
138724
|
+
ind.push(...[ 0, 1, 2, 0, 2, 3 ].map(i => i + baseIdx));
|
|
138725
|
+
}
|
|
138726
|
+
|
|
138727
|
+
|
|
138728
|
+
if (this._zoneMesh) {
|
|
138729
|
+
this._zoneMesh.destroy();
|
|
138730
|
+
}
|
|
138731
|
+
|
|
138732
|
+
|
|
138733
|
+
const positions = [].concat(...pos);
|
|
138734
|
+
this._zoneMesh = new Mesh(scene, {
|
|
138735
|
+
edges: this._edges,
|
|
138736
|
+
geometry: new ReadableGeometry(
|
|
138737
|
+
scene,
|
|
138738
|
+
{
|
|
138739
|
+
positions: positions,
|
|
138740
|
+
indices: ind,
|
|
138741
|
+
normals: math.buildNormals(positions, ind)
|
|
138742
|
+
}),
|
|
138743
|
+
material: new PhongMaterial(scene, {
|
|
138744
|
+
alpha: this._alpha,
|
|
138745
|
+
backfaces: true,
|
|
138746
|
+
diffuse: hex2rgb(this._color)
|
|
138747
|
+
}),
|
|
138748
|
+
visible: this._visible
|
|
138749
|
+
});
|
|
138750
|
+
this._zoneMesh.highlighted = this._highlighted;
|
|
138751
|
+
|
|
138752
|
+
this._zoneMesh.zone = this;
|
|
138753
|
+
|
|
138754
|
+
|
|
138755
|
+
const min = idx => Math.min(...pos.map(p => p[idx]));
|
|
138756
|
+
const max = idx => Math.max(...pos.map(p => p[idx]));
|
|
138757
|
+
|
|
138758
|
+
const xmin = min(0);
|
|
138759
|
+
const ymin = min(1);
|
|
138760
|
+
const zmin = min(2);
|
|
138761
|
+
const xmax = max(0);
|
|
138762
|
+
const ymax = max(1);
|
|
138763
|
+
const zmax = max(2);
|
|
138764
|
+
|
|
138765
|
+
this._center = math.vec3([ (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2 ]);
|
|
138766
|
+
}
|
|
138767
|
+
|
|
138768
|
+
sectionedAverage(sectionPlanes) {
|
|
138769
|
+
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
138770
|
+
|
|
138771
|
+
let faces = [ ];
|
|
138772
|
+
{
|
|
138773
|
+
const h = this._geometry.height;
|
|
138774
|
+
const a = this._geometry.altitude;
|
|
138775
|
+
const c = a + Math.max(0, h);
|
|
138776
|
+
const f = a + Math.min(0, h);
|
|
138777
|
+
|
|
138778
|
+
const addPlane = (isCeiling) => {
|
|
138779
|
+
const face = planeCoords.map(p => [ p[0], isCeiling ? c : f, p[1] ]);
|
|
138780
|
+
faces.push(isCeiling ? face : face.slice(0).reverse());
|
|
138781
|
+
};
|
|
138782
|
+
addPlane(true); // ceiling
|
|
138783
|
+
addPlane(false); // floor
|
|
138784
|
+
|
|
138785
|
+
// sides
|
|
138786
|
+
const p = (idx, y) => [ planeCoords[idx][0], y, planeCoords[idx][1] ];
|
|
138787
|
+
for (let i = 0; i < planeCoords.length; ++i)
|
|
138788
|
+
{
|
|
138789
|
+
const j = (i + 1) % planeCoords.length;
|
|
138790
|
+
faces.push([ p(i, f), p(j, f), p(j, c), p(i, c) ]);
|
|
138791
|
+
}
|
|
138792
|
+
}
|
|
138793
|
+
|
|
138794
|
+
for (const s of sectionPlanes)
|
|
138795
|
+
{
|
|
138796
|
+
const dir = s.dir;
|
|
138797
|
+
const dist = s.dist;
|
|
138798
|
+
const newFaces = [ ];
|
|
138799
|
+
|
|
138800
|
+
for (const face of faces)
|
|
138801
|
+
{
|
|
138802
|
+
const EPSILON = 1e-5;
|
|
138803
|
+
const COPLANAR = 0;
|
|
138804
|
+
const FRONT = 1;
|
|
138805
|
+
const BACK = 2;
|
|
138806
|
+
const SPANNING = 3;
|
|
138807
|
+
|
|
138808
|
+
// Classify each point as well as the entire polygon into one of the above four classes.
|
|
138809
|
+
let polygonType = 0;
|
|
138810
|
+
const types = [ ];
|
|
138811
|
+
for (let i = 0; i < face.length; i++) {
|
|
138812
|
+
const t = math.dotVec3(dir, face[i]) + dist;
|
|
138813
|
+
const type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR;
|
|
138814
|
+
polygonType |= type;
|
|
138815
|
+
types.push(type);
|
|
138816
|
+
}
|
|
138817
|
+
|
|
138818
|
+
// Put the polygon in the correct list, splitting it when necessary.
|
|
138819
|
+
switch (polygonType) {
|
|
138820
|
+
case COPLANAR:
|
|
138821
|
+
newFaces.push(face);
|
|
138822
|
+
break;
|
|
138823
|
+
case FRONT:
|
|
138824
|
+
newFaces.push(face);
|
|
138825
|
+
break;
|
|
138826
|
+
case BACK:
|
|
138827
|
+
break;
|
|
138828
|
+
case SPANNING:
|
|
138829
|
+
const f = [ ];
|
|
138830
|
+
for (let i = 0; i < face.length; i++)
|
|
138831
|
+
{
|
|
138832
|
+
var j = (i + 1) % face.length;
|
|
138833
|
+
const ti = types[i];
|
|
138834
|
+
const tj = types[j];
|
|
138835
|
+
const vi = face[i];
|
|
138836
|
+
const vj = face[j];
|
|
138837
|
+
if (ti !== BACK)
|
|
138838
|
+
{
|
|
138839
|
+
f.push(vi);
|
|
138840
|
+
}
|
|
138841
|
+
|
|
138842
|
+
if ((ti | tj) === SPANNING)
|
|
138843
|
+
{
|
|
138844
|
+
const diff = math.vec3();
|
|
138845
|
+
math.subVec3(vj, vi, diff);
|
|
138846
|
+
const t = - (dist + math.dotVec3(dir, vi)) / math.dotVec3(dir, diff);
|
|
138847
|
+
const v = [0,0,0];
|
|
138848
|
+
math.lerpVec3(t, 0, 1, vi, vj, v);
|
|
138849
|
+
f.push(v);
|
|
138850
|
+
}
|
|
138851
|
+
}
|
|
138852
|
+
if (f.length >= 3)
|
|
138853
|
+
{
|
|
138854
|
+
newFaces.push(f);
|
|
138855
|
+
}
|
|
138856
|
+
break;
|
|
138857
|
+
}
|
|
138858
|
+
}
|
|
138859
|
+
|
|
138860
|
+
faces = newFaces;
|
|
138861
|
+
}
|
|
138862
|
+
|
|
138863
|
+
if (faces.length === 0)
|
|
138864
|
+
{
|
|
138865
|
+
return null;
|
|
138866
|
+
}
|
|
138867
|
+
else
|
|
138868
|
+
{
|
|
138869
|
+
const avg = math.vec3([ 0, 0, 0 ]);
|
|
138870
|
+
const unique = new Set();
|
|
138871
|
+
|
|
138872
|
+
for (const f of faces)
|
|
138873
|
+
{
|
|
138874
|
+
for (const p of f)
|
|
138875
|
+
{
|
|
138876
|
+
const id = p.map(x => x.toFixed(3)).join(":");
|
|
138877
|
+
if (! (unique.has(id)))
|
|
138878
|
+
{
|
|
138879
|
+
unique.add(id);
|
|
138880
|
+
math.addVec3(avg, p, avg);
|
|
138881
|
+
}
|
|
138882
|
+
}
|
|
138883
|
+
}
|
|
138884
|
+
|
|
138885
|
+
math.mulVec3Scalar(avg, 1 / unique.size, avg);
|
|
138886
|
+
|
|
138887
|
+
return avg;
|
|
138888
|
+
}
|
|
138889
|
+
}
|
|
138890
|
+
|
|
138891
|
+
get center() {
|
|
138892
|
+
return this._center;
|
|
138893
|
+
}
|
|
138894
|
+
|
|
138895
|
+
get altitude() {
|
|
138896
|
+
return this._geometry.altitude;
|
|
138897
|
+
}
|
|
138898
|
+
|
|
138899
|
+
set altitude(value) {
|
|
138900
|
+
this._geometry.altitude = value;
|
|
138901
|
+
this._rebuildMesh();
|
|
138902
|
+
}
|
|
138903
|
+
|
|
138904
|
+
get height() {
|
|
138905
|
+
return this._geometry.height;
|
|
138906
|
+
}
|
|
138907
|
+
|
|
138908
|
+
set height(value) {
|
|
138909
|
+
this._geometry.height = value;
|
|
138910
|
+
this._rebuildMesh();
|
|
138911
|
+
}
|
|
138912
|
+
|
|
138913
|
+
get highlighted() {
|
|
138914
|
+
return this._highlighted;
|
|
138915
|
+
}
|
|
138916
|
+
|
|
138917
|
+
set highlighted(value)
|
|
138918
|
+
{
|
|
138919
|
+
this._highlighted = value;
|
|
138920
|
+
if (this._zoneMesh) {
|
|
138921
|
+
this._zoneMesh.highlighted = value;
|
|
138922
|
+
}
|
|
138923
|
+
}
|
|
138924
|
+
|
|
138925
|
+
set color(value) {
|
|
138926
|
+
this._color = value;
|
|
138927
|
+
if (this._zoneMesh) {
|
|
138928
|
+
this._zoneMesh.material.diffuse = hex2rgb(this._color);
|
|
138929
|
+
}
|
|
138930
|
+
}
|
|
138931
|
+
|
|
138932
|
+
get color() {
|
|
138933
|
+
return this._color;
|
|
138934
|
+
}
|
|
138935
|
+
|
|
138936
|
+
set alpha(value) {
|
|
138937
|
+
this._alpha = value;
|
|
138938
|
+
if (this._zoneMesh) {
|
|
138939
|
+
this._zoneMesh.material.alpha = this._alpha;
|
|
138940
|
+
}
|
|
138941
|
+
}
|
|
138942
|
+
|
|
138943
|
+
get alpha() {
|
|
138944
|
+
return this._alpha;
|
|
138945
|
+
}
|
|
138946
|
+
|
|
138947
|
+
get edges() {
|
|
138948
|
+
return this._edges;
|
|
138949
|
+
}
|
|
138950
|
+
|
|
138951
|
+
set edges(edges) {
|
|
138952
|
+
this._edges = edges;
|
|
138953
|
+
if (this._zoneMesh) {
|
|
138954
|
+
this._zoneMesh.edges = this._edges;
|
|
138955
|
+
}
|
|
138956
|
+
}
|
|
138957
|
+
|
|
138958
|
+
/**
|
|
138959
|
+
* Sets whether this Zone is visible or not.
|
|
138960
|
+
*
|
|
138961
|
+
* @type {Boolean}
|
|
138962
|
+
*/
|
|
138963
|
+
set visible(value) {
|
|
138964
|
+
this._visible = !!value;
|
|
138965
|
+
this._zoneMesh.visible = this._visible;
|
|
138966
|
+
this._needUpdate();
|
|
138967
|
+
}
|
|
138968
|
+
|
|
138969
|
+
/**
|
|
138970
|
+
* Gets whether this Zone is visible or not.
|
|
138971
|
+
*
|
|
138972
|
+
* @type {Boolean}
|
|
138973
|
+
*/
|
|
138974
|
+
get visible() {
|
|
138975
|
+
return this._visible;
|
|
138976
|
+
}
|
|
138977
|
+
|
|
138978
|
+
/**
|
|
138979
|
+
* Gets this Zone as JSON.
|
|
138980
|
+
*
|
|
138981
|
+
* @returns {JSON}
|
|
138982
|
+
*/
|
|
138983
|
+
|
|
138984
|
+
getJSON() {
|
|
138985
|
+
return {
|
|
138986
|
+
id: this.id,
|
|
138987
|
+
geometry: this._geometry,
|
|
138988
|
+
alpha: this._alpha,
|
|
138989
|
+
color: this._color
|
|
138990
|
+
};
|
|
138991
|
+
}
|
|
138992
|
+
|
|
138993
|
+
duplicate() {
|
|
138994
|
+
return this.plugin.createZone(
|
|
138995
|
+
{
|
|
138996
|
+
id: math.createUUID(),
|
|
138997
|
+
geometry: {
|
|
138998
|
+
planeCoordinates: this._geometry.planeCoordinates.map(c => c.slice()),
|
|
138999
|
+
altitude: this._geometry.altitude,
|
|
139000
|
+
height: this._geometry.height
|
|
139001
|
+
},
|
|
139002
|
+
alpha: this._alpha,
|
|
139003
|
+
color: this._color
|
|
139004
|
+
});
|
|
139005
|
+
}
|
|
139006
|
+
|
|
139007
|
+
/**
|
|
139008
|
+
* @private
|
|
139009
|
+
*/
|
|
139010
|
+
destroy() {
|
|
139011
|
+
this._zoneMesh.destroy();
|
|
139012
|
+
super.destroy();
|
|
139013
|
+
}
|
|
139014
|
+
}
|
|
139015
|
+
|
|
139016
|
+
/**
|
|
139017
|
+
* Creates {@link Zone}s in a {@link ZonesPlugin} from mouse input.
|
|
139018
|
+
*
|
|
139019
|
+
* ## Usage
|
|
139020
|
+
*
|
|
139021
|
+
* [[Run example](/examples/measurement/#distance_createWithMouse_snapping)]
|
|
139022
|
+
*
|
|
139023
|
+
* ````javascript
|
|
139024
|
+
* import {Viewer, XKTLoaderPlugin, ZonesPlugin, ZonesMouseControl} from "xeokit-sdk.es.js";
|
|
139025
|
+
*
|
|
139026
|
+
* const viewer = new Viewer({
|
|
139027
|
+
* canvasId: "myCanvas",
|
|
139028
|
+
* });
|
|
139029
|
+
*
|
|
139030
|
+
* viewer.camera.eye = [-3.93, 2.85, 27.01];
|
|
139031
|
+
* viewer.camera.look = [4.40, 3.72, 8.89];
|
|
139032
|
+
* viewer.camera.up = [-0.01, 0.99, 0.039];
|
|
139033
|
+
*
|
|
139034
|
+
* const xktLoader = new XKTLoaderPlugin(viewer);
|
|
139035
|
+
*
|
|
139036
|
+
* const sceneModel = xktLoader.load({
|
|
139037
|
+
* id: "myModel",
|
|
139038
|
+
* src: "Duplex.xkt"
|
|
139039
|
+
* });
|
|
139040
|
+
*
|
|
139041
|
+
* const zones = new ZonesPlugin(viewer);
|
|
139042
|
+
*
|
|
139043
|
+
* const zonesControl = new ZonesMouseControl(Zones)
|
|
139044
|
+
* ````
|
|
139045
|
+
*/
|
|
139046
|
+
class ZonesMouseControl extends Component {
|
|
139047
|
+
|
|
139048
|
+
/**
|
|
139049
|
+
* Creates a ZonesMouseControl bound to the given ZonesPlugin.
|
|
139050
|
+
*
|
|
139051
|
+
* @param {ZonesPlugin} zonesPlugin The ZonesPlugin to control.
|
|
139052
|
+
* @param [cfg] Configuration
|
|
139053
|
+
* @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor when snapping is enabled.
|
|
139054
|
+
*/
|
|
139055
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139056
|
+
super(zonesPlugin.viewer.scene);
|
|
139057
|
+
|
|
139058
|
+
this.zonesPlugin = zonesPlugin;
|
|
139059
|
+
this.pointerLens = cfg.pointerLens;
|
|
139060
|
+
this._deactivate = null;
|
|
139061
|
+
}
|
|
139062
|
+
|
|
139063
|
+
get active() {
|
|
139064
|
+
return !! this._deactivate;
|
|
139065
|
+
}
|
|
139066
|
+
|
|
139067
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139068
|
+
|
|
139069
|
+
if (this._deactivate) {
|
|
139070
|
+
return;
|
|
139071
|
+
}
|
|
139072
|
+
|
|
139073
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139074
|
+
const params = zoneAltitude;
|
|
139075
|
+
const param = (name, defaultValue) => {
|
|
139076
|
+
if (name in params) {
|
|
139077
|
+
return params[name];
|
|
139078
|
+
} else if (defaultValue !== undefined) {
|
|
139079
|
+
return defaultValue;
|
|
139080
|
+
} else {
|
|
139081
|
+
throw "config missing: " + name;
|
|
139082
|
+
}
|
|
139083
|
+
};
|
|
139084
|
+
|
|
139085
|
+
zoneAltitude = param("altitude");
|
|
139086
|
+
zoneHeight = param("height");
|
|
139087
|
+
zoneColor = param("color", "#008000");
|
|
139088
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139089
|
+
}
|
|
139090
|
+
|
|
139091
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139092
|
+
const viewer = zonesPlugin.viewer;
|
|
139093
|
+
const scene = viewer.scene;
|
|
139094
|
+
const self = this;
|
|
139095
|
+
|
|
139096
|
+
const select3dPoint = mousePointSelector(
|
|
139097
|
+
viewer,
|
|
139098
|
+
function(origin, direction) {
|
|
139099
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139100
|
+
});
|
|
139101
|
+
|
|
139102
|
+
(function rec() {
|
|
139103
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139104
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139105
|
+
zone => {
|
|
139106
|
+
let reactivate = true;
|
|
139107
|
+
self._deactivate = () => { reactivate = false; };
|
|
139108
|
+
self.fire("zoneEnd", zone);
|
|
139109
|
+
if (reactivate)
|
|
139110
|
+
{
|
|
139111
|
+
rec();
|
|
139112
|
+
}
|
|
139113
|
+
}).deactivate;
|
|
139114
|
+
})();
|
|
139115
|
+
}
|
|
139116
|
+
|
|
139117
|
+
deactivate() {
|
|
139118
|
+
if (this._deactivate)
|
|
139119
|
+
{
|
|
139120
|
+
this._deactivate();
|
|
139121
|
+
this._deactivate = null;
|
|
139122
|
+
}
|
|
139123
|
+
}
|
|
139124
|
+
|
|
139125
|
+
/**
|
|
139126
|
+
* Destroys this ZonesMouseControl.
|
|
139127
|
+
*
|
|
139128
|
+
* Destroys any {@link Zone} under construction by this ZonesMouseControl.
|
|
139129
|
+
*/
|
|
139130
|
+
destroy() {
|
|
139131
|
+
this.deactivate();
|
|
139132
|
+
super.destroy();
|
|
139133
|
+
}
|
|
139134
|
+
}
|
|
139135
|
+
|
|
139136
|
+
/**
|
|
139137
|
+
* ZonesPlugin documentation to be added, mostly compatible with DistanceMeasurementsPlugin.
|
|
139138
|
+
*/
|
|
139139
|
+
class ZonesPlugin extends Plugin {
|
|
139140
|
+
|
|
139141
|
+
/**
|
|
139142
|
+
* @constructor
|
|
139143
|
+
* @param {Viewer} viewer The Viewer.
|
|
139144
|
+
* @param {Object} [cfg] Plugin configuration.
|
|
139145
|
+
* @param {String} [cfg.id="Zones"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
|
|
139146
|
+
* @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
|
|
139147
|
+
* @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label.
|
|
139148
|
+
* @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels).
|
|
139149
|
+
* @param {PointerCircle} [cfg.pointerLens] A PointerLens to help the user position the pointer. This can be shared with other plugins.
|
|
139150
|
+
*/
|
|
139151
|
+
constructor(viewer, cfg = {}) {
|
|
139152
|
+
|
|
139153
|
+
super("Zones", viewer);
|
|
139154
|
+
|
|
139155
|
+
this._pointerLens = cfg.pointerLens;
|
|
139156
|
+
|
|
139157
|
+
this._container = cfg.container || document.body;
|
|
139158
|
+
|
|
139159
|
+
this._zones = [ ];
|
|
139160
|
+
|
|
139161
|
+
this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF";
|
|
139162
|
+
this.zIndex = cfg.zIndex || 10000;
|
|
139163
|
+
|
|
139164
|
+
this._onMouseOver = (event, zone) => {
|
|
139165
|
+
this.fire("mouseOver", {
|
|
139166
|
+
plugin: this,
|
|
139167
|
+
zone,
|
|
139168
|
+
event
|
|
139169
|
+
});
|
|
139170
|
+
};
|
|
139171
|
+
|
|
139172
|
+
this._onMouseLeave = (event, zone) => {
|
|
139173
|
+
this.fire("mouseLeave", {
|
|
139174
|
+
plugin: this,
|
|
139175
|
+
zone,
|
|
139176
|
+
event
|
|
139177
|
+
});
|
|
139178
|
+
};
|
|
139179
|
+
|
|
139180
|
+
this._onContextMenu = (event, zone) => {
|
|
139181
|
+
this.fire("contextMenu", {
|
|
139182
|
+
plugin: this,
|
|
139183
|
+
zone,
|
|
139184
|
+
event
|
|
139185
|
+
});
|
|
139186
|
+
};
|
|
139187
|
+
}
|
|
139188
|
+
|
|
139189
|
+
/**
|
|
139190
|
+
* Creates a {@link Zone}.
|
|
139191
|
+
*
|
|
139192
|
+
* The Zone is then registered by {@link Zone#id} in {@link ZonesPlugin#zones}.
|
|
139193
|
+
*
|
|
139194
|
+
* @param {Object} params {@link Zone} configuration.
|
|
139195
|
+
* @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}.
|
|
139196
|
+
* @param {Number[]} params.origin.worldPos Origin World-space 3D position.
|
|
139197
|
+
* @param {Entity} params.origin.entity Origin Entity.
|
|
139198
|
+
* @param {Number[]} params.target.worldPos Target World-space 3D position.
|
|
139199
|
+
* @param {Entity} params.target.entity Target Entity.
|
|
139200
|
+
* @param {string} [params.color] The color of the length dot, wire and label.
|
|
139201
|
+
* @returns {Zone} The new {@link Zone}.
|
|
139202
|
+
*/
|
|
139203
|
+
createZone(params = {}) {
|
|
139204
|
+
if (this.viewer.scene.components[params.id]) {
|
|
139205
|
+
this.error("Viewer scene component with this ID already exists: " + params.id);
|
|
139206
|
+
delete params.id;
|
|
139207
|
+
}
|
|
139208
|
+
|
|
139209
|
+
const zone = new Zone(this, {
|
|
139210
|
+
id: params.id,
|
|
139211
|
+
plugin: this,
|
|
139212
|
+
container: this._container,
|
|
139213
|
+
geometry: params.geometry,
|
|
139214
|
+
alpha: params.alpha,
|
|
139215
|
+
color: params.color,
|
|
139216
|
+
onMouseOver: this._onMouseOver,
|
|
139217
|
+
onMouseLeave: this._onMouseLeave,
|
|
139218
|
+
onContextMenu: this._onContextMenu
|
|
139219
|
+
});
|
|
139220
|
+
this._zones.push(zone);
|
|
139221
|
+
zone.on("destroyed", () => {
|
|
139222
|
+
const idx = this._zones.indexOf(zone);
|
|
139223
|
+
if (idx >= 0) {
|
|
139224
|
+
this._zones.splice(idx, 1);
|
|
139225
|
+
}
|
|
139226
|
+
});
|
|
139227
|
+
this.fire("zoneCreated", zone);
|
|
139228
|
+
return zone;
|
|
139229
|
+
}
|
|
139230
|
+
|
|
139231
|
+
/**
|
|
139232
|
+
* Gets the existing {@link Zone}s, each mapped to its {@link Zone#id}.
|
|
139233
|
+
*
|
|
139234
|
+
* @type {{String:Zone}}
|
|
139235
|
+
*/
|
|
139236
|
+
get zones() {
|
|
139237
|
+
return this._zones;
|
|
139238
|
+
}
|
|
139239
|
+
|
|
139240
|
+
/**
|
|
139241
|
+
* Destroys this ZonesPlugin.
|
|
139242
|
+
*
|
|
139243
|
+
* Destroys all {@link Zone}s first.
|
|
139244
|
+
*/
|
|
139245
|
+
destroy() {
|
|
139246
|
+
super.destroy();
|
|
139247
|
+
}
|
|
139248
|
+
}
|
|
139249
|
+
|
|
139250
|
+
class ZonesTouchControl extends Component {
|
|
139251
|
+
|
|
139252
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139253
|
+
super(zonesPlugin.viewer.scene);
|
|
139254
|
+
|
|
139255
|
+
this.zonesPlugin = zonesPlugin;
|
|
139256
|
+
this.pointerLens = cfg.pointerLens;
|
|
139257
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139258
|
+
this._deactivate = null;
|
|
139259
|
+
}
|
|
139260
|
+
|
|
139261
|
+
get active() {
|
|
139262
|
+
return !! this._deactivate;
|
|
139263
|
+
}
|
|
139264
|
+
|
|
139265
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139266
|
+
|
|
139267
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139268
|
+
const params = zoneAltitude;
|
|
139269
|
+
const param = (name, defaultValue) => {
|
|
139270
|
+
if (name in params) {
|
|
139271
|
+
return params[name];
|
|
139272
|
+
} else if (defaultValue !== undefined) {
|
|
139273
|
+
return defaultValue;
|
|
139274
|
+
} else {
|
|
139275
|
+
throw "config missing: " + name;
|
|
139276
|
+
}
|
|
139277
|
+
};
|
|
139278
|
+
|
|
139279
|
+
zoneAltitude = param("altitude");
|
|
139280
|
+
zoneHeight = param("height");
|
|
139281
|
+
zoneColor = param("color", "#008000");
|
|
139282
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139283
|
+
}
|
|
139284
|
+
|
|
139285
|
+
if (this._deactivate) {
|
|
139286
|
+
return;
|
|
139287
|
+
}
|
|
139288
|
+
|
|
139289
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139290
|
+
const viewer = zonesPlugin.viewer;
|
|
139291
|
+
const scene = viewer.scene;
|
|
139292
|
+
const self = this;
|
|
139293
|
+
|
|
139294
|
+
const select3dPoint = touchPointSelector(
|
|
139295
|
+
viewer,
|
|
139296
|
+
this.pointerCircle,
|
|
139297
|
+
function(origin, direction) {
|
|
139298
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139299
|
+
});
|
|
139300
|
+
|
|
139301
|
+
(function rec() {
|
|
139302
|
+
self._deactivate = startAAZoneCreateUI(
|
|
139303
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139304
|
+
zone => {
|
|
139305
|
+
let reactivate = true;
|
|
139306
|
+
self._deactivate = () => { reactivate = false; };
|
|
139307
|
+
self.fire("zoneEnd", zone);
|
|
139308
|
+
if (reactivate)
|
|
139309
|
+
{
|
|
139310
|
+
rec();
|
|
139311
|
+
}
|
|
139312
|
+
}).deactivate;
|
|
139313
|
+
})();
|
|
139314
|
+
}
|
|
139315
|
+
|
|
139316
|
+
deactivate() {
|
|
139317
|
+
if (this._deactivate)
|
|
139318
|
+
{
|
|
139319
|
+
this._deactivate();
|
|
139320
|
+
this._deactivate = null;
|
|
139321
|
+
}
|
|
139322
|
+
}
|
|
139323
|
+
|
|
139324
|
+
destroy() {
|
|
139325
|
+
this.deactivate();
|
|
139326
|
+
super.destroy();
|
|
139327
|
+
}
|
|
139328
|
+
}
|
|
139329
|
+
|
|
139330
|
+
const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
139331
|
+
const updatePointerLens = (pointerLens
|
|
139332
|
+
? function(canvasPos) {
|
|
139333
|
+
pointerLens.visible = !! canvasPos;
|
|
139334
|
+
if (canvasPos)
|
|
139335
|
+
{
|
|
139336
|
+
pointerLens.canvasPos = canvasPos;
|
|
139337
|
+
}
|
|
139338
|
+
}
|
|
139339
|
+
: () => { });
|
|
139340
|
+
|
|
139341
|
+
let deactivatePointSelection;
|
|
139342
|
+
const cleanups = [ () => updatePointerLens(null) ];
|
|
139343
|
+
|
|
139344
|
+
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
139345
|
+
cleanups.push(() => basePolygon.destroy());
|
|
139346
|
+
|
|
139347
|
+
(function selectNextPoint(markers) {
|
|
139348
|
+
const marker = marker3D(scene, zoneColor);
|
|
139349
|
+
const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
|
|
139350
|
+
|
|
139351
|
+
cleanups.push(() => {
|
|
139352
|
+
marker.destroy();
|
|
139353
|
+
wire && wire.destroy();
|
|
139354
|
+
});
|
|
139355
|
+
|
|
139356
|
+
const firstMarker = (markers.length > 0) && markers[0];
|
|
139357
|
+
const getSnappedFirst = function(canvasPos) {
|
|
139358
|
+
const firstCanvasPos = firstMarker && firstMarker.getCanvasPos();
|
|
139359
|
+
const snapToFirst = firstCanvasPos && (math.distVec2(firstCanvasPos, canvasPos) < 10);
|
|
139360
|
+
return snapToFirst && { canvasPos: firstCanvasPos, worldPos: firstMarker.getWorldPos() };
|
|
139361
|
+
};
|
|
139362
|
+
|
|
139363
|
+
const lastSegmentIntersects = (function() {
|
|
139364
|
+
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
139365
|
+
(q[0] >= Math.min(p[0], r[0])) &&
|
|
139366
|
+
(q[1] <= Math.max(p[1], r[1])) &&
|
|
139367
|
+
(q[1] >= Math.min(p[1], r[1])));
|
|
139368
|
+
|
|
139369
|
+
const orient = (p, q, r) => {
|
|
139370
|
+
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
139371
|
+
// collinear
|
|
139372
|
+
// clockwise
|
|
139373
|
+
// counterclockwise
|
|
139374
|
+
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
139375
|
+
};
|
|
139376
|
+
|
|
139377
|
+
return function(pos2D, excludeFirstSegment) {
|
|
139378
|
+
const a = pos2D[pos2D.length - 2];
|
|
139379
|
+
const b = pos2D[pos2D.length - 1];
|
|
139380
|
+
|
|
139381
|
+
for (let i = excludeFirstSegment ? 1 : 0; i < pos2D.length - 2 - 1; ++i)
|
|
139382
|
+
{
|
|
139383
|
+
const c = pos2D[i];
|
|
139384
|
+
const d = pos2D[i + 1];
|
|
139385
|
+
|
|
139386
|
+
const o1 = orient(a, b, c);
|
|
139387
|
+
const o2 = orient(a, b, d);
|
|
139388
|
+
const o3 = orient(c, d, a);
|
|
139389
|
+
const o4 = orient(c, d, b);
|
|
139390
|
+
|
|
139391
|
+
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
139392
|
+
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
139393
|
+
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
139394
|
+
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
139395
|
+
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
139396
|
+
{
|
|
139397
|
+
return true;
|
|
139398
|
+
}
|
|
139399
|
+
}
|
|
139400
|
+
|
|
139401
|
+
return false;
|
|
139402
|
+
};
|
|
139403
|
+
})();
|
|
139404
|
+
|
|
139405
|
+
deactivatePointSelection = select3dPoint(
|
|
139406
|
+
() => {
|
|
139407
|
+
updatePointerLens(null);
|
|
139408
|
+
marker.update(null);
|
|
139409
|
+
wire && wire.update(null);
|
|
139410
|
+
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
139411
|
+
},
|
|
139412
|
+
(canvasPos, worldPos) => {
|
|
139413
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139414
|
+
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
139415
|
+
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
139416
|
+
marker.update((! snappedFirst) && worldPos);
|
|
139417
|
+
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
139418
|
+
if ((markers.length >= 2))
|
|
139419
|
+
{
|
|
139420
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139421
|
+
const inter = lastSegmentIntersects(pos.map(p => [ p[0], p[2] ]), snappedFirst);
|
|
139422
|
+
basePolygon.updateBase(inter ? null : pos);
|
|
139423
|
+
}
|
|
139424
|
+
else
|
|
139425
|
+
basePolygon.updateBase(null);
|
|
139426
|
+
},
|
|
139427
|
+
function(canvasPos, worldPos) {
|
|
139428
|
+
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
139429
|
+
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
139430
|
+
basePolygon.updateBase(pos);
|
|
139431
|
+
const pos2D = pos.map(p => [ p[0], p[2] ]);
|
|
139432
|
+
if ((markers.length > 2) && lastSegmentIntersects(pos2D, snappedFirst))
|
|
139433
|
+
{
|
|
139434
|
+
cleanups.pop()();
|
|
139435
|
+
selectNextPoint(markers);
|
|
139436
|
+
}
|
|
139437
|
+
else if (snappedFirst)
|
|
139438
|
+
{
|
|
139439
|
+
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
139440
|
+
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
139441
|
+
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
139442
|
+
marker.update(worldPos);
|
|
139443
|
+
|
|
139444
|
+
cleanups.forEach(c => c());
|
|
139445
|
+
onZoneCreated(
|
|
139446
|
+
zonesPlugin.createZone(
|
|
139447
|
+
{
|
|
139448
|
+
id: math.createUUID(),
|
|
139449
|
+
geometry: {
|
|
139450
|
+
planeCoordinates: pos2D,
|
|
139451
|
+
altitude: zoneAltitude,
|
|
139452
|
+
height: zoneHeight
|
|
139453
|
+
},
|
|
139454
|
+
alpha: zoneAlpha,
|
|
139455
|
+
color: zoneColor
|
|
139456
|
+
}));
|
|
139457
|
+
}
|
|
139458
|
+
else
|
|
139459
|
+
{
|
|
139460
|
+
marker.update(worldPos);
|
|
139461
|
+
wire && wire.update(worldPos);
|
|
139462
|
+
selectNextPoint(markers.concat(marker));
|
|
139463
|
+
}
|
|
139464
|
+
});
|
|
139465
|
+
})([ ]);
|
|
139466
|
+
|
|
139467
|
+
return {
|
|
139468
|
+
closeSurface: function() {
|
|
139469
|
+
throw "TODO";
|
|
139470
|
+
},
|
|
139471
|
+
deactivate: function() {
|
|
139472
|
+
deactivatePointSelection();
|
|
139473
|
+
cleanups.forEach(c => c());
|
|
139474
|
+
}
|
|
139475
|
+
};
|
|
139476
|
+
};
|
|
139477
|
+
|
|
139478
|
+
class ZonesPolysurfaceMouseControl extends Component {
|
|
139479
|
+
|
|
139480
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139481
|
+
super(zonesPlugin.viewer.scene);
|
|
139482
|
+
|
|
139483
|
+
this.zonesPlugin = zonesPlugin;
|
|
139484
|
+
this.pointerLens = cfg.pointerLens;
|
|
139485
|
+
this._action = null;
|
|
139486
|
+
}
|
|
139487
|
+
|
|
139488
|
+
get active() {
|
|
139489
|
+
return !! this._action;
|
|
139490
|
+
}
|
|
139491
|
+
|
|
139492
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139493
|
+
|
|
139494
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139495
|
+
const params = zoneAltitude;
|
|
139496
|
+
const param = (name, defaultValue) => {
|
|
139497
|
+
if (name in params) {
|
|
139498
|
+
return params[name];
|
|
139499
|
+
} else if (defaultValue !== undefined) {
|
|
139500
|
+
return defaultValue;
|
|
139501
|
+
} else {
|
|
139502
|
+
throw "config missing: " + name;
|
|
139503
|
+
}
|
|
139504
|
+
};
|
|
139505
|
+
|
|
139506
|
+
zoneAltitude = param("altitude");
|
|
139507
|
+
zoneHeight = param("height");
|
|
139508
|
+
zoneColor = param("color", "#008000");
|
|
139509
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139510
|
+
}
|
|
139511
|
+
|
|
139512
|
+
if (this._action) {
|
|
139513
|
+
return;
|
|
139514
|
+
}
|
|
139515
|
+
|
|
139516
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139517
|
+
const viewer = zonesPlugin.viewer;
|
|
139518
|
+
const scene = viewer.scene;
|
|
139519
|
+
const self = this;
|
|
139520
|
+
|
|
139521
|
+
const select3dPoint = mousePointSelector(
|
|
139522
|
+
viewer,
|
|
139523
|
+
function(origin, direction) {
|
|
139524
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139525
|
+
});
|
|
139526
|
+
|
|
139527
|
+
(function rec() {
|
|
139528
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139529
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139530
|
+
zone => {
|
|
139531
|
+
let reactivate = true;
|
|
139532
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139533
|
+
self.fire("zoneEnd", zone);
|
|
139534
|
+
if (reactivate)
|
|
139535
|
+
{
|
|
139536
|
+
rec();
|
|
139537
|
+
}
|
|
139538
|
+
});
|
|
139539
|
+
})();
|
|
139540
|
+
}
|
|
139541
|
+
|
|
139542
|
+
deactivate() {
|
|
139543
|
+
if (this._action)
|
|
139544
|
+
{
|
|
139545
|
+
this._action.deactivate();
|
|
139546
|
+
this._action = null;
|
|
139547
|
+
}
|
|
139548
|
+
}
|
|
139549
|
+
|
|
139550
|
+
destroy() {
|
|
139551
|
+
this.deactivate();
|
|
139552
|
+
super.destroy();
|
|
139553
|
+
}
|
|
139554
|
+
}
|
|
139555
|
+
|
|
139556
|
+
class ZonesPolysurfaceTouchControl extends Component {
|
|
139557
|
+
|
|
139558
|
+
constructor(zonesPlugin, cfg = {}) {
|
|
139559
|
+
super(zonesPlugin.viewer.scene);
|
|
139560
|
+
|
|
139561
|
+
this.zonesPlugin = zonesPlugin;
|
|
139562
|
+
this.pointerLens = cfg.pointerLens;
|
|
139563
|
+
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
139564
|
+
this._action = null;
|
|
139565
|
+
}
|
|
139566
|
+
|
|
139567
|
+
get active() {
|
|
139568
|
+
return !! this._action;
|
|
139569
|
+
}
|
|
139570
|
+
|
|
139571
|
+
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
139572
|
+
|
|
139573
|
+
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
139574
|
+
const params = zoneAltitude;
|
|
139575
|
+
const param = (name, defaultValue) => {
|
|
139576
|
+
if (name in params) {
|
|
139577
|
+
return params[name];
|
|
139578
|
+
} else if (defaultValue !== undefined) {
|
|
139579
|
+
return defaultValue;
|
|
139580
|
+
} else {
|
|
139581
|
+
throw "config missing: " + name;
|
|
139582
|
+
}
|
|
139583
|
+
};
|
|
139584
|
+
|
|
139585
|
+
zoneAltitude = param("altitude");
|
|
139586
|
+
zoneHeight = param("height");
|
|
139587
|
+
zoneColor = param("color", "#008000");
|
|
139588
|
+
zoneAlpha = param("alpha", 0.5);
|
|
139589
|
+
}
|
|
139590
|
+
|
|
139591
|
+
if (this._action) {
|
|
139592
|
+
return;
|
|
139593
|
+
}
|
|
139594
|
+
|
|
139595
|
+
const zonesPlugin = this.zonesPlugin;
|
|
139596
|
+
const viewer = zonesPlugin.viewer;
|
|
139597
|
+
const scene = viewer.scene;
|
|
139598
|
+
const self = this;
|
|
139599
|
+
|
|
139600
|
+
const select3dPoint = touchPointSelector(
|
|
139601
|
+
viewer,
|
|
139602
|
+
this.pointerCircle,
|
|
139603
|
+
function(origin, direction) {
|
|
139604
|
+
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
139605
|
+
});
|
|
139606
|
+
|
|
139607
|
+
(function rec() {
|
|
139608
|
+
self._action = startPolysurfaceZoneCreateUI(
|
|
139609
|
+
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
139610
|
+
zone => {
|
|
139611
|
+
let reactivate = true;
|
|
139612
|
+
self._action = { deactivate: () => { reactivate = false; } };
|
|
139613
|
+
self.fire("zoneEnd", zone);
|
|
139614
|
+
if (reactivate)
|
|
139615
|
+
{
|
|
139616
|
+
rec();
|
|
139617
|
+
}
|
|
139618
|
+
});
|
|
139619
|
+
})();
|
|
139620
|
+
}
|
|
139621
|
+
|
|
139622
|
+
deactivate() {
|
|
139623
|
+
if (this._action)
|
|
139624
|
+
{
|
|
139625
|
+
this._action.deactivate();
|
|
139626
|
+
this._action = null;
|
|
139627
|
+
}
|
|
139628
|
+
}
|
|
139629
|
+
|
|
139630
|
+
destroy() {
|
|
139631
|
+
this.deactivate();
|
|
139632
|
+
super.destroy();
|
|
139633
|
+
}
|
|
139634
|
+
}
|
|
139635
|
+
|
|
139636
|
+
class ZoneEditControl extends Component {
|
|
139637
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139638
|
+
super(zone.plugin.viewer.scene);
|
|
139639
|
+
const self = this;
|
|
139640
|
+
|
|
139641
|
+
const altitude = zone._geometry.altitude;
|
|
139642
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139643
|
+
const updatePointerLens = (pointerLens
|
|
139644
|
+
? function(canvasPos) {
|
|
139645
|
+
pointerLens.visible = !! canvasPos;
|
|
139646
|
+
if (canvasPos)
|
|
139647
|
+
{
|
|
139648
|
+
pointerLens.canvasPos = canvasPos;
|
|
139649
|
+
}
|
|
139650
|
+
}
|
|
139651
|
+
: () => { });
|
|
139652
|
+
|
|
139653
|
+
const dots = zone._geometry.planeCoordinates.map(planeCoord => {
|
|
139654
|
+
let initWorldPos, initPlaneCoord;
|
|
139655
|
+
const setPlaneCoord = function(coord) {
|
|
139656
|
+
planeCoord[0] = coord[0];
|
|
139657
|
+
planeCoord[1] = coord[1];
|
|
139658
|
+
try {
|
|
139659
|
+
zone._rebuildMesh();
|
|
139660
|
+
} catch (e) {
|
|
139661
|
+
if (zone._zoneMesh) {
|
|
139662
|
+
zone._zoneMesh.destroy();
|
|
139663
|
+
zone._zoneMesh = null;
|
|
139664
|
+
}
|
|
139665
|
+
}
|
|
139666
|
+
};
|
|
139667
|
+
|
|
139668
|
+
const dot = draggableDot3D(
|
|
139669
|
+
handleMouseEvents,
|
|
139670
|
+
handleTouchEvents,
|
|
139671
|
+
zone.plugin.viewer,
|
|
139672
|
+
math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
|
|
139673
|
+
zone._color,
|
|
139674
|
+
(orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
|
|
139675
|
+
() => {
|
|
139676
|
+
initWorldPos = dot.getWorldPos().slice();
|
|
139677
|
+
initPlaneCoord = planeCoord.slice();
|
|
139678
|
+
set_other_dots_active(false, dot);
|
|
139679
|
+
},
|
|
139680
|
+
(canvasPos, worldPos) => {
|
|
139681
|
+
updatePointerLens(canvasPos);
|
|
139682
|
+
setPlaneCoord([ worldPos[0], worldPos[2] ]);
|
|
139683
|
+
},
|
|
139684
|
+
() => {
|
|
139685
|
+
if (zone._zoneMesh)
|
|
139686
|
+
{
|
|
139687
|
+
self.fire("edited");
|
|
139688
|
+
}
|
|
139689
|
+
else
|
|
139690
|
+
{
|
|
139691
|
+
dot.setWorldPos(initWorldPos);
|
|
139692
|
+
setPlaneCoord(initPlaneCoord);
|
|
139693
|
+
}
|
|
139694
|
+
updatePointerLens(null);
|
|
139695
|
+
set_other_dots_active(true, dot);
|
|
139696
|
+
});
|
|
139697
|
+
return dot;
|
|
139698
|
+
});
|
|
139699
|
+
const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
|
|
139700
|
+
set_other_dots_active(true);
|
|
139701
|
+
|
|
139702
|
+
const cleanup = function() {
|
|
139703
|
+
dots.forEach(m => m.destroy());
|
|
139704
|
+
updatePointerLens(null);
|
|
139705
|
+
};
|
|
139706
|
+
|
|
139707
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139708
|
+
|
|
139709
|
+
this._deactivate = function() {
|
|
139710
|
+
zone.off("destroyed", destroyCb);
|
|
139711
|
+
cleanup();
|
|
139712
|
+
};
|
|
139713
|
+
}
|
|
139714
|
+
|
|
139715
|
+
deactivate() {
|
|
139716
|
+
this._deactivate();
|
|
139717
|
+
super.destroy();
|
|
139718
|
+
}
|
|
139719
|
+
}
|
|
139720
|
+
|
|
139721
|
+
class ZoneEditMouseControl extends ZoneEditControl {
|
|
139722
|
+
constructor(zone, cfg) {
|
|
139723
|
+
super(zone, cfg, true, false);
|
|
139724
|
+
}
|
|
139725
|
+
}
|
|
139726
|
+
|
|
139727
|
+
class ZoneEditTouchControl extends ZoneEditControl {
|
|
139728
|
+
constructor(zone, cfg) {
|
|
139729
|
+
super(zone, cfg, false, true);
|
|
139730
|
+
}
|
|
139731
|
+
}
|
|
139732
|
+
|
|
139733
|
+
|
|
139734
|
+
class ZoneTranslateControl extends Component {
|
|
139735
|
+
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
139736
|
+
const viewer = zone.plugin.viewer;
|
|
139737
|
+
const scene = viewer.scene;
|
|
139738
|
+
const canvas = scene.canvas.canvas;
|
|
139739
|
+
|
|
139740
|
+
super(scene);
|
|
139741
|
+
const self = this;
|
|
139742
|
+
|
|
139743
|
+
const altitude = zone._geometry.altitude;
|
|
139744
|
+
const pointerLens = cfg && cfg.pointerLens;
|
|
139745
|
+
const updatePointerLens = (pointerLens
|
|
139746
|
+
? function(canvasPos) {
|
|
139747
|
+
pointerLens.visible = !! canvasPos;
|
|
139748
|
+
if (canvasPos)
|
|
139749
|
+
{
|
|
139750
|
+
pointerLens.canvasPos = canvasPos;
|
|
139751
|
+
}
|
|
139752
|
+
}
|
|
139753
|
+
: () => { });
|
|
139754
|
+
|
|
139755
|
+
const ray2WorldPos = (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir);
|
|
139756
|
+
|
|
139757
|
+
const pickWorldPos = canvasPos => {
|
|
139758
|
+
const origin = math.vec3();
|
|
139759
|
+
const direction = math.vec3();
|
|
139760
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
|
|
139761
|
+
return ray2WorldPos(origin, direction);
|
|
139762
|
+
};
|
|
139763
|
+
|
|
139764
|
+
const copyCanvasPos = (event, vec2) => {
|
|
139765
|
+
vec2[0] = event.clientX;
|
|
139766
|
+
vec2[1] = event.clientY;
|
|
139767
|
+
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
139768
|
+
return vec2;
|
|
139769
|
+
};
|
|
139770
|
+
|
|
139771
|
+
const canvasHandle = function(type, cb) {
|
|
139772
|
+
const callback = event => {
|
|
139773
|
+
event.preventDefault();
|
|
139774
|
+
cb(event);
|
|
139775
|
+
};
|
|
139776
|
+
canvas.addEventListener(type, callback);
|
|
139777
|
+
return () => canvas.removeEventListener(type, callback);
|
|
139778
|
+
};
|
|
139779
|
+
|
|
139780
|
+
let cleanupCurrentDrag = () => { };
|
|
139781
|
+
|
|
139782
|
+
const startDrag = function(event, onMoveType, onEndType, matchesEvent) {
|
|
139783
|
+
const e = matchesEvent(event);
|
|
139784
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139785
|
+
const pickRecord = viewer.scene.pick({ canvasPos: canvasPos, includeEntities: [ zone._zoneMesh.id ] });
|
|
139786
|
+
const pickZone = pickRecord && pickRecord.entity && pickRecord.entity.zone;
|
|
139787
|
+
|
|
139788
|
+
if (pickZone === zone)
|
|
139789
|
+
{
|
|
139790
|
+
cleanupCurrentDrag();
|
|
139791
|
+
|
|
139792
|
+
canvas.style.cursor = "move";
|
|
139793
|
+
viewer.cameraControl.active = false;
|
|
139794
|
+
|
|
139795
|
+
const onChange = (function() {
|
|
139796
|
+
const initCoords = zone._geometry.planeCoordinates.map(c => c.slice());
|
|
139797
|
+
const initWorldPos = pickWorldPos(canvasPos);
|
|
139798
|
+
const initDragCoord = math.vec2([ initWorldPos[0], initWorldPos[2] ]);
|
|
139799
|
+
const dPos = math.vec2();
|
|
139800
|
+
|
|
139801
|
+
return function(canvasPos) {
|
|
139802
|
+
const worldPos = pickWorldPos(canvasPos);
|
|
139803
|
+
dPos[0] = worldPos[0];
|
|
139804
|
+
dPos[1] = worldPos[2];
|
|
139805
|
+
math.subVec2(initDragCoord, dPos, dPos);
|
|
139806
|
+
|
|
139807
|
+
zone._geometry.planeCoordinates.forEach((planeCoord, idx) => {
|
|
139808
|
+
math.subVec2(initCoords[idx], dPos, planeCoord);
|
|
139809
|
+
});
|
|
139810
|
+
|
|
139811
|
+
try {
|
|
139812
|
+
zone._rebuildMesh();
|
|
139813
|
+
} catch (e) {
|
|
139814
|
+
if (zone._zoneMesh) {
|
|
139815
|
+
zone._zoneMesh.destroy();
|
|
139816
|
+
zone._zoneMesh = null;
|
|
139817
|
+
}
|
|
139818
|
+
}
|
|
139819
|
+
};
|
|
139820
|
+
})();
|
|
139821
|
+
|
|
139822
|
+
const cleanupMove = canvasHandle(
|
|
139823
|
+
onMoveType,
|
|
139824
|
+
function(event) {
|
|
139825
|
+
const e = matchesEvent(event);
|
|
139826
|
+
if (e)
|
|
139827
|
+
{
|
|
139828
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139829
|
+
onChange(canvasPos);
|
|
139830
|
+
updatePointerLens(canvasPos);
|
|
139831
|
+
}
|
|
139832
|
+
});
|
|
139833
|
+
|
|
139834
|
+
const cleanupEnd = canvasHandle(
|
|
139835
|
+
onEndType,
|
|
139836
|
+
function(event) {
|
|
139837
|
+
const e = matchesEvent(event);
|
|
139838
|
+
if (e)
|
|
139839
|
+
{
|
|
139840
|
+
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
139841
|
+
onChange(canvasPos);
|
|
139842
|
+
updatePointerLens(null);
|
|
139843
|
+
cleanupCurrentDrag();
|
|
139844
|
+
self.fire("translated");
|
|
139845
|
+
}
|
|
139846
|
+
});
|
|
139847
|
+
|
|
139848
|
+
cleanupCurrentDrag = function() {
|
|
139849
|
+
cleanupCurrentDrag = () => { };
|
|
139850
|
+
canvas.style.cursor = "default";
|
|
139851
|
+
viewer.cameraControl.active = true;
|
|
139852
|
+
cleanupMove();
|
|
139853
|
+
cleanupEnd();
|
|
139854
|
+
};
|
|
139855
|
+
}
|
|
139856
|
+
};
|
|
139857
|
+
|
|
139858
|
+
const startDragCbs = [ ];
|
|
139859
|
+
|
|
139860
|
+
if (handleMouseEvents) {
|
|
139861
|
+
startDragCbs.push(
|
|
139862
|
+
canvasHandle("mousedown", event => {
|
|
139863
|
+
if (event.which === 1) {
|
|
139864
|
+
startDrag(
|
|
139865
|
+
event,
|
|
139866
|
+
"mousemove",
|
|
139867
|
+
"mouseup",
|
|
139868
|
+
event => (event.which === 1) && event);
|
|
139869
|
+
}
|
|
139870
|
+
}));
|
|
139871
|
+
}
|
|
139872
|
+
|
|
139873
|
+
if (handleTouchEvents) {
|
|
139874
|
+
startDragCbs.push(
|
|
139875
|
+
canvasHandle("touchstart", event => {
|
|
139876
|
+
if (event.touches.length === 1) {
|
|
139877
|
+
const touchStartId = event.touches[0].identifier;
|
|
139878
|
+
startDrag(
|
|
139879
|
+
event,
|
|
139880
|
+
"touchmove",
|
|
139881
|
+
"touchend",
|
|
139882
|
+
event => [...event.changedTouches].find(e => e.identifier === touchStartId));
|
|
139883
|
+
}
|
|
139884
|
+
}));
|
|
139885
|
+
}
|
|
139886
|
+
|
|
139887
|
+
const cleanup = function() {
|
|
139888
|
+
cleanupCurrentDrag();
|
|
139889
|
+
startDragCbs.forEach(cb => cb());
|
|
139890
|
+
updatePointerLens(null);
|
|
139891
|
+
};
|
|
139892
|
+
|
|
139893
|
+
const destroyCb = zone.on("destroyed", cleanup);
|
|
139894
|
+
|
|
139895
|
+
this._deactivate = function() {
|
|
139896
|
+
zone.off("destroyed", destroyCb);
|
|
139897
|
+
cleanup();
|
|
139898
|
+
};
|
|
139899
|
+
}
|
|
139900
|
+
|
|
139901
|
+
deactivate() {
|
|
139902
|
+
this._deactivate();
|
|
139903
|
+
super.destroy();
|
|
139904
|
+
}
|
|
139905
|
+
}
|
|
139906
|
+
|
|
139907
|
+
class ZoneTranslateMouseControl extends ZoneTranslateControl {
|
|
139908
|
+
constructor(zone, cfg) {
|
|
139909
|
+
super(zone, cfg, true, false);
|
|
139910
|
+
}
|
|
139911
|
+
}
|
|
139912
|
+
|
|
139913
|
+
class ZoneTranslateTouchControl extends ZoneTranslateControl {
|
|
139914
|
+
constructor(zone, cfg) {
|
|
139915
|
+
super(zone, cfg, false, true);
|
|
139916
|
+
}
|
|
139917
|
+
}
|
|
139918
|
+
|
|
137700
139919
|
exports.AlphaFormat = AlphaFormat;
|
|
137701
139920
|
exports.AmbientLight = AmbientLight;
|
|
137702
139921
|
exports.AngleMeasurementsControl = AngleMeasurementsControl;
|
|
@@ -137856,6 +140075,17 @@ exports.WorkerPool = WorkerPool$1;
|
|
|
137856
140075
|
exports.XKTDefaultDataSource = XKTDefaultDataSource;
|
|
137857
140076
|
exports.XKTLoaderPlugin = XKTLoaderPlugin;
|
|
137858
140077
|
exports.XML3DLoaderPlugin = XML3DLoaderPlugin;
|
|
140078
|
+
exports.ZoneEditControl = ZoneEditControl;
|
|
140079
|
+
exports.ZoneEditMouseControl = ZoneEditMouseControl;
|
|
140080
|
+
exports.ZoneEditTouchControl = ZoneEditTouchControl;
|
|
140081
|
+
exports.ZoneTranslateControl = ZoneTranslateControl;
|
|
140082
|
+
exports.ZoneTranslateMouseControl = ZoneTranslateMouseControl;
|
|
140083
|
+
exports.ZoneTranslateTouchControl = ZoneTranslateTouchControl;
|
|
140084
|
+
exports.ZonesMouseControl = ZonesMouseControl;
|
|
140085
|
+
exports.ZonesPlugin = ZonesPlugin;
|
|
140086
|
+
exports.ZonesPolysurfaceMouseControl = ZonesPolysurfaceMouseControl;
|
|
140087
|
+
exports.ZonesPolysurfaceTouchControl = ZonesPolysurfaceTouchControl;
|
|
140088
|
+
exports.ZonesTouchControl = ZonesTouchControl;
|
|
137859
140089
|
exports.buildBoxGeometry = buildBoxGeometry;
|
|
137860
140090
|
exports.buildBoxLinesGeometry = buildBoxLinesGeometry;
|
|
137861
140091
|
exports.buildBoxLinesGeometryFromAABB = buildBoxLinesGeometryFromAABB;
|