Skip to content

Commit 43d0ac9

Browse files
georginahalpernGeorgina Halpern
andauthored
Move arcrotate's multiTouch logic into BasePointerInput (#17453)
This is so that geospatialcamera can use the multitouch logic and not rewrite it Associated with #17451 --------- Co-authored-by: Georgina Halpern <[email protected]>
1 parent 4813496 commit 43d0ac9

File tree

3 files changed

+155
-74
lines changed

3 files changed

+155
-74
lines changed

packages/dev/core/src/Cameras/Inputs/arcRotateCameraPointersInput.ts

Lines changed: 11 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import type { Nullable } from "../../types";
22
import { serialize } from "../../Misc/decorators";
33
import type { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
44
import { CameraInputTypes } from "../../Cameras/cameraInputsManager";
5-
import { BaseCameraPointersInput } from "../../Cameras/Inputs/BaseCameraPointersInput";
5+
import { OrbitCameraPointersInput } from "../../Cameras/Inputs/orbitCameraPointersInput";
66
import type { PointerTouch } from "../../Events/pointerEvents";
77
import type { IPointerEvent } from "../../Events/deviceInputEvents";
88

99
/**
1010
* Manage the pointers inputs to control an arc rotate camera.
1111
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
1212
*/
13-
export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
13+
export class ArcRotateCameraPointersInput extends OrbitCameraPointersInput {
1414
/**
1515
* Defines the camera the input is attached to.
1616
*/
@@ -73,46 +73,25 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
7373
@serialize()
7474
public useNaturalPinchZoom: boolean = false;
7575

76-
/**
77-
* Defines whether zoom (2 fingers pinch) is enabled through multitouch
78-
*/
79-
@serialize()
80-
public pinchZoom: boolean = true;
81-
8276
/**
8377
* Defines the pointer panning sensibility or how fast is the camera moving.
8478
*/
8579
@serialize()
8680
public panningSensibility: number = 1000.0;
8781

88-
/**
89-
* Defines whether panning (2 fingers swipe) is enabled through multitouch.
90-
*/
91-
@serialize()
92-
public multiTouchPanning: boolean = true;
93-
94-
/**
95-
* Defines whether panning is enabled for both pan (2 fingers swipe) and
96-
* zoom (pinch) through multitouch.
97-
*/
98-
@serialize()
99-
public multiTouchPanAndZoom: boolean = true;
100-
10182
/**
10283
* Revers pinch action direction.
10384
*/
10485
public pinchInwards = true;
10586

10687
private _isPanClick: boolean = false;
107-
private _twoFingerActivityCount: number = 0;
108-
private _isPinching: boolean = false;
10988

11089
/**
11190
* Move camera from multi touch panning positions.
11291
* @param previousMultiTouchPanPosition
11392
* @param multiTouchPanPosition
11493
*/
115-
private _computeMultiTouchPanning(previousMultiTouchPanPosition: Nullable<PointerTouch>, multiTouchPanPosition: Nullable<PointerTouch>): void {
94+
protected override _computeMultiTouchPanning(previousMultiTouchPanPosition: Nullable<PointerTouch>, multiTouchPanPosition: Nullable<PointerTouch>): void {
11695
if (this.panningSensibility !== 0 && previousMultiTouchPanPosition && multiTouchPanPosition) {
11796
const moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
11897
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
@@ -122,11 +101,11 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
122101
}
123102

124103
/**
125-
* Move camera from pinch zoom distances.
104+
* Move camera from multitouch (pinch) zoom distances.
126105
* @param previousPinchSquaredDistance
127106
* @param pinchSquaredDistance
128107
*/
129-
private _computePinchZoom(previousPinchSquaredDistance: number, pinchSquaredDistance: number): void {
108+
protected override _computePinchZoom(previousPinchSquaredDistance: number, pinchSquaredDistance: number): void {
130109
const radius = this.camera.radius || ArcRotateCameraPointersInput.MinimumRadiusForPinch;
131110
if (this.useNaturalPinchZoom) {
132111
this.camera.radius = (radius * Math.sqrt(previousPinchSquaredDistance)) / Math.sqrt(pinchSquaredDistance);
@@ -181,48 +160,9 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
181160
previousMultiTouchPanPosition: Nullable<PointerTouch>,
182161
multiTouchPanPosition: Nullable<PointerTouch>
183162
): void {
184-
if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) {
185-
// First time this method is called for new pinch.
186-
// Next time this is called there will be a
187-
// previousPinchSquaredDistance and pinchSquaredDistance to compare.
188-
return;
189-
}
190-
if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) {
191-
// Last time this method is called at the end of a pinch.
192-
return;
193-
}
194-
195-
// Zoom and panning enabled together
196-
if (this.multiTouchPanAndZoom) {
197-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
198-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
199-
200-
// Zoom and panning enabled but only one at a time
201-
} else if (this.multiTouchPanning && this.pinchZoom) {
202-
this._twoFingerActivityCount++;
203-
204-
if (
205-
this._isPinching ||
206-
(this._twoFingerActivityCount < 20 && Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > this.camera.pinchToPanMaxDistance)
207-
) {
208-
// Since pinch has not been active long, assume we intend to zoom.
209-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
210-
211-
// Since we are pinching, remain pinching on next iteration.
212-
this._isPinching = true;
213-
} else {
214-
// Pause between pinch starting and moving implies not a zoom event. Pan instead.
215-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
216-
}
217-
218-
// Panning enabled, zoom disabled
219-
} else if (this.multiTouchPanning) {
220-
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
221-
222-
// Zoom enabled, panning disabled
223-
} else if (this.pinchZoom) {
224-
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
225-
}
163+
this._shouldStartPinchZoom =
164+
this._twoFingerActivityCount < 20 && Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > this.camera.pinchToPanMaxDistance;
165+
super.onMultiTouch(pointA, pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition);
226166
}
227167

228168
/**
@@ -232,6 +172,7 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
232172
*/
233173
public override onButtonDown(evt: IPointerEvent): void {
234174
this._isPanClick = evt.button === this.camera._panningMouseButton;
175+
super.onButtonDown(evt);
235176
}
236177

237178
/**
@@ -240,17 +181,15 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
240181
* @param _evt Defines the event to track
241182
*/
242183
public override onButtonUp(_evt: IPointerEvent): void {
243-
this._twoFingerActivityCount = 0;
244-
this._isPinching = false;
184+
super.onButtonUp(_evt);
245185
}
246186

247187
/**
248188
* Called when window becomes inactive.
249189
*/
250190
public override onLostFocus(): void {
251191
this._isPanClick = false;
252-
this._twoFingerActivityCount = 0;
253-
this._isPinching = false;
192+
super.onLostFocus();
254193
}
255194
}
256195
(<any>CameraInputTypes)["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;

packages/dev/core/src/Cameras/Inputs/geospatialCameraPointersInput.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { PointerTouch } from "../../Events/pointerEvents";
66
import { Plane } from "../../Maths/math.plane";
77
import { TmpVectors, Vector3 } from "../../Maths/math.vector";
88
import type { Nullable } from "../../types";
9-
import { BaseCameraPointersInput } from "./BaseCameraPointersInput";
9+
import { OrbitCameraPointersInput } from "./orbitCameraPointersInput";
1010

1111
/**
1212
* @experimental
@@ -21,7 +21,7 @@ import { BaseCameraPointersInput } from "./BaseCameraPointersInput";
2121
* Right mouse button: tilt globe around center of screen
2222
*
2323
*/
24-
export class GeospatialCameraPointersInput extends BaseCameraPointersInput {
24+
export class GeospatialCameraPointersInput extends OrbitCameraPointersInput {
2525
public camera: GeospatialCamera;
2626

2727
/**
@@ -81,9 +81,36 @@ export class GeospatialCameraPointersInput extends BaseCameraPointersInput {
8181
}
8282
}
8383

84+
/**
85+
* Move camera from multi touch panning positions.
86+
* In geospatialcamera, multi touch panning tilts the globe (whereas single touch will pan/drag it)
87+
* @param previousMultiTouchPanPosition
88+
* @param multiTouchPanPosition
89+
*/
90+
protected override _computeMultiTouchPanning(previousMultiTouchPanPosition: Nullable<PointerTouch>, multiTouchPanPosition: Nullable<PointerTouch>): void {
91+
if (previousMultiTouchPanPosition && multiTouchPanPosition) {
92+
const moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
93+
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
94+
this._handleTilt(moveDeltaX, moveDeltaY);
95+
}
96+
}
97+
98+
public override onMultiTouch(
99+
pointA: Nullable<PointerTouch>,
100+
pointB: Nullable<PointerTouch>,
101+
previousPinchSquaredDistance: number,
102+
pinchSquaredDistance: number,
103+
previousMultiTouchPanPosition: Nullable<PointerTouch>,
104+
multiTouchPanPosition: Nullable<PointerTouch>
105+
): void {
106+
this._shouldStartPinchZoom = this._twoFingerActivityCount < 20 && Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > 20; // move to limits once limits exist
107+
super.onMultiTouch(pointA, pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition);
108+
}
109+
84110
public override onButtonUp(_evt: IPointerEvent): void {
85111
this._hitPointRadius = undefined;
86112
this.camera._alternateRotationPt = null;
113+
super.onButtonUp(_evt);
87114
}
88115

89116
/**
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import type { Nullable } from "../../types";
2+
import { serialize } from "../../Misc/decorators";
3+
import type { PointerTouch } from "../../Events/pointerEvents";
4+
import type { IPointerEvent } from "../../Events/deviceInputEvents";
5+
import { BaseCameraPointersInput } from "./BaseCameraPointersInput";
6+
7+
/**
8+
* Used by both arcrotatecamera and geospatialcamera, OrbitCameraPointersInputs handle pinchToZoom and multiTouchPanning
9+
* as though you are orbiting around a target point
10+
*/
11+
export abstract class OrbitCameraPointersInput extends BaseCameraPointersInput {
12+
/**
13+
* Defines whether zoom (2 fingers pinch) is enabled through multitouch
14+
*/
15+
@serialize()
16+
public pinchZoom: boolean = true;
17+
18+
/**
19+
* Defines whether panning (2 fingers swipe) is enabled through multitouch.
20+
*/
21+
@serialize()
22+
public multiTouchPanning: boolean = true;
23+
24+
/**
25+
* Defines whether panning is enabled for both pan (2 fingers swipe) and
26+
* zoom (pinch) through multitouch.
27+
*/
28+
@serialize()
29+
public multiTouchPanAndZoom: boolean = true;
30+
31+
protected _isPinching: boolean = false;
32+
protected _twoFingerActivityCount: number = 0;
33+
protected _shouldStartPinchZoom: boolean = false;
34+
35+
protected _computePinchZoom(_previousPinchSquaredDistance: number, _pinchSquaredDistance: number): void {}
36+
37+
protected _computeMultiTouchPanning(_previousMultiTouchPanPosition: Nullable<PointerTouch>, _multiTouchPanPosition: Nullable<PointerTouch>): void {}
38+
39+
/**
40+
* Called on pointer POINTERMOVE event if multiple touches are active.
41+
* Override this method to provide functionality.
42+
* @param _pointA First point in the pair
43+
* @param _pointB Second point in the pair
44+
* @param previousPinchSquaredDistance Sqr Distance between the points the last time this event was fired (by this input)
45+
* @param pinchSquaredDistance Sqr Distance between the points this time
46+
* @param previousMultiTouchPanPosition Previous center point between the points
47+
* @param multiTouchPanPosition Current center point between the points
48+
*/
49+
public override onMultiTouch(
50+
_pointA: Nullable<PointerTouch>,
51+
_pointB: Nullable<PointerTouch>,
52+
previousPinchSquaredDistance: number,
53+
pinchSquaredDistance: number,
54+
previousMultiTouchPanPosition: Nullable<PointerTouch>,
55+
multiTouchPanPosition: Nullable<PointerTouch>
56+
): void {
57+
if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) {
58+
// First time this method is called for new pinch.
59+
// Next time this is called there will be a
60+
// previousPinchSquaredDistance and pinchSquaredDistance to compare.
61+
return;
62+
}
63+
if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) {
64+
// Last time this method is called at the end of a pinch.
65+
return;
66+
}
67+
68+
// Zoom and panning enabled together
69+
if (this.multiTouchPanAndZoom) {
70+
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
71+
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
72+
73+
// Zoom and panning enabled but only one at a time
74+
} else if (this.multiTouchPanning && this.pinchZoom) {
75+
this._twoFingerActivityCount++;
76+
77+
if (this._isPinching || this._shouldStartPinchZoom) {
78+
// Since pinch has not been active long, assume we intend to zoom.
79+
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
80+
81+
// Since we are pinching, remain pinching on next iteration.
82+
this._isPinching = true;
83+
} else {
84+
// Pause between pinch starting and moving implies not a zoom event. Pan instead.
85+
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
86+
}
87+
88+
// Panning enabled, zoom disabled
89+
} else if (this.multiTouchPanning) {
90+
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition);
91+
92+
// Zoom enabled, panning disabled
93+
} else if (this.pinchZoom) {
94+
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance);
95+
}
96+
}
97+
98+
/**
99+
* Called each time a new POINTERUP event occurs. Ie, for each button
100+
* release.
101+
* @param _evt Defines the event to track
102+
*/
103+
public override onButtonUp(_evt: IPointerEvent): void {
104+
this._twoFingerActivityCount = 0;
105+
this._isPinching = false;
106+
}
107+
108+
/**
109+
* Called when window becomes inactive.
110+
*/
111+
public override onLostFocus(): void {
112+
this._twoFingerActivityCount = 0;
113+
this._isPinching = false;
114+
}
115+
}

0 commit comments

Comments
 (0)