@xeokit/xeokit-sdk 2.4.2-beta-14 → 2.4.2-beta-19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1041,8 +1041,8 @@ class PointerLens {
1041
1041
  this._lensCanvasContext = this._lensCanvas.getContext('2d');
1042
1042
  this._canvasElement = this.viewer.scene.canvas.canvas;
1043
1043
 
1044
- this._centerPos = null;
1045
- this._cursorPos = null;
1044
+ this._canvasPos = null;
1045
+ this._snappedCanvasPos = null;
1046
1046
  this._lensPosToggle = true;
1047
1047
 
1048
1048
  this._zoomLevel = cfg.zoomLevel || 2;
@@ -1065,14 +1065,14 @@ class PointerLens {
1065
1065
  if (!this._active || !this._visible) {
1066
1066
  return;
1067
1067
  }
1068
- if (!this._centerPos) {
1068
+ if (!this._canvasPos) {
1069
1069
  return;
1070
1070
  }
1071
1071
  const lensRect = this._lensContainer.getBoundingClientRect();
1072
1072
  const canvasRect = this._canvasElement.getBoundingClientRect();
1073
1073
  const pointerOnLens =
1074
- this._centerPos[0] < lensRect.right && this._centerPos[0] > lensRect.left &&
1075
- this._centerPos[1] < lensRect.bottom && this._centerPos[1] > lensRect.top;
1074
+ this._canvasPos[0] < lensRect.right && this._canvasPos[0] > lensRect.left &&
1075
+ this._canvasPos[1] < lensRect.bottom && this._canvasPos[1] > lensRect.top;
1076
1076
  this._lensContainer.style.marginLeft = `25px`;
1077
1077
  if (pointerOnLens) {
1078
1078
  if (this._lensPosToggle) {
@@ -1086,8 +1086,8 @@ class PointerLens {
1086
1086
  const size = Math.max(this._lensCanvas.width, this._lensCanvas.height) / this._zoomLevel;
1087
1087
  this._lensCanvasContext.drawImage(
1088
1088
  this._canvasElement, // source canvas
1089
- this._centerPos[0] - size / 2, // source x (zoom center)
1090
- this._centerPos[1] - size / 2, // source y (zoom center)
1089
+ this._canvasPos[0] - size / 2, // source x (zoom center)
1090
+ this._canvasPos[1] - size / 2, // source y (zoom center)
1091
1091
  size, // source width
1092
1092
  size, // source height
1093
1093
  0, // destination x
@@ -1101,9 +1101,9 @@ class PointerLens {
1101
1101
  (lensRect.top + lensRect.bottom) / 2
1102
1102
  ];
1103
1103
 
1104
- if (this._cursorPos) {
1105
- const deltaX = this._cursorPos[0] - this._centerPos[0];
1106
- const deltaY = this._cursorPos[1] - this._centerPos[1];
1104
+ if (this._snappedCanvasPos) {
1105
+ const deltaX = this._snappedCanvasPos[0] - this._canvasPos[0];
1106
+ const deltaY = this._snappedCanvasPos[1] - this._canvasPos[1];
1107
1107
 
1108
1108
  this._lensCursorDiv.style.marginLeft = `${centerLensCanvas[0] + deltaX * this._zoomLevel - 10}px`;
1109
1109
  this._lensCursorDiv.style.marginTop = `${centerLensCanvas[1] + deltaY * this._zoomLevel - 10}px`;
@@ -1139,10 +1139,10 @@ class PointerLens {
1139
1139
 
1140
1140
  /**
1141
1141
  * Sets the canvas central position of the lens.
1142
- * @param centerPos
1142
+ * @param canvasPos
1143
1143
  */
1144
- set centerPos(centerPos) {
1145
- this._centerPos = centerPos;
1144
+ set canvasPos(canvasPos) {
1145
+ this._canvasPos = canvasPos;
1146
1146
  this.update();
1147
1147
  }
1148
1148
 
@@ -1150,25 +1150,25 @@ class PointerLens {
1150
1150
  * Gets the canvas central position of the lens.
1151
1151
  * @returns {Number[]}
1152
1152
  */
1153
- get centerPos() {
1154
- return this._centerPos;
1153
+ get canvasPos() {
1154
+ return this._canvasPos;
1155
1155
  }
1156
1156
 
1157
1157
  /**
1158
1158
  * Sets the canvas coordinates of the pointer.
1159
- * @param cursorPos
1159
+ * @param snappedCanvasPos
1160
1160
  */
1161
- set cursorPos(cursorPos) {
1162
- this._cursorPos = cursorPos;
1161
+ set snappedCanvasPos(snappedCanvasPos) {
1162
+ this._snappedCanvasPos = snappedCanvasPos;
1163
1163
  this.update();
1164
1164
  }
1165
1165
 
1166
1166
  /**
1167
- * Gets the canvas coordinates of the pointer.
1167
+ * Gets the canvas coordinates of the snapped pointer.
1168
1168
  * @returns {Number[]}
1169
1169
  */
1170
- get cursorPos() {
1171
- return this._cursorPos;
1170
+ get snappedCanvasPos() {
1171
+ return this._snappedCanvasPos;
1172
1172
  }
1173
1173
 
1174
1174
  /**
@@ -6649,6 +6649,8 @@ const kdTreeDimLength$1 = new Float32Array(3);
6649
6649
  * Automatically indexes a {@link Viewer}'s {@link Entity}s in a 3D k-d tree
6650
6650
  * to support fast collision detection with 3D World-space axis-aligned boundaries (AABBs) and frustums.
6651
6651
  *
6652
+ * See {@link MarqueePicker} for usage example.
6653
+ *
6652
6654
  * An ObjectsKdTree3 is configured with a Viewer, and will then automatically
6653
6655
  * keep itself populated with k-d nodes that contain the Viewer's Entitys.
6654
6656
  *
@@ -8577,6 +8579,87 @@ function frustumIntersectsAABB3(frustum, aabb) {
8577
8579
 
8578
8580
  /**
8579
8581
  * Picks a {@link Viewer}'s {@link Entity}s with a canvas-space 2D marquee box.
8582
+ *
8583
+ * [<img src="https://xeokit.github.io/xeokit-sdk/assets/images/MarqueeSelect.gif">](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)
8584
+ *
8585
+ * * [[Example 1: Select Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)]
8586
+ * * [[Example 2: View-Fit Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_viewFit)]
8587
+ *
8588
+ * # Usage
8589
+ *
8590
+ * In the example below, we
8591
+ *
8592
+ * 1. Create a {@link Viewer}, arrange the {@link Camera}
8593
+ * 2. Use an {@link XKTLoaderPlugin} to load a BIM model,
8594
+ * 3. Create a {@link ObjectsKdTree3} to automatically index the `Viewer's` {@link Entity}s for fast spatial lookup,
8595
+ * 4. Create a `MarqueePicker` to pick {@link Entity}s in the {@link Viewer}, using the {@link ObjectsKdTree3} to accelerate picking
8596
+ * 5. Create a {@link MarqueePickerMouseControl} to perform the marquee-picking with the `MarqueePicker`, using mouse input to draw the marquee box on the `Viewer's` canvas.
8597
+ *
8598
+ * When the {@link MarqueePickerMouseControl} is active:
8599
+ *
8600
+ * * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
8601
+ * * Drag left-to-right to pick {@link Entity}s that intersect the box.
8602
+ * * Drag right-to-left to pick {@link Entity}s that are fully inside the box.
8603
+ * * On release, the `MarqueePicker` will fire a "picked" event with IDs of the picked {@link Entity}s, if any.
8604
+ * * Handling that event, we mark the {@link Entity}s as selected.
8605
+ * * Hold down CTRL to multi-pick.
8606
+ *
8607
+ * ````javascript
8608
+ * import {
8609
+ * Viewer,
8610
+ * XKTLoaderPlugin,
8611
+ * ObjectsKdTree3,
8612
+ * MarqueePicker,
8613
+ * MarqueePickerMouseControl
8614
+ * } from "xeokit-sdk.es.js";
8615
+ *
8616
+ * // 1
8617
+ *
8618
+ * const viewer = new Viewer({
8619
+ * canvasId: "myCanvas"
8620
+ * });
8621
+ *
8622
+ * viewer.scene.camera.eye = [14.9, 14.3, 5.4];
8623
+ * viewer.scene.camera.look = [6.5, 8.3, -4.1];
8624
+ * viewer.scene.camera.up = [-0.28, 0.9, -0.3];
8625
+ *
8626
+ * // 2
8627
+ *
8628
+ * const xktLoader = new XKTLoaderPlugin(viewer);
8629
+ *
8630
+ * const sceneModel = xktLoader.load({
8631
+ * id: "myModel",
8632
+ * src: "../../assets/models/xkt/v8/ifc/HolterTower.ifc.xkt"
8633
+ * });
8634
+ *
8635
+ * // 3
8636
+ *
8637
+ * const objectsKdTree3 = new ObjectsKdTree3({viewer});
8638
+ *
8639
+ * // 4
8640
+ *
8641
+ * const marqueePicker = new MarqueePicker({viewer, objectsKdTree3});
8642
+ *
8643
+ * // 5
8644
+ *
8645
+ * const marqueePickerMouseControl = new MarqueePickerMouseControl({marqueePicker});
8646
+ *
8647
+ * marqueePicker.on("clear", () => {
8648
+ * viewer.scene.setObjectsSelected(viewer.scene.selectedObjectIds, false);
8649
+ * });
8650
+ *
8651
+ * marqueePicker.on("picked", (objectIds) => {
8652
+ * viewer.scene.setObjectsSelected(objectIds, true);
8653
+ * });
8654
+ *
8655
+ * marqueePickerMouseControl.setActive(true);
8656
+ * ````
8657
+ *
8658
+ * # Design Notes
8659
+ *
8660
+ * * The {@link ObjectsKdTree3} can be shared with any other components that want to use it to spatially search for {@link Entity}s.
8661
+ * * The {@link MarqueePickerMouseControl} can be replaced with other types of controllers (i.e. touch), or used alongside them.
8662
+ * * The `MarqueePicker` has no input handlers of its own, and provides an API through which to programmatically control marquee picking. By firing the "picked" events, `MarqueePicker` implements the *Blackboard Pattern*.
8580
8663
  */
8581
8664
  class MarqueePicker extends Component {
8582
8665
 
@@ -8846,6 +8929,8 @@ MarqueePicker.PICK_MODE_INSIDE = 1;
8846
8929
  /**
8847
8930
  * Controls a {@link MarqueePicker} with mouse input.
8848
8931
  *
8932
+ * See {@link MarqueePicker} for usage example.
8933
+ *
8849
8934
  * When the MarqueePickerMouseControl is active:
8850
8935
  *
8851
8936
  * * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
@@ -11924,8 +12009,8 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
11924
12009
  if (event.snappedToVertex || event.snappedToEdge) {
11925
12010
  if (pointerLens) {
11926
12011
  pointerLens.visible = true;
11927
- pointerLens.centerPos = event.cursorPos || event.canvasPos;
11928
- pointerLens.cursorPos = event.canvasPos;
12012
+ pointerLens.canvasPos = event.canvasPos;
12013
+ pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
11929
12014
  pointerLens.snapped = true;
11930
12015
  }
11931
12016
  this.markerDiv.style.background = "greenyellow";
@@ -11933,21 +12018,22 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
11933
12018
  } else {
11934
12019
  if (pointerLens) {
11935
12020
  pointerLens.visible = true;
11936
- pointerLens.centerPos = event.cursorPos || event.canvasPos;
11937
- pointerLens.cursorPos = event.canvasPos;
12021
+ pointerLens.canvasPos = event.canvasPos;
12022
+ pointerLens.snappedCanvasPos = event.canvasPos;
11938
12023
  pointerLens.snapped = false;
11939
12024
  }
11940
12025
  this.markerDiv.style.background = "pink";
11941
12026
  this.markerDiv.style.border = "2px solid red";
11942
12027
  }
12028
+ const canvasPos = event.snappedCanvasPos || event.canvasPos;
11943
12029
  mouseHovering = true;
11944
12030
  mouseHoverEntity = event.entity;
11945
12031
  mouseWorldPos.set(event.worldPos);
11946
- mouseHoverCanvasPos.set(event.canvasPos);
12032
+ mouseHoverCanvasPos.set(canvasPos);
11947
12033
  switch (this._mouseState) {
11948
12034
  case MOUSE_FINDING_ORIGIN:
11949
- this.markerDiv.style.marginLeft = `${event.canvasPos[0] - 5}px`;
11950
- this.markerDiv.style.marginTop = `${event.canvasPos[1] - 5}px`;
12035
+ this.markerDiv.style.marginLeft = `${canvasPos[0] - 5}px`;
12036
+ this.markerDiv.style.marginTop = `${canvasPos[1] - 5}px`;
11951
12037
  break;
11952
12038
  case MOUSE_FINDING_CORNER:
11953
12039
  if (this._currentAngleMeasurement) {
@@ -12063,8 +12149,8 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12063
12149
  mouseHovering = false;
12064
12150
  if (pointerLens) {
12065
12151
  pointerLens.visible = true;
12066
- pointerLens.centerPos = event.cursorPos;
12067
- pointerLens.cursorPos = event.cursorPos;
12152
+ pointerLens.pointerPos = event.canvasPos;
12153
+ pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
12068
12154
  pointerLens.snapped = false;
12069
12155
  }
12070
12156
  this.markerDiv.style.marginLeft = `-100px`;
@@ -14704,13 +14790,14 @@ class PickResult {
14704
14790
  */
14705
14791
  this.snappedToVertex = false;
14706
14792
 
14707
- this._canvasPos = new Int16Array([0, 0]);
14708
14793
  this._origin = new Float64Array([0, 0, 0]);
14709
14794
  this._direction = new Float64Array([0, 0, 0]);
14710
14795
  this._indices = new Int32Array(3);
14711
14796
  this._localPos = new Float64Array([0, 0, 0]);
14712
14797
  this._worldPos = new Float64Array([0, 0, 0]);
14713
14798
  this._viewPos = new Float64Array([0, 0, 0]);
14799
+ this._canvasPos = new Int16Array([0, 0]);
14800
+ this._snappedCanvasPos = new Int16Array([0, 0]);
14714
14801
  this._bary = new Float64Array([0, 0, 0]);
14715
14802
  this._worldNormal = new Float64Array([0, 0, 0]);
14716
14803
  this._uv = new Float64Array([0, 0]);
@@ -14719,7 +14806,7 @@ class PickResult {
14719
14806
  }
14720
14807
 
14721
14808
  /**
14722
- * Canvas coordinates when picking with a 2D pointer.
14809
+ * Canvas pick coordinates.
14723
14810
  * @property canvasPos
14724
14811
  * @type {Number[]}
14725
14812
  */
@@ -14837,6 +14924,29 @@ class PickResult {
14837
14924
  }
14838
14925
  }
14839
14926
 
14927
+ /**
14928
+ * Canvas cursor coordinates, snapped when snap picking, otherwise same as {@link PickResult#pointerPos}.
14929
+ * @property snappedCanvasPos
14930
+ * @type {Number[]}
14931
+ */
14932
+ get snappedCanvasPos() {
14933
+ return this._gotSnappedCanvasPos ? this._snappedCanvasPos : null;
14934
+ }
14935
+
14936
+ /**
14937
+ * @private
14938
+ * @param value
14939
+ */
14940
+ set snappedCanvasPos(value) {
14941
+ if (value) {
14942
+ this._snappedCanvasPos[0] = value[0];
14943
+ this._snappedCanvasPos[1] = value[1];
14944
+ this._gotSnappedCanvasPos = true;
14945
+ } else {
14946
+ this._gotSnappedCanvasPos = false;
14947
+ }
14948
+ }
14949
+
14840
14950
  /**
14841
14951
  * Picked World-space point.
14842
14952
  * @property worldPos
@@ -14965,6 +15075,7 @@ class PickResult {
14965
15075
  this.primitive = null;
14966
15076
  this.pickSurfacePrecision = false;
14967
15077
  this._gotCanvasPos = false;
15078
+ this._gotSnappedCanvasPos = false;
14968
15079
  this._gotOrigin = false;
14969
15080
  this._gotDirection = false;
14970
15081
  this._gotIndices = false;
@@ -18361,254 +18472,258 @@ const Renderer$1 = function (scene, options) {
18361
18472
  * @param {number} [snapRadiusInPixels=30]
18362
18473
  * @param {boolean} [snapToVertex=true]
18363
18474
  * @param {boolean} [snapToEdge=true]
18364
- *
18365
- * @returns {{worldPos:number[],snappedWorldPos:null|number[],snappedCanvasPos:null|number[], snapType:null|"vertex"|"edge"}}
18475
+ * @param pickResult
18476
+ * @returns {PickResult}
18366
18477
  */
18367
- this.snapPick = function (canvasPos, snapRadiusInPixels = 30, snapToVertex = true, snapToEdge = true) {
18478
+ this.snapPick = (function () {
18368
18479
 
18369
- if (!snapToVertex && !snapToEdge) {
18370
- return this.pick({canvasPos, pickSurface: true});
18371
- }
18480
+ const _pickResult = new PickResult();
18372
18481
 
18373
- const resolutionScale = scene.canvas.resolutionScale;
18482
+ return function (canvasPos, snapRadiusInPixels, snapToVertex, snapToEdge, pickResult = _pickResult) {
18374
18483
 
18375
- frameCtx.reset();
18376
- frameCtx.backfaces = true;
18377
- frameCtx.frontface = true; // "ccw"
18378
- frameCtx.pickZNear = scene.camera.project.near;
18379
- frameCtx.pickZFar = scene.camera.project.far;
18380
-
18381
- const vertexPickBuffer = renderBufferManager.getRenderBuffer("uniquePickColors-aabs", {
18382
- depthTexture: true,
18383
- size: [
18384
- 2 * snapRadiusInPixels + 1,
18385
- 2 * snapRadiusInPixels + 1,
18386
- ]
18387
- });
18484
+ if (!snapToVertex && !snapToEdge) {
18485
+ return this.pick({canvasPos, pickSurface: true});
18486
+ }
18388
18487
 
18389
- frameCtx.snapVectorA = [
18390
- getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
18391
- getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
18392
- ];
18488
+ const resolutionScale = scene.canvas.resolutionScale;
18393
18489
 
18394
- frameCtx.snapInvVectorAB = [
18395
- gl.drawingBufferWidth / (2 * snapRadiusInPixels),
18396
- gl.drawingBufferHeight / (2 * snapRadiusInPixels),
18397
- ];
18490
+ frameCtx.reset();
18491
+ frameCtx.backfaces = true;
18492
+ frameCtx.frontface = true; // "ccw"
18493
+ frameCtx.pickZNear = scene.camera.project.near;
18494
+ frameCtx.pickZFar = scene.camera.project.far;
18398
18495
 
18399
- // Bind and clear the snap render target
18496
+ snapRadiusInPixels = snapRadiusInPixels || 30;
18400
18497
 
18401
- vertexPickBuffer.bind(gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI);
18402
- gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
18403
- gl.enable(gl.DEPTH_TEST);
18404
- gl.frontFace(gl.CCW);
18405
- gl.disable(gl.CULL_FACE);
18406
- gl.depthMask(true);
18407
- gl.disable(gl.BLEND);
18408
- gl.depthFunc(gl.LEQUAL);
18409
- gl.clear(gl.DEPTH_BUFFER_BIT);
18410
- gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
18411
- gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
18412
- gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
18498
+ const vertexPickBuffer = renderBufferManager.getRenderBuffer("uniquePickColors-aabs", {
18499
+ depthTexture: true,
18500
+ size: [
18501
+ 2 * snapRadiusInPixels + 1,
18502
+ 2 * snapRadiusInPixels + 1,
18503
+ ]
18504
+ });
18413
18505
 
18414
- //////////////////////////////////
18415
- // Set view and proj mats for VBO renderers
18416
- ///////////////////////////////////////
18506
+ frameCtx.snapVectorA = [
18507
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
18508
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
18509
+ ];
18417
18510
 
18418
- const pickViewMatrix = scene.camera.viewMatrix;
18419
- const pickProjMatrix = scene.camera.projMatrix;
18511
+ frameCtx.snapInvVectorAB = [
18512
+ gl.drawingBufferWidth / (2 * snapRadiusInPixels),
18513
+ gl.drawingBufferHeight / (2 * snapRadiusInPixels),
18514
+ ];
18420
18515
 
18421
- for (let type in drawableTypeInfo) {
18422
- if (drawableTypeInfo.hasOwnProperty(type)) {
18423
- const drawableList = drawableTypeInfo[type].drawableList;
18424
- for (let i = 0, len = drawableList.length; i < len; i++) {
18425
- const drawable = drawableList[i];
18426
- if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
18427
- drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
18516
+ // Bind and clear the snap render target
18517
+
18518
+ vertexPickBuffer.bind(gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI);
18519
+ gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
18520
+ gl.enable(gl.DEPTH_TEST);
18521
+ gl.frontFace(gl.CCW);
18522
+ gl.disable(gl.CULL_FACE);
18523
+ gl.depthMask(true);
18524
+ gl.disable(gl.BLEND);
18525
+ gl.depthFunc(gl.LEQUAL);
18526
+ gl.clear(gl.DEPTH_BUFFER_BIT);
18527
+ gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
18528
+ gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
18529
+ gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
18530
+
18531
+ //////////////////////////////////
18532
+ // Set view and proj mats for VBO renderers
18533
+ ///////////////////////////////////////
18534
+
18535
+ const pickViewMatrix = scene.camera.viewMatrix;
18536
+ const pickProjMatrix = scene.camera.projMatrix;
18537
+
18538
+ for (let type in drawableTypeInfo) {
18539
+ if (drawableTypeInfo.hasOwnProperty(type)) {
18540
+ const drawableList = drawableTypeInfo[type].drawableList;
18541
+ for (let i = 0, len = drawableList.length; i < len; i++) {
18542
+ const drawable = drawableList[i];
18543
+ if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
18544
+ drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
18545
+ }
18428
18546
  }
18429
18547
  }
18430
18548
  }
18431
- }
18432
18549
 
18433
- // a) init z-buffer
18434
- gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
18435
- const layerParamsSurface = snapInitDepthBuf(frameCtx);
18550
+ // a) init z-buffer
18551
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
18552
+ const layerParamsSurface = snapInitDepthBuf(frameCtx);
18436
18553
 
18437
- // b) snap-pick
18438
- const layerParamsSnap = [];
18439
- frameCtx.snapPickLayerParams = layerParamsSnap;
18554
+ // b) snap-pick
18555
+ const layerParamsSnap = [];
18556
+ frameCtx.snapPickLayerParams = layerParamsSnap;
18440
18557
 
18441
- gl.depthMask(false);
18442
- gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
18558
+ gl.depthMask(false);
18559
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
18443
18560
 
18444
- if (snapToVertex && snapToEdge) {
18445
- frameCtx.snapMode = "edge";
18446
- snapPickDrawSnapDepths(frameCtx);
18561
+ if (snapToVertex && snapToEdge) {
18562
+ frameCtx.snapMode = "edge";
18563
+ snapPickDrawSnapDepths(frameCtx);
18447
18564
 
18448
- frameCtx.snapMode = "vertex";
18449
- frameCtx.snapPickLayerNumber++;
18565
+ frameCtx.snapMode = "vertex";
18566
+ frameCtx.snapPickLayerNumber++;
18450
18567
 
18451
- snapPickDrawSnapDepths(frameCtx);
18452
- } else {
18453
- frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
18568
+ snapPickDrawSnapDepths(frameCtx);
18569
+ } else {
18570
+ frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
18454
18571
 
18455
- snapPickDrawSnapDepths(frameCtx);
18456
- }
18572
+ snapPickDrawSnapDepths(frameCtx);
18573
+ }
18457
18574
 
18458
- gl.depthMask(true);
18575
+ gl.depthMask(true);
18459
18576
 
18460
- // Read and decode the snapped coordinates
18577
+ // Read and decode the snapped coordinates
18461
18578
 
18462
- const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
18463
- const snapPickNormalResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4, 1);
18464
- const snapPickIdResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.UNSIGNED_INT, Uint32Array, 4, 2);
18579
+ const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
18580
+ const snapPickNormalResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4, 1);
18581
+ const snapPickIdResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.UNSIGNED_INT, Uint32Array, 4, 2);
18465
18582
 
18466
- vertexPickBuffer.unbind();
18583
+ vertexPickBuffer.unbind();
18467
18584
 
18468
- // result 1) regular hi-precision world position
18585
+ // result 1) regular hi-precision world position
18469
18586
 
18470
- let worldPos = null;
18471
- let worldNormal = null;
18587
+ let worldPos = null;
18472
18588
 
18473
- const middleX = snapRadiusInPixels;
18474
- const middleY = snapRadiusInPixels;
18475
- const middleIndex = (middleX * 4) + (middleY * vertexPickBuffer.size[0] * 4);
18476
- const pickResultMiddleXY = snapPickResultArray.slice(middleIndex, middleIndex + 4);
18477
- const pickNormalResultMiddleXY = snapPickNormalResultArray.slice(middleIndex, middleIndex + 4);
18478
- const pickPickableResultMiddleXY = snapPickIdResultArray.slice(middleIndex, middleIndex + 4);
18589
+ const middleX = snapRadiusInPixels;
18590
+ const middleY = snapRadiusInPixels;
18591
+ const middleIndex = (middleX * 4) + (middleY * vertexPickBuffer.size[0] * 4);
18592
+ const pickResultMiddleXY = snapPickResultArray.slice(middleIndex, middleIndex + 4);
18593
+ const pickNormalResultMiddleXY = snapPickNormalResultArray.slice(middleIndex, middleIndex + 4);
18594
+ const pickPickableResultMiddleXY = snapPickIdResultArray.slice(middleIndex, middleIndex + 4);
18479
18595
 
18480
- if (pickResultMiddleXY[3] !== 0) {
18481
- const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
18482
- const origin = pickedLayerParmasSurface.origin;
18483
- const scale = pickedLayerParmasSurface.coordinateScale;
18484
- worldPos = [
18485
- pickResultMiddleXY[0] * scale[0] + origin[0],
18486
- pickResultMiddleXY[1] * scale[1] + origin[1],
18487
- pickResultMiddleXY[2] * scale[2] + origin[2],
18488
- ];
18489
- worldNormal = math.normalizeVec3([
18490
- pickNormalResultMiddleXY[0] / math.MAX_INT,
18491
- pickNormalResultMiddleXY[1] / math.MAX_INT,
18492
- pickNormalResultMiddleXY[2] / math.MAX_INT,
18493
- ]);
18494
-
18495
- const pickID =
18496
- pickPickableResultMiddleXY[0]
18497
- + (pickPickableResultMiddleXY[1] << 8)
18498
- + (pickPickableResultMiddleXY[2] << 16)
18499
- + (pickPickableResultMiddleXY[3] << 24);
18500
-
18501
- pickIDs.items[pickID];
18502
- }
18503
-
18504
- // result 2) hi-precision snapped (to vertex/edge) world position
18505
-
18506
- let snapPickResult = [];
18507
-
18508
- for (let i = 0; i < snapPickResultArray.length; i += 4) {
18509
- if (snapPickResultArray[i + 3] > 0) {
18510
- const pixelNumber = Math.floor(i / 4);
18511
- const w = vertexPickBuffer.size[0];
18512
- const x = pixelNumber % w - Math.floor(w / 2);
18513
- const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
18514
- const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
18515
- snapPickResult.push({
18516
- x,
18517
- y,
18518
- dist,
18519
- isVertex: snapToVertex && snapToEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapToVertex,
18520
- result: [
18521
- snapPickResultArray[i + 0],
18522
- snapPickResultArray[i + 1],
18523
- snapPickResultArray[i + 2],
18524
- snapPickResultArray[i + 3],
18525
- ],
18526
- normal: [
18527
- snapPickNormalResultArray[i + 0],
18528
- snapPickNormalResultArray[i + 1],
18529
- snapPickNormalResultArray[i + 2],
18530
- snapPickNormalResultArray[i + 3],
18531
- ],
18532
- id: [
18533
- snapPickIdResultArray[i + 0],
18534
- snapPickIdResultArray[i + 1],
18535
- snapPickIdResultArray[i + 2],
18536
- snapPickIdResultArray[i + 3],
18537
- ]
18538
- });
18596
+ if (pickResultMiddleXY[3] !== 0) {
18597
+ const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
18598
+ const origin = pickedLayerParmasSurface.origin;
18599
+ const scale = pickedLayerParmasSurface.coordinateScale;
18600
+ worldPos = [
18601
+ pickResultMiddleXY[0] * scale[0] + origin[0],
18602
+ pickResultMiddleXY[1] * scale[1] + origin[1],
18603
+ pickResultMiddleXY[2] * scale[2] + origin[2],
18604
+ ];
18605
+ math.normalizeVec3([
18606
+ pickNormalResultMiddleXY[0] / math.MAX_INT,
18607
+ pickNormalResultMiddleXY[1] / math.MAX_INT,
18608
+ pickNormalResultMiddleXY[2] / math.MAX_INT,
18609
+ ]);
18610
+
18611
+ const pickID =
18612
+ pickPickableResultMiddleXY[0]
18613
+ + (pickPickableResultMiddleXY[1] << 8)
18614
+ + (pickPickableResultMiddleXY[2] << 16)
18615
+ + (pickPickableResultMiddleXY[3] << 24);
18616
+
18617
+ pickIDs.items[pickID];
18618
+ }
18619
+
18620
+ // result 2) hi-precision snapped (to vertex/edge) world position
18621
+
18622
+ let snapPickResult = [];
18623
+
18624
+ for (let i = 0; i < snapPickResultArray.length; i += 4) {
18625
+ if (snapPickResultArray[i + 3] > 0) {
18626
+ const pixelNumber = Math.floor(i / 4);
18627
+ const w = vertexPickBuffer.size[0];
18628
+ const x = pixelNumber % w - Math.floor(w / 2);
18629
+ const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
18630
+ const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
18631
+ snapPickResult.push({
18632
+ x,
18633
+ y,
18634
+ dist,
18635
+ isVertex: snapToVertex && snapToEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapToVertex,
18636
+ result: [
18637
+ snapPickResultArray[i + 0],
18638
+ snapPickResultArray[i + 1],
18639
+ snapPickResultArray[i + 2],
18640
+ snapPickResultArray[i + 3],
18641
+ ],
18642
+ normal: [
18643
+ snapPickNormalResultArray[i + 0],
18644
+ snapPickNormalResultArray[i + 1],
18645
+ snapPickNormalResultArray[i + 2],
18646
+ snapPickNormalResultArray[i + 3],
18647
+ ],
18648
+ id: [
18649
+ snapPickIdResultArray[i + 0],
18650
+ snapPickIdResultArray[i + 1],
18651
+ snapPickIdResultArray[i + 2],
18652
+ snapPickIdResultArray[i + 3],
18653
+ ]
18654
+ });
18655
+ }
18539
18656
  }
18540
- }
18541
18657
 
18542
- let snappedWorldPos = null;
18543
- let snappedWorldNormal = null;
18544
- let snappedPickable = null;
18545
- let snapType = null;
18658
+ let snappedWorldPos = null;
18659
+ let snappedWorldNormal = null;
18660
+ let snappedPickable = null;
18661
+ let snapType = null;
18546
18662
 
18547
- if (snapPickResult.length > 0) {
18548
- // vertex snap first, then edge snap
18549
- snapPickResult.sort((a, b) => {
18550
- if (a.isVertex !== b.isVertex) {
18551
- return a.isVertex ? -1 : 1;
18552
- } else {
18553
- return a.dist - b.dist;
18554
- }
18555
- });
18663
+ if (snapPickResult.length > 0) {
18664
+ // vertex snap first, then edge snap
18665
+ snapPickResult.sort((a, b) => {
18666
+ if (a.isVertex !== b.isVertex) {
18667
+ return a.isVertex ? -1 : 1;
18668
+ } else {
18669
+ return a.dist - b.dist;
18670
+ }
18671
+ });
18556
18672
 
18557
- snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
18558
- const snapPick = snapPickResult[0].result;
18559
- const snapPickNormal = snapPickResult[0].normal;
18560
- const snapPickId = snapPickResult[0].id;
18673
+ snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
18674
+ const snapPick = snapPickResult[0].result;
18675
+ const snapPickNormal = snapPickResult[0].normal;
18676
+ const snapPickId = snapPickResult[0].id;
18561
18677
 
18562
- const pickedLayerParmas = layerParamsSnap[snapPick[3]];
18678
+ const pickedLayerParmas = layerParamsSnap[snapPick[3]];
18563
18679
 
18564
- const origin = pickedLayerParmas.origin;
18565
- const scale = pickedLayerParmas.coordinateScale;
18680
+ const origin = pickedLayerParmas.origin;
18681
+ const scale = pickedLayerParmas.coordinateScale;
18566
18682
 
18567
- snappedWorldNormal = math.normalizeVec3([
18568
- snapPickNormal[0] / math.MAX_INT,
18569
- snapPickNormal[1] / math.MAX_INT,
18570
- snapPickNormal[2] / math.MAX_INT,
18571
- ]);
18683
+ snappedWorldNormal = math.normalizeVec3([
18684
+ snapPickNormal[0] / math.MAX_INT,
18685
+ snapPickNormal[1] / math.MAX_INT,
18686
+ snapPickNormal[2] / math.MAX_INT,
18687
+ ]);
18572
18688
 
18573
- snappedWorldPos = [
18574
- snapPick[0] * scale[0] + origin[0],
18575
- snapPick[1] * scale[1] + origin[1],
18576
- snapPick[2] * scale[2] + origin[2],
18577
- ];
18689
+ snappedWorldPos = [
18690
+ snapPick[0] * scale[0] + origin[0],
18691
+ snapPick[1] * scale[1] + origin[1],
18692
+ snapPick[2] * scale[2] + origin[2],
18693
+ ];
18578
18694
 
18579
- snappedPickable = pickIDs.items[
18695
+ snappedPickable = pickIDs.items[
18580
18696
  snapPickId[0]
18581
18697
  + (snapPickId[1] << 8)
18582
18698
  + (snapPickId[2] << 16)
18583
18699
  + (snapPickId[3] << 24)
18584
- ];
18585
- }
18700
+ ];
18701
+ }
18586
18702
 
18587
- if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
18588
- return null;
18589
- }
18703
+ if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
18704
+ return null;
18705
+ }
18590
18706
 
18591
- let snappedCanvasPos = null;
18707
+ let snappedCanvasPos = null;
18592
18708
 
18593
- if (null !== snappedWorldPos) {
18594
- snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
18595
- }
18709
+ if (null !== snappedWorldPos) {
18710
+ snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
18711
+ }
18596
18712
 
18597
- const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
18713
+ const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
18598
18714
 
18599
- return {
18600
- snapType,
18601
- snappedToVertex: snapType === "vertex",
18602
- snappedToEdge: snapType === "edge",
18603
- worldPos,
18604
- worldNormal,
18605
- snappedWorldPos,
18606
- snappedWorldNormal,
18607
- snappedCanvasPos,
18608
- snappedEntity,
18609
- entity: snappedEntity
18715
+ pickResult.reset();
18716
+ pickResult.snappedToEdge = (snapType === "edge");
18717
+ pickResult.snappedToVertex = (snapType === "vertex");
18718
+ pickResult.worldPos = snappedWorldPos;
18719
+ pickResult.worldNormal = snappedWorldNormal;
18720
+ pickResult.entity = snappedEntity;
18721
+ pickResult.canvasPos = canvasPos;
18722
+ pickResult.snappedCanvasPos = snappedCanvasPos || canvasPos;
18723
+
18724
+ return pickResult;
18610
18725
  };
18611
- };
18726
+ })();
18612
18727
 
18613
18728
  function unpackDepth(depthZ) {
18614
18729
  const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];
@@ -20014,23 +20129,31 @@ class Input extends Component {
20014
20129
  }
20015
20130
  });
20016
20131
 
20132
+ const tickifedMouseMoveFn = this.scene.tickify(
20133
+ () => this.fire("mousemove", this.mouseCanvasPos, true)
20134
+ );
20135
+
20017
20136
  this.element.addEventListener("mousemove", this._mouseMoveListener = (e) => {
20018
20137
  if (!this.enabled) {
20019
20138
  return;
20020
20139
  }
20021
20140
  this._getMouseCanvasPos(e);
20022
- this.fire("mousemove", this.mouseCanvasPos, true);
20141
+ tickifedMouseMoveFn();
20023
20142
  if (this.mouseover) {
20024
20143
  e.preventDefault();
20025
20144
  }
20026
20145
  });
20027
20146
 
20147
+ const tickifiedMouseWheelFn = this.scene.tickify(
20148
+ (delta) => { this.fire("mousewheel", delta, true); }
20149
+ );
20150
+
20028
20151
  this.element.addEventListener("wheel", this._mouseWheelListener = (e, d) => {
20029
20152
  if (!this.enabled) {
20030
20153
  return;
20031
20154
  }
20032
20155
  const delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
20033
- this.fire("mousewheel", delta, true);
20156
+ tickifiedMouseWheelFn(delta);
20034
20157
  }, {passive: true});
20035
20158
 
20036
20159
  // mouseclicked
@@ -27854,6 +27977,11 @@ class Scene extends Component {
27854
27977
  throw "Mandatory config expected: valid canvasId or canvasElement";
27855
27978
  }
27856
27979
 
27980
+ /**
27981
+ * @type {{[key: string]: {wrapperFunc: Function, tickSubId: string}}}
27982
+ */
27983
+ this._tickifiedFunctions = {};
27984
+
27857
27985
  const transparent = (!!cfg.transparent);
27858
27986
  const alphaDepthMask = (!!cfg.alphaDepthMask);
27859
27987
 
@@ -29603,6 +29731,9 @@ class Scene extends Component {
29603
29731
  * @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
29604
29732
  * @param {String[]} [params.includeEntities] IDs of {@link Entity}s to restrict picking to. When given, ignores {@link Entity}s whose IDs are not in this list.
29605
29733
  * @param {String[]} [params.excludeEntities] IDs of {@link Entity}s to ignore. When given, will pick *through* these {@link Entity}s, as if they were not there.
29734
+ * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
29735
+ * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
29736
+ * @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
29606
29737
  * @param {PickResult} [pickResult] Holds the results of the pick attempt. Will use the Scene's singleton PickResult if you don't supply your own.
29607
29738
  * @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
29608
29739
  */
@@ -29637,14 +29768,25 @@ class Scene extends Component {
29637
29768
  this._needRecompile = false;
29638
29769
  }
29639
29770
 
29640
- pickResult = this._renderer.pick(params, pickResult);
29771
+ if (params.snapToEdge || params.snapToVertex) {
29772
+ pickResult = this._renderer.snapPick(
29773
+ params.canvasPos,
29774
+ params.snapRadius || 30,
29775
+ params.snapToVertex,
29776
+ params.snapToEdge,
29777
+ pickResult
29778
+ );
29779
+ } else {
29780
+ pickResult = this._renderer.pick(params, pickResult);
29781
+ }
29641
29782
 
29642
29783
  if (pickResult) {
29643
29784
  if (pickResult.entity && pickResult.entity.fire) {
29644
- pickResult.entity.fire("picked", pickResult); // TODO: PerformanceModelNode doesn't fire events
29785
+ pickResult.entity.fire("picked", pickResult); // TODO: SceneModelEntity doesn't fire events
29645
29786
  }
29646
- return pickResult;
29647
29787
  }
29788
+
29789
+ return pickResult;
29648
29790
  }
29649
29791
 
29650
29792
  /**
@@ -29653,8 +29795,13 @@ class Scene extends Component {
29653
29795
  * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
29654
29796
  * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
29655
29797
  * @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
29798
+ * @deprecated
29656
29799
  */
29657
29800
  snapPick(params) {
29801
+ if (undefined === this._warnSnapPickDeprecated) {
29802
+ this._warnSnapPickDeprecated = true;
29803
+ this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead");
29804
+ }
29658
29805
  return this._renderer.snapPick(
29659
29806
  params.canvasPos,
29660
29807
  params.snapRadius || 30,
@@ -30016,6 +30163,63 @@ class Scene extends Component {
30016
30163
  return changed;
30017
30164
  }
30018
30165
 
30166
+ /**
30167
+ * This method will "tickify" the provided `cb` function.
30168
+ *
30169
+ * This means, the function will be wrapped so:
30170
+ *
30171
+ * - it runs time-aligned to scene ticks
30172
+ * - it runs maximum once per scene-tick
30173
+ *
30174
+ * @param {Function} cb The function to tickify
30175
+ * @returns {Function)}
30176
+ */
30177
+ tickify(cb) {
30178
+ const cbString = cb.toString();
30179
+
30180
+ /**
30181
+ * Check if the function is already tickified, and if so return the cached one.
30182
+ */
30183
+ if (cbString in this._tickifiedFunctions) {
30184
+ return this._tickifiedFunctions[cbString].wrapperFunc;
30185
+ }
30186
+
30187
+ let alreadyRun = 0;
30188
+ let needToRun = 0;
30189
+
30190
+ let lastArgs;
30191
+
30192
+ /**
30193
+ * The provided `cb` function is replaced with a "set-dirty" function
30194
+ *
30195
+ * @type {Function}
30196
+ */
30197
+ const wrapperFunc = function (...args) {
30198
+ lastArgs = args;
30199
+ needToRun++;
30200
+ };
30201
+
30202
+ /**
30203
+ * An each scene tick, if the "dirty-flag" is set, run the `cb` function.
30204
+ *
30205
+ * This will make it run time-aligned to the scene tick.
30206
+ */
30207
+ const tickSubId = this.on("tick", () => {
30208
+ const tmp = needToRun;
30209
+ if (tmp > alreadyRun) {
30210
+ alreadyRun = tmp;
30211
+ cb(...lastArgs);
30212
+ }
30213
+ });
30214
+
30215
+ /**
30216
+ * And, store the list of subscribers.
30217
+ */
30218
+ this._tickifiedFunctions[cbString] = { tickSubId, wrapperFunc };
30219
+
30220
+ return wrapperFunc;
30221
+ }
30222
+
30019
30223
  /**
30020
30224
  * Destroys this Scene.
30021
30225
  */
@@ -49770,18 +49974,19 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
49770
49974
  this._snapping
49771
49975
  ? "hoverSnapOrSurface"
49772
49976
  : "hoverSurface", event => {
49977
+ const canvasPos = event.snappedCanvasPos || event.canvasPos;
49773
49978
  mouseHovering = true;
49774
49979
  pointerWorldPos.set(event.worldPos);
49775
49980
  pointerCanvasPos.set(event.canvasPos);
49776
49981
  if (this._mouseState === MOUSE_FIRST_CLICK_EXPECTED) {
49777
- this._markerDiv.style.marginLeft = `${event.canvasPos[0] - 5}px`;
49778
- this._markerDiv.style.marginTop = `${event.canvasPos[1] - 5}px`;
49982
+ this._markerDiv.style.marginLeft = `${canvasPos[0] - 5}px`;
49983
+ this._markerDiv.style.marginTop = `${canvasPos[1] - 5}px`;
49779
49984
  this._markerDiv.style.background = "pink";
49780
49985
  if (event.snappedToVertex || event.snappedToEdge) {
49781
49986
  if (this.pointerLens) {
49782
49987
  this.pointerLens.visible = true;
49783
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
49784
- this.pointerLens.cursorPos = event.canvasPos;
49988
+ this.pointerLens.canvasPos = event.canvasPos;
49989
+ this.pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
49785
49990
  this.pointerLens.snapped = true;
49786
49991
  }
49787
49992
  this._markerDiv.style.background = "greenyellow";
@@ -49789,8 +49994,8 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
49789
49994
  } else {
49790
49995
  if (this.pointerLens) {
49791
49996
  this.pointerLens.visible = true;
49792
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
49793
- this.pointerLens.cursorPos = event.canvasPos;
49997
+ this.pointerLens.canvasPos = event.canvasPos;
49998
+ this.pointerLens.snappedCanvasPos = event.canvasPos;
49794
49999
  this.pointerLens.snapped = false;
49795
50000
  }
49796
50001
  this._markerDiv.style.background = "pink";
@@ -49872,8 +50077,8 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
49872
50077
  : "hoverOff", event => {
49873
50078
  if (this.pointerLens) {
49874
50079
  this.pointerLens.visible = true;
49875
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
49876
- this.pointerLens.cursorPos = event.canvasPos;
50080
+ this.pointerLens.canvasPos = event.canvasPos;
50081
+ this.pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
49877
50082
  }
49878
50083
  mouseHovering = false;
49879
50084
  this._markerDiv.style.marginLeft = `-100px`;
@@ -87283,29 +87488,12 @@ class PickController {
87283
87488
  this._lastPickedEntityId = null;
87284
87489
 
87285
87490
  this._needFireEvents = 0;
87286
-
87287
- this._needToUpdate = false;
87288
-
87289
- this._tickSub = this._scene.on("tick", () => {
87290
- this.runUpdate();
87291
- });
87292
- }
87293
-
87294
- update() {
87295
- this._needToUpdate = true;
87296
87491
  }
87297
87492
 
87298
87493
  /**
87299
87494
  * Immediately attempts a pick, if scheduled.
87300
87495
  */
87301
- runUpdate() {
87302
-
87303
- if (!this._needToUpdate) {
87304
- return;
87305
- }
87306
-
87307
- this._needToUpdate = false;
87308
-
87496
+ update() {
87309
87497
  if (!this._configs.pointerEnabled) {
87310
87498
  return;
87311
87499
  }
@@ -87322,13 +87510,13 @@ class PickController {
87322
87510
  const hasHoverSurfaceSubs = this._cameraControl.hasSubs("hoverSurface");
87323
87511
 
87324
87512
  if (this.scheduleSnapOrPick) {
87325
- const snapPickResult = this._scene.snapPick({
87513
+ const snapPickResult = this._scene.pick({
87326
87514
  canvasPos: this.pickCursorPos,
87327
87515
  snapRadius: this._configs.snapRadius,
87328
87516
  snapToVertex: this._configs.snapToVertex,
87329
87517
  snapToEdge: this._configs.snapToEdge,
87330
87518
  });
87331
- if (snapPickResult && snapPickResult.snappedWorldPos) {
87519
+ if (snapPickResult && (snapPickResult.snappedToEdge || snapPickResult.snappedToVertex)) {
87332
87520
  this.snapPickResult = snapPickResult;
87333
87521
  this.snappedOrPicked = true;
87334
87522
  this._needFireEvents++;
@@ -87410,14 +87598,14 @@ class PickController {
87410
87598
 
87411
87599
  fireEvents() {
87412
87600
 
87413
- if (this._needFireEvents == 0) {
87601
+ if (this._needFireEvents === 0) {
87414
87602
  return;
87415
87603
  }
87416
87604
 
87417
87605
  if (this.hoveredSnappedOrSurfaceOff) {
87418
87606
  this._cameraControl.fire("hoverSnapOrSurfaceOff", {
87419
87607
  canvasPos: this.pickCursorPos,
87420
- cursorPos : this.pickCursorPos
87608
+ pointerPos : this.pickCursorPos
87421
87609
  }, true);
87422
87610
  }
87423
87611
 
@@ -87426,9 +87614,9 @@ class PickController {
87426
87614
  const pickResult = new PickResult();
87427
87615
  pickResult.snappedToVertex = this.snapPickResult.snappedToVertex;
87428
87616
  pickResult.snappedToEdge = this.snapPickResult.snappedToEdge;
87429
- pickResult.worldPos = this.snapPickResult.snappedWorldPos;
87430
- pickResult.cursorPos = this.pickCursorPos;
87431
- pickResult.canvasPos = this.snapPickResult.snappedCanvasPos;
87617
+ pickResult.worldPos = this.snapPickResult.worldPos;
87618
+ pickResult.canvasPos = this.pickCursorPos;
87619
+ pickResult.snappedCanvasPos = this.snapPickResult.snappedCanvasPos;
87432
87620
  this._cameraControl.fire("hoverSnapOrSurface", pickResult, true);
87433
87621
  this.snapPickResult = null;
87434
87622
  } else {
@@ -87480,10 +87668,6 @@ class PickController {
87480
87668
 
87481
87669
  this._needFireEvents = 0;
87482
87670
  }
87483
-
87484
- destroy() {
87485
- this._scene.off(this._tickSub);
87486
- }
87487
87671
  }
87488
87672
 
87489
87673
  /**
@@ -87978,75 +88162,78 @@ class MousePickHandler {
87978
88162
  }
87979
88163
  };
87980
88164
 
87981
- canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => {
88165
+ const tickifiedMouseMoveFn = scene.tickify (
88166
+ this._canvasMouseMoveHandler = (e) => {
88167
+ if (!(configs.active && configs.pointerEnabled)) {
88168
+ return;
88169
+ }
87982
88170
 
87983
- if (!(configs.active && configs.pointerEnabled)) {
87984
- return;
87985
- }
88171
+ if (leftDown || rightDown) {
88172
+ return;
88173
+ }
87986
88174
 
87987
- if (leftDown || rightDown) {
87988
- return;
87989
- }
88175
+ const hoverSubs = cameraControl.hasSubs("hover");
88176
+ const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
88177
+ const hoverOutSubs = cameraControl.hasSubs("hoverOut");
88178
+ const hoverOffSubs = cameraControl.hasSubs("hoverOff");
88179
+ const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
88180
+ const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
87990
88181
 
87991
- const hoverSubs = cameraControl.hasSubs("hover");
87992
- const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
87993
- const hoverOutSubs = cameraControl.hasSubs("hoverOut");
87994
- const hoverOffSubs = cameraControl.hasSubs("hoverOff");
87995
- const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
87996
- const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
88182
+ if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) {
87997
88183
 
87998
- if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) {
88184
+ pickController.pickCursorPos = states.pointerCanvasPos;
88185
+ pickController.schedulePickEntity = true;
88186
+ pickController.schedulePickSurface = hoverSurfaceSubs;
88187
+ pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs;
87999
88188
 
88000
- pickController.pickCursorPos = states.pointerCanvasPos;
88001
- pickController.schedulePickEntity = true;
88002
- pickController.schedulePickSurface = hoverSurfaceSubs;
88003
- pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs;
88189
+ pickController.update();
88004
88190
 
88005
- pickController.update();
88191
+ if (pickController.pickResult) {
88006
88192
 
88007
- if (pickController.pickResult) {
88193
+ if (pickController.pickResult.entity) {
88194
+ const pickedEntityId = pickController.pickResult.entity.id;
88008
88195
 
88009
- if (pickController.pickResult.entity) {
88010
- const pickedEntityId = pickController.pickResult.entity.id;
88196
+ if (this._lastPickedEntityId !== pickedEntityId) {
88011
88197
 
88012
- if (this._lastPickedEntityId !== pickedEntityId) {
88198
+ if (this._lastPickedEntityId !== undefined) {
88013
88199
 
88014
- if (this._lastPickedEntityId !== undefined) {
88200
+ cameraControl.fire("hoverOut", { // Hovered off an entity
88201
+ entity: scene.objects[this._lastPickedEntityId]
88202
+ }, true);
88203
+ }
88204
+
88205
+ cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity
88015
88206
 
88016
- cameraControl.fire("hoverOut", { // Hovered off an entity
88017
- entity: scene.objects[this._lastPickedEntityId]
88018
- }, true);
88207
+ this._lastPickedEntityId = pickedEntityId;
88019
88208
  }
88209
+ }
88020
88210
 
88021
- cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity
88211
+ cameraControl.fire("hover", pickController.pickResult, true);
88022
88212
 
88023
- this._lastPickedEntityId = pickedEntityId;
88213
+ if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity
88214
+ cameraControl.fire("hoverSurface", pickController.pickResult, true);
88024
88215
  }
88025
- }
88026
88216
 
88027
- cameraControl.fire("hover", pickController.pickResult, true);
88217
+ } else {
88028
88218
 
88029
- if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity
88030
- cameraControl.fire("hoverSurface", pickController.pickResult, true);
88031
- }
88219
+ if (this._lastPickedEntityId !== undefined) {
88032
88220
 
88033
- } else {
88221
+ cameraControl.fire("hoverOut", { // Hovered off an entity
88222
+ entity: scene.objects[this._lastPickedEntityId]
88223
+ }, true);
88034
88224
 
88035
- if (this._lastPickedEntityId !== undefined) {
88225
+ this._lastPickedEntityId = undefined;
88226
+ }
88036
88227
 
88037
- cameraControl.fire("hoverOut", { // Hovered off an entity
88038
- entity: scene.objects[this._lastPickedEntityId]
88228
+ cameraControl.fire("hoverOff", { // Not hovering on any entity
88229
+ canvasPos: pickController.pickCursorPos
88039
88230
  }, true);
88040
-
88041
- this._lastPickedEntityId = undefined;
88042
88231
  }
88043
-
88044
- cameraControl.fire("hoverOff", { // Not hovering on any entity
88045
- canvasPos: pickController.pickCursorPos
88046
- }, true);
88047
88232
  }
88048
88233
  }
88049
- });
88234
+ );
88235
+
88236
+ canvas.addEventListener("mousemove", tickifiedMouseMoveFn);
88050
88237
 
88051
88238
  canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => {
88052
88239