Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
MAPSJS-2660: Support oblique perspective projection in orbitAroundScr…
Browse files Browse the repository at this point in the history
…eenPoint.

Deprecate old orbitAroundScreenPoint signature.
Create new signature where orbit center is optional, defaulting to
camera principal point.

Signed-off-by: Andres Mandado <[email protected]>
  • Loading branch information
atomicsulfate committed Aug 23, 2021
1 parent fbba18f commit b068983
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 103 deletions.
75 changes: 39 additions & 36 deletions @here/harp-map-controls/lib/MapControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
*/

import * as geoUtils from "@here/harp-geoutils";
import { EventDispatcher, MapView, MapViewEventNames, MapViewUtils } from "@here/harp-mapview";
import {
CameraUtils,
EventDispatcher,
MapView,
MapViewEventNames,
MapViewUtils
} from "@here/harp-mapview";
import * as THREE from "three";

import * as utils from "./Utils";
Expand Down Expand Up @@ -618,14 +624,11 @@ export class MapControls extends EventDispatcher {

const deltaAzimuth = this.m_currentAzimuth - this.m_lastAzimuth;

MapViewUtils.orbitAroundScreenPoint(
this.mapView,
0,
0,
MapViewUtils.orbitAroundScreenPoint(this.mapView, {
deltaAzimuth,
0,
this.m_maxTiltAngle
);
deltaTilt: 0,
maxTiltAngle: this.m_maxTiltAngle
});
this.updateMapView();
}

Expand Down Expand Up @@ -671,9 +674,13 @@ export class MapControls extends EventDispatcher {
: this.targetedTilt;

const initialTilt = this.currentTilt;
const deltaAngle = this.m_currentTilt - initialTilt;
const deltaTilt = this.m_currentTilt - initialTilt;

MapViewUtils.orbitAroundScreenPoint(this.mapView, 0, 0, 0, deltaAngle, this.m_maxTiltAngle);
MapViewUtils.orbitAroundScreenPoint(this.mapView, {
deltaAzimuth: 0,
deltaTilt,
maxTiltAngle: this.m_maxTiltAngle
});
this.updateMapView();

if (tiltAnimationFinished) {
Expand Down Expand Up @@ -941,7 +948,7 @@ export class MapControls extends EventDispatcher {
utils.calculateNormalizedDeviceCoordinates(mousePos.x, mousePos.y, width, height)
);
} else {
this.m_initialMousePosition.set(0, 0);
CameraUtils.getPrincipalPoint(this.mapView.camera, this.m_initialMousePosition);
}

const onMouseMove = this.mouseMove.bind(this);
Expand Down Expand Up @@ -990,14 +997,15 @@ export class MapControls extends EventDispatcher {
} else if (this.m_state === State.ORBIT) {
this.stopExistingAnimations();

MapViewUtils.orbitAroundScreenPoint(
this.mapView,
this.m_initialMousePosition.x,
this.m_initialMousePosition.y,
this.orbitingMouseDeltaFactor * this.m_mouseDelta.x,
-this.orbitingMouseDeltaFactor * this.m_mouseDelta.y,
this.m_maxTiltAngle
);
MapViewUtils.orbitAroundScreenPoint(this.mapView, {
center: this.m_tmpVector2.set(
this.m_initialMousePosition.x,
this.m_initialMousePosition.y
),
deltaAzimuth: this.orbitingMouseDeltaFactor * this.m_mouseDelta.x,
deltaTilt: -this.orbitingMouseDeltaFactor * this.m_mouseDelta.y,
maxTiltAngle: this.m_maxTiltAngle
});
}

this.m_lastMousePosition.set(mousePos.x, mousePos.y);
Expand Down Expand Up @@ -1296,18 +1304,16 @@ export class MapControls extends EventDispatcher {

if (this.rotateEnabled) {
this.updateCurrentRotation();
const deltaRotation =
const deltaAzimuth =
this.m_touchState.currentRotation - this.m_touchState.initialRotation;
this.stopExistingAnimations();

MapViewUtils.orbitAroundScreenPoint(
this.mapView,
center.x,
center.y,
deltaRotation,
0,
this.m_maxTiltAngle
);
MapViewUtils.orbitAroundScreenPoint(this.mapView, {
center: this.m_tmpVector2.set(center.x, center.y),
deltaAzimuth,
deltaTilt: 0,
maxTiltAngle: this.m_maxTiltAngle
});
}
}

Expand All @@ -1319,14 +1325,11 @@ export class MapControls extends EventDispatcher {
firstTouch.lastTouchPoint
);
this.stopExistingAnimations();
MapViewUtils.orbitAroundScreenPoint(
this.mapView,
0,
0,
this.orbitingTouchDeltaFactor * diff.x,
-this.orbitingTouchDeltaFactor * diff.y,
this.m_maxTiltAngle
);
MapViewUtils.orbitAroundScreenPoint(this.mapView, {
deltaAzimuth: this.orbitingTouchDeltaFactor * diff.x,
deltaTilt: -this.orbitingTouchDeltaFactor * diff.y,
maxTiltAngle: this.m_maxTiltAngle
});
}

