@xeokit/xeokit-sdk 2.6.17 → 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.
Files changed (37) hide show
  1. package/dist/xeokit-sdk.cjs.js +2345 -117
  2. package/dist/xeokit-sdk.es.js +2335 -118
  3. package/dist/xeokit-sdk.es5.js +558 -418
  4. package/dist/xeokit-sdk.min.cjs.js +4 -4
  5. package/dist/xeokit-sdk.min.es.js +5 -5
  6. package/dist/xeokit-sdk.min.es5.js +4 -4
  7. package/package.json +2 -2
  8. package/src/extras/PointerLens/PointerLens.js +2 -2
  9. package/src/plugins/AnnotationsPlugin/Annotation.js +1 -0
  10. package/src/plugins/CityJSONLoaderPlugin/CityJSONDefaultDataSource.js +15 -2
  11. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +1 -1
  12. package/src/plugins/DotBIMLoaderPlugin/DotBIMDefaultDataSource.js +15 -2
  13. package/src/plugins/GLTFLoaderPlugin/GLTFDefaultDataSource.js +18 -5
  14. package/src/plugins/LASLoaderPlugin/LASDefaultDataSource.js +15 -1
  15. package/src/plugins/STLLoaderPlugin/STLDefaultDataSource.js +17 -0
  16. package/src/plugins/WebIFCLoaderPlugin/WebIFCDefaultDataSource.js +16 -1
  17. package/src/plugins/XKTLoaderPlugin/XKTDefaultDataSource.js +18 -4
  18. package/src/plugins/ZonesPlugin/index.js +2046 -0
  19. package/src/plugins/index.js +2 -1
  20. package/src/plugins/lib/html/Dot.js +19 -1
  21. package/src/viewer/Viewer.js +3 -1
  22. package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +9 -0
  23. package/src/viewer/scene/geometry/builders/buildLineGeometry.js +267 -0
  24. package/src/viewer/scene/input/Input.js +41 -0
  25. package/src/viewer/scene/marker/Marker.js +1 -1
  26. package/src/viewer/scene/mesh/Mesh.js +5 -0
  27. package/src/viewer/scene/model/SceneModel.js +7 -1
  28. package/src/viewer/scene/scene/Scene.js +30 -4
  29. package/src/viewer/scene/sectionPlane/SectionPlane.js +3 -7
  30. package/src/viewer/scene/webgl/Renderer.js +84 -79
  31. package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
  32. package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +8 -4
  33. package/types/viewer/Viewer.d.ts +2 -0
  34. package/types/viewer/scene/geometry/builders/buildLineGeometry.d.ts +22 -0
  35. package/types/viewer/scene/geometry/builders/buildPolylineGeometry.d.ts +2 -2
  36. package/types/viewer/scene/scene/Scene.d.ts +11 -0
  37. package/dist/web-ifc.wasm +0 -0
@@ -1118,8 +1118,8 @@ class PointerLens {
1118
1118
  );
1119
1119
 
1120
1120
  const centerLensCanvas = [
1121
- (lensRect.left + lensRect.right) / 2,
1122
- (lensRect.top + lensRect.bottom) / 2
1121
+ (lensRect.left + lensRect.right) / 2 - canvasRect.left,
1122
+ (lensRect.top + lensRect.bottom) / 2 - canvasRect.top
1123
1123
  ];
1124
1124
 
