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