@xeokit/xeokit-sdk 2.6.63 → 2.6.65

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 (27) hide show
  1. package/dist/xeokit-sdk.cjs.js +592 -1237
  2. package/dist/xeokit-sdk.es.js +592 -1237
  3. package/dist/xeokit-sdk.es5.js +155 -197
  4. package/dist/xeokit-sdk.min.cjs.js +5 -5
  5. package/dist/xeokit-sdk.min.es.js +5 -5
  6. package/dist/xeokit-sdk.min.es5.js +4 -4
  7. package/package.json +1 -1
  8. package/src/extras/PointerLens/PointerLens.js +27 -46
  9. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js +29 -20
  10. package/src/plugins/AnnotationsPlugin/Annotation.js +3 -0
  11. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +27 -33
  12. package/src/plugins/SectionPlanesPlugin/Control.js +462 -1142
  13. package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +10 -4
  14. package/src/plugins/lib/html/MenuEvent.js +3 -1
  15. package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +1 -2
  16. package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +1 -1
  17. package/types/plugins/AngleMeasurementsPlugin/index.d.ts +2 -1
  18. package/types/plugins/CityJSONLoaderPlugin/CityJSONLoaderPlugin.d.ts +4 -0
  19. package/types/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.d.ts +121 -0
  20. package/types/plugins/DotBIMLoaderPlugin/index.d.ts +1 -0
  21. package/types/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.d.ts +4 -0
  22. package/types/plugins/LASLoaderPlugin/LASLoaderPlugin.d.ts +4 -0
  23. package/types/plugins/STLLoaderPlugin/STLLoaderPlugin.d.ts +4 -0
  24. package/types/plugins/TreeViewPlugin/TreeViewPlugin.d.ts +4 -0
  25. package/types/plugins/WebIFCLoaderPlugin/WebIFCLoaderPlugin.d.ts +4 -0
  26. package/types/plugins/XKTLoaderPlugin/XKTLoaderPlugin.d.ts +19 -1
  27. package/types/plugins/index.d.ts +1 -0