this.m_zoomAnimationStartTime = performance.now();
Expand Down
85 changes: 71 additions & 14 deletions @here/harp-mapview/lib/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ProjectionType,
sphereProjection,
TileKey,
Vector2Like,
Vector3Like
} from "@here/harp-geoutils";
import { GeoCoordLike } from "@here/harp-geoutils/lib/coordinates/GeoCoordLike";
Expand Down Expand Up @@ -65,7 +66,7 @@ const cache = {
box3: [new THREE.Box3()],
obox3: [new OrientedBox3()],
quaternions: [new THREE.Quaternion(), new THREE.Quaternion()],
vector2: [new THREE.Vector2()],
vector2: [new THREE.Vector2(), new THREE.Vector2()],
vector3: [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
matrix4: [new THREE.Matrix4(), new THREE.Matrix4()],
transforms: [
Expand Down Expand Up @@ -228,15 +229,39 @@ export namespace MapViewUtils {
return true;
}

/**
* Parameters for {@link orbitAroundScreenPoint}.
*/
export interface OrbitParams {
/**
* Delta azimuth in radians.
*/
deltaAzimuth: number;
/**
* Delta tilt in radians.
*/
deltaTilt: number;
/**
* Maximum tilt between the camera and its target in radians.
*/
maxTiltAngle: number;
/**
* Orbiting center in NDC coordinates, defaults to camera's principal point.
* @see {@link CameraUtils.getPrincipalPoint}.
*/
center?: Vector2Like;
}

/**
* Orbits the camera around a given point on the screen.
*
* @param mapView - The {@link MapView} instance to manipulate.
* @param offsetX - Orbit point in NDC space.
* @param offsetY - Orbit point in NDC space.
* @param deltaAzimuth - Delta azimuth in radians.
* @param deltaTil - Delta tilt in radians.
* @param deltaTilt - Delta tilt in radians.
* @param maxTiltAngle - The maximum tilt between the camera and its target in radian.
* @deprecated Use overload with {@link OrbitParams} object parameter.
*/
export function orbitAroundScreenPoint(
mapView: MapView,
Expand All @@ -245,28 +270,60 @@ export namespace MapViewUtils {
deltaAzimuth: number,
deltaTilt: number,
maxTiltAngle: number
) {
const rotationTargetWorld = MapViewUtils.rayCastWorldCoordinates(mapView, offsetX, offsetY);
if (rotationTargetWorld === null) {
): void;

/**
* Orbits the camera around a given point on the screen.
*
* @param mapView - The {@link MapView} instance to manipulate.
* @param orbitParams - {@link OrbitParams}.
*/
export function orbitAroundScreenPoint(mapView: MapView, orbitParams: OrbitParams): void;

export function orbitAroundScreenPoint(
mapView: MapView,
offsetXOrOrbitParams: number | OrbitParams,
offsetY?: number,
deltaAzimuth?: number,
deltaTilt?: number,
maxTiltAngle?: number
): void {
const ppalPoint = CameraUtils.getPrincipalPoint(mapView.camera, cache.vector2[1]);
const mapTargetWorld = MapViewUtils.rayCastWorldCoordinates(
mapView,
ppalPoint.x,
ppalPoint.y
);
if (mapTargetWorld === null) {
return;
}

const mapTargetWorld =
offsetX === 0 && offsetY === 0
? rotationTargetWorld
: MapViewUtils.rayCastWorldCoordinates(mapView, 0, 0);
if (mapTargetWorld === null) {
const orbitParams: OrbitParams =
typeof offsetXOrOrbitParams === "number"
? {
center: cache.vector2[0].set(offsetXOrOrbitParams, offsetY!),
deltaAzimuth: deltaAzimuth!,
deltaTilt: deltaTilt!,
maxTiltAngle: maxTiltAngle!
}
: offsetXOrOrbitParams;
const orbitCenter = orbitParams.center ?? ppalPoint;
const orbitAroundPpalPoint = orbitCenter.x === ppalPoint.x && orbitCenter.y === ppalPoint.y;
const rotationTargetWorld = orbitAroundPpalPoint
? mapTargetWorld
: MapViewUtils.rayCastWorldCoordinates(mapView, orbitCenter.x, orbitCenter.y);
if (rotationTargetWorld === null) {
return;
}

applyAzimuthAroundTarget(mapView, rotationTargetWorld, -deltaAzimuth);
applyAzimuthAroundTarget(mapView, rotationTargetWorld, -orbitParams.deltaAzimuth);

const tiltAxis = new THREE.Vector3(1, 0, 0).applyQuaternion(mapView.camera.quaternion);
const clampedDeltaTilt = computeClampedDeltaTilt(
mapView,
offsetY,
deltaTilt,
maxTiltAngle,
orbitCenter.y - ppalPoint.y,
orbitParams.deltaTilt,
orbitParams.maxTiltAngle,
mapTargetWorld,
rotationTargetWorld,
tiltAxis
Expand Down
Loading

0 comments on commit b068983

Please sign in to comment.