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