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