Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve CameraControl touch dolly/pan #415

Merged
merged 1 commit into from
Aug 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions src/viewer/scene/CameraControl/lib/CameraUpdater.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,7 @@ class CameraUpdater {
countDown = SCALE_DOLLY_EACH_FRAME;

if (updates.dollyDelta !== 0) {

if (updates.rotateDeltaY === 0 && updates.rotateDeltaX === 0) {

pickController.pickCursorPos = states.pointerCanvasPos;
pickController.schedulePickSurface = true;

pickController.update();

if (pickController.pickResult && pickController.pickResult.worldPos) {
const worldPos = pickController.pickResult.worldPos;
pivotController.setPivotPos(worldPos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class KeyboardPanRotateDollyHandler {

const canvas = scene.canvas.canvas;

const pickController = controllers.pickController;

document.addEventListener("keydown", this._documentKeyDownHandler = (e) => {
if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) {
return;
Expand Down Expand Up @@ -116,6 +118,9 @@ class KeyboardPanRotateDollyHandler {
} else if (dollyBackwards) {
updates.dollyDelta += dollyDelta;
}
pickController.pickCursorPos = states.pointerCanvasPos;
pickController.schedulePickSurface = true;
pickController.update();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ class MousePanRotateDollyHandler {
}
const normalizedDelta = delta / Math.abs(delta);
updates.dollyDelta += -normalizedDelta * secsElapsed * configs.mouseWheelDollyRate;
pickController.pickCursorPos = states.pointerCanvasPos;
pickController.schedulePickSurface = true;
pickController.update();

e.preventDefault();
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ class TouchPanRotateAndDollyHandler {

const canvas = this._scene.canvas.canvas;

let waitForTick = false;

this._onTick = scene.on("tick", () => {
waitForTick = false;
});


canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {

if (!(configs.active && configs.pointerEnabled)) {
Expand Down Expand Up @@ -62,6 +69,16 @@ class TouchPanRotateAndDollyHandler {
tapStartTime = -1;
}

if (touches.length === 2) {
const touch0 = touches[0];
const touch1 = touches[1];
const currentMiddleTouch = math.geometricMeanVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]);

pickController.pickCursorPos = currentMiddleTouch;
pickController.schedulePickSurface = true;
pickController.update();
}

while (lastTouches.length < touches.length) {
lastTouches.push(new Float32Array(2));
}
Expand All @@ -81,6 +98,11 @@ class TouchPanRotateAndDollyHandler {
if (!(configs.active && configs.pointerEnabled)) {
return;
}
if (waitForTick) {
// Limit changes detection to one per frame
return;
}
waitForTick = true;
// Scaling drag-rotate to canvas boundary

const canvasBoundary = scene.canvas.boundary;
Expand Down Expand Up @@ -140,62 +162,52 @@ class TouchPanRotateAndDollyHandler {
const touch0 = touches[0];
const touch1 = touches[1];

math.subVec2([touch0.pageX, touch0.pageY], lastTouches[0], touch0Vec);
math.subVec2([touch1.pageX, touch1.pageY], lastTouches[1], touch1Vec);

const panning = math.dotVec2(touch0Vec, touch1Vec) > 0;

if (panning) {

math.subVec2([touch0.pageX, touch0.pageY], lastTouches[0], touch0Vec);
const lastMiddleTouch = math.geometricMeanVec2(lastTouches[0], lastTouches[1]);
const currentMiddleTouch = math.geometricMeanVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]);

const xPanDelta = touch0Vec[0];
const yPanDelta = touch0Vec[1];

const camera = scene.camera;
const touchDelta = new Float32Array(2);

// We use only canvasHeight here so that aspect ratio does not distort speed
math.subVec2(lastMiddleTouch, currentMiddleTouch, touchDelta);

if (camera.projection === "perspective") {

//----------------------------
// TODO: Pick on first touch
//----------------------------
// PANNING
const xPanDelta = touchDelta[0];
const yPanDelta = touchDelta[1];

const touchPicked = false;
const pickedWorldPos = [0, 0, 0];
const camera = scene.camera;

const depth = Math.abs(touchPicked ? math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, [])) : scene.camera.eyeLookDist);
const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0);
// We use only canvasHeight here so that aspect ratio does not distort speed

updates.panDeltaX += (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate;
updates.panDeltaY += (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate;
if (camera.projection === "perspective") {
const pickedWorldPos = pickController.pickResult ? pickController.pickResult.worldPos : scene.center;

} else {
const depth = Math.abs(math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, [])));
const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0);

updates.panDeltaX += 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate;
updates.panDeltaY += 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate;
}
updates.panDeltaX -= (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate;
updates.panDeltaY -= (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate;

} else {

// Dollying
updates.panDeltaX -= 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate;
updates.panDeltaY -= 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate;
}

const d1 = math.distVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]);
const d2 = math.distVec2(lastTouches[0], lastTouches[1]);
// Dollying
states.skipNextPick = true;

updates.dollyDelta = (d2 - d1) * configs.touchDollyRate;
const d1 = math.distVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]);
const d2 = math.distVec2(lastTouches[0], lastTouches[1]);

states.pointerCanvasPos[0] = ((touch1.pageX + touch0.pageX) / 2);
states.pointerCanvasPos[1] = ((touch1.pageY + touch0.pageY) / 2);
}
updates.dollyDelta = (d2 - d1) * configs.touchDollyRate;

states.pointerCanvasPos = currentMiddleTouch;
}

for (let i = 0; i < numTouches; ++i) {
lastTouches[i][0] = touches[i].pageX;
lastTouches[i][1] = touches[i].pageY;
}

event.stopPropagation();

}, {passive: true});
Expand All @@ -205,11 +217,10 @@ class TouchPanRotateAndDollyHandler {
}

destroy() {

const canvas = this._scene.canvas.canvas;

canvas.removeEventListener("touchstart", this._canvasTouchStartHandler);
canvas.removeEventListener("touchmove", this._canvasTouchMoveHandler);
this._scene.off(this._onTick);
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/viewer/scene/math/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,24 @@ const math = {
return dest;
},

/**
* Get the geometric mean of the vectors.
* @method geometricMeanVec2
* @static
* @param {...Array(Number)} vectors Vec2 to mean
* @return {Array(Number)} The geometric mean vec2
*/
geometricMeanVec2(...vectors) {
const geometricMean = new Float32Array(vectors[0]);
for (let i = 1; i < vectors.length; i++) {
geometricMean[0] += vectors[i][0];
geometricMean[1] += vectors[i][1];
}
geometricMean[0] /= vectors.length;
geometricMean[1] /= vectors.length;
return geometricMean;
},

/**
* Subtracts a scalar value from each element of a four-element vector.
* @method subVec4Scalar
Expand Down