@@ -1055,13 +1055,10 @@ class PointerLens {
1055
1055
  this.scene = this.viewer.scene;
1056
1056
 
1057
1057
  this._lensCursorDiv = document.createElement('div');
1058
- this.viewer.scene.canvas.canvas.parentNode.insertBefore(this._lensCursorDiv, this.viewer.scene.canvas.canvas);
1059
- this._lensCursorDiv.style.background = "pink";
1060
- this._lensCursorDiv.style.border = "2px solid red";
1061
- this._lensCursorDiv.style.borderRadius = "20px";
1062
- this._lensCursorDiv.style.width = "10px";
1063
- this._lensCursorDiv.style.height = "10px";
1064
- this._lensCursorDiv.style.margin = "-200px -200px";
1058
+ this._lensParams = { canvasSize: 300, cursorBorder: 2, cursorSize: 10 };
1059
+ this._lensCursorDiv.style.borderRadius = "50%";
1060
+ this._lensCursorDiv.style.width = this._lensParams.cursorSize + "px";
1061
+ this._lensCursorDiv.style.height = this._lensParams.cursorSize + "px";
1065
1062
  this._lensCursorDiv.style.zIndex = "100000";
1066
1063
  this._lensCursorDiv.style.position = "absolute";
1067
1064
  this._lensCursorDiv.style.pointerEvents = "none";
@@ -1074,8 +1071,8 @@ class PointerLens {
1074
1071
  this._lensContainer.style.background = "white";
1075
1072
  // this._lensContainer.style.opacity = "0";
1076
1073
  this._lensContainer.style.borderRadius = "50%";
1077
- this._lensContainer.style.width = "300px";
1078
- this._lensContainer.style.height = "300px";
1074
+ this._lensContainer.style.width = this._lensParams.canvasSize + "px";
1075
+ this._lensContainer.style.height = this._lensParams.canvasSize + "px";
1079
1076
 
1080
1077
  this._lensContainer.style.zIndex = "15000";
1081
1078
  this._lensContainer.style.position = "absolute";
@@ -1087,13 +1084,14 @@ class PointerLens {
1087
1084
  // this._lensCanvas.style.background = "darkblue";
1088
1085
  this._lensCanvas.style.borderRadius = "50%";
1089
1086
 
1090
- this._lensCanvas.style.width = "300px";
1091
- this._lensCanvas.style.height = "300px";
1087
+ this._lensCanvas.style.width = this._lensParams.canvasSize + "px";
1088
+ this._lensCanvas.style.height = this._lensParams.canvasSize + "px";
1092
1089
  this._lensCanvas.style.zIndex = "15000";
1093
1090
  this._lensCanvas.style.pointerEvents = "none";
1094
1091
 
1095
1092
  document.body.appendChild(this._lensContainer);
1096
1093
  this._lensContainer.appendChild(this._lensCanvas);
1094
+ this._lensContainer.appendChild(this._lensCursorDiv);
1097
1095
 
1098
1096
  this._lensCanvasContext = this._lensCanvas.getContext('2d');
1099
1097
  this._canvasElement = this.viewer.scene.canvas.canvas;
@@ -1111,7 +1109,7 @@ class PointerLens {
1111
1109
 
1112
1110
  this._active = (cfg.active !== false);
1113
1111
  this._visible = false;
1114
- this._snapped = false;
1112
+ this.snapped = false;
1115
1113
 
1116
1114
  this._onViewerRendering = this.viewer.scene.on("rendering", () => {
1117
1115
  if (this._active && this._visible) {
@@ -1158,21 +1156,13 @@ class PointerLens {
1158
1156
  this._lensCanvas.height // destination height
1159
1157
  );
1160
1158
 
1161
- const centerLensCanvas = [
1162
- (lensRect.left + lensRect.right) / 2 - canvasRect.left,
1163
- (lensRect.top + lensRect.bottom) / 2 - canvasRect.top
1164
- ];
1159
+ const middle = this._lensParams.canvasSize / 2 - this._lensParams.cursorSize / 2 - this._lensParams.cursorBorder;
1165
1160
 
1166
- if (this._snappedCanvasPos) {
1167
- const deltaX = this._snappedCanvasPos[0] - this._canvasPos[0];
1168
- const deltaY = this._snappedCanvasPos[1] - this._canvasPos[1];
1161
+ const deltaX = this._snappedCanvasPos ? (this._snappedCanvasPos[0] - this._canvasPos[0]) : 0;
1162
+ const deltaY = this._snappedCanvasPos ? (this._snappedCanvasPos[1] - this._canvasPos[1]) : 0;
1169
1163
 
1170
- this._lensCursorDiv.style.marginLeft = `${centerLensCanvas[0] + deltaX * this._zoomLevel - 10}px`;
1171
- this._lensCursorDiv.style.marginTop = `${centerLensCanvas[1] + deltaY * this._zoomLevel - 10}px`;
1172
- } else {
1173
- this._lensCursorDiv.style.marginLeft = `${centerLensCanvas[0] - 10}px`;
1174
- this._lensCursorDiv.style.marginTop = `${centerLensCanvas[1] - 10}px`;
1175
- }
1164
+ this._lensCursorDiv.style.left = `${middle + deltaX * this._zoomLevel}px`;
1165
+ this._lensCursorDiv.style.top = `${middle + deltaY * this._zoomLevel}px`;
1176
1166
  }
1177
1167
 
1178
1168
 
@@ -1240,14 +1230,10 @@ class PointerLens {
1240
1230
  * @private
1241
1231
  */
1242
1232
  set snapped(snapped) {
1243
- this._snapped = snapped;
1244
- if (snapped) {
1245
- this._lensCursorDiv.style.background = "greenyellow";
1246
- this._lensCursorDiv.style.border = "2px solid green";
1247
- } else {
1248
- this._lensCursorDiv.style.background = "pink";
1249
- this._lensCursorDiv.style.border = "2px solid red";
1250
- }
1233
+ this._snapped = snapped;
1234
+ const [ bg, border ] = snapped ? [ "greenyellow", "green" ] : [ "pink", "red" ];
1235
+ this._lensCursorDiv.style.background = bg;
1236
+ this._lensCursorDiv.style.border = this._lensParams.cursorBorder + "px solid " + border;
1251
1237
  }
1252
1238
 
1253
1239
  /**
@@ -1259,19 +1245,19 @@ class PointerLens {
1259
1245
  get snapped() {
1260
1246
  return this._snapped;
1261
1247
  }
1262
-
1248
+
1249
+ _updateActiveVisible() {
1250
+ this._lensContainer.style.visibility = (this._active && this._visible) ? "visible" : "hidden";
1251
+ this.update();
1252
+ }
1253
+
1263
1254
  /**
1264
1255
  * Sets if this PointerLens is active.
1265
1256
  * @param active
1266
1257
  */
1267
1258
  set active(active) {
1268
1259
  this._active = active;
1269
- this._lensContainer.style.visibility = (active && this._visible) ? "visible" : "hidden";
1270
- if (!active || !this._visible ) {
1271
- this._lensCursorDiv.style.marginLeft = `-100px`;
1272
- this._lensCursorDiv.style.marginTop = `-100px`;
1273
- }
1274
- this.update();
1260
+ this._updateActiveVisible();
1275
1261
  }
1276
1262
 
1277
1263
  /**
@@ -1290,12 +1276,7 @@ class PointerLens {
1290
1276
  */
1291
1277
  set visible(visible) {
1292
1278
  this._visible = visible;
1293
- this._lensContainer.style.visibility = (visible && this._active) ? "visible" : "hidden";
1294
- if (!visible || !this._active) {
1295
- this._lensCursorDiv.style.marginLeft = `-100px`;
1296
- this._lensCursorDiv.style.marginTop = `-100px`;
1297
- }
1298
- this.update();
1279
+ this._updateActiveVisible();
1299
1280
  }
1300
1281
 
1301
1282
  /**
@@ -9586,7 +9567,8 @@ const os = {
9586
9567
  }
9587
9568
  };
9588
9569
 
9589
- function addContextMenuListener(elem, callback) {
9570
+ //failCallback will be called when the press is not long enough to considered a long press
9571
+ function addContextMenuListener(elem, callback, failCallback = () => {}) {
9590
9572
  if (!elem || !callback) return;
9591
9573
 
9592
9574
  let timeout = null;
@@ -9640,6 +9622,7 @@ function addContextMenuListener(elem, callback) {
9640
9622
  const touchEndHandler = (event) => {
9641
9623
  event.preventDefault();
9642
9624
  if (timeout) {
9625
+ failCallback(event);
9643
9626
  clearTimeout(timeout);
9644
9627
  timeout = null;
9645
9628
  }
@@ -13781,6 +13764,8 @@ const WAITING_FOR_TARGET_LONG_TOUCH_END$1 = 8;
13781
13764
 
13782
13765
  const TOUCH_CANCELING$1 = 7;
13783
13766
 
13767
+ const tmpVec2$1 = math.vec2();
13768
+
13784
13769
  /**
13785
13770
  * Creates {@link AngleMeasurement}s from touch input.
13786
13771
  *
@@ -13919,6 +13904,19 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13919
13904
  this._touchState = WAITING_FOR_ORIGIN_TOUCH_START$1;
13920
13905
  };
13921
13906
 
13907
+ const copyCanvasPos = (event, dst) => {
13908
+ dst[0] = event.clientX;
13909
+ dst[1] = event.clientY;
13910
+ transformToNode(canvas.ownerDocument.documentElement, canvas, dst);
13911
+ return dst;
13912
+ };
13913
+
13914
+ const toBodyPos = (pos, dst) => {
13915
+ dst.set(pos);
13916
+ transformToNode(canvas, canvas.ownerDocument.documentElement, dst);
13917
+ return dst;
13918
+ };
13919
+
13922
13920
  canvas.addEventListener("touchstart", this._onCanvasTouchStart = (event) => {
13923
13921
 
13924
13922
  const currentNumTouches = event.touches.length;
@@ -13932,11 +13930,8 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13932
13930
  }
13933
13931
 
13934
13932
  const touch = event.touches[0];
13935
- const touchX = touch.clientX;
13936
- const touchY = touch.clientY;
13937
-
13938
- touchStartCanvasPos.set([touchX, touchY]);
13939
- touchMoveCanvasPos.set([touchX, touchY]);
13933
+ copyCanvasPos(touch, touchStartCanvasPos);
13934
+ touchMoveCanvasPos.set(touchStartCanvasPos);
13940
13935
 
13941
13936
  switch (this._touchState) {
13942
13937
 
@@ -13952,7 +13947,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13952
13947
  });
13953
13948
  if (snapPickResult && snapPickResult.snapped) {
13954
13949
  pointerWorldPos.set(snapPickResult.worldPos);
13955
- this.pointerCircle.start(snapPickResult.snappedCanvasPos);
13950
+ this.pointerCircle.start(toBodyPos(snapPickResult.snappedCanvasPos, tmpVec2$1));
13956
13951
  } else {
13957
13952
  const pickResult = scene.pick({
13958
13953
  canvasPos: touchMoveCanvasPos,
@@ -13960,7 +13955,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13960
13955
  });
13961
13956
  if (pickResult && pickResult.worldPos) {
13962
13957
  pointerWorldPos.set(pickResult.worldPos);
13963
- this.pointerCircle.start(pickResult.canvasPos);
13958
+ this.pointerCircle.start(toBodyPos(pickResult.canvasPos, tmpVec2$1));
13964
13959
  } else {
13965
13960
  return;
13966
13961
  }
@@ -14067,7 +14062,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14067
14062
  this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
14068
14063
  this.pointerLens.snapped = true;
14069
14064
  }
14070
- this.pointerCircle.start(snapPickResult.snappedCanvasPos);
14065
+ this.pointerCircle.start(toBodyPos(snapPickResult.snappedCanvasPos, tmpVec2$1));
14071
14066
  pointerWorldPos.set(snapPickResult.worldPos);
14072
14067
  this._currentAngleMeasurement.corner.worldPos = snapPickResult.worldPos;
14073
14068
  this._currentAngleMeasurement.corner.entity = snapPickResult.entity;
@@ -14089,7 +14084,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14089
14084
  this.pointerLens.cursorPos = pickResult.canvasPos;
14090
14085
  this.pointerLens.snapped = false;
14091
14086
  }
14092
- this.pointerCircle.start(pickResult.canvasPos);
14087
+ this.pointerCircle.start(toBodyPos(pickResult.canvasPos, tmpVec2$1));
14093
14088
  pointerWorldPos.set(pickResult.worldPos);
14094
14089
  this._currentAngleMeasurement.corner.worldPos = pickResult.worldPos;
14095
14090
  this._currentAngleMeasurement.corner.entity = pickResult.entity;
@@ -14160,7 +14155,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14160
14155
  this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
14161
14156
  this.pointerLens.snapped = true;
14162
14157
  }
14163
- this.pointerCircle.start(snapPickResult.snappedCanvasPos);
14158
+ this.pointerCircle.start(toBodyPos(snapPickResult.snappedCanvasPos, tmpVec2$1));
14164
14159
  pointerWorldPos.set(snapPickResult.worldPos);
14165
14160
  this._currentAngleMeasurement.target.worldPos = snapPickResult.worldPos;
14166
14161
  this._currentAngleMeasurement.target.entity = snapPickResult.entity;
@@ -14182,7 +14177,7 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14182
14177
  this.pointerLens.cursorPos = pickResult.canvasPos;
14183
14178
  this.pointerLens.snapped = false;
14184
14179
  }
14185
- this.pointerCircle.start(pickResult.canvasPos);
14180
+ this.pointerCircle.start(toBodyPos(pickResult.canvasPos, tmpVec2$1));
14186
14181
  pointerWorldPos.set(pickResult.worldPos);
14187
14182
  this._currentAngleMeasurement.target.worldPos = pickResult.worldPos;
14188
14183
  this._currentAngleMeasurement.target.entity = pickResult.entity;
@@ -14246,14 +14241,11 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14246
14241
  }
14247
14242
 
14248
14243
  const touch = event.touches[0];
14249
- const touchX = touch.clientX;
14250
- const touchY = touch.clientY;
14251
-
14252
14244
  if (touch.identifier !== touchId) {
14253
14245
  return;
14254
14246
  }
14255
14247
 
14256
- touchMoveCanvasPos.set([touchX, touchY]);
14248
+ copyCanvasPos(touch, touchMoveCanvasPos);
14257
14249
 
14258
14250
  let snapPickResult;
14259
14251
  let pickResult;
@@ -14423,9 +14415,6 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14423
14415
  }
14424
14416
 
14425
14417
  const touch = event.changedTouches[0];
14426
- const touchX = touch.clientX;
14427
- const touchY = touch.clientY;
14428
-
14429
14418
  if (touch.identifier !== touchId) {
14430
14419
  return;
14431
14420
  }
@@ -14435,7 +14424,10 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14435
14424
  longTouchTimeout = null;
14436
14425
  }
14437
14426
 
14438
- touchEndCanvasPos.set([touchX, touchY]);
14427
+ copyCanvasPos(touch, touchEndCanvasPos);
14428
+
14429
+ const touchX = touchEndCanvasPos[0];
14430
+ const touchY = touchEndCanvasPos[1];
14439
14431
 
14440
14432
  switch (this._touchState) {
14441
14433
 
@@ -14916,6 +14908,9 @@ class Annotation extends Marker {
14916
14908
  addContextMenuListener(this._marker, e => {
14917
14909
  e.preventDefault();
14918
14910
  this.plugin.fire("contextmenu", this);
14911
+ }, e => {
14912
+ e.preventDefault();
14913
+ this.plugin.fire("markerClicked", this);
14919
14914
  });
14920
14915
  this._marker.addEventListener("mouseenter", () => {
14921
14916
  this.plugin.fire("markerMouseEnter", this);
@@ -66120,7 +66115,7 @@ class VBOInstancingLinesLayer {
66120
66115
 
66121
66116
  let pickFlag = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED;
66122
66117
 
66123
- const clippableFlag = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0;
66118
+ const clippableFlag = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 1 : 0;
66124
66119
 
66125
66120
  let vertFlag = 0;
66126
66121
  vertFlag |= colorFlag;
@@ -80697,8 +80692,7 @@ class DTXTrianglesLayer {
80697
80692
  worldPos[2] = positions[i + 2];
80698
80693
  worldPos[3] = 1.0;
80699
80694
  math.decompressPosition(worldPos, positionsDecodeMatrix);
80700
- math.transformPoint4(this.model.worldMatrix, worldPos, worldPos);
80701
- math.transformPoint4(this.model.worldMatrix, worldPos, worldPos);
80695
+ math.mulMat4v4(this.model.worldMatrix, worldPos, worldPos);
80702
80696
  worldPos[0] += offsetX;
80703
80697
  worldPos[1] += offsetY;
80704
80698
  worldPos[2] += offsetZ;
@@ -89874,6 +89868,8 @@ const WAITING_FOR_TARGET_LONG_TOUCH_END = 5;
89874
89868
 
89875
89869
  const TOUCH_CANCELING = 7;
89876
89870
 
89871
+ const tmpVec2 = math.vec2();
89872
+
89877
89873
  /**
89878
89874
  * Creates {@link DistanceMeasurement}s from touch input.
89879
89875
  *
@@ -90020,6 +90016,19 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90020
90016
  this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
90021
90017
  };
90022
90018
 
90019
+ const copyCanvasPos = (event, dst) => {
90020
+ dst[0] = event.clientX;
90021
+ dst[1] = event.clientY;
90022
+ transformToNode(canvas.ownerDocument.documentElement, canvas, dst);
90023
+ return dst;
90024
+ };
90025
+
90026
+ const toBodyPos = (pos, dst) => {
90027
+ dst.set(pos);
90028
+ transformToNode(canvas, canvas.ownerDocument.documentElement, dst);
90029
+ return dst;
90030
+ };
90031
+
90023
90032
  canvas.addEventListener("touchstart", this._onCanvasTouchStart = (event) => {
90024
90033
 
90025
90034
  const currentNumTouches = event.touches.length;
@@ -90033,16 +90042,8 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90033
90042
  }
90034
90043
 
90035
90044
  const touch = event.touches[0];
90036
-
90037
- // Get the canvas's bounding rectangle
90038
- const rect = canvas.getBoundingClientRect();
90039
-
90040
- // Calculate the touch position relative to the canvas
90041
- const touchX = touch.clientX - rect.left;
90042
- const touchY = touch.clientY - rect.top;
90043
-
90044
- touchStartCanvasPos.set([touchX, touchY]);
90045
- touchMoveCanvasPos.set([touchX, touchY]);
90045
+ copyCanvasPos(touch, touchStartCanvasPos);
90046
+ touchMoveCanvasPos.set(touchStartCanvasPos);
90046
90047
 
90047
90048
  switch (this._touchState) {
90048
90049
 
@@ -90058,7 +90059,7 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90058
90059
  });
90059
90060
  if (snapPickResult && snapPickResult.snapped) {
90060
90061
  pointerWorldPos.set(snapPickResult.worldPos);
90061
- this.pointerCircle.start(snapPickResult.snappedCanvasPos);
90062
+ this.pointerCircle.start(toBodyPos(snapPickResult.snappedCanvasPos, tmpVec2));
90062
90063
  } else {
90063
90064
  const pickResult = scene.pick({
90064
90065
  canvasPos: touchMoveCanvasPos,
@@ -90066,7 +90067,7 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90066
90067
  });
90067
90068
  if (pickResult && pickResult.worldPos) {
90068
90069
  pointerWorldPos.set(pickResult.worldPos);
90069
- this.pointerCircle.start(pickResult.canvasPos);
90070
+ this.pointerCircle.start(toBodyPos(pickResult.canvasPos, tmpVec2));
90070
90071
  } else {
90071
90072
  return;
90072
90073
  }
@@ -90170,7 +90171,7 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90170
90171
  this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
90171
90172
  this.pointerLens.snapped = true;
90172
90173
  }
90173
- this.pointerCircle.start(snapPickResult.snappedCanvasPos);
90174
+ this.pointerCircle.start(toBodyPos(snapPickResult.snappedCanvasPos, tmpVec2));
90174
90175
  pointerWorldPos.set(snapPickResult.worldPos);
90175
90176
  this._currentDistanceMeasurement.target.worldPos = snapPickResult.worldPos;
90176
90177
  this._currentDistanceMeasurement.target.entity = snapPickResult.entity;
@@ -90188,7 +90189,7 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90188
90189
  this.pointerLens.cursorPos = pickResult.canvasPos;
90189
90190
  this.pointerLens.snapped = false;
90190
90191
  }
90191
- this.pointerCircle.start(pickResult.canvasPos);
90192
+ this.pointerCircle.start(toBodyPos(pickResult.canvasPos, tmpVec2));
90192
90193
  pointerWorldPos.set(pickResult.worldPos);
90193
90194
  this._currentDistanceMeasurement.target.worldPos = pickResult.worldPos;
90194
90195
  this._currentDistanceMeasurement.target.entity = pickResult.entity;
@@ -90247,19 +90248,11 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90247
90248
  }
90248
90249
 
90249
90250
  const touch = event.touches[0];
90250
-
90251
- // Get the canvas's bounding rectangle
90252
- const rect = canvas.getBoundingClientRect();
90253
-
90254
- // Calculate the touch position relative to the canvas
90255
- const touchX = touch.clientX - rect.left;
90256
- const touchY = touch.clientY - rect.top;
90257
-
90258
90251
  if (touch.identifier !== touchId) {
90259
90252
  return;
90260
90253
  }
90261
90254
 
90262
- touchMoveCanvasPos.set([touchX, touchY]);
90255
+ copyCanvasPos(touch, touchMoveCanvasPos);
90263
90256
 
90264
90257
  let snapPickResult;
90265
90258
  let pickResult;
@@ -90421,14 +90414,6 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90421
90414
  }
90422
90415
 
90423
90416
  const touch = event.changedTouches[0];
90424
-
90425
- // Get the canvas's bounding rectangle
90426
- const rect = canvas.getBoundingClientRect();
90427
-
90428
- // Calculate the touch position relative to the canvas
90429
- const touchX = touch.clientX - rect.left;
90430
- const touchY = touch.clientY - rect.top;
90431
-
90432
90417
  if (touch.identifier !== touchId) {
90433
90418
  return;
90434
90419
  }
@@ -90438,7 +90423,10 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
90438
90423
  longTouchTimeout = null;
90439
90424
  }
90440
90425
 
90441
- touchEndCanvasPos.set([touchX, touchY]);
90426
+ copyCanvasPos(touch, touchEndCanvasPos);
90427
+
90428
+ const touchX = touchEndCanvasPos[0];
90429
+ const touchY = touchEndCanvasPos[1];
90442
90430
 
90443
90431
  switch (this._touchState) {
90444
90432
 
@@ -97135,6 +97123,14 @@ class MousePanRotateDollyHandler {
97135
97123
  keyDown[keyCode] = false;
97136
97124
  });
97137
97125
 
97126
+ document.addEventListener("visibilitychange", this._onVisibilityChange = () => {
97127
+ keyDown.splice(0);
97128
+ });
97129
+
97130
+ window.addEventListener("blur", this._onBlur = () => {
97131
+ keyDown.splice(0);
97132
+ });
97133
+
97138
97134
  function setMousedownState(pick = true) {
97139
97135
  setMousedownPositions();
97140
97136
  if (pick) {
@@ -97400,6 +97396,8 @@ class MousePanRotateDollyHandler {
97400
97396
 
97401
97397
  document.removeEventListener("keydown", this._documentKeyDownHandler);
97402
97398
  document.removeEventListener("keyup", this._documentKeyUpHandler);
97399
+ document.removeEventListener("visibilitychange", this._onVisibilityChange);
97400
+ window.removeEventListener("blur", this._onBlur);
97403
97401
  canvas.removeEventListener("mousedown", this._mouseDownHandler);
97404
97402
  document.removeEventListener("mousemove", this._documentMouseMoveHandler);
97405
97403
  canvas.removeEventListener("mousemove", this._canvasMouseMoveHandler);
@@ -97955,6 +97953,14 @@ class KeyboardPanRotateDollyHandler {
97955
97953
  }
97956
97954
  });
97957
97955
 
97956
+ document.addEventListener("visibilitychange", this._onVisibilityChange = () => {
97957
+ keyDownMap.splice(0);
97958
+ });
97959
+
97960
+ window.addEventListener("blur", this._onBlur = () => {
97961
+ keyDownMap.splice(0);
97962
+ });
97963
+
97958
97964
  this._onTick = scene.on("tick", (e) => {
97959
97965
 
97960
97966
  if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) {
@@ -98084,6 +98090,8 @@ class KeyboardPanRotateDollyHandler {
98084
98090
 
98085
98091
  this._scene.input.off(this._onSceneMouseMove);
98086
98092
  this._scene.input.off(this._onSceneKeyDown);
98093
+ document.removeEventListener("visibilitychange", this._onVisibilityChange);
98094
+ window.removeEventListener("blur", this._onBlur);
98087
98095
  this._scene.input.off(this._onSceneKeyUp);
98088
98096
  }
98089
98097
  }
@@ -120732,322 +120740,336 @@ class Control {
120732
120740
  */
120733
120741
  this.id = null;
120734
120742
 
120735
- this._viewer = plugin.viewer;
120743
+ const viewer = plugin.viewer;
120744
+ const camera = viewer.camera;
120745
+ const cameraControl = viewer.cameraControl;
120746
+ const scene = viewer.scene;
120747
+ const canvas = scene.canvas.canvas;
120736
120748
 
120737
120749
  this._visible = false;
120738
- this._pos = math.vec3(); // Full-precision position of the center of the Control
120739
- this._origin = math.vec3();
120740
- this._rtcPos = math.vec3();
120741
120750
 
120742
- this._baseDir = math.vec3(); // Saves direction of clip plane when we start dragging an arrow or ring.
120743
- this._rootNode = null; // Root of Node graph that represents this control in the 3D scene
120744
- this._displayMeshes = null; // Meshes that are always visible
120745
- this._affordanceMeshes = null; // Meshes displayed momentarily for affordance
120751
+ let ignoreNextSectionPlaneDirUpdate = false;
120746
120752
 
120747
- this._ignoreNextSectionPlaneDirUpdate = false;
120753
+ // Builds the Entities that represent this Control.
120754
+ const NO_STATE_INHERIT = false;
120755
+ const arrowLength = 1.0;
120756
+ const handleRadius = 0.09;
120757
+ const tubeRadius = 0.01;
120748
120758
 
120749
- this._createNodes();
120750
- this._bindEvents();
120751
- }
120759
+ const rootNode = new Node$2(scene, { // Root of Node graph that represents this control in the 3D scene
120760
+ position: [0, 0, 0],
120761
+ scale: [5, 5, 5],
120762
+ isObject: false
120763
+ });
120752
120764
 
120753
- /**
120754
- * Called by SectionPlanesPlugin to assign this Control to a SectionPlane.
120755
- * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool.
120756
- * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to.
120757
- * @private
120758
- */
120759
- _setSectionPlane(sectionPlane) {
120760
- if (this._sectionPlane) {
120761
- this._sectionPlane.off(this._onSectionPlanePos);
120762
- this._sectionPlane.off(this._onSectionPlaneDir);
120763
- this._onSectionPlanePos = null;
120764
- this._onSectionPlaneDir = null;
120765
- this._sectionPlane = null;
120766
- }
120767
- if (sectionPlane) {
120768
- this.id = sectionPlane.id;
120769
- this._setPos(sectionPlane.pos);
120770
- this._setDir(sectionPlane.dir);
120771
- this._sectionPlane = sectionPlane;
120772
- this._onSectionPlanePos = sectionPlane.on("pos", () => {
120773
- this._setPos(this._sectionPlane.pos);
120774
- });
120775
- this._onSectionPlaneDir = sectionPlane.on("dir", () => {
120776
- if (!this._ignoreNextSectionPlaneDirUpdate) {
120777
- this._setDir(this._sectionPlane.dir);
120778
- } else {
120779
- this._ignoreNextSectionPlaneDirUpdate = false;
120780
- }
120781
- });
120782
- }
120783
- }
120765
+ const pos = math.vec3();
120766
+ const setPos = (function() {
120767
+ const origin = math.vec3();
120768
+ const rtcPos = math.vec3();
120769
+ return function(p) {
120770
+ pos.set(p);
120771
+ worldToRTCPos(p, origin, rtcPos);
120772
+ rootNode.origin = origin;
120773
+ rootNode.position = rtcPos;
120774
+ };
120775
+ })();
120784
120776
 
120785
- /**
120786
- * Gets the {@link SectionPlane} controlled by this Control.
120787
- * @returns {SectionPlane} The SectionPlane.
120788
- */
120789
- get sectionPlane() {
120790
- return this._sectionPlane;
120791
- }
120777
+ const arrowGeometry = (radiusBottom, height) => new ReadableGeometry(rootNode, buildCylinderGeometry({
120778
+ radiusTop: 0.001,
120779
+ radiusBottom: radiusBottom,
120780
+ radialSegments: 32,
120781
+ heightSegments: 1,
120782
+ height: height,
120783
+ openEnded: false
120784
+ }));
120792
120785
 
120793
- /** @private */
120794
- _setPos(xyz) {
120786
+ const tubeGeometry = (radius, height, radialSegments) => new ReadableGeometry(rootNode, buildCylinderGeometry({
120787
+ radiusTop: radius,
120788
+ radiusBottom: radius,
120789
+ radialSegments: radialSegments,
120790
+ heightSegments: 1,
120791
+ height: height,
120792
+ openEnded: false
120793
+ }));
120795
120794
 
120796
- this._pos.set(xyz);
120795
+ const torusGeometry = (tube, arcFraction, tubeSegments) => new ReadableGeometry(rootNode, buildTorusGeometry({
120796
+ radius: arrowLength - 0.2,
120797
+ tube: tube,
120798
+ radialSegments: 64,
120799
+ tubeSegments: tubeSegments,
120800
+ arc: (Math.PI * 2.0) * arcFraction
120801
+ }));
120797
120802
 
120798
- worldToRTCPos(this._pos, this._origin, this._rtcPos);
120803
+ const shapes = {// Reusable geometries
120799
120804
 
120800
- this._rootNode.origin = this._origin;
120801
- this._rootNode.position = this._rtcPos;
120802
- }
120805
+ curve: torusGeometry(tubeRadius, 0.25, 14),
120806
+ curveHandle: torusGeometry(handleRadius, 0.25, 14),
120807
+ hoop: torusGeometry(tubeRadius, 1, 8),
120803
120808
 
120804
- /** @private */
120805
- _setDir(xyz) {
120806
- this._baseDir.set(xyz);
120807
- this._rootNode.quaternion = math.vec3PairToQuaternion(zeroVec$1, xyz, quat$1);
120808
- }
120809
+ arrowHead: arrowGeometry(0.07, 0.2),
120810
+ arrowHeadBig: arrowGeometry(0.09, 0.25),
120811
+ arrowHeadHandle: tubeGeometry(handleRadius, 0.37, 8),
120809
120812
 
120810
- _setSectionPlaneDir(dir) {
120811
- if (this._sectionPlane) {
120812
- this._ignoreNextSectionPlaneDirUpdate = true;
120813
- this._sectionPlane.dir = dir;
120814
- }
120815
- }
120813
+ axis: tubeGeometry(tubeRadius, arrowLength, 20),
120814
+ axisHandle: tubeGeometry(handleRadius, arrowLength, 20)
120815
+ };
120816
120816
 
120817
- /**
120818
- * Sets if this Control is visible.
120819
- *
120820
- * @type {Boolean}
120821
- */
120822
- setVisible(visible = true) {
120823
- if (this._visible === visible) {
120824
- return;
120825
- }
120826
- this._visible = visible;
120827
- var id;
120828
- for (id in this._displayMeshes) {
120829
- if (this._displayMeshes.hasOwnProperty(id)) {
120830
- this._displayMeshes[id].visible = visible;
120831
- }
120832
- }
120833
- if (!visible) {
120834
- for (id in this._affordanceMeshes) {
120835
- if (this._affordanceMeshes.hasOwnProperty(id)) {
120836
- this._affordanceMeshes[id].visible = visible;
120837
- }
120838
- }
120839
- }
120840
- }
120817
+ const colorMaterial = (rgb) => new PhongMaterial(rootNode, {
120818
+ diffuse: rgb,
120819
+ emissive: rgb,
120820
+ ambient: [0.0, 0.0, 0.0],
120821
+ specular: [.6, .6, .3],
120822
+ shininess: 80,
120823
+ lineWidth: 2
120824
+ });
120841
120825
 
120842
- /**
120843
- * Gets if this Control is visible.
120844
- *
120845
- * @type {Boolean}
120846
- */
120847
- getVisible() {
120848
- return this._visible;
120849
- }
120826
+ const highlightMaterial = (rgb, fillAlpha) => new EmphasisMaterial(rootNode, {
120827
+ edges: false,
120828
+ fill: true,
120829
+ fillColor: rgb,
120830
+ fillAlpha: fillAlpha
120831
+ });
120850
120832
 
120851
- /**
120852
- * Sets if this Control is culled. This is called by SectionPlanesPlugin to
120853
- * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot().
120854
- * @param culled
120855
- */
120856
- setCulled(culled) {
120857
- var id;
120858
- for (id in this._displayMeshes) {
120859
- if (this._displayMeshes.hasOwnProperty(id)) {
120860
- this._displayMeshes[id].culled = culled;
120861
- }
120862
- }
120863
- if (!culled) {
120864
- for (id in this._affordanceMeshes) {
120865
- if (this._affordanceMeshes.hasOwnProperty(id)) {
120866
- this._affordanceMeshes[id].culled = culled;
120867
- }
120868
- }
120869
- }
120870
- }
120833
+ const pickableMaterial = new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area
120834
+ diffuse: [1, 1, 0],
120835
+ alpha: 0, // Invisible
120836
+ alphaMode: "blend"
120837
+ });
120871
120838
 
120872
- /**
120873
- * Builds the Entities that represent this Control.
120874
- * @private
120875
- */
120876
- _createNodes() {
120839
+ const handlers = { };
120840
+ const addAxis = (rgb, axisDirection, hoopDirection) => {
120841
+ const material = colorMaterial(rgb);
120877
120842
 
120878
- const NO_STATE_INHERIT = false;
120879
- const scene = this._viewer.scene;
120880
- const radius = 1.0;
120881
- const handleTubeRadius = 0.06;
120882
- const hoopRadius = radius - 0.2;
120883
- const tubeRadius = 0.01;
120884
- const arrowRadius = 0.07;
120843
+ const rotateToHorizontal = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
120844
+ const hoopRotation = math.quaternionToRotationMat4(math.vec3PairToQuaternion([ 0, 1, 0 ], hoopDirection), math.identityMat4());
120845
+ const hoopMatrix = math.mulMat4(hoopRotation, rotateToHorizontal, math.identityMat4());
120885
120846
 
120886
- this._rootNode = new Node$2(scene, {
120887
- position: [0, 0, 0],
120888
- scale: [5, 5, 5],
120889
- isObject: false
120890
- });
120847
+ const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
120891
120848
 
120892
- const rootNode = this._rootNode;
120849
+ const scaledArrowMatrix = (t, matR) => {
120850
+ const matT = math.translateMat4v(t, math.identityMat4());
120851
+ const ret = math.identityMat4();
120852
+ math.mulMat4(matT, matR, ret);
120853
+ math.mulMat4(hoopMatrix, ret, ret);
120854
+ return math.mulMat4(ret, scale, math.identityMat4());
120855
+ };
120893
120856
 
120894
- const shapes = {// Reusable geometries
120857
+ const curve = rootNode.addChild(new Mesh(rootNode, {
120858
+ geometry: shapes.curve,
120859
+ material: material,
120860
+ matrix: hoopMatrix,
120861
+ pickable: false,
120862
+ collidable: true,
120863
+ clippable: false,
120864
+ backfaces: true,
120865
+ visible: false,
120866
+ isObject: false
120867
+ }), NO_STATE_INHERIT);
120895
120868
 
120896
- arrowHead: new ReadableGeometry(rootNode, buildCylinderGeometry({
120897
- radiusTop: 0.001,
120898
- radiusBottom: arrowRadius,
120899
- radialSegments: 32,
120900
- heightSegments: 1,
120901
- height: 0.2,
120902
- openEnded: false
120903
- })),
120869
+ const rotateHandle = rootNode.addChild(new Mesh(rootNode, {
120870
+ geometry: shapes.curveHandle,
120871
+ material: pickableMaterial,
120872
+ matrix: hoopMatrix,
120873
+ pickable: true,
120874
+ collidable: true,
120875
+ clippable: false,
120876
+ backfaces: true,
120877
+ visible: false,
120878
+ isObject: false
120879
+ }), NO_STATE_INHERIT);
120904
120880
 
120905
- arrowHeadBig: new ReadableGeometry(rootNode, buildCylinderGeometry({
120906
- radiusTop: 0.001,
120907
- radiusBottom: 0.09,
120908
- radialSegments: 32,
120909
- heightSegments: 1,
120910
- height: 0.25,
120911
- openEnded: false
120912
- })),
120881
+ const arrow1 = rootNode.addChild(new Mesh(rootNode, {
120882
+ geometry: shapes.arrowHead,
120883
+ material: material,
120884
+ matrix: scaledArrowMatrix([ .8, .07, 0 ], math.rotationMat4v(180 * math.DEGTORAD, [0, 0, 1], math.identityMat4())),
120885
+ pickable: true,
120886
+ collidable: true,
120887
+ clippable: false,
120888
+ visible: false,
120889
+ isObject: false
120890
+ }), NO_STATE_INHERIT);
120913
120891
 
120914
- arrowHeadHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({
120915
- radiusTop: 0.09,
120916
- radiusBottom: 0.09,
120917
- radialSegments: 8,
120918
- heightSegments: 1,
120919
- height: 0.37,
120920
- openEnded: false
120921
- })),
120892
+ const arrow2 = rootNode.addChild(new Mesh(rootNode, {
120893
+ geometry: shapes.arrowHead,
120894
+ material: material,
120895
+ matrix: scaledArrowMatrix([ .07, .8, 0 ], math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4())),
120896
+ pickable: true,
120897
+ collidable: true,
120898
+ clippable: false,
120899
+ visible: false,
120900
+ isObject: false
120901
+ }), NO_STATE_INHERIT);
120922
120902
 
120923
- curve: new ReadableGeometry(rootNode, buildTorusGeometry({
120924
- radius: hoopRadius,
120925
- tube: tubeRadius,
120926
- radialSegments: 64,
120927
- tubeSegments: 14,
120928
- arc: (Math.PI * 2.0) / 4.0
120929
- })),
120903
+ const hoop = rootNode.addChild(new Mesh(rootNode, {
120904
+ geometry: shapes.hoop,
120905
+ material: material,
120906
+ highlighted: true,
120907
+ highlightMaterial: highlightMaterial(rgb, 0.6),
120908
+ matrix: hoopMatrix,
120909
+ pickable: false,
120910
+ collidable: true,
120911
+ clippable: false,
120912
+ visible: false,
120913
+ isObject: false
120914
+ }), NO_STATE_INHERIT);
120930
120915
 
120931
- curveHandle: new ReadableGeometry(rootNode, buildTorusGeometry({
120932
- radius: hoopRadius,
120933
- tube: handleTubeRadius,
120934
- radialSegments: 64,
120935
- tubeSegments: 14,
120936
- arc: (Math.PI * 2.0) / 4.0
120937
- })),
120938
120916
 
120939
- hoop: new ReadableGeometry(rootNode, buildTorusGeometry({
120940
- radius: hoopRadius,
120941
- tube: tubeRadius,
120942
- radialSegments: 64,
120943
- tubeSegments: 8,
120944
- arc: (Math.PI * 2.0)
120945
- })),
120917
+ const axisRotation = math.quaternionToRotationMat4(math.vec3PairToQuaternion([ 0, 1, 0 ], axisDirection), math.identityMat4());
120946
120918
 
120947
- axis: new ReadableGeometry(rootNode, buildCylinderGeometry({
120948
- radiusTop: tubeRadius,
120949
- radiusBottom: tubeRadius,
120950
- radialSegments: 20,
120951
- heightSegments: 1,
120952
- height: radius,
120953
- openEnded: false
120954
- })),
120919
+ const translatedAxisMatrix = (yOffset) => math.mulMat4(axisRotation, math.translateMat4c(0, yOffset, 0, math.identityMat4()), math.identityMat4());
120920
+ const arrowMatrix = translatedAxisMatrix(arrowLength + .1);
120921
+ const shaftMatrix = translatedAxisMatrix(arrowLength / 2);
120955
120922
 
120956
- axisHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({
120957
- radiusTop: 0.08,
120958
- radiusBottom: 0.08,
120959
- radialSegments: 20,
120960
- heightSegments: 1,
120961
- height: radius,
120962
- openEnded: false
120963
- }))
120964
- };
120923
+ const arrow = rootNode.addChild(new Mesh(rootNode, {
120924
+ geometry: shapes.arrowHead,
120925
+ material: material,
120926
+ matrix: arrowMatrix,
120927
+ pickable: false,
120928
+ collidable: true,
120929
+ clippable: false,
120930
+ visible: false,
120931
+ isObject: false
120932
+ }), NO_STATE_INHERIT);
120965
120933
 
120966
- const materials = { // Reusable materials
120934
+ const arrowHandle = rootNode.addChild(new Mesh(rootNode, {
120935
+ geometry: shapes.arrowHeadHandle,
120936
+ material: pickableMaterial,
120937
+ matrix: arrowMatrix,
120938
+ pickable: true,
120939
+ collidable: true,
120940
+ clippable: false,
120941
+ visible: false,
120942
+ isObject: false
120943
+ }), NO_STATE_INHERIT);
120967
120944
 
120968
- pickable: new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area
120969
- diffuse: [1, 1, 0],
120970
- alpha: 0, // Invisible
120971
- alphaMode: "blend"
120972
- }),
120945
+ const shaft = rootNode.addChild(new Mesh(rootNode, {
120946
+ geometry: shapes.axis,
120947
+ material: material,
120948
+ matrix: shaftMatrix,
120949
+ pickable: false,
120950
+ collidable: true,
120951
+ clippable: false,
120952
+ visible: false,
120953
+ isObject: false
120954
+ }), NO_STATE_INHERIT);
120973
120955
 
120974
- red: new PhongMaterial(rootNode, {
120975
- diffuse: [1, 0.0, 0.0],
120976
- emissive: [1, 0.0, 0.0],
120977
- ambient: [0.0, 0.0, 0.0],
120978
- specular: [.6, .6, .3],
120979
- shininess: 80,
120980
- lineWidth: 2
120981
- }),
120956
+ const shaftHandle = rootNode.addChild(new Mesh(rootNode, {
120957
+ geometry: shapes.axisHandle,
120958
+ material: pickableMaterial,
120959
+ matrix: shaftMatrix,
120960
+ pickable: true,
120961
+ collidable: true,
120962
+ clippable: false,
120963
+ visible: false,
120964
+ isObject: false
120965
+ }), NO_STATE_INHERIT);
120982
120966
 
120983
- highlightRed: new EmphasisMaterial(rootNode, { // Emphasis for red rotation affordance hoop
120984
- edges: false,
120985
- fill: true,
120986
- fillColor: [1, 0, 0],
120987
- fillAlpha: 0.6
120988
- }),
120967
+ const bigArrowHead = rootNode.addChild(new Mesh(rootNode, {
120968
+ geometry: shapes.arrowHeadBig,
120969
+ material: material,
120970
+ matrix: arrowMatrix,
120971
+ pickable: false,
120972
+ collidable: true,
120973
+ clippable: false,
120974
+ visible: false,
120975
+ isObject: false
120976
+ }), NO_STATE_INHERIT);
120989
120977
 
120990
- green: new PhongMaterial(rootNode, {
120991
- diffuse: [0.0, 1, 0.0],
120992
- emissive: [0.0, 1, 0.0],
120993
- ambient: [0.0, 0.0, 0.0],
120994
- specular: [.6, .6, .3],
120995
- shininess: 80,
120996
- lineWidth: 2
120997
- }),
120978
+ const localToWorldVec = (localVec, worldVec) => math.vec3ApplyQuaternion(rootNode.quaternion, localVec, worldVec);
120998
120979
 
120999
- highlightGreen: new EmphasisMaterial(rootNode, { // Emphasis for green rotation affordance hoop
121000
- edges: false,
121001
- fill: true,
121002
- fillColor: [0, 1, 0],
121003
- fillAlpha: 0.6
121004
- }),
120980
+ const closestPointOnAxis = (function() {
120981
+ const worldAxis = math.vec3();
120982
+ const org = math.vec3();
120983
+ const dir = math.vec3();
120984
+ return (canvasPos, dst) => {
120985
+ localToWorldVec(rgb, worldAxis);
121005
120986
 
121006
- blue: new PhongMaterial(rootNode, {
121007
- diffuse: [0.0, 0.0, 1],
121008
- emissive: [0.0, 0.0, 1],
121009
- ambient: [0.0, 0.0, 0.0],
121010
- specular: [.6, .6, .3],
121011
- shininess: 80,
121012
- lineWidth: 2
121013
- }),
120987
+ const P = pos;
120988
+ const D = worldAxis;
121014
120989
 
121015
- highlightBlue: new EmphasisMaterial(rootNode, { // Emphasis for blue rotation affordance hoop
121016
- edges: false,
121017
- fill: true,
121018
- fillColor: [0, 0, 1],
121019
- fillAlpha: 0.2
121020
- }),
120990
+ math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, org, dir);
121021
120991
 
121022
- center: new PhongMaterial(rootNode, {
121023
- diffuse: [0.0, 0.0, 0.0],
121024
- emissive: [0, 0, 0],
121025
- ambient: [0.0, 0.0, 0.0],
121026
- specular: [.6, .6, .3],
121027
- shininess: 80
121028
- }),
120992
+ const d01 = math.dotVec3(D, dir);
120993
+ const v = math.subVec3(org, P, dst);
120994
+ const v0 = math.dotVec3(v, D);
120995
+ const v1 = math.dotVec3(v, dir);
120996
+ const det = 1 - d01 * d01;
121029
120997
 
121030
- highlightBall: new EmphasisMaterial(rootNode, {
121031
- edges: false,
121032
- fill: true,
121033
- fillColor: [0.5, 0.5, 0.5],
121034
- fillAlpha: 0.5,
121035
- vertices: false
121036
- }),
120998
+ if (Math.abs(det) > 1e-10) { // if lines are not parallel
120999
+ const s = (v0 - d01 * v1) / det;
121000
+ math.addVec3(P, math.mulVec3Scalar(D, s, dst), dst);
121001
+ return true;
121002
+ } else {
121003
+ return false;
121004
+ }
121005
+ };
121006
+ })();
121007
+ const initOffset = math.vec3();
121008
+ const tempVec3 = math.vec3();
121009
+ handlers[arrowHandle.id] = handlers[shaftHandle.id] = {
121010
+ setActivated: a => bigArrowHead.visible = a,
121011
+ initDragAction: (initCanvasPos) => {
121012
+ return closestPointOnAxis(initCanvasPos, initOffset) && math.subVec3(initOffset, pos, initOffset) && ((canvasPos) => {
121013
+ if (closestPointOnAxis(canvasPos, tempVec3)) {
121014
+ math.subVec3(tempVec3, initOffset, tempVec3);
121015
+ setPos(tempVec3);
121016
+ if (this._sectionPlane) {
121017
+ this._sectionPlane.pos = tempVec3;
121018
+ }
121019
+ }
121020
+ });
121021
+ }
121022
+ };
121037
121023
 
121038
- highlightPlane: new EmphasisMaterial(rootNode, {
121039
- edges: true,
121040
- edgeWidth: 3,
121041
- fill: false,
121042
- fillColor: [0.5, 0.5, .5],
121043
- fillAlpha: 0.5,
121044
- vertices: false
121045
- })
121046
- };
121024
+ handlers[rotateHandle.id] = {
121025
+ setActivated: a => hoop.visible = a,
121026
+ initDragAction: (initCanvasPos) => {
121027
+ const rotationFromCanvasPos = (function() {
121028
+ const planeCanvasPos = camera.projectWorldPos(pos);
121029
+ localToWorldVec(rgb, tempVec3);
121030
+ math.transformVec3(camera.normalMatrix, tempVec3, tempVec3);
121031
+ const axisCoeff = Math.sign(tempVec3[2]);
121032
+ return (canvasPos) => {
121033
+ const dx = canvasPos[0] - planeCanvasPos[0];
121034
+ const dy = canvasPos[1] - planeCanvasPos[1];
121035
+ return axisCoeff * Math.atan2(-dy, dx);
121036
+ };
121037
+ })();
121047
121038
 
121048
- this._displayMeshes = {
121039
+ let lastRotation = rotationFromCanvasPos(initCanvasPos);
121049
121040
 
121050
- plane: rootNode.addChild(new Mesh(rootNode, {
121041
+ return canvasPos => {
121042
+ const rotation = rotationFromCanvasPos(canvasPos);
121043
+ rootNode.rotate(rgb, (rotation - lastRotation) * 180 / Math.PI);
121044
+ if (this._sectionPlane) {
121045
+ ignoreNextSectionPlaneDirUpdate = true;
121046
+ this._sectionPlane.dir = math.vec3ApplyQuaternion(rootNode.quaternion, [0, 0, 1], tempVec3);
121047
+ }
121048
+ lastRotation = rotation;
121049
+ };
121050
+ }
121051
+ };
121052
+
121053
+ return {
121054
+ set visible(v) {
121055
+ arrow.visible = arrowHandle.visible = shaft.visible = shaftHandle.visible = curve.visible = rotateHandle.visible = arrow1.visible = arrow2.visible = v;
121056
+ if (! v) {
121057
+ bigArrowHead.visible = v;
121058
+ hoop.visible = v;
121059
+ }
121060
+ },
121061
+ set culled(c) {
121062
+ arrow.culled = arrowHandle.culled = shaft.culled = shaftHandle.culled = curve.culled = rotateHandle.culled = arrow1.culled = arrow2.culled = c;
121063
+ if (! c) {
121064
+ bigArrowHead.culled = c;
121065
+ hoop.culled = c;
121066
+ }
121067
+ }
121068
+ };
121069
+ };
121070
+
121071
+ this._displayMeshes = [ // Meshes that are always visible
121072
+ rootNode.addChild(new Mesh(rootNode, { // plane
121051
121073
  geometry: new ReadableGeometry(rootNode, {
121052
121074
  primitive: "triangles",
121053
121075
  positions: [
@@ -121081,7 +121103,7 @@ class Control {
121081
121103
  isObject: false
121082
121104
  }), NO_STATE_INHERIT),
121083
121105
 
121084
- planeFrame: rootNode.addChild(new Mesh(rootNode, { // Visible frame
121106
+ rootNode.addChild(new Mesh(rootNode, { // Visible frame
121085
121107
  geometry: new ReadableGeometry(rootNode, buildTorusGeometry({
121086
121108
  center: [0, 0, 0],
121087
121109
  radius: 1.7,
@@ -121113,310 +121135,17 @@ class Control {
121113
121135
  isObject: false
121114
121136
  }), NO_STATE_INHERIT),
121115
121137
 
121116
- //----------------------------------------------------------------------------------------------------------
121117
- //
121118
- //----------------------------------------------------------------------------------------------------------
121119
-
121120
- xCurve: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis
121121
- geometry: shapes.curve,
121122
- material: materials.red,
121123
- matrix: (function () {
121124
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
121125
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121126
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
121127
- })(),
121128
- pickable: false,
121129
- collidable: true,
121130
- clippable: false,
121131
- backfaces: true,
121132
- visible: false,
121133
- isObject: false
121134
- }), NO_STATE_INHERIT),
121135
-
121136
- xCurveHandle: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis
121137
- geometry: shapes.curveHandle,
121138
- material: materials.pickable,
121139
- matrix: (function () {
121140
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
121141
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121142
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
121143
- })(),
121144
- pickable: true,
121145
- collidable: true,
121146
- clippable: false,
121147
- backfaces: true,
121148
- visible: false,
121149
- isObject: false
121150
- }), NO_STATE_INHERIT),
121151
-
121152
- xCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
121153
- geometry: shapes.arrowHead,
121154
- material: materials.red,
121155
- matrix: (function () {
121156
- const translate = math.translateMat4c(0., -0.07, -0.8, math.identityMat4());
121157
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121158
- const rotate = math.rotationMat4v(0 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121159
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
121160
- })(),
121161
- pickable: true,
121162
- collidable: true,
121163
- clippable: false,
121164
- visible: false,
121165
- isObject: false
121166
- }), NO_STATE_INHERIT),
121167
-
121168
- xCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
121169
- geometry: shapes.arrowHead,
121170
- material: materials.red,
121171
- matrix: (function () {
121172
- const translate = math.translateMat4c(0.0, -0.8, -0.07, math.identityMat4());
121173
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121174
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121175
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
121176
- })(),
121177
- pickable: true,
121178
- collidable: true,
121179
- clippable: false,
121180
- visible: false,
121181
- isObject: false
121182
- }), NO_STATE_INHERIT),
121183
-
121184
- //----------------------------------------------------------------------------------------------------------
121185
- //
121186
- //----------------------------------------------------------------------------------------------------------
121187
-
121188
- yCurve: rootNode.addChild(new Mesh(rootNode, {
121189
- geometry: shapes.curve,
121190
- material: materials.green,
121191
- rotation: [-90, 0, 0],
121192
- pickable: false,
121193
- collidable: true,
121194
- clippable: false,
121195
- backfaces: true,
121196
- visible: false,
121197
- isObject: false
121198
- }), NO_STATE_INHERIT),
121199
-
121200
- yCurveHandle: rootNode.addChild(new Mesh(rootNode, {
121201
- geometry: shapes.curveHandle,
121202
- material: materials.pickable,
121203
- rotation: [-90, 0, 0],
121204
- pickable: true,
121205
- collidable: true,
121206
- clippable: false,
121207
- backfaces: true,
121208
- visible: false,
121209
- isObject: false
121210
- }), NO_STATE_INHERIT),
121211
-
121212
- yCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
121213
- geometry: shapes.arrowHead,
121214
- material: materials.green,
121215
- matrix: (function () {
121216
- const translate = math.translateMat4c(0.07, 0, -0.8, math.identityMat4());
121217
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121218
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121219
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
121220
- })(),
121221
- pickable: true,
121222
- collidable: true,
121223
- clippable: false,
121224
- visible: false,
121225
- isObject: false
121226
- }), NO_STATE_INHERIT),
121227
-
121228
- yCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
121229
- geometry: shapes.arrowHead,
121230
- material: materials.green,
121231
- matrix: (function () {
121232
- const translate = math.translateMat4c(0.8, 0.0, -0.07, math.identityMat4());
121233
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121234
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121235
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
121236
- })(),
121237
- pickable: true,
121238
- collidable: true,
121239
- clippable: false,
121240
- visible: false,
121241
- isObject: false
121242
- }), NO_STATE_INHERIT),
121243
-
121244
- //----------------------------------------------------------------------------------------------------------
121245
- //
121246
- //----------------------------------------------------------------------------------------------------------
121247
-
121248
- zCurve: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis
121249
- geometry: shapes.curve,
121250
- material: materials.blue,
121251
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
121252
- pickable: false,
121253
- collidable: true,
121254
- clippable: false,
121255
- visible: false,
121256
- isObject: false
121257
- }), NO_STATE_INHERIT),
121258
-
121259
- zCurveHandle: rootNode.addChild(new Mesh(rootNode, {
121260
- geometry: shapes.curveHandle,
121261
- material: materials.pickable,
121262
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
121263
- pickable: true,
121264
- collidable: true,
121265
- clippable: false,
121266
- visible: false,
121267
- isObject: false
121268
- }), NO_STATE_INHERIT),
121269
-
121270
- zCurveCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
121271
- geometry: shapes.arrowHead,
121272
- material: materials.blue,
121273
- matrix: (function () {
121274
- const translate = math.translateMat4c(.8, -0.07, 0, math.identityMat4());
121275
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121276
- return math.mulMat4(translate, scale, math.identityMat4());
121277
- })(),
121278
- pickable: true,
121279
- collidable: true,
121280
- clippable: false,
121281
- visible: false,
121282
- isObject: false
121283
- }), NO_STATE_INHERIT),
121284
-
121285
- zCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
121286
- geometry: shapes.arrowHead,
121287
- material: materials.blue,
121288
- matrix: (function () {
121289
- const translate = math.translateMat4c(.05, -0.8, 0, math.identityMat4());
121290
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
121291
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121292
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
121293
- })(),
121294
- pickable: true,
121295
- collidable: true,
121296
- clippable: false,
121297
- visible: false,
121298
- isObject: false
121299
- }), NO_STATE_INHERIT),
121300
-
121301
- //----------------------------------------------------------------------------------------------------------
121302
- //
121303
- //----------------------------------------------------------------------------------------------------------
121304
-
121305
- center: rootNode.addChild(new Mesh(rootNode, {
121138
+ rootNode.addChild(new Mesh(rootNode, { // center
121306
121139
  geometry: new ReadableGeometry(rootNode, buildSphereGeometry({
121307
121140
  radius: 0.05
121308
121141
  })),
121309
- material: materials.center,
121310
- pickable: false,
121311
- collidable: true,
121312
- clippable: false,
121313
- visible: false,
121314
- isObject: false
121315
- }), NO_STATE_INHERIT),
121316
-
121317
- //----------------------------------------------------------------------------------------------------------
121318
- //
121319
- //----------------------------------------------------------------------------------------------------------
121320
-
121321
- xAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121322
- geometry: shapes.arrowHead,
121323
- material: materials.red,
121324
- matrix: (function () {
121325
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121326
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121327
- return math.mulMat4(rotate, translate, math.identityMat4());
121328
- })(),
121329
- pickable: false,
121330
- collidable: true,
121331
- clippable: false,
121332
- visible: false,
121333
- isObject: false
121334
- }), NO_STATE_INHERIT),
121335
-
121336
- xAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
121337
- geometry: shapes.arrowHeadHandle,
121338
- material: materials.pickable,
121339
- matrix: (function () {
121340
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121341
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121342
- return math.mulMat4(rotate, translate, math.identityMat4());
121343
- })(),
121344
- pickable: true,
121345
- collidable: true,
121346
- clippable: false,
121347
- visible: false,
121348
- isObject: false
121349
- }), NO_STATE_INHERIT),
121350
-
121351
- xAxis: rootNode.addChild(new Mesh(rootNode, {
121352
- geometry: shapes.axis,
121353
- material: materials.red,
121354
- matrix: (function () {
121355
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
121356
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121357
- return math.mulMat4(rotate, translate, math.identityMat4());
121358
- })(),
121359
- pickable: false,
121360
- collidable: true,
121361
- clippable: false,
121362
- visible: false,
121363
- isObject: false
121364
- }), NO_STATE_INHERIT),
121365
-
121366
- xAxisHandle: rootNode.addChild(new Mesh(rootNode, {
121367
- geometry: shapes.axisHandle,
121368
- material: materials.pickable,
121369
- matrix: (function () {
121370
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
121371
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121372
- return math.mulMat4(rotate, translate, math.identityMat4());
121373
- })(),
121374
- pickable: true,
121375
- collidable: true,
121376
- clippable: false,
121377
- visible: false,
121378
- isObject: false
121379
- }), NO_STATE_INHERIT),
121380
-
121381
- //----------------------------------------------------------------------------------------------------------
121382
- //
121383
- //----------------------------------------------------------------------------------------------------------
121384
-
121385
- yAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121386
- geometry: shapes.arrowHead,
121387
- material: materials.green,
121388
- matrix: (function () {
121389
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121390
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121391
- return math.mulMat4(rotate, translate, math.identityMat4());
121392
- })(),
121393
- pickable: false,
121394
- collidable: true,
121395
- clippable: false,
121396
- visible: false,
121397
- isObject: false
121398
- }), NO_STATE_INHERIT),
121399
-
121400
- yAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
121401
- geometry: shapes.arrowHeadHandle,
121402
- material: materials.pickable,
121403
- matrix: (function () {
121404
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121405
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121406
- return math.mulMat4(rotate, translate, math.identityMat4());
121407
- })(),
121408
- pickable: true,
121409
- collidable: true,
121410
- clippable: false,
121411
- visible: false,
121412
- opacity: 0.2,
121413
- isObject: false
121414
- }), NO_STATE_INHERIT),
121415
-
121416
- yShaft: rootNode.addChild(new Mesh(rootNode, {
121417
- geometry: shapes.axis,
121418
- material: materials.green,
121419
- position: [0, -radius / 2, 0],
121142
+ material: new PhongMaterial(rootNode, {
121143
+ diffuse: [0.0, 0.0, 0.0],
121144
+ emissive: [0, 0, 0],
121145
+ ambient: [0.0, 0.0, 0.0],
121146
+ specular: [.6, .6, .3],
121147
+ shininess: 80
121148
+ }),
121420
121149
  pickable: false,
121421
121150
  collidable: true,
121422
121151
  clippable: false,
@@ -121424,615 +121153,235 @@ class Control {
121424
121153
  isObject: false
121425
121154
  }), NO_STATE_INHERIT),
121426
121155
 
121427
- yShaftHandle: rootNode.addChild(new Mesh(rootNode, {
121428
- geometry: shapes.axisHandle,
121429
- material: materials.pickable,
121430
- position: [0, -radius / 2, 0],
121431
- pickable: true,
121432
- collidable: true,
121433
- clippable: false,
121434
- visible: false,
121435
- isObject: false
121436
- }), NO_STATE_INHERIT),
121437
-
121438
121156
  //----------------------------------------------------------------------------------------------------------
121439
121157
  //
121440
121158
  //----------------------------------------------------------------------------------------------------------
121441
121159
 
121442
- zAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121443
- geometry: shapes.arrowHead,
121444
- material: materials.blue,
121445
- matrix: (function () {
121446
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121447
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
121448
- return math.mulMat4(rotate, translate, math.identityMat4());
121449
- })(),
121450
- pickable: false,
121451
- collidable: true,
121452
- clippable: false,
121453
- visible: false,
121454
- isObject: false
121455
- }), NO_STATE_INHERIT),
121456
-
121457
- zAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
121458
- geometry: shapes.arrowHeadHandle,
121459
- material: materials.pickable,
121460
- matrix: (function () {
121461
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121462
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
121463
- return math.mulMat4(rotate, translate, math.identityMat4());
121464
- })(),
121465
- pickable: true,
121466
- collidable: true,
121467
- clippable: false,
121468
- visible: false,
121469
- isObject: false
121470
- }), NO_STATE_INHERIT),
121471
-
121472
-
121473
- zShaft: rootNode.addChild(new Mesh(rootNode, {
121474
- geometry: shapes.axis,
121475
- material: materials.blue,
121476
- matrix: (function () {
121477
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
121478
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121479
- return math.mulMat4(rotate, translate, math.identityMat4());
121480
- })(),
121481
- clippable: false,
121482
- pickable: false,
121483
- collidable: true,
121484
- visible: false,
121485
- isObject: false
121486
- }), NO_STATE_INHERIT),
121487
-
121488
- zAxisHandle: rootNode.addChild(new Mesh(rootNode, {
121489
- geometry: shapes.axisHandle,
121490
- material: materials.pickable,
121491
- matrix: (function () {
121492
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
121493
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121494
- return math.mulMat4(rotate, translate, math.identityMat4());
121495
- })(),
121496
- clippable: false,
121497
- pickable: true,
121498
- collidable: true,
121499
- visible: false,
121500
- isObject: false
121501
- }), NO_STATE_INHERIT)
121502
- };
121503
-
121504
- this._affordanceMeshes = {
121505
-
121506
- planeFrame: rootNode.addChild(new Mesh(rootNode, {
121507
- geometry: new ReadableGeometry(rootNode, buildTorusGeometry({
121508
- center: [0, 0, 0],
121509
- radius: 2,
121510
- tube: tubeRadius,
121511
- radialSegments: 4,
121512
- tubeSegments: 4,
121513
- arc: Math.PI * 2.0
121514
- })),
121515
- material: new PhongMaterial(rootNode, {
121516
- ambient: [1, 1, 1],
121517
- diffuse: [0, 0, 0],
121518
- emissive: [1, 1, 0]
121519
- }),
121520
- highlighted: true,
121521
- highlightMaterial: new EmphasisMaterial(rootNode, {
121522
- edges: false,
121523
- filled: true,
121524
- fillColor: [1, 1, 0],
121525
- fillAlpha: 1.0
121526
- }),
121527
- pickable: false,
121528
- collidable: false,
121529
- clippable: false,
121530
- visible: false,
121531
- scale: [1, 1, 1],
121532
- rotation: [0, 0, 45],
121533
- isObject: false
121534
- }), NO_STATE_INHERIT),
121535
-
121536
- xHoop: rootNode.addChild(new Mesh(rootNode, { // Full
121537
- geometry: shapes.hoop,
121538
- material: materials.red,
121539
- highlighted: true,
121540
- highlightMaterial: materials.highlightRed,
121541
- matrix: (function () {
121542
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
121543
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121544
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
121545
- })(),
121546
- pickable: false,
121547
- collidable: true,
121548
- clippable: false,
121549
- visible: false,
121550
- isObject: false
121551
- }), NO_STATE_INHERIT),
121552
-
121553
- yHoop: rootNode.addChild(new Mesh(rootNode, {
121554
- geometry: shapes.hoop,
121555
- material: materials.green,
121556
- highlighted: true,
121557
- highlightMaterial: materials.highlightGreen,
121558
- rotation: [-90, 0, 0],
121559
- pickable: false,
121560
- collidable: true,
121561
- clippable: false,
121562
- visible: false,
121563
- isObject: false
121564
- }), NO_STATE_INHERIT),
121565
-
121566
- zHoop: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis
121567
- geometry: shapes.hoop,
121568
- material: materials.blue,
121569
- highlighted: true,
121570
- highlightMaterial: materials.highlightBlue,
121571
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
121572
- pickable: false,
121573
- collidable: true,
121574
- clippable: false,
121575
- backfaces: true,
121576
- visible: false,
121577
- isObject: false
121578
- }), NO_STATE_INHERIT),
121579
-
121580
- xAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121581
- geometry: shapes.arrowHeadBig,
121582
- material: materials.red,
121583
- matrix: (function () {
121584
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121585
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
121586
- return math.mulMat4(rotate, translate, math.identityMat4());
121587
- })(),
121588
- pickable: false,
121589
- collidable: true,
121590
- clippable: false,
121591
- visible: false,
121592
- isObject: false
121593
- }), NO_STATE_INHERIT),
121594
-
121595
- yAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121596
- geometry: shapes.arrowHeadBig,
121597
- material: materials.green,
121598
- matrix: (function () {
121599
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121600
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
121601
- return math.mulMat4(rotate, translate, math.identityMat4());
121602
- })(),
121603
- pickable: false,
121604
- collidable: true,
121605
- clippable: false,
121606
- visible: false,
121607
- isObject: false
121608
- }), NO_STATE_INHERIT),
121609
-
121610
- zAxisArrow: rootNode.addChild(new Mesh(rootNode, {
121611
- geometry: shapes.arrowHeadBig,
121612
- material: materials.blue,
121613
- matrix: (function () {
121614
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
121615
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
121616
- return math.mulMat4(rotate, translate, math.identityMat4());
121617
- })(),
121618
- pickable: false,
121619
- collidable: true,
121620
- clippable: false,
121621
- visible: false,
121622
- isObject: false
121623
- }), NO_STATE_INHERIT)
121624
- };
121625
- }
121626
-
121627
- _bindEvents() {
121628
-
121629
- const self = this;
121630
-
121631
- var grabbed = false;
121632
-
121633
- const DRAG_ACTIONS = {
121634
- none: -1,
121635
- xTranslate: 0,
121636
- yTranslate: 1,
121637
- zTranslate: 2,
121638
- xRotate: 3,
121639
- yRotate: 4,
121640
- zRotate: 5
121641
- };
121642
-
121643
- const rootNode = this._rootNode;
121644
-
121645
- var nextDragAction = null; // As we hover grabbed an arrow or hoop, self is the action we would do if we then dragged it.
121646
- var dragAction = null; // Action we're doing while we drag an arrow or hoop.
121647
- const lastCanvasPos = math.vec2();
121648
-
121649
- const xBaseAxis = math.vec3([1, 0, 0]);
121650
- const yBaseAxis = math.vec3([0, 1, 0]);
121651
- const zBaseAxis = math.vec3([0, 0, 1]);
121160
+ addAxis([1,0,0], [ 1, 0, 0 ], [ 1, 0, 0 ]),
121161
+ addAxis([0,1,0], [ 0, -1, 0 ], [ 0, 1, 0 ]),
121162
+ addAxis([0,0,1], [ 0, 0, -1 ], [ 0, 0, -1 ])
121163
+ ];
121652
121164
 
121653
- const canvas = this._viewer.scene.canvas.canvas;
121654
- const camera = this._viewer.camera;
121655
- const scene = this._viewer.scene;
121165
+ const cleanups = [ ];
121656
121166
 
121657
121167
  { // Keep gizmo screen size constant
121658
-
121659
- const tempVec3a = math.vec3([0, 0, 0]);
121660
121168
  let lastDist = -1;
121661
-
121662
- this._onCameraViewMatrix = scene.camera.on("viewMatrix", () => {
121663
- });
121664
-
121665
- this._onCameraProjMatrix = scene.camera.on("projMatrix", () => {
121666
- });
121667
-
121668
- this._onSceneTick = scene.on("tick", () => {
121669
-
121670
- const dist = Math.abs(math.lenVec3(math.subVec3(scene.camera.eye, this._pos, tempVec3a)));
121671
-
121672
- if (dist !== lastDist) {
121673
- if (camera.projection === "perspective") {
121674
- const worldSize = (Math.tan(camera.perspective.fov * math.DEGTORAD)) * dist;
121675
- const size = 0.07 * worldSize;
121676
- rootNode.scale = [size, size, size];
121677
- lastDist = dist;
121169
+ const setRootNodeScale = size => rootNode.scale = [size, size, size];
121170
+ const onSceneTick = scene.on("tick", () => {
121171
+ const dist = Math.abs(math.distVec3(camera.eye, pos));
121172
+ if (camera.projection === "perspective") {
121173
+ if (dist !== lastDist) {
121174
+ setRootNodeScale(0.07 * dist * Math.tan(camera.perspective.fov * math.DEGTORAD));
121678
121175
  }
121176
+ } else if (camera.projection === "ortho") {
121177
+ setRootNodeScale(camera.ortho.scale / 10);
121679
121178
  }
121680
-
121681
- if (camera.projection === "ortho") {
121682
- const worldSize = camera.ortho.scale / 10;
121683
- const size = worldSize;
121684
- rootNode.scale = [size, size, size];
121685
- lastDist = dist;
121686
- }
121179
+ lastDist = dist;
121687
121180
  });
121181
+ cleanups.push(() => scene.off(onSceneTick));
121688
121182
  }
121689
121183
 
121690
- const getClickCoordsWithinElement = (function () {
121691
- const canvasPos = new Float64Array(2);
121692
- return function (event) {
121693
- if (!event) {
121694
- event = window.event;
121695
- canvasPos[0] = event.x;
121696
- canvasPos[1] = event.y;
121697
- } else {
121698
- var element = event.target;
121699
- var totalOffsetLeft = 0;
121700
- var totalOffsetTop = 0;
121701
-
121702
- while (element.offsetParent) {
121703
- totalOffsetLeft += element.offsetLeft;
121704
- totalOffsetTop += element.offsetTop;
121705
- element = element.offsetParent;
121706
- }
121707
- canvasPos[0] = event.pageX - totalOffsetLeft;
121708
- canvasPos[1] = event.pageY - totalOffsetTop;
121709
- }
121710
- return canvasPos;
121184
+ {
121185
+ let deactivateActive = null;
121186
+ let currentDrag = null;
121187
+ cleanups.push(() => { if (currentDrag) { currentDrag.cleanup(); } });
121188
+ const canvasPos = math.vec2();
121189
+
121190
+ const copyCanvasPos = (event, vec2) => {
121191
+ vec2[0] = event.clientX;
121192
+ vec2[1] = event.clientY;
121193
+ transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
121711
121194
  };
121712
- })();
121713
121195
 
121714
- const localToWorldVec = (function () {
121715
- const mat = math.mat4();
121716
- return function (localVec, worldVec) {
121717
- math.quaternionToMat4(self._rootNode.quaternion, mat);
121718
- math.transformVec3(mat, localVec, worldVec);
121719
- math.normalizeVec3(worldVec);
121720
- return worldVec;
121196
+ const pickHandler = (e) => {
121197
+ copyCanvasPos(e, canvasPos);
121198
+ const pickResult = viewer.scene.pick({ canvasPos: canvasPos });
121199
+ const pickEntity = pickResult && pickResult.entity;
121200
+ const pickId = pickEntity && pickEntity.id;
121201
+ return (pickId in handlers) && handlers[pickId];
121721
121202
  };
121722
- })();
121723
-
121724
- var getTranslationPlane = (function () {
121725
- const planeNormal = math.vec3();
121726
- return function (worldAxis) {
121727
- const absX = Math.abs(worldAxis[0]);
121728
- if (absX > Math.abs(worldAxis[1]) && absX > Math.abs(worldAxis[2])) {
121729
- math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal);
121730
- } else {
121731
- math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal);
121732
- }
121733
- math.cross3Vec3(planeNormal, worldAxis, planeNormal);
121734
- math.normalizeVec3(planeNormal);
121735
- return planeNormal;
121736
- }
121737
- })();
121738
-
121739
- const dragTranslateSectionPlane = (function () {
121740
- const p1 = math.vec3();
121741
- const p2 = math.vec3();
121742
- const worldAxis = math.vec4();
121743
- return function (baseAxis, fromMouse, toMouse) {
121744
- localToWorldVec(baseAxis, worldAxis);
121745
- const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
121746
- getPointerPlaneIntersect(fromMouse, planeNormal, p1);
121747
- getPointerPlaneIntersect(toMouse, planeNormal, p2);
121748
- math.subVec3(p2, p1);
121749
- const dot = math.dotVec3(p2, worldAxis);
121750
- self._pos[0] += worldAxis[0] * dot;
121751
- self._pos[1] += worldAxis[1] * dot;
121752
- self._pos[2] += worldAxis[2] * dot;
121753
- self._rootNode.position = self._pos;
121754
- if (self._sectionPlane) {
121755
- self._sectionPlane.pos = self._pos;
121756
- }
121757
- }
121758
- })();
121759
121203
 
121760
- var dragRotateSectionPlane = (function () {
121761
- const p1 = math.vec4();
121762
- const p2 = math.vec4();
121763
- const c = math.vec4();
121764
- const worldAxis = math.vec4();
121765
- return function (baseAxis, fromMouse, toMouse) {
121766
- localToWorldVec(baseAxis, worldAxis);
121767
- const hasData = getPointerPlaneIntersect(fromMouse, worldAxis, p1) && getPointerPlaneIntersect(toMouse, worldAxis, p2);
121768
- if (!hasData) { // Find intersections with view plane and project down to origin
121769
- const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
121770
- getPointerPlaneIntersect(fromMouse, planeNormal, p1, 1); // Ensure plane moves closer to camera so angles become workable
121771
- getPointerPlaneIntersect(toMouse, planeNormal, p2, 1);
121772
- var dot = math.dotVec3(p1, worldAxis);
121773
- p1[0] -= dot * worldAxis[0];
121774
- p1[1] -= dot * worldAxis[1];
121775
- p1[2] -= dot * worldAxis[2];
121776
- dot = math.dotVec3(p2, worldAxis);
121777
- p2[0] -= dot * worldAxis[0];
121778
- p2[1] -= dot * worldAxis[1];
121779
- p2[2] -= dot * worldAxis[2];
121780
- }
121781
- math.normalizeVec3(p1);
121782
- math.normalizeVec3(p2);
121783
- dot = math.dotVec3(p1, p2);
121784
- dot = math.clamp(dot, -1.0, 1.0); // Rounding errors cause dot to exceed allowed range
121785
- var incDegrees = Math.acos(dot) * math.RADTODEG;
121786
- math.cross3Vec3(p1, p2, c);
121787
- if (math.dotVec3(c, worldAxis) < 0.0) {
121788
- incDegrees = -incDegrees;
121789
- }
121790
- self._rootNode.rotate(baseAxis, incDegrees);
121791
- rotateSectionPlane();
121792
- }
121793
- })();
121794
-
121795
- var getPointerPlaneIntersect = (function () {
121796
- const dir = math.vec4([0, 0, 0, 1]);
121797
- const matrix = math.mat4();
121798
- return function (mouse, axis, dest, offset) {
121799
- offset = offset || 0;
121800
- dir[0] = mouse[0] / canvas.width * 2.0 - 1.0;
121801
- dir[1] = -(mouse[1] / canvas.height * 2.0 - 1.0);
121802
- dir[2] = 0.0;
121803
- dir[3] = 1.0;
121804
- math.mulMat4(camera.projMatrix, camera.viewMatrix, matrix); // Unproject norm device coords to view coords
121805
- math.inverseMat4(matrix);
121806
- math.transformVec4(matrix, dir, dir);
121807
- math.mulVec4Scalar(dir, 1.0 / dir[3]); // This is now point A on the ray in world space
121808
- var rayO = camera.eye; // The direction
121809
- math.subVec4(dir, rayO, dir);
121810
- const origin = self._sectionPlane.pos; // Plane origin:
121811
- var d = -math.dotVec3(origin, axis) - offset;
121812
- var dot = math.dotVec3(axis, dir);
121813
- if (Math.abs(dot) > 0.005) {
121814
- var t = -(math.dotVec3(axis, rayO) + d) / dot;
121815
- math.mulVec3Scalar(dir, t, dest);
121816
- math.addVec3(dest, rayO);
121817
- math.subVec3(dest, origin, dest);
121818
- return true;
121819
- }
121820
- return false;
121821
- }
121822
- })();
121204
+ const startDrag = (event, matchesEvent) => {
121205
+ const handler = pickHandler(matchesEvent(event));
121206
+ if (handler) {
121207
+ if (currentDrag) {
121208
+ currentDrag.cleanup();
121209
+ }
121823
121210
 
121824
- const rotateSectionPlane = (function () {
121825
- const dir = math.vec3();
121826
- const mat = math.mat4();
121827
- return function () {
121828
- if (self.sectionPlane) {
121829
- math.quaternionToMat4(rootNode.quaternion, mat); // << ---
121830
- math.transformVec3(mat, [0, 0, 1], dir);
121831
- self._setSectionPlaneDir(dir);
121211
+ const dragAction = handler.initDragAction(canvasPos);
121212
+ if (dragAction) {
121213
+ cameraControl.pointerEnabled = false; // or .active = false ?
121214
+ handler.setActivated(true);
121215
+
121216
+ currentDrag = {
121217
+ onChange: event => {
121218
+ const e = matchesEvent(event);
121219
+ if (e) {
121220
+ copyCanvasPos(e, canvasPos);
121221
+ dragAction(canvasPos);
121222
+ }
121223
+ },
121224
+ cleanup: function() {
121225
+ currentDrag = null;
121226
+ cameraControl.pointerEnabled = true; // or .active = true ?
121227
+ handler.setActivated(false);
121228
+ }
121229
+ };
121230
+ }
121832
121231
  }
121833
121232
  };
121834
- })();
121835
-
121836
- {
121837
- var down = false;
121838
- var lastAffordanceMesh;
121839
-
121840
- this._onCameraControlHover = this._viewer.cameraControl.on("hoverEnter", (hit) => {
121841
- if (!this._visible) {
121842
- return;
121843
- }
121844
- if (down) {
121845
- return;
121846
- }
121847
- grabbed = false;
121848
- if (lastAffordanceMesh) {
121849
- lastAffordanceMesh.visible = false;
121850
- }
121851
- var affordanceMesh;
121852
- const meshId = hit.entity.id;
121853
- switch (meshId) {
121854
-
121855
- case this._displayMeshes.xAxisArrowHandle.id:
121856
- affordanceMesh = this._affordanceMeshes.xAxisArrow;
121857
- nextDragAction = DRAG_ACTIONS.xTranslate;
121858
- break;
121859
-
121860
- case this._displayMeshes.xAxisHandle.id:
121861
- affordanceMesh = this._affordanceMeshes.xAxisArrow;
121862
- nextDragAction = DRAG_ACTIONS.xTranslate;
121863
- break;
121864
-
121865
- case this._displayMeshes.yAxisArrowHandle.id:
121866
- affordanceMesh = this._affordanceMeshes.yAxisArrow;
121867
- nextDragAction = DRAG_ACTIONS.yTranslate;
121868
- break;
121869
-
121870
- case this._displayMeshes.yShaftHandle.id:
121871
- affordanceMesh = this._affordanceMeshes.yAxisArrow;
121872
- nextDragAction = DRAG_ACTIONS.yTranslate;
121873
- break;
121874
121233
 
121875
- case this._displayMeshes.zAxisArrowHandle.id:
121876
- affordanceMesh = this._affordanceMeshes.zAxisArrow;
121877
- nextDragAction = DRAG_ACTIONS.zTranslate;
121878
- break;
121879
-
121880
- case this._displayMeshes.zAxisHandle.id:
121881
- affordanceMesh = this._affordanceMeshes.zAxisArrow;
121882
- nextDragAction = DRAG_ACTIONS.zTranslate;
121883
- break;
121884
-
121885
- case this._displayMeshes.xCurveHandle.id:
121886
- affordanceMesh = this._affordanceMeshes.xHoop;
121887
- nextDragAction = DRAG_ACTIONS.xRotate;
121888
- break;
121889
-
121890
- case this._displayMeshes.yCurveHandle.id:
121891
- affordanceMesh = this._affordanceMeshes.yHoop;
121892
- nextDragAction = DRAG_ACTIONS.yRotate;
121893
- break;
121894
-
121895
- case this._displayMeshes.zCurveHandle.id:
121896
- affordanceMesh = this._affordanceMeshes.zHoop;
121897
- nextDragAction = DRAG_ACTIONS.zRotate;
121898
- break;
121234
+ const addCanvasEventListener = (type, listener) => {
121235
+ canvas.addEventListener(type, listener);
121236
+ cleanups.push(() => canvas.removeEventListener(type, listener));
121237
+ };
121899
121238
 
121900
- default:
121901
- nextDragAction = DRAG_ACTIONS.none;
121902
- return; // Not clicked an arrow or hoop
121903
- }
121904
- if (affordanceMesh) {
121905
- affordanceMesh.visible = true;
121239
+ addCanvasEventListener("mousedown", (e) => {
121240
+ e.preventDefault();
121241
+ if (e.which === 1) {
121242
+ startDrag(e, event => (event.which === 1) && event);
121906
121243
  }
121907
- lastAffordanceMesh = affordanceMesh;
121908
- grabbed = true;
121909
121244
  });
121910
121245
 
121911
- this._onCameraControlHoverLeave = this._viewer.cameraControl.on("hoverOutEntity", (hit) => {
121912
- if (!this._visible) {
121913
- return;
121914
- }
121915
- if (lastAffordanceMesh) {
121916
- lastAffordanceMesh.visible = false;
121246
+ addCanvasEventListener("mousemove", (e) => {
121247
+ if (currentDrag) {
121248
+ currentDrag.onChange(e);
121249
+ } else {
121250
+ if (deactivateActive) {
121251
+ deactivateActive();
121252
+ }
121253
+ const handler = pickHandler(e);
121254
+ if (handler) {
121255
+ handler.setActivated(true);
121256
+ deactivateActive = () => handler.setActivated(false);
121257
+ } else {
121258
+ deactivateActive = null;
121259
+ }
121917
121260
  }
121918
- lastAffordanceMesh = null;
121919
- nextDragAction = DRAG_ACTIONS.none;
121920
121261
  });
121921
121262
 
121922
- canvas.addEventListener("mousedown", this._canvasMouseDownListener = (e) => {
121923
- e.preventDefault();
121924
- if (!this._visible) {
121925
- return;
121926
- }
121927
- if (!grabbed) {
121928
- return;
121929
- }
121930
- this._viewer.cameraControl.pointerEnabled = false;
121931
- switch (e.which) {
121932
- case 1: // Left button
121933
- down = true;
121934
- var canvasPos = getClickCoordsWithinElement(e);
121935
- dragAction = nextDragAction;
121936
- lastCanvasPos[0] = canvasPos[0];
121937
- lastCanvasPos[1] = canvasPos[1];
121938
- break;
121263
+ addCanvasEventListener("mouseup", (e) => {
121264
+ if (currentDrag) {
121265
+ currentDrag.onChange(e);
121266
+ currentDrag.cleanup();
121939
121267
  }
121940
121268
  });
121941
121269
 
121942
- canvas.addEventListener("mousemove", this._canvasMouseMoveListener = (e) => {
121943
- if (!this._visible) {
121944
- return;
121945
- }
121946
- if (!down) {
121947
- return;
121948
- }
121949
- var canvasPos = getClickCoordsWithinElement(e);
121950
- const x = canvasPos[0];
121951
- const y = canvasPos[1];
121952
121270
 
121953
- switch (dragAction) {
121954
- case DRAG_ACTIONS.xTranslate:
121955
- dragTranslateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos);
121956
- break;
121957
- case DRAG_ACTIONS.yTranslate:
121958
- dragTranslateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos);
121959
- break;
121960
- case DRAG_ACTIONS.zTranslate:
121961
- dragTranslateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos);
121962
- break;
121963
- case DRAG_ACTIONS.xRotate:
121964
- dragRotateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos);
121965
- break;
121966
- case DRAG_ACTIONS.yRotate:
121967
- dragRotateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos);
121968
- break;
121969
- case DRAG_ACTIONS.zRotate:
121970
- dragRotateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos);
121971
- break;
121271
+ addCanvasEventListener("touchstart", event => {
121272
+ event.preventDefault();
121273
+ if (event.touches.length === 1)
121274
+ {
121275
+ const touchStartId = event.touches[0].identifier;
121276
+ startDrag(event, event => [...event.changedTouches].find(e => e.identifier === touchStartId));
121972
121277
  }
121278
+ });
121973
121279
 
121974
- lastCanvasPos[0] = x;
121975
- lastCanvasPos[1] = y;
121280
+ addCanvasEventListener("touchmove", event => {
121281
+ event.preventDefault();
121282
+ currentDrag && currentDrag.onChange(event);
121976
121283
  });
121977
121284
 
121978
- canvas.addEventListener("mouseup", this._canvasMouseUpListener = (e) => {
121979
- if (!this._visible) {
121980
- return;
121981
- }
121982
- this._viewer.cameraControl.pointerEnabled = true;
121983
- if (!down) {
121984
- return;
121285
+ addCanvasEventListener("touchend", event => {
121286
+ event.preventDefault();
121287
+ if (currentDrag) {
121288
+ currentDrag.onChange(event);
121289
+ currentDrag.cleanup();
121985
121290
  }
121986
- switch (e.which) {
121987
- }
121988
- down = false;
121989
- grabbed = false;
121990
121291
  });
121292
+ }
121991
121293
 
121992
- canvas.addEventListener("wheel", this._canvasWheelListener = (e) => {
121993
- if (!this._visible) {
121994
- return;
121995
- }
121996
- var delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
121997
- if (delta === 0) {
121998
- return;
121294
+ this._unbindSectionPlane = () => { };
121295
+
121296
+ this.__setSectionPlane = sectionPlane => {
121297
+ this.id = sectionPlane.id;
121298
+ this._sectionPlane = sectionPlane;
121299
+ const setPosFromSectionPlane = () => setPos(sectionPlane.pos);
121300
+ const setDirFromSectionPlane = () => rootNode.quaternion = math.vec3PairToQuaternion(zeroVec$1, sectionPlane.dir, quat$1);
121301
+ setPosFromSectionPlane();
121302
+ setDirFromSectionPlane();
121303
+ const onSectionPlanePos = sectionPlane.on("pos", setPosFromSectionPlane);
121304
+ const onSectionPlaneDir = sectionPlane.on("dir", () => {
121305
+ if (!ignoreNextSectionPlaneDirUpdate) {
121306
+ setDirFromSectionPlane();
121307
+ } else {
121308
+ ignoreNextSectionPlaneDirUpdate = false;
121999
121309
  }
122000
121310
  });
122001
- }
121311
+
121312
+ this._unbindSectionPlane = () => {
121313
+ this.id = null;
121314
+ this._sectionPlane = null;
121315
+ sectionPlane.off(onSectionPlanePos);
121316
+ sectionPlane.off(onSectionPlaneDir);
121317
+ this._unbindSectionPlane = () => { };
121318
+ };
121319
+ };
121320
+
121321
+ this.__destroy = () => {
121322
+ cleanups.forEach(c => c());
121323
+ this._unbindSectionPlane();
121324
+ rootNode.destroy();
121325
+ this._displayMeshes = [ ];
121326
+ for (let id in handlers) {
121327
+ delete handlers[id];
121328
+ }
121329
+ };
122002
121330
  }
122003
121331
 
122004
121332
  _destroy() {
122005
- this._unbindEvents();
122006
- this._destroyNodes();
121333
+ this.__destroy();
122007
121334
  }
122008
121335
 
122009
- _unbindEvents() {
122010
-
122011
- const viewer = this._viewer;
122012
- const scene = viewer.scene;
122013
- const canvas = scene.canvas.canvas;
122014
- const camera = viewer.camera;
122015
- const cameraControl = viewer.cameraControl;
122016
-
122017
- scene.off(this._onSceneTick);
121336
+ /**
121337
+ * Called by SectionPlanesPlugin to assign this Control to a SectionPlane.
121338
+ * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool.
121339
+ * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to.
121340
+ * @private
121341
+ */
121342
+ _setSectionPlane(sectionPlane) {
121343
+ this._unbindSectionPlane();
121344
+ if (sectionPlane) {
121345
+ this.__setSectionPlane(sectionPlane);
121346
+ }
121347
+ }
122018
121348
 
122019
- canvas.removeEventListener("mousedown", this._canvasMouseDownListener);
122020
- canvas.removeEventListener("mousemove", this._canvasMouseMoveListener);
122021
- canvas.removeEventListener("mouseup", this._canvasMouseUpListener);
122022
- canvas.removeEventListener("wheel", this._canvasWheelListener);
121349
+ /**
121350
+ * Gets the {@link SectionPlane} controlled by this Control.
121351
+ * @returns {SectionPlane} The SectionPlane.
121352
+ */
121353
+ get sectionPlane() {
121354
+ return this._sectionPlane;
121355
+ }
122023
121356
 
122024
- camera.off(this._onCameraViewMatrix);
122025
- camera.off(this._onCameraProjMatrix);
121357
+ /**
121358
+ * Sets if this Control is visible.
121359
+ *
121360
+ * @type {Boolean}
121361
+ */
121362
+ setVisible(visible = true) {
121363
+ if (this._visible !== visible) {
121364
+ this._visible = visible;
121365
+ this._displayMeshes.forEach(m => m.visible = visible);
121366
+ }
121367
+ }
122026
121368
 
122027
- cameraControl.off(this._onCameraControlHover);
122028
- cameraControl.off(this._onCameraControlHoverLeave);
121369
+ /**
121370
+ * Gets if this Control is visible.
121371
+ *
121372
+ * @type {Boolean}
121373
+ */
121374
+ getVisible() {
121375
+ return this._visible;
122029
121376
  }
122030
121377
 
122031
- _destroyNodes() {
122032
- this._setSectionPlane(null);
122033
- this._rootNode.destroy();
122034
- this._displayMeshes = {};
122035
- this._affordanceMeshes = {};
121378
+ /**
121379
+ * Sets if this Control is culled. This is called by SectionPlanesPlugin to
121380
+ * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot().
121381
+ * @param culled
121382
+ */
121383
+ setCulled(culled) {
121384
+ this._displayMeshes.forEach(m => m.culled = culled);
122036
121385
  }
122037
121386
  }
122038
121387
 
@@ -126614,6 +125963,8 @@ class TreeViewPlugin extends Plugin {
126614
125963
  * @param {RenderService} [cfg.renderService] Optional {@link RenderService} to use. Defaults to the {@link TreeViewPlugin}'s default {@link RenderService}.
126615
125964
  * @param {Boolean} [cfg.showIndeterminate=false] When true, will show indeterminate state for checkboxes when some but not all child nodes are checked
126616
125965
  * @param {Boolean} [cfg.showProjectNode=false] When true, will show top level project node when hierarchy is set to "storeys"
125966
+ * @param {Function} [cfg.elevationSortFunction] Optional function to replace the default elevation sort function. The function should take two nodes and return -1, 0 or 1.
125967
+ * @param {Function} [cfg.defaultSortFunction] Optional function to replace the default sort function. The function should take two nodes and return -1, 0 or 1.
126617
125968
  */
126618
125969
  constructor(viewer, cfg = {}) {
126619
125970
 
@@ -126667,6 +126018,8 @@ class TreeViewPlugin extends Plugin {
126667
126018
  this._renderService = cfg.renderService || new RenderService();
126668
126019
  this._showIndeterminate = cfg.showIndeterminate ?? false;
126669
126020
  this._showProjectNode = cfg.showProjectNode ?? false;
126021
+ this._elevationSortFunction = cfg.elevationSortFunction ?? undefined;
126022
+ this._defaultSortFunction = cfg.defaultSortFunction ?? undefined;
126670
126023
 
126671
126024
  if (!this._renderService) {
126672
126025
  throw new Error('TreeViewPlugin: no render service set');
@@ -127480,9 +126833,11 @@ class TreeViewPlugin extends Plugin {
127480
126833
  }
127481
126834
  const firstChild = children[0];
127482
126835
  if ((this._hierarchy === "storeys" || this._hierarchy === "containment") && firstChild.type === "IfcBuildingStorey") {
127483
- children.sort(this._getSpatialSortFunc());
126836
+ if (this._elevationSortFunction) children.sort(this._elevationSortFunction);
126837
+ else children.sort(this._getSpatialSortFunc());
127484
126838
  } else {
127485
- children.sort(this._alphaSortFunc);
126839
+ if (this._defaultSortFunction) children.sort(this._defaultSortFunction);
126840
+ else children.sort(this._alphaSortFunc);
127486
126841
  }
127487
126842
  for (let i = 0, len = children.length; i < len; i++) {
127488
126843
  const node = children[i];