1125
1125
  if (this._snappedCanvasPos) {
@@ -10759,7 +10759,7 @@ class Marker extends Component {
10759
10759
  this.scene.camera.off(this._onCameraProjMatrix);
10760
10760
  if (this._entity) {
10761
10761
  if (this._onEntityDestroyed !== null) {
10762
- this._entity.off(this._onEntityDestroyed);
10762
+ this._entity.model.off(this._onEntityDestroyed);
10763
10763
  }
10764
10764
  if (this._onEntityModelDestroyed !== null) {
10765
10765
  this._entity.model.off(this._onEntityModelDestroyed);
@@ -11159,7 +11159,25 @@ class Dot {
11159
11159
  }
11160
11160
 
11161
11161
  }
11162
-
11162
+
11163
+ if (cfg.onTouchstart) {
11164
+ dotClickable.addEventListener('touchstart', (event) => {
11165
+ cfg.onTouchstart(event, this);
11166
+ });
11167
+ }
11168
+
11169
+ if (cfg.onTouchmove) {
11170
+ dotClickable.addEventListener('touchmove', (event) => {
11171
+ cfg.onTouchmove(event, this);
11172
+ });
11173
+ }
11174
+
11175
+ if (cfg.onTouchend) {
11176
+ dotClickable.addEventListener('touchend', (event) => {
11177
+ cfg.onTouchend(event, this);
11178
+ });
11179
+ }
11180
+
11163
11181
  this.setPos(cfg.x || 0, cfg.y || 0);
11164
11182
  this.setFillColor(cfg.fillColor);
11165
11183
  this.setBorderColor(cfg.borderColor);
@@ -14427,6 +14445,7 @@ class Annotation extends Marker {
14427
14445
  if (this._marker) {
14428
14446
  if (!this._markerExternal) {
14429
14447
  this._marker.parentNode.removeChild(this._marker);
14448
+ this._marker = null;
14430
14449
  } else {
14431
14450
  this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
14432
14451
  this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
@@ -17055,7 +17074,7 @@ class OcclusionLayer {
17055
17074
  _buildVBOs() {
17056
17075
  if (this.positionsBuf) {
17057
17076
  if (this.lenPositionsBuf === this.positions.length) { // Just updating buffer elements, don't need to reallocate
17058
- this.positionsBuf.setData(this.positions); // Indices don't need updating
17077
+ this.positionsBuf.setData(new Float32Array(this.positions)); // Indices don't need updating
17059
17078
  return;
17060
17079
  }
17061
17080
  this.positionsBuf.destroy();
@@ -17144,7 +17163,6 @@ class OcclusionLayer {
17144
17163
 
17145
17164
  const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]);
17146
17165
  const POINT_SIZE = 20;
17147
- const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces
17148
17166
 
17149
17167
  const tempVec3a$J = math.vec3();
17150
17168
 
@@ -17225,7 +17243,7 @@ class OcclusionTester {
17225
17243
  let newOcclusionLayer = this._occlusionLayers[originHash];
17226
17244
  if (!newOcclusionLayer) {
17227
17245
  newOcclusionLayer = new OcclusionLayer(this._scene, marker.origin);
17228
- this._occlusionLayers[originHash] = occlusionLayer;
17246
+ this._occlusionLayers[originHash] = newOcclusionLayer;
17229
17247
  this._occlusionLayersListDirty = true;
17230
17248
  }
17231
17249
  newOcclusionLayer.addMarker(marker);
@@ -17355,7 +17373,9 @@ class OcclusionTester {
17355
17373
  if (scene.logarithmicDepthBufferEnabled) {
17356
17374
  src.push("vFragDepth = 1.0 + clipPos.w;");
17357
17375
  } else {
17358
- src.push("clipPos.z += " + MARKER_SPRITE_CLIPZ_OFFSET + ";");
17376
+ if (scene.markerZOffset < 0.000) {
17377
+ src.push("clipPos.z += " + scene.markerZOffset + ";");
17378
+ }
17359
17379
  }
17360
17380
  src.push(" gl_Position = clipPos;");
17361
17381
  src.push("}");
@@ -17469,7 +17489,10 @@ class OcclusionTester {
17469
17489
  continue;
17470
17490
  }
17471
17491
 
17472
- const origin = occlusionLayer.origin;
17492
+ // The `origin` has been changed from `occlusionLayer.origin` to `[ 0, 0, 0 ]`
17493
+ // because OcclusionLayer markers' transformation is being applied through the
17494
+ // OcclusionLayer::positions array. See XEOK-33
17495
+ const origin = [ 0, 0, 0 ];
17473
17496
 
17474
17497
  gl.uniformMatrix4fv(this._uViewMatrix, false, createRTCViewMat(camera.viewMatrix, origin));
17475
17498
 
@@ -18708,6 +18731,9 @@ const Renderer$1 = function (scene, options) {
18708
18731
  let drawableTypeInfo = {};
18709
18732
  let drawables = {};
18710
18733
 
18734
+ let postSortDrawableList = [];
18735
+ let postCullDrawableList = [];
18736
+
18711
18737
  let drawableListDirty = true;
18712
18738
  let stateSortDirty = true;
18713
18739
  let imageDirty = true;
@@ -18933,28 +18959,38 @@ const Renderer$1 = function (scene, options) {
18933
18959
  const drawableInfo = drawableTypeInfo[type];
18934
18960
  if (drawableInfo.isStateSortable) {
18935
18961
  drawableInfo.drawableListPreCull.sort(drawableInfo.stateSortCompare);
18962
+
18963
+ drawableInfo.drawableList = drawableInfo.drawableListPreCull;
18936
18964
  }
18937
18965
  }
18938
18966
  }
18939
- }
18940
-
18941
- function cullDrawableList() {
18967
+ let lenDrawableList = 0;
18942
18968
  for (let type in drawableTypeInfo) {
18943
18969
  if (drawableTypeInfo.hasOwnProperty(type)) {
18944
18970
  const drawableInfo = drawableTypeInfo[type];
18945
18971
  const drawableListPreCull = drawableInfo.drawableListPreCull;
18946
- const drawableList = drawableInfo.drawableList;
18947
- let lenDrawableList = 0;
18948
18972
  for (let i = 0, len = drawableListPreCull.length; i < len; i++) {
18949
18973
  const drawable = drawableListPreCull[i];
18950
- drawable.rebuildRenderFlags();
18951
- if (!drawable.renderFlags.culled) {
18952
- drawableList[lenDrawableList++] = drawable;
18953
- }
18974
+ postSortDrawableList[lenDrawableList++] = drawable;
18954
18975
  }
18955
- drawableList.length = lenDrawableList;
18956
18976
  }
18957
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;
18958
18994
  }
18959
18995
 
18960
18996
  function draw(params) {
@@ -19187,7 +19223,6 @@ const Renderer$1 = function (scene, options) {
19187
19223
  }
19188
19224
 
19189
19225
  let i;
19190
- let len;
19191
19226
  let drawable;
19192
19227
 
19193
19228
  const startTime = Date.now();
@@ -19220,93 +19255,85 @@ const Renderer$1 = function (scene, options) {
19220
19255
  // Render normal opaque solids, defer others to bins to render after
19221
19256
  //------------------------------------------------------------------------------------------------------
19222
19257
 
19223
- for (let type in drawableTypeInfo) {
19224
- if (drawableTypeInfo.hasOwnProperty(type)) {
19225
-
19226
- const drawableInfo = drawableTypeInfo[type];
19227
- const drawableList = drawableInfo.drawableList;
19228
-
19229
- for (i = 0, len = drawableList.length; i < len; i++) {
19258
+ for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
19230
19259
 
19231
- drawable = drawableList[i];
19260
+ drawable = postCullDrawableList[i];
19232
19261
 
19233
- if (drawable.culled === true || drawable.visible === false) {
19234
- continue;
19235
- }
19262
+ if (drawable.culled === true || drawable.visible === false) {
19263
+ continue;
19264
+ }
19236
19265
 
19237
- const renderFlags = drawable.renderFlags;
19266
+ const renderFlags = drawable.renderFlags;
19238
19267
 
19239
- if (renderFlags.colorOpaque) {
19240
- if (saoEnabled && saoPossible && drawable.saoEnabled) {
19241
- normalDrawSAOBin[normalDrawSAOBinLen++] = drawable;
19242
- } else {
19243
- drawable.drawColorOpaque(frameCtx);
19244
- }
19245
- }
19268
+ if (renderFlags.colorOpaque) {
19269
+ if (saoEnabled && saoPossible && drawable.saoEnabled) {
19270
+ normalDrawSAOBin[normalDrawSAOBinLen++] = drawable;
19271
+ } else {
19272
+ drawable.drawColorOpaque(frameCtx);
19273
+ }
19274
+ }
19246
19275
 
19247
- if (transparentEnabled) {
19248
- if (renderFlags.colorTransparent) {
19249
- normalFillTransparentBin[normalFillTransparentBinLen++] = drawable;
19250
- }
19251
- }
19276
+ if (transparentEnabled) {
19277
+ if (renderFlags.colorTransparent) {
19278
+ normalFillTransparentBin[normalFillTransparentBinLen++] = drawable;
19279
+ }
19280
+ }
19252
19281
 
19253
- if (renderFlags.xrayedSilhouetteTransparent) {
19254
- xrayedFillTransparentBin[xrayedFillTransparentBinLen++] = drawable;
19255
- }
19282
+ if (renderFlags.xrayedSilhouetteTransparent) {
19283
+ xrayedFillTransparentBin[xrayedFillTransparentBinLen++] = drawable;
19284
+ }
19256
19285
 
19257
- if (renderFlags.xrayedSilhouetteOpaque) {
19258
- xrayedFillOpaqueBin[xrayedFillOpaqueBinLen++] = drawable;
19259
- }
19286
+ if (renderFlags.xrayedSilhouetteOpaque) {
19287
+ xrayedFillOpaqueBin[xrayedFillOpaqueBinLen++] = drawable;
19288
+ }
19260
19289
 
19261
- if (renderFlags.highlightedSilhouetteTransparent) {
19262
- highlightedFillTransparentBin[highlightedFillTransparentBinLen++] = drawable;
19263
- }
19290
+ if (renderFlags.highlightedSilhouetteTransparent) {
19291
+ highlightedFillTransparentBin[highlightedFillTransparentBinLen++] = drawable;
19292
+ }
19264
19293
 
19265
- if (renderFlags.highlightedSilhouetteOpaque) {
19266
- highlightedFillOpaqueBin[highlightedFillOpaqueBinLen++] = drawable;
19267
- }
19294
+ if (renderFlags.highlightedSilhouetteOpaque) {
19295
+ highlightedFillOpaqueBin[highlightedFillOpaqueBinLen++] = drawable;
19296
+ }
19268
19297
 
19269
- if (renderFlags.selectedSilhouetteTransparent) {
19270
- selectedFillTransparentBin[selectedFillTransparentBinLen++] = drawable;
19271
- }
19298
+ if (renderFlags.selectedSilhouetteTransparent) {
19299
+ selectedFillTransparentBin[selectedFillTransparentBinLen++] = drawable;
19300
+ }
19272
19301
 
19273
- if (renderFlags.selectedSilhouetteOpaque) {
19274
- selectedFillOpaqueBin[selectedFillOpaqueBinLen++] = drawable;
19275
- }
19302
+ if (renderFlags.selectedSilhouetteOpaque) {
19303
+ selectedFillOpaqueBin[selectedFillOpaqueBinLen++] = drawable;
19304
+ }
19276
19305
 
19277
- if (drawable.edges && edgesEnabled) {
19278
- if (renderFlags.edgesOpaque) {
19279
- normalEdgesOpaqueBin[normalEdgesOpaqueBinLen++] = drawable;
19280
- }
19306
+ if (drawable.edges && edgesEnabled) {
19307
+ if (renderFlags.edgesOpaque) {
19308
+ normalEdgesOpaqueBin[normalEdgesOpaqueBinLen++] = drawable;
19309
+ }
19281
19310
 
19282
- if (renderFlags.edgesTransparent) {
19283
- normalEdgesTransparentBin[normalEdgesTransparentBinLen++] = drawable;
19284
- }
19311
+ if (renderFlags.edgesTransparent) {
19312
+ normalEdgesTransparentBin[normalEdgesTransparentBinLen++] = drawable;
19313
+ }
19285
19314
 
19286
- if (renderFlags.selectedEdgesTransparent) {
19287
- selectedEdgesTransparentBin[selectedEdgesTransparentBinLen++] = drawable;
19288
- }
19315
+ if (renderFlags.selectedEdgesTransparent) {
19316
+ selectedEdgesTransparentBin[selectedEdgesTransparentBinLen++] = drawable;
19317
+ }
19289
19318
 
19290
- if (renderFlags.selectedEdgesOpaque) {
19291
- selectedEdgesOpaqueBin[selectedEdgesOpaqueBinLen++] = drawable;
19292
- }
19319
+ if (renderFlags.selectedEdgesOpaque) {
19320
+ selectedEdgesOpaqueBin[selectedEdgesOpaqueBinLen++] = drawable;
19321
+ }
19293
19322
 
19294
- if (renderFlags.xrayedEdgesTransparent) {
19295
- xrayEdgesTransparentBin[xrayEdgesTransparentBinLen++] = drawable;
19296
- }
19323
+ if (renderFlags.xrayedEdgesTransparent) {
19324
+ xrayEdgesTransparentBin[xrayEdgesTransparentBinLen++] = drawable;
19325
+ }
19297
19326
 
19298
- if (renderFlags.xrayedEdgesOpaque) {
19299
- xrayEdgesOpaqueBin[xrayEdgesOpaqueBinLen++] = drawable;
19300
- }
19327
+ if (renderFlags.xrayedEdgesOpaque) {
19328
+ xrayEdgesOpaqueBin[xrayEdgesOpaqueBinLen++] = drawable;
19329
+ }
19301
19330
 
19302
- if (renderFlags.highlightedEdgesTransparent) {
19303
- highlightedEdgesTransparentBin[highlightedEdgesTransparentBinLen++] = drawable;
19304
- }
19331
+ if (renderFlags.highlightedEdgesTransparent) {
19332
+ highlightedEdgesTransparentBin[highlightedEdgesTransparentBinLen++] = drawable;
19333
+ }
19305
19334
 
19306
- if (renderFlags.highlightedEdgesOpaque) {
19307
- highlightedEdgesOpaqueBin[highlightedEdgesOpaqueBinLen++] = drawable;
19308
- }
19309
- }
19335
+ if (renderFlags.highlightedEdgesOpaque) {
19336
+ highlightedEdgesOpaqueBin[highlightedEdgesOpaqueBinLen++] = drawable;
19310
19337
  }
19311
19338
  }
19312
19339
  }
@@ -19619,7 +19646,7 @@ const Renderer$1 = function (scene, options) {
19619
19646
  math.cross3Vec3(worldRayDir, randomVec3, up);
19620
19647
 
19621
19648
  pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
19622
- // pickProjMatrix = scene.camera.projMatrix;
19649
+ // pickProjMatrix = scene.camera.projMatrix;
19623
19650
  pickProjMatrix = scene.camera.ortho.matrix;
19624
19651
 
19625
19652
  pickResult.origin = worldRayOrigin;
@@ -21606,6 +21633,14 @@ class Input extends Component {
21606
21633
  }
21607
21634
  });
21608
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
+
21609
21644
  const tickifiedMouseWheelFn = this.scene.tickify(
21610
21645
  (delta) => { this.fire("mousewheel", delta, true); }
21611
21646
  );
@@ -21639,6 +21674,24 @@ class Input extends Component {
21639
21674
  });
21640
21675
  }
21641
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
+
21642
21695
  this._eventsBound = true;
21643
21696
  }
21644
21697
 
@@ -21655,7 +21708,10 @@ class Input extends Component {
21655
21708
  document.removeEventListener("click", this._clickListener);
21656
21709
  document.removeEventListener("dblclick", this._dblClickListener);
21657
21710
  this.element.removeEventListener("mousemove", this._mouseMoveListener);
21711
+ this.element.removeEventListener("contextmenu", this._contextmenuListener);
21658
21712
  this.element.removeEventListener("wheel", this._mouseWheelListener);
21713
+ this.element.removeEventListener("touchstart", this._touchstartListener);
21714
+ this.element.removeEventListener("touchend", this._touchendListener);
21659
21715
  if (window.OrientationChangeEvent) {
21660
21716
  window.removeEventListener('orientationchange', this._orientationchangedListener);
21661
21717
  }
@@ -21668,6 +21724,18 @@ class Input extends Component {
21668
21724
  this._eventsBound = false;
21669
21725
  }
21670
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
+
21671
21739
  _getMouseCanvasPos(event) {
21672
21740
  if (!event) {
21673
21741
  event = window.event;
@@ -30152,6 +30220,7 @@ class Scene extends Component {
30152
30220
  this._pbrEnabled = !!cfg.pbrEnabled;
30153
30221
  this._colorTextureEnabled = (cfg.colorTextureEnabled !== false);
30154
30222
  this._dtxEnabled = !!cfg.dtxEnabled;
30223
+ this._markerZOffset = cfg.markerZOffset;
30155
30224
 
30156
30225
  // Register Scene on xeokit
30157
30226
  // Do this BEFORE we add components below
@@ -30672,6 +30741,22 @@ class Scene extends Component {
30672
30741
  return this._colorTextureEnabled;
30673
30742
  }
30674
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
+
30675
30760
  /**
30676
30761
  * Performs an occlusion test on all {@link Marker}s in this {@link Scene}.
30677
30762
  *
@@ -31516,9 +31601,9 @@ class Scene extends Component {
31516
31601
  * @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
31517
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.
31518
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.
31519
- * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
31520
- * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
31521
- * @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.
31522
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.
31523
31608
  * @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
31524
31609
  */
@@ -31529,6 +31614,11 @@ class Scene extends Component {
31529
31614
  return null;
31530
31615
  }
31531
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
+
31532
31622
  params = params || {};
31533
31623
 
31534
31624
  params.pickSurface = params.pickSurface || params.rayPick; // Backwards compatibility
@@ -31576,7 +31666,7 @@ class Scene extends Component {
31576
31666
 
31577
31667
  /**
31578
31668
  * @param {Object} params Picking parameters.
31579
- * @param {Number[]} [params.canvasPos] Canvas-space coordinates. When ray-picking, this will override the **origin** and ** direction** parameters and will cause the ray to be fired through the canvas at this position, directly along the negative View-space Z-axis.
31669
+ * @param {Number[]} params.canvasPos Canvas-space coordinates.
31580
31670
  * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
31581
31671
  * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
31582
31672
  * @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
@@ -31587,6 +31677,10 @@ class Scene extends Component {
31587
31677
  this._warnSnapPickDeprecated = true;
31588
31678
  this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead");
31589
31679
  }
31680
+ if (!params.canvasPos) {
31681
+ this.error("Scene.snapPick() canvasPos parameter expected");
31682
+ return;
31683
+ }
31590
31684
  return this._renderer.snapPick(
31591
31685
  params.canvasPos,
31592
31686
  params.snapRadius || 30,
@@ -37649,11 +37743,16 @@ class Mesh extends Component {
37649
37743
  * @param {EmphasisMaterial} [cfg.highlightMaterial] {@link EmphasisMaterial} to define the xrayed appearance for this Mesh. Inherits {@link Scene#highlightMaterial} by default.
37650
37744
  * @param {EmphasisMaterial} [cfg.selectedMaterial] {@link EmphasisMaterial} to define the selected appearance for this Mesh. Inherits {@link Scene#selectedMaterial} by default.
37651
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.
37652
37749
  */
37653
37750
  constructor(owner, cfg = {}) {
37654
37751
 
37655
37752
  super(owner, cfg);
37656
37753
 
37754
+ this.renderOrder = cfg.renderOrder || 0;
37755
+
37657
37756
  /**
37658
37757
  * ID of the corresponding object within the originating system, if any.
37659
37758
  *
@@ -42178,6 +42277,7 @@ class SectionPlane extends Component {
42178
42277
  this._state.active = value !== false;
42179
42278
  this.glRedraw();
42180
42279
  this.fire("active", this._state.active);
42280
+ this.scene.fire("sectionPlaneUpdated", this);
42181
42281
  }
42182
42282
 
42183
42283
  /**
@@ -42258,13 +42358,8 @@ class SectionPlane extends Component {
42258
42358
  * Inverts the direction of {@link SectionPlane#dir}.
42259
42359
  */
42260
42360
  flipDir() {
42261
- const dir = this._state.dir;
42262
- dir[0] *= -1.0;
42263
- dir[1] *= -1.0;
42264
- dir[2] *= -1.0;
42265
- this._state.dist = (-math.dotVec3(this._state.pos, this._state.dir));
42266
- this.fire("dir", this._state.dir);
42267
- this.glRedraw();
42361
+ math.mulVec3Scalar(this._state.dir, -1.0, this._state.dir);
42362
+ this.dir = this._state.dir;
42268
42363
  }
42269
42364
 
42270
42365
  /**
@@ -82246,11 +82341,16 @@ class SceneModel extends Component {
82246
82341
  * represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
82247
82342
  * to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
82248
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.
82249
82347
  */
82250
82348
  constructor(owner, cfg = {}) {
82251
82349
 
82252
82350
  super(owner, cfg);
82253
82351
 
82352
+ this.renderOrder = cfg.renderOrder || 0;
82353
+
82254
82354
  this._dtxEnabled = this.scene.dtxEnabled && (cfg.dtxEnabled !== false);
82255
82355
 
82256
82356
  this._enableVertexWelding = false; // Not needed for most objects, and very expensive, so disabled
@@ -84317,6 +84417,7 @@ class SceneModel extends Component {
84317
84417
  _getVBOBatchingLayer(cfg) {
84318
84418
  const model = this;
84319
84419
  const origin = cfg.origin;
84420
+ cfg.renderLayer || 0;
84320
84421
  const positionsDecodeHash = cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary ?
84321
84422
  this._createHashStringFromMatrix(cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary)
84322
84423
  : "-";
@@ -84803,7 +84904,7 @@ class SceneModel extends Component {
84803
84904
  // -------------- RENDERING ---------------------------------------------------------------------------------------
84804
84905
 
84805
84906
  /** @private */
84806
- drawColorOpaque(frameCtx) {
84907
+ drawColorOpaque(frameCtx, layerList) {
84807
84908
  const renderFlags = this.renderFlags;
84808
84909
  for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) {
84809
84910
  const layerIndex = renderFlags.visibleLayers[i];
@@ -86597,7 +86698,7 @@ class DistanceMeasurement extends Component {
86597
86698
 
86598
86699
  if (this._wpDirty) {
86599
86700
 
86600
- this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 1);
86701
+ this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0);
86601
86702
  if(this._measurementOrientation === 'Vertical' && this.useRotationAdjustment){
86602
86703
  this._wp[0] = this._originWorld[0];
86603
86704
  this._wp[1] = this._originWorld[1];
@@ -89724,7 +89825,20 @@ class FastNavPlugin extends Plugin {
89724
89825
  */
89725
89826
  class GLTFDefaultDataSource {
89726
89827
 
89727
- 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
+ }
89728
89842
  }
89729
89843
 
89730
89844
  /**
@@ -89735,7 +89849,7 @@ class GLTFDefaultDataSource {
89735
89849
  * @param {Function} error Fired on error while loading the metamodel JSON asset.
89736
89850
  */
89737
89851
  getMetaModel(metaModelSrc, ok, error) {
89738
- utils.loadJSON(metaModelSrc,
89852
+ utils.loadJSON(this._cacheBusterURL(metaModelSrc),
89739
89853
  (json) => {
89740
89854
  ok(json);
89741
89855
  },
@@ -89752,7 +89866,7 @@ class GLTFDefaultDataSource {
89752
89866
  * @param {Function} error Fired on error while loading the glTF JSON asset.
89753
89867
  */
89754
89868
  getGLTF(glTFSrc, ok, error) {
89755
- utils.loadArraybuffer(glTFSrc,
89869
+ utils.loadArraybuffer(this._cacheBusterURL(glTFSrc),
89756
89870
  (gltf) => {
89757
89871
  ok(gltf);
89758
89872
  },
@@ -89769,7 +89883,7 @@ class GLTFDefaultDataSource {
89769
89883
  * @param {Function} error Fired on error while loading the .glb asset.
89770
89884
  */
89771
89885
  getGLB(glbSrc, ok, error) {
89772
- utils.loadArraybuffer(glbSrc,
89886
+ utils.loadArraybuffer(this._cacheBusterURL(glbSrc),
89773
89887
  (arraybuffer) => {
89774
89888
  ok(arraybuffer);
89775
89889
  },
@@ -89790,7 +89904,7 @@ class GLTFDefaultDataSource {
89790
89904
  * @param {Function} error Fired on error while loading the glTF binary asset.
89791
89905
  */
89792
89906
  getArrayBuffer(glTFSrc, binarySrc, ok, error) {
89793
- loadArraybuffer(glTFSrc, binarySrc,
89907
+ loadArraybuffer(this._cacheBusterURL(glTFSrc), binarySrc,
89794
89908
  (arrayBuffer) => {
89795
89909
  ok(arrayBuffer);
89796
89910
  },
@@ -96106,6 +96220,15 @@ class MousePickHandler {
96106
96220
  return;
96107
96221
  }
96108
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
+
96109
96232
  const hoverSubs = cameraControl.hasSubs("hover");
96110
96233
  const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
96111
96234
  const hoverOutSubs = cameraControl.hasSubs("hoverOut");
@@ -108198,6 +108321,7 @@ class Viewer {
108198
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
108199
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)
108200
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.
108201
108325
  * @param {number} [cfg.numCachedSectionPlanes=0] Enhances the efficiency of SectionPlane creation by proactively allocating Viewer resources for a specified quantity
108202
108326
  * of SectionPlanes. Introducing this parameter streamlines the initial creation speed of SectionPlanes, particularly up to the designated quantity. This parameter internally
108203
108327
  * configures renderer logic for the specified number of SectionPlanes, eliminating the need for setting up logic with each SectionPlane creation and thereby enhancing
@@ -108261,6 +108385,7 @@ class Viewer {
108261
108385
  pbrEnabled: (!!cfg.pbrEnabled),
108262
108386
  colorTextureEnabled: (cfg.colorTextureEnabled !== false),
108263
108387
  dtxEnabled: (!!cfg.dtxEnabled),
108388
+ markerZOffset: cfg.markerZOffset,
108264
108389
  numCachedSectionPlanes: cfg.numCachedSectionPlanes
108265
108390
  });
108266
108391
 
@@ -123705,6 +123830,22 @@ class SkyboxesPlugin extends Plugin {
123705
123830
  */
123706
123831
  class STLDefaultDataSource {
123707
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
+
123708
123849
  /**
123709
123850
  * Gets STL data.
123710
123851
  *
@@ -123713,6 +123854,7 @@ class STLDefaultDataSource {
123713
123854
  * @param {Function} error Fired on error while loading the STL file.
123714
123855
  */
123715
123856
  getSTL(src, ok, error) {
123857
+ src = this._cacheBusterURL(src);
123716
123858
  const request = new XMLHttpRequest();
123717
123859
  request.overrideMimeType("application/json");
123718
123860
  request.open('GET', src, true);
@@ -126335,7 +126477,20 @@ class ViewCullPlugin extends Plugin {
126335
126477
  */
126336
126478
  class XKTDefaultDataSource {
126337
126479
 
126338
- 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
+ }
126339
126494
  }
126340
126495
 
126341
126496
  /**
@@ -126346,7 +126501,7 @@ class XKTDefaultDataSource {
126346
126501
  * @param {Function} error Fired on error while loading the manifest JSON asset.
126347
126502
  */
126348
126503
  getManifest(manifestSrc, ok, error) {
126349
- utils.loadJSON(manifestSrc,
126504
+ utils.loadJSON(this._cacheBusterURL(manifestSrc),
126350
126505
  (json) => {
126351
126506
  ok(json);
126352
126507
  },
@@ -126363,7 +126518,7 @@ class XKTDefaultDataSource {
126363
126518
  * @param {Function} error Fired on error while loading the metamodel JSON asset.
126364
126519
  */
126365
126520
  getMetaModel(metaModelSrc, ok, error) {
126366
- utils.loadJSON(metaModelSrc,
126521
+ utils.loadJSON(this._cacheBusterURL(metaModelSrc),
126367
126522
  (json) => {
126368
126523
  ok(json);
126369
126524
  },
@@ -126405,7 +126560,7 @@ class XKTDefaultDataSource {
126405
126560
  }
126406
126561
  } else {
126407
126562
  const request = new XMLHttpRequest();
126408
- request.open('GET', src, true);
126563
+ request.open('GET', this._cacheBusterURL(src), true);
126409
126564
  request.responseType = 'arraybuffer';
126410
126565
  request.onreadystatechange = function () {
126411
126566
  if (request.readyState === 4) {
@@ -133806,7 +133961,20 @@ class XML3DLoaderPlugin extends Plugin {
133806
133961
  */
133807
133962
  class WebIFCDefaultDataSource {
133808
133963
 
133809
- 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
+ }
133810
133978
  }
133811
133979
 
133812
133980
  /**
@@ -133817,6 +133985,8 @@ class WebIFCDefaultDataSource {
133817
133985
  * @param {Function} error Callback fired on error.
133818
133986
  */
133819
133987
  getIFC(src, ok, error) {
133988
+ src = this._cacheBusterURL(src);
133989
+
133820
133990
  var defaultCallback = () => {
133821
133991
  };
133822
133992
  ok = ok || defaultCallback;
@@ -134814,7 +134984,20 @@ class WebIFCLoaderPlugin extends Plugin {
134814
134984
  */
134815
134985
  class LASDefaultDataSource {
134816
134986
 
134817
- 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
+ }
134818
135001
  }
134819
135002
 
134820
135003
  /**
@@ -134825,6 +135008,7 @@ class LASDefaultDataSource {
134825
135008
  * @param {Function} error Callback fired on error.
134826
135009
  */
134827
135010
  getLAS(src, ok, error) {
135011
+ src = this._cacheBusterURL(src);
134828
135012
  var defaultCallback = () => {
134829
135013
  };
134830
135014
  ok = ok || defaultCallback;
@@ -135679,7 +135863,20 @@ function chunkArray(array, chunkSize) {
135679
135863
  */
135680
135864
  class CityJSONDefaultDataSource {
135681
135865
 
135682
- 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
+ }
135683
135880
  }
135684
135881
 
135685
135882
  /**
@@ -135690,7 +135887,7 @@ class CityJSONDefaultDataSource {
135690
135887
  * @param {Function} error Callback fired on error.
135691
135888
  */
135692
135889
  getCityJSON(src, ok, error) {
135693
- utils.loadJSON(src,
135890
+ utils.loadJSON(this._cacheBusterURL(src),
135694
135891
  (json) => {
135695
135892
  ok(json);
135696
135893
  },
@@ -137122,7 +137319,20 @@ class CityJSONLoaderPlugin extends Plugin {
137122
137319
  */
137123
137320
  class DotBIMDefaultDataSource {
137124
137321
 
137125
- 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
+ }
137126
137336
  }
137127
137337
 
137128
137338
  /**
@@ -137133,7 +137343,7 @@ class DotBIMDefaultDataSource {
137133
137343
  * @param {Function} error Fired on error while loading the .BIM JSON asset.
137134
137344
  */
137135
137345
  getDotBIM(dotBIMSrc, ok, error) {
137136
- utils.loadJSON(dotBIMSrc,
137346
+ utils.loadJSON(this._cacheBusterURL(dotBIMSrc),
137137
137347
  (json) => {
137138
137348
  ok(json);
137139
137349
  },
@@ -137695,4 +137905,2011 @@ class DotBIMLoaderPlugin extends Plugin {
137695
137905
  }
137696
137906
  }
137697
137907
 
137698
- 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, 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 };
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 };