ol-cesium
Version:
OpenLayers Cesium integration library
348 lines • 24.4 kB
JavaScript
import { unByKey as olObservableUnByKey } from 'ol/Observable.js';
import { toRadians, toDegrees } from './math';
import { getTransform } from 'ol/proj.js';
import { pickCenterPoint, calcDistanceForResolution, calcResolutionForDistance } from './core';
/**
* @param input Input coordinate array.
* @param opt_output Output array of coordinate values.
* @param opt_dimension Dimension.
* @return Input coordinate array (same array as input).
*/
export function identityProjection(input, opt_output, opt_dimension) {
const dim = opt_dimension || input.length;
if (opt_output) {
for (let i = 0; i < dim; ++i) {
opt_output[i] = input[i];
}
}
return input;
}
export default class Camera {
scene_;
cam_;
map_;
view_;
viewListenKey_ = null;
toLonLat_ = identityProjection;
fromLonLat_ = identityProjection;
/**
* 0 -- topdown, PI/2 -- the horizon
*/
tilt_ = 0;
distance_ = 0;
lastCameraViewMatrix_ = null;
/**
* This is used to discard change events on view caused by updateView method.
*/
viewUpdateInProgress_ = false;
/**
* This object takes care of additional 3d-specific properties of the view and
* ensures proper synchronization with the underlying raw Cesium.Camera object.
*/
constructor(scene, map) {
this.scene_ = scene;
this.cam_ = scene.camera;
this.map_ = map;
this.map_.on('change:view', (e) => {
this.setView_(this.map_.getView());
});
this.setView_(this.map_.getView());
}
destroy() {
olObservableUnByKey(this.viewListenKey_);
this.viewListenKey_ = null;
}
/**
* @param {?ol.View} view New view to use.
* @private
*/
setView_(view) {
if (this.view_) {
olObservableUnByKey(this.viewListenKey_);
this.viewListenKey_ = null;
}
this.view_ = view;
if (view) {
const toLonLat = getTransform(view.getProjection(), 'EPSG:4326');
const fromLonLat = getTransform('EPSG:4326', view.getProjection());
console.assert(toLonLat && fromLonLat);
this.toLonLat_ = toLonLat;
this.fromLonLat_ = fromLonLat;
this.viewListenKey_ = view.on('propertychange', e => this.handleViewChangedEvent_());
this.readFromView();
}
else {
this.toLonLat_ = identityProjection;
this.fromLonLat_ = identityProjection;
}
}
handleViewChangedEvent_() {
if (!this.viewUpdateInProgress_) {
this.readFromView();
}
}
/**
* @deprecated
* @param heading In radians.
*/
setHeading(heading) {
if (!this.view_) {
return;
}
this.view_.setRotation(heading);
}
/**
* @deprecated
* @return Heading in radians.
*/
getHeading() {
if (!this.view_) {
return undefined;
}
const rotation = this.view_.getRotation();
return rotation || 0;
}
/**
* @param tilt In radians.
*/
setTilt(tilt) {
this.tilt_ = tilt;
this.updateCamera_();
}
/**
* @return Tilt in radians.
*/
getTilt() {
return this.tilt_;
}
/**
* @param distance In meters.
*/
setDistance(distance) {
this.distance_ = distance;
this.updateCamera_();
this.updateView();
}
/**
* @return Distance in meters.
*/
getDistance() {
return this.distance_;
}
/**
* @deprecated
* Shortcut for ol.View.setCenter().
* @param center Same projection as the ol.View.
*/
setCenter(center) {
if (!this.view_) {
return;
}
this.view_.setCenter(center);
}
/**
* @deprecated
* Shortcut for ol.View.getCenter().
* @return {ol.Coordinate|undefined} Same projection as the ol.View.
* @api
*/
getCenter() {
if (!this.view_) {
return undefined;
}
return this.view_.getCenter();
}
/**
* Sets the position of the camera.
* @param position Same projection as the ol.View.
*/
setPosition(position) {
if (!this.toLonLat_) {
return;
}
const ll = this.toLonLat_(position);
console.assert(ll);
const carto = new Cesium.Cartographic(toRadians(ll[0]), toRadians(ll[1]), this.getAltitude());
this.cam_.setView({
destination: Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto)
});
this.updateView();
}
/**
* Calculates position under the camera.
* @return Coordinates in same projection as the ol.View.
* @api
*/
getPosition() {
if (!this.fromLonLat_) {
return undefined;
}
const carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.cam_.position);
const pos = this.fromLonLat_([
toDegrees(carto.longitude),
toDegrees(carto.latitude)
]);
console.assert(pos);
return pos;
}
/**
* @param altitude In meters.
*/
setAltitude(altitude) {
const carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.cam_.position);
carto.height = altitude;
this.cam_.position = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto);
this.updateView();
}
/**
* @return Altitude in meters.
*/
getAltitude() {
const carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.cam_.position);
return carto.height;
}
/**
* Updates the state of the underlying Cesium.Camera
* according to the current values of the properties.
*/
updateCamera_() {
if (!this.view_ || !this.toLonLat_) {
return;
}
const center = this.view_.getCenter();
if (!center) {
return;
}
const ll = this.toLonLat_(center);
console.assert(ll);
const carto = new Cesium.Cartographic(toRadians(ll[0]), toRadians(ll[1]));
if (this.scene_.globe) {
const height = this.scene_.globe.getHeight(carto);
carto.height = height || 0;
}
const destination = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto);
const orientation = {
pitch: this.tilt_ - Cesium.Math.PI_OVER_TWO,
heading: -this.view_.getRotation(),
roll: undefined
};
this.cam_.setView({
destination,
orientation
});
this.cam_.moveBackward(this.distance_);
this.checkCameraChange(true);
}
/**
* Calculates the values of the properties from the current ol.View state.
*/
readFromView() {
if (!this.view_ || !this.toLonLat_) {
return;
}
const center = this.view_.getCenter();
if (center === undefined || center === null) {
return;
}
const ll = this.toLonLat_(center);
console.assert(ll);
const resolution = this.view_.getResolution();
this.distance_ = this.calcDistanceForResolution(resolution || 0, toRadians(ll[1]));
this.updateCamera_();
}
/**
* Calculates the values of the properties from the current Cesium.Camera state.
* Modifies the center, resolution and rotation properties of the view.
*/
updateView() {
if (!this.view_ || !this.fromLonLat_) {
return;
}
this.viewUpdateInProgress_ = true;
// target & distance
const ellipsoid = Cesium.Ellipsoid.WGS84;
const scene = this.scene_;
const target = pickCenterPoint(scene);
let bestTarget = target;
if (!bestTarget) {
//TODO: how to handle this properly ?
const globe = scene.globe;
const carto = this.cam_.positionCartographic.clone();
const height = globe.getHeight(carto);
carto.height = height || 0;
bestTarget = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto);
}
this.distance_ = Cesium.Cartesian3.distance(bestTarget, this.cam_.position);
const bestTargetCartographic = ellipsoid.cartesianToCartographic(bestTarget);
this.view_.setCenter(this.fromLonLat_([
toDegrees(bestTargetCartographic.longitude),
toDegrees(bestTargetCartographic.latitude)
]));
// resolution
this.view_.setResolution(this.calcResolutionForDistance(this.distance_, bestTargetCartographic ? bestTargetCartographic.latitude : 0));
/*
* Since we are positioning the target, the values of heading and tilt
* need to be calculated _at the target_.
*/
if (target) {
const pos = this.cam_.position;
// normal to the ellipsoid at the target
const targetNormal = new Cesium.Cartesian3();
ellipsoid.geocentricSurfaceNormal(target, targetNormal);
// vector from the target to the camera
const targetToCamera = new Cesium.Cartesian3();
Cesium.Cartesian3.subtract(pos, target, targetToCamera);
Cesium.Cartesian3.normalize(targetToCamera, targetToCamera);
// HEADING
const up = this.cam_.up;
const right = this.cam_.right;
const normal = new Cesium.Cartesian3(-target.y, target.x, 0); // what is it?
const heading = Cesium.Cartesian3.angleBetween(right, normal);
const cross = Cesium.Cartesian3.cross(target, up, new Cesium.Cartesian3());
const orientation = cross.z;
this.view_.setRotation((orientation < 0 ? heading : -heading));
// TILT
const tiltAngle = Math.acos(Cesium.Cartesian3.dot(targetNormal, targetToCamera));
this.tilt_ = isNaN(tiltAngle) ? 0 : tiltAngle;
}
else {
// fallback when there is no target
this.view_.setRotation(this.cam_.heading);
this.tilt_ = -this.cam_.pitch + Math.PI / 2;
}
this.viewUpdateInProgress_ = false;
}
/**
* Check if the underlying camera state has changed and ensure synchronization.
* @param opt_dontSync Do not synchronize the view.
*/
checkCameraChange(opt_dontSync) {
const old = this.lastCameraViewMatrix_;
const current = this.cam_.viewMatrix;
if (!old || !Cesium.Matrix4.equalsEpsilon(old, current, 1e-7)) {
this.lastCameraViewMatrix_ = current.clone();
if (opt_dontSync !== true) {
this.updateView();
}
}
}
/**
* calculate the distance between camera and centerpoint based on the resolution and latitude value
* @param resolution Number of map units per pixel.
* @param latitude Latitude in radians.
* @return The calculated distance.
*/
calcDistanceForResolution(resolution, latitude) {
return calcDistanceForResolution(resolution, latitude, this.scene_, this.view_.getProjection());
}
/**
* calculate the resolution based on a distance(camera to position) and latitude value
* @param distance
* @param latitude
* @return} The calculated resolution.
*/
calcResolutionForDistance(distance, latitude) {
return calcResolutionForDistance(distance, latitude, this.scene_, this.view_.getProjection());
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FtZXJhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29sY3MvQ2FtZXJhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxPQUFPLElBQUksbUJBQW1CLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUNoRSxPQUFPLEVBQUMsU0FBUyxFQUFFLFNBQVMsRUFBQyxNQUFNLFFBQVEsQ0FBQztBQUM1QyxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBQ3hDLE9BQU8sRUFBQyxlQUFlLEVBQUUseUJBQXlCLEVBQUUseUJBQXlCLEVBQUMsTUFBTSxRQUFRLENBQUM7QUFLN0Y7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsS0FBZSxFQUFFLFVBQXFCLEVBQUUsYUFBc0I7SUFDL0YsTUFBTSxHQUFHLEdBQUcsYUFBYSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDMUMsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNmLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUM3QixVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQsTUFBTSxDQUFDLE9BQU8sT0FBTyxNQUFNO0lBQ2pCLE1BQU0sQ0FBUTtJQUNkLElBQUksQ0FBZTtJQUNuQixJQUFJLENBQU07SUFDVixLQUFLLENBQU87SUFFWixjQUFjLEdBQWMsSUFBSSxDQUFDO0lBRWpDLFNBQVMsR0FBRyxrQkFBa0IsQ0FBQztJQUMvQixXQUFXLEdBQUcsa0JBQWtCLENBQUM7SUFFekM7O09BRUc7SUFDSyxLQUFLLEdBQVcsQ0FBQyxDQUFDO0lBQ2xCLFNBQVMsR0FBRyxDQUFDLENBQUM7SUFDZCxxQkFBcUIsR0FB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