ol-cesium
Version:
OpenLayers Cesium integration library
237 lines • 17.5 kB
JavaScript
import olcsContribLazyLoader from './LazyLoader';
import OLCesium from '../OLCesium';
import { resetToNorthZenith, rotateAroundBottomCenter, computeSignedTiltAngleOnGlobe, pickBottomPoint, setHeadingUsingBottomCenter, limitCameraToBoundingSphere } from '../core';
import { toRadians } from '../math';
import Observable from 'ol/Observable.js';
/**
* @typedef {Object} ManagerOptions
* @property {import('ol/Map.js').default} map
* @property {import('ol/extent.js').Extent} [cameraExtentInRadians]
* @property {string} [cesiumIonDefaultAccessToken]
*/
export default class Manager extends Observable {
cesiumUrl_;
boundingSphere_;
promise_;
cesiumIonDefaultAccessToken_;
map;
cameraExtentInRadians;
ol3d;
cesiumInitialTilt_ = toRadians(50);
fogDensity = 0.0001;
fogSSEFactor = 25;
minimumZoomDistance = 2;
/**
* Limit the maximum distance to the earth to 10'000km.
*/
maximumZoomDistance = 10000000;
// when closer to 3000m, restrict the available positions harder
limitCameraToBoundingSphereRatio = (height) => (height > 3000 ? 9 : 3);
/**
* @param {string} cesiumUrl
* @param {olcsx.contrib.ManagerOptions} options
* @api
*/
constructor(cesiumUrl, { map, cameraExtentInRadians, cesiumIonDefaultAccessToken }) {
super();
this.cesiumUrl_ = cesiumUrl;
console.assert(map);
this.map = map;
this.cameraExtentInRadians = cameraExtentInRadians || null;
this.cesiumIonDefaultAccessToken_ = cesiumIonDefaultAccessToken;
}
/**
* Lazy load Cesium.
*/
load() {
if (!this.promise_) {
const cesiumLazyLoader = new olcsContribLazyLoader(this.cesiumUrl_);
this.promise_ = cesiumLazyLoader.load().then(() => this.onCesiumLoaded());
}
return this.promise_;
}
/**
* Hook called when Cesium has been lazy loaded.
*/
onCesiumLoaded() {
if (this.cameraExtentInRadians) {
const rect = new Cesium.Rectangle(...this.cameraExtentInRadians);
// Set the fly home rectangle
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = rect;
this.boundingSphere_ = Cesium.BoundingSphere.fromRectangle3D(rect, Cesium.Ellipsoid.WGS84, 300); // lux mean height is 300m
}
if (this.cesiumIonDefaultAccessToken_) {
Cesium.Ion.defaultAccessToken = this.cesiumIonDefaultAccessToken_;
}
this.ol3d = this.instantiateOLCesium();
const scene = this.ol3d.getCesiumScene();
this.configureForUsability(scene);
this.configureForPerformance(scene);
this.dispatchEvent('load');
return this.ol3d;
}
/**
* Application code should override this method.
*/
instantiateOLCesium() {
const ol3d = new OLCesium({ map: this.map });
const scene = ol3d.getCesiumScene();
// LEGACY
if ('createWorldTerrain' in Cesium) {
// @ts-ignore
const terrainProvider = Cesium.createWorldTerrain();
scene.terrainProvider = terrainProvider;
}
else {
// v107+
Cesium.createWorldTerrainAsync().then(tp => scene.terrainProvider = tp);
}
return ol3d;
}
/**
* Override with custom performance optimization logics, if needed.
*/
configureForPerformance(scene) {
const fog = scene.fog;
fog.enabled = true;
fog.density = this.fogDensity;
fog.screenSpaceErrorFactor = this.fogSSEFactor;
}
/**
* Override with custom usabliity logics, id needed.
*/
configureForUsability(scene) {
const sscController = scene.screenSpaceCameraController;
sscController.minimumZoomDistance = this.minimumZoomDistance;
sscController.maximumZoomDistance = this.maximumZoomDistance;
// Do not see through the terrain. Seeing through the terrain does not make
// sense anyway, except for debugging
scene.globe.depthTestAgainstTerrain = true;
// Use white instead of the black default colour for the globe when tiles are missing
scene.globe.baseColor = Cesium.Color.WHITE;
scene.backgroundColor = Cesium.Color.WHITE;
if (this.boundingSphere_) {
scene.postRender.addEventListener(this.limitCameraToBoundingSphere.bind(this));
}
// Stop rendering Cesium when there is nothing to do. This drastically reduces CPU/GPU consumption.
this.ol3d.enableAutoRenderLoop();
}
/**
* Constrain the camera so that it stays close to the bounding sphere of the map extent.
* Near the ground the allowed distance is shorter.
*/
limitCameraToBoundingSphere() {
const scene = this.ol3d.getCesiumScene();
limitCameraToBoundingSphere(scene.camera, this.boundingSphere_, this.limitCameraToBoundingSphereRatio);
}
/**
* Enable or disable ol3d with a default animation.
*/
toggle3d() {
return this.load().then((/** @const {!olcs.OLCesium} */ ol3d) => {
const is3DCurrentlyEnabled = ol3d.getEnabled();
const scene = ol3d.getCesiumScene();
if (is3DCurrentlyEnabled) {
// Disable 3D
console.assert(this.map);
return resetToNorthZenith(this.map, scene).then(() => {
ol3d.setEnabled(false);
this.dispatchEvent('toggle');
});
}
else {
// Enable 3D
ol3d.setEnabled(true);
this.dispatchEvent('toggle');
return rotateAroundBottomCenter(scene, this.cesiumInitialTilt_);
}
});
}
/**
* Enable ol3d with a view built from parameters.
*/
set3dWithView(lon, lat, elevation, headingDeg, pitchDeg) {
return this.load().then((ol3d) => {
const is3DCurrentlyEnabled = ol3d.getEnabled();
const scene = ol3d.getCesiumScene();
const camera = scene.camera;
const destination = Cesium.Cartesian3.fromDegrees(lon, lat, elevation);
const heading = Cesium.Math.toRadians(headingDeg);
const pitch = Cesium.Math.toRadians(pitchDeg);
const roll = 0;
const orientation = { heading, pitch, roll };
if (!is3DCurrentlyEnabled) {
ol3d.setEnabled(true);
this.dispatchEvent('toggle');
}
camera.setView({
destination,
orientation
});
});
}
/**
* Whether OL-Cesium has been loaded and 3D mode is enabled.
*/
is3dEnabled() {
return !!this.ol3d && this.ol3d.getEnabled();
}
/**
* @return {number}
*/
getHeading() {
return this.map ? this.map.getView().getRotation() || 0 : 0;
}
/**
* @return {number|undefined}
*/
getTiltOnGlobe() {
const scene = this.ol3d.getCesiumScene();
const tiltOnGlobe = computeSignedTiltAngleOnGlobe(scene);
return -tiltOnGlobe;
}
/**
* Set heading.
* This assumes ol3d has been loaded.
*/
setHeading(angle) {
const scene = this.ol3d.getCesiumScene();
const bottom = pickBottomPoint(scene);
if (bottom) {
setHeadingUsingBottomCenter(scene, angle, bottom);
}
}
getOl3d() {
return this.ol3d;
}
getCesiumViewMatrix() {
return this.ol3d.getCesiumScene().camera.viewMatrix;
}
getCesiumScene() {
return this.ol3d.getCesiumScene();
}
/**
* Fly to some rectangle.
* This assumes ol3d has been loaded.
*/
flyToRectangle(rectangle, offset = 0) {
const camera = this.getCesiumScene().camera;
const destination = camera.getRectangleCameraCoordinates(rectangle);
const mag = Cesium.Cartesian3.magnitude(destination) + offset;
Cesium.Cartesian3.normalize(destination, destination);
Cesium.Cartesian3.multiplyByScalar(destination, mag, destination);
return new Promise((resolve, reject) => {
if (!this.cameraExtentInRadians) {
reject();
return;
}
camera.flyTo({
destination,
complete: () => resolve(),
cancel: () => reject(),
endTransform: Cesium.Matrix4.IDENTITY
});
});
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9vbGNzL2NvbnRyaWIvTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLHFCQUFxQixNQUFNLGNBQWMsQ0FBQztBQUNqRCxPQUFPLFFBQVEsTUFBTSxhQUFhLENBQUM7QUFDbkMsT0FBTyxFQUFDLGtCQUFrQixFQUFFLHdCQUF3QixFQUFFLDZCQUE2QixFQUFFLGVBQWUsRUFBRSwyQkFBMkIsRUFBRSwyQkFBMkIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUMvSyxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sU0FBUyxDQUFDO0FBQ2xDLE9BQU8sVUFBVSxNQUFNLGtCQUFrQixDQUFDO0FBTTFDOzs7OztHQUtHO0FBR0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxPQUFRLFNBQVEsVUFBVTtJQUNyQyxVQUFVLENBQVM7SUFDbkIsZUFBZSxDQUFpQjtJQUNoQyxRQUFRLENBQW9CO0lBQzVCLDRCQUE0QixDQUFTO0lBQ25DLEdBQUcsQ0FBUTtJQUNYLHFCQUFxQixDQUFTO0lBQzlCLElBQUksQ0FBVztJQUNqQixrQkFBa0IsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFakMsVUFBVSxHQUFHLE1BQU0sQ0FBQztJQUVwQixZQUFZLEdBQUcsRUFBRSxDQUFDO0lBRWxCLG1CQUFtQixHQUFHLENBQUMsQ0FBQztJQUVsQzs7T0FFRztJQUNPLG1CQUFtQixHQUFXLFFBQVEsQ0FBQztJQUVqRCxnRUFBZ0U7SUFDdEQsZ0NBQWdDLEdBQUcsQ0FBQyxNQUFjLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUV6Rjs7OztPQUlHO0lBQ0gsWUFBWSxTQUFpQixFQUFFLEVBQUMsR0FBRyxFQUFFLHFCQUFxQixFQUFFLDJCQUEyQixFQUFxRjtRQUMx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