mapillary-js
Version:
A WebGL interactive street imagery library
151 lines (133 loc) • 4.27 kB
text/typescript
import * as THREE from "three";
import { isSpherical } from "./Geo";
import { Transform } from "./Transform";
/**
* @class Camera
*
* @classdesc Holds information about a camera.
*/
export class Camera {
private _position: THREE.Vector3;
private _lookat: THREE.Vector3;
private _up: THREE.Vector3;
private _focal: number;
/**
* Create a new camera instance.
* @param {Transform} [transform] - Optional transform instance.
*/
constructor(transform?: Transform) {
if (transform != null) {
this._position = new THREE.Vector3().fromArray(transform.unprojectSfM([0, 0], 0));
this._lookat = new THREE.Vector3().fromArray(transform.unprojectSfM([0, 0], 10));
this._up = transform.upVector();
this._focal = this._getFocal(transform);
} else {
this._position = new THREE.Vector3(0, 0, 0);
this._lookat = new THREE.Vector3(1, 0, 0);
this._up = new THREE.Vector3(0, 0, 1);
this._focal = 1;
}
}
/**
* Get position.
* @returns {THREE.Vector3} The position vector.
*/
public get position(): THREE.Vector3 {
return this._position;
}
/**
* Get lookat.
* @returns {THREE.Vector3} The lookat vector.
*/
public get lookat(): THREE.Vector3 {
return this._lookat;
}
/**
* Get up.
* @returns {THREE.Vector3} The up vector.
*/
public get up(): THREE.Vector3 {
return this._up;
}
/**
* Get focal.
* @returns {number} The focal length.
*/
public get focal(): number {
return this._focal;
}
/**
* Set focal.
*/
public set focal(value: number) {
this._focal = value;
}
/**
* Update this camera to the linearly interpolated value of two other cameras.
*
* @param {Camera} a - First camera.
* @param {Camera} b - Second camera.
* @param {number} alpha - Interpolation value on the interval [0, 1].
*/
public lerpCameras(a: Camera, b: Camera, alpha: number): void {
this._position.subVectors(b.position, a.position).multiplyScalar(alpha).add(a.position);
this._lookat.subVectors(b.lookat, a.lookat).multiplyScalar(alpha).add(a.lookat);
this._up.subVectors(b.up, a.up).multiplyScalar(alpha).add(a.up);
this._focal = (1 - alpha) * a.focal + alpha * b.focal;
}
/**
* Copy the properties of another camera to this camera.
*
* @param {Camera} other - Another camera.
*/
public copy(other: Camera): void {
this._position.copy(other.position);
this._lookat.copy(other.lookat);
this._up.copy(other.up);
this._focal = other.focal;
}
/**
* Clone this camera.
*
* @returns {Camera} A camera with cloned properties equal to this camera.
*/
public clone(): Camera {
let camera: Camera = new Camera();
camera.position.copy(this._position);
camera.lookat.copy(this._lookat);
camera.up.copy(this._up);
camera.focal = this._focal;
return camera;
}
/**
* Determine the distance between this camera and another camera.
*
* @param {Camera} other - Another camera.
* @returns {number} The distance between the cameras.
*/
public diff(other: Camera): number {
let pd: number = this._position.distanceToSquared(other.position);
let ld: number = this._lookat.distanceToSquared(other.lookat);
let ud: number = this._up.distanceToSquared(other.up);
let fd: number = 100 * Math.abs(this._focal - other.focal);
return Math.max(pd, ld, ud, fd);
}
/**
* Get the focal length based on the transform.
*
* @description Returns the focal length corresponding
* to a 90 degree field of view for spherical
* transforms.
*
* Returns the transform focal length for other
* projection types.
*
* @returns {number} Focal length.
*/
private _getFocal(transform: Transform): number {
if (!isSpherical(transform.cameraType)) {
return transform.focal;
}
return 0.5 / Math.tan(Math.PI / 2);
}
}