123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- import BoundingRectangle from "../Core/BoundingRectangle.js";
- import Cartesian2 from "../Core/Cartesian2.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartesian4 from "../Core/Cartesian4.js";
- import Cartographic from "../Core/Cartographic.js";
- import defined from "../Core/defined.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import CesiumMath from "../Core/Math.js";
- import Matrix4 from "../Core/Matrix4.js";
- import OrthographicFrustum from "../Core/OrthographicFrustum.js";
- import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
- import Transforms from "../Core/Transforms.js";
- import SceneMode from "./SceneMode.js";
- /**
- * Functions that do scene-dependent transforms between rendering-related coordinate systems.
- *
- * @namespace SceneTransforms
- */
- const SceneTransforms = {};
- const actualPositionScratch = new Cartesian4(0, 0, 0, 1);
- let positionCC = new Cartesian4();
- const scratchViewport = new BoundingRectangle();
- const scratchWindowCoord0 = new Cartesian2();
- const scratchWindowCoord1 = new Cartesian2();
- /**
- * Transforms a position in WGS84 coordinates to window coordinates. This is commonly used to place an
- * HTML element at the same screen position as an object in the scene.
- *
- * @param {Scene} scene The scene.
- * @param {Cartesian3} position The position in WGS84 (world) coordinates.
- * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
- * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
- *
- * @example
- * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
- * const scene = widget.scene;
- * const ellipsoid = scene.globe.ellipsoid;
- * const position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
- * const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
- * handler.setInputAction(function(movement) {
- * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
- * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
- */
- SceneTransforms.wgs84ToWindowCoordinates = function (scene, position, result) {
- return SceneTransforms.wgs84WithEyeOffsetToWindowCoordinates(
- scene,
- position,
- Cartesian3.ZERO,
- result
- );
- };
- const scratchCartesian4 = new Cartesian4();
- const scratchEyeOffset = new Cartesian3();
- function worldToClip(position, eyeOffset, camera, result) {
- const viewMatrix = camera.viewMatrix;
- const positionEC = Matrix4.multiplyByVector(
- viewMatrix,
- Cartesian4.fromElements(
- position.x,
- position.y,
- position.z,
- 1,
- scratchCartesian4
- ),
- scratchCartesian4
- );
- const zEyeOffset = Cartesian3.multiplyComponents(
- eyeOffset,
- Cartesian3.normalize(positionEC, scratchEyeOffset),
- scratchEyeOffset
- );
- positionEC.x += eyeOffset.x + zEyeOffset.x;
- positionEC.y += eyeOffset.y + zEyeOffset.y;
- positionEC.z += zEyeOffset.z;
- return Matrix4.multiplyByVector(
- camera.frustum.projectionMatrix,
- positionEC,
- result
- );
- }
- const scratchMaxCartographic = new Cartographic(
- Math.PI,
- CesiumMath.PI_OVER_TWO
- );
- const scratchProjectedCartesian = new Cartesian3();
- const scratchCameraPosition = new Cartesian3();
- /**
- * @private
- */
- SceneTransforms.wgs84WithEyeOffsetToWindowCoordinates = function (
- scene,
- position,
- eyeOffset,
- result
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(scene)) {
- throw new DeveloperError("scene is required.");
- }
- if (!defined(position)) {
- throw new DeveloperError("position is required.");
- }
- //>>includeEnd('debug');
- // Transform for 3D, 2D, or Columbus view
- const frameState = scene.frameState;
- const actualPosition = SceneTransforms.computeActualWgs84Position(
- frameState,
- position,
- actualPositionScratch
- );
- if (!defined(actualPosition)) {
- return undefined;
- }
- // Assuming viewport takes up the entire canvas...
- const canvas = scene.canvas;
- const viewport = scratchViewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = canvas.clientWidth;
- viewport.height = canvas.clientHeight;
- const camera = scene.camera;
- let cameraCentered = false;
- if (frameState.mode === SceneMode.SCENE2D) {
- const projection = scene.mapProjection;
- const maxCartographic = scratchMaxCartographic;
- const maxCoord = projection.project(
- maxCartographic,
- scratchProjectedCartesian
- );
- const cameraPosition = Cartesian3.clone(
- camera.position,
- scratchCameraPosition
- );
- const frustum = camera.frustum.clone();
- const viewportTransformation = Matrix4.computeViewportTransformation(
- viewport,
- 0.0,
- 1.0,
- new Matrix4()
- );
- const projectionMatrix = camera.frustum.projectionMatrix;
- const x = camera.positionWC.y;
- const eyePoint = Cartesian3.fromElements(
- CesiumMath.sign(x) * maxCoord.x - x,
- 0.0,
- -camera.positionWC.x
- );
- const windowCoordinates = Transforms.pointToGLWindowCoordinates(
- projectionMatrix,
- viewportTransformation,
- eyePoint
- );
- if (
- x === 0.0 ||
- windowCoordinates.x <= 0.0 ||
- windowCoordinates.x >= canvas.clientWidth
- ) {
- cameraCentered = true;
- } else {
- if (windowCoordinates.x > canvas.clientWidth * 0.5) {
- viewport.width = windowCoordinates.x;
- camera.frustum.right = maxCoord.x - x;
- positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
- SceneTransforms.clipToGLWindowCoordinates(
- viewport,
- positionCC,
- scratchWindowCoord0
- );
- viewport.x += windowCoordinates.x;
- camera.position.x = -camera.position.x;
- const right = camera.frustum.right;
- camera.frustum.right = -camera.frustum.left;
- camera.frustum.left = -right;
- positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
- SceneTransforms.clipToGLWindowCoordinates(
- viewport,
- positionCC,
- scratchWindowCoord1
- );
- } else {
- viewport.x += windowCoordinates.x;
- viewport.width -= windowCoordinates.x;
- camera.frustum.left = -maxCoord.x - x;
- positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
- SceneTransforms.clipToGLWindowCoordinates(
- viewport,
- positionCC,
- scratchWindowCoord0
- );
- viewport.x = viewport.x - viewport.width;
- camera.position.x = -camera.position.x;
- const left = camera.frustum.left;
- camera.frustum.left = -camera.frustum.right;
- camera.frustum.right = -left;
- positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
- SceneTransforms.clipToGLWindowCoordinates(
- viewport,
- positionCC,
- scratchWindowCoord1
- );
- }
- Cartesian3.clone(cameraPosition, camera.position);
- camera.frustum = frustum.clone();
- result = Cartesian2.clone(scratchWindowCoord0, result);
- if (result.x < 0.0 || result.x > canvas.clientWidth) {
- result.x = scratchWindowCoord1.x;
- }
- }
- }
- if (frameState.mode !== SceneMode.SCENE2D || cameraCentered) {
- // View-projection matrix to transform from world coordinates to clip coordinates
- positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
- if (
- positionCC.z < 0 &&
- !(camera.frustum instanceof OrthographicFrustum) &&
- !(camera.frustum instanceof OrthographicOffCenterFrustum)
- ) {
- return undefined;
- }
- result = SceneTransforms.clipToGLWindowCoordinates(
- viewport,
- positionCC,
- result
- );
- }
- result.y = canvas.clientHeight - result.y;
- return result;
- };
- /**
- * Transforms a position in WGS84 coordinates to drawing buffer coordinates. This may produce different
- * results from SceneTransforms.wgs84ToWindowCoordinates when the browser zoom is not 100%, or on high-DPI displays.
- *
- * @param {Scene} scene The scene.
- * @param {Cartesian3} position The position in WGS84 (world) coordinates.
- * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
- * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
- *
- * @example
- * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
- * const scene = widget.scene;
- * const ellipsoid = scene.globe.ellipsoid;
- * const position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
- * const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
- * handler.setInputAction(function(movement) {
- * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
- * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
- */
- SceneTransforms.wgs84ToDrawingBufferCoordinates = function (
- scene,
- position,
- result
- ) {
- result = SceneTransforms.wgs84ToWindowCoordinates(scene, position, result);
- if (!defined(result)) {
- return undefined;
- }
- return SceneTransforms.transformWindowToDrawingBuffer(scene, result, result);
- };
- const projectedPosition = new Cartesian3();
- const positionInCartographic = new Cartographic();
- /**
- * @private
- */
- SceneTransforms.computeActualWgs84Position = function (
- frameState,
- position,
- result
- ) {
- const mode = frameState.mode;
- if (mode === SceneMode.SCENE3D) {
- return Cartesian3.clone(position, result);
- }
- const projection = frameState.mapProjection;
- const cartographic = projection.ellipsoid.cartesianToCartographic(
- position,
- positionInCartographic
- );
- if (!defined(cartographic)) {
- return undefined;
- }
- projection.project(cartographic, projectedPosition);
- if (mode === SceneMode.COLUMBUS_VIEW) {
- return Cartesian3.fromElements(
- projectedPosition.z,
- projectedPosition.x,
- projectedPosition.y,
- result
- );
- }
- if (mode === SceneMode.SCENE2D) {
- return Cartesian3.fromElements(
- 0.0,
- projectedPosition.x,
- projectedPosition.y,
- result
- );
- }
- // mode === SceneMode.MORPHING
- const morphTime = frameState.morphTime;
- return Cartesian3.fromElements(
- CesiumMath.lerp(projectedPosition.z, position.x, morphTime),
- CesiumMath.lerp(projectedPosition.x, position.y, morphTime),
- CesiumMath.lerp(projectedPosition.y, position.z, morphTime),
- result
- );
- };
- const positionNDC = new Cartesian3();
- const positionWC = new Cartesian3();
- const viewportTransform = new Matrix4();
- /**
- * @private
- */
- SceneTransforms.clipToGLWindowCoordinates = function (
- viewport,
- position,
- result
- ) {
- // Perspective divide to transform from clip coordinates to normalized device coordinates
- Cartesian3.divideByScalar(position, position.w, positionNDC);
- // Viewport transform to transform from clip coordinates to window coordinates
- Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, viewportTransform);
- Matrix4.multiplyByPoint(viewportTransform, positionNDC, positionWC);
- return Cartesian2.fromCartesian3(positionWC, result);
- };
- /**
- * @private
- */
- SceneTransforms.transformWindowToDrawingBuffer = function (
- scene,
- windowPosition,
- result
- ) {
- const canvas = scene.canvas;
- const xScale = scene.drawingBufferWidth / canvas.clientWidth;
- const yScale = scene.drawingBufferHeight / canvas.clientHeight;
- return Cartesian2.fromElements(
- windowPosition.x * xScale,
- windowPosition.y * yScale,
- result
- );
- };
- const scratchNDC = new Cartesian4();
- const scratchWorldCoords = new Cartesian4();
- /**
- * @private
- */
- SceneTransforms.drawingBufferToWgs84Coordinates = function (
- scene,
- drawingBufferPosition,
- depth,
- result
- ) {
- const context = scene.context;
- const uniformState = context.uniformState;
- const currentFrustum = uniformState.currentFrustum;
- const near = currentFrustum.x;
- const far = currentFrustum.y;
- if (scene.frameState.useLogDepth) {
- // transforming logarithmic depth of form
- // log2(z + 1) / log2( far + 1);
- // to perspective form
- // (far - far * near / z) / (far - near)
- const log2Depth = depth * uniformState.log2FarDepthFromNearPlusOne;
- const depthFromNear = Math.pow(2.0, log2Depth) - 1.0;
- depth = (far * (1.0 - near / (depthFromNear + near))) / (far - near);
- }
- const viewport = scene.view.passState.viewport;
- const ndc = Cartesian4.clone(Cartesian4.UNIT_W, scratchNDC);
- ndc.x = ((drawingBufferPosition.x - viewport.x) / viewport.width) * 2.0 - 1.0;
- ndc.y =
- ((drawingBufferPosition.y - viewport.y) / viewport.height) * 2.0 - 1.0;
- ndc.z = depth * 2.0 - 1.0;
- ndc.w = 1.0;
- let worldCoords;
- let frustum = scene.camera.frustum;
- if (!defined(frustum.fovy)) {
- if (defined(frustum._offCenterFrustum)) {
- frustum = frustum._offCenterFrustum;
- }
- worldCoords = scratchWorldCoords;
- worldCoords.x =
- (ndc.x * (frustum.right - frustum.left) + frustum.left + frustum.right) *
- 0.5;
- worldCoords.y =
- (ndc.y * (frustum.top - frustum.bottom) + frustum.bottom + frustum.top) *
- 0.5;
- worldCoords.z = (ndc.z * (near - far) - near - far) * 0.5;
- worldCoords.w = 1.0;
- worldCoords = Matrix4.multiplyByVector(
- uniformState.inverseView,
- worldCoords,
- worldCoords
- );
- } else {
- worldCoords = Matrix4.multiplyByVector(
- uniformState.inverseViewProjection,
- ndc,
- scratchWorldCoords
- );
- // Reverse perspective divide
- const w = 1.0 / worldCoords.w;
- Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
- }
- return Cartesian3.fromCartesian4(worldCoords, result);
- };
- export default SceneTransforms;
|