diff --git a/Apps/Sandcastle/gallery/3D Models Coloring.html b/Apps/Sandcastle/gallery/3D Models Coloring.html index 979c9a6f955a..46c9dfad832c 100644 --- a/Apps/Sandcastle/gallery/3D Models Coloring.html +++ b/Apps/Sandcastle/gallery/3D Models Coloring.html @@ -172,11 +172,11 @@ viewer.entities.removeAll(); var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height); - var heading = Cesium.Math.toRadians(135); + var heading = -Cesium.Math.toRadians(135); var pitch = 0; var roll = 0; var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); - var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); + var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr, undefined, undefined, undefined, true); entity = viewer.entities.add({ name : url, diff --git a/Apps/Sandcastle/gallery/3D Models.html b/Apps/Sandcastle/gallery/3D Models.html index faa2af95ed0a..30caabdb7188 100644 --- a/Apps/Sandcastle/gallery/3D Models.html +++ b/Apps/Sandcastle/gallery/3D Models.html @@ -94,4 +94,4 @@ } - \ No newline at end of file + diff --git a/Apps/Sandcastle/gallery/Classification.html b/Apps/Sandcastle/gallery/Classification.html index b5ec8301a0bc..ea43207e72e1 100644 --- a/Apps/Sandcastle/gallery/Classification.html +++ b/Apps/Sandcastle/gallery/Classification.html @@ -56,7 +56,7 @@ var center = new Cesium.Cartesian3(1216378.730451297, -4736275.917774027, 4081266.871000864); var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center); - var hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(2.619728786416368, 0.0, 0.0)); + var hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(-2.619728786416368, 0.0, 0.0), undefined, true); var hpr = Cesium.Matrix4.fromRotationTranslation(hprRotation, new Cesium.Cartesian3(0.0, 0.0, -2.0)); Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix); @@ -91,7 +91,7 @@ var center = new Cesium.Cartesian3(1216398.6054139996, -4736204.533089285, 4081338.6585485404); var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center); - var hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(5.785339046755887, 0.0, 0.0)); + var hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(-5.785339046755887, 0.0, 0.0), undefined, true); var hpr = Cesium.Matrix4.fromRotationTranslation(hprRotation, new Cesium.Cartesian3(0.4, 0.0, -2.0)); Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix); @@ -111,7 +111,7 @@ center = new Cesium.Cartesian3(1216394.3346955755, -4736207.431365568, 4081336.7768881875); modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center); - hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(5.785339046755887, 0.0, 0.0)); + hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(-5.785339046755887, 0.0, 0.0), undefined, true); hpr = Cesium.Matrix4.fromRotationTranslation(hprRotation, new Cesium.Cartesian3(-0.25, 0.0, -2.0)); Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix); diff --git a/Apps/Sandcastle/gallery/Distance Display Conditions.html b/Apps/Sandcastle/gallery/Distance Display Conditions.html index d4475cabe5d8..6e656bb6dd17 100644 --- a/Apps/Sandcastle/gallery/Distance Display Conditions.html +++ b/Apps/Sandcastle/gallery/Distance Display Conditions.html @@ -54,8 +54,8 @@ var position = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 0.0); var heading = Cesium.Math.toRadians(135); - var hpr = new Cesium.HeadingPitchRoll(heading, 0.0, 0.0); - var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); + var hpr = new Cesium.HeadingPitchRoll(-heading, 0.0, 0.0); + var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr, undefined, undefined, undefined, true); viewer.entities.add({ position : position, diff --git a/Apps/Sandcastle/gallery/HeadingPitchRoll.html b/Apps/Sandcastle/gallery/HeadingPitchRoll.html index 6dc4987bf4eb..b227b8ffc4e6 100644 --- a/Apps/Sandcastle/gallery/HeadingPitchRoll.html +++ b/Apps/Sandcastle/gallery/HeadingPitchRoll.html @@ -110,7 +110,7 @@

Loading...

var planePrimitive = scene.primitives.add(Cesium.Model.fromGltf({ url : '../../SampleData/models/CesiumAir/Cesium_Air.glb', - modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform), + modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, undefined, true), minimumPixelSize : 128 })); @@ -208,7 +208,7 @@

Loading...

speedVector = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.UNIT_X, speed / 10, speedVector); position = Cesium.Matrix4.multiplyByPoint(planePrimitive.modelMatrix, speedVector, position); pathPosition.addSample(Cesium.JulianDate.now(), position); - Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, planePrimitive.modelMatrix); + Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, planePrimitive.modelMatrix, true); if (fromBehind.checked) { // Zoom to model diff --git a/Apps/Sandcastle/gallery/LocalToFixedFrame.html b/Apps/Sandcastle/gallery/LocalToFixedFrame.html index e2ac326ceee2..29e3bc3c83d5 100644 --- a/Apps/Sandcastle/gallery/LocalToFixedFrame.html +++ b/Apps/Sandcastle/gallery/LocalToFixedFrame.html @@ -110,12 +110,12 @@

Loading...

var comments = localFrames[i].comments; var planePrimitive = scene.primitives.add(Cesium.Model.fromGltf({ url : '../../SampleData/models/CesiumAir/Cesium_Air.glb', - modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, converter), + modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, converter, undefined, true), minimumPixelSize : 128 })); primitives.push({primitive : planePrimitive, converter : converter, position : position}); - var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hprRollZero, Cesium.Ellipsoid.WGS84, converter); + var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hprRollZero, Cesium.Ellipsoid.WGS84, converter, undefined, true); scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({ modelMatrix : modelMatrix, length : 300.0, @@ -221,7 +221,7 @@

Loading...

var primitive = primitives[i].primitive; var converter = primitives[i].converter; var position = primitives[i].position; - Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, converter, primitive.modelMatrix); + Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, converter, primitive.modelMatrix, true); } }); //Sandcastle_End diff --git a/Apps/Sandcastle/gallery/Projection.html b/Apps/Sandcastle/gallery/Projection.html index faa01ed692d1..470d2764face 100644 --- a/Apps/Sandcastle/gallery/Projection.html +++ b/Apps/Sandcastle/gallery/Projection.html @@ -36,8 +36,8 @@ viewer.projectionPicker.viewModel.switchToOrthographic(); var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 0.0); -var hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(135), 0.0, 0.0); -var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); +var hpr = new Cesium.HeadingPitchRoll(-Cesium.Math.toRadians(135), 0.0, 0.0); +var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr, undefined, undefined, undefined, true); var entity = viewer.entities.add({ position : position, diff --git a/Apps/Sandcastle/gallery/development/3D Models.html b/Apps/Sandcastle/gallery/development/3D Models.html index 9739f74752ef..4151357601e4 100644 --- a/Apps/Sandcastle/gallery/development/3D Models.html +++ b/Apps/Sandcastle/gallery/development/3D Models.html @@ -123,13 +123,13 @@ function createModel(url, height, heading, pitch, roll) { height = Cesium.defaultValue(height, 0.0); - heading = Cesium.defaultValue(heading, 0.0); - pitch = Cesium.defaultValue(pitch, 0.0); + heading = -Cesium.defaultValue(heading, 0.0); + pitch = -Cesium.defaultValue(pitch, 0.0); roll = Cesium.defaultValue(roll, 0.0); var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); var origin = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height); - var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(origin, hpr); + var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(origin, hpr, undefined, undefined, undefined, true); scene.primitives.removeAll(); // Remove previous model model = scene.primitives.add(Cesium.Model.fromGltf({ diff --git a/CHANGES.md b/CHANGES.md index 6a04cd71c154..f7cee7beb820 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,8 @@ Change Log * `Scene/OrthographicOffCenterFrustum` has been removed. Use `Core/OrthographicOffCenterFrustum`. * `Scene/PerspectiveFrustum` has been removed. Use `Core/PerspectiveFrustum`. * `Scene/PerspectiveOffCenterFrustum` has been removed. Use `Core/PerspectiveOffCenterFrustum`. +* Deprecated + * The default behavior of the functions `HeadingPitchRoll.fromQuaternion`, `Matrix3.fromHeadingPitchRoll`, `Quaternion.fromHeadingPitchRoll`, `Transforms.headingPitchRollToFixedFrame`, and `Transforms.headingPitchRollQuaternion` has been deprecated. An optional boolean flag can be supplied to these functions that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40.[#5666](https://github.com/AnalyticalGraphicsInc/cesium/issues/5666) * Added ability to add an animation to `ModelAnimationCollection` by its index. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815) * Fixed a bug in `ModelAnimationCollection` that caused adding an animation by its name to throw an error. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815) * Zoom about mouse now maintains camera heading, pitch, and roll [#4639](https://github.com/AnalyticalGraphicsInc/cesium/pull/5603) diff --git a/Source/Core/HeadingPitchRoll.js b/Source/Core/HeadingPitchRoll.js index b934f6d04f3e..03b3b4444519 100644 --- a/Source/Core/HeadingPitchRoll.js +++ b/Source/Core/HeadingPitchRoll.js @@ -2,12 +2,14 @@ define([ './defaultValue', './defined', './DeveloperError', - './Math' + './Math', + './deprecationWarning' ], function( defaultValue, defined, DeveloperError, - CesiumMath) { + CesiumMath, + deprecationWarning) { 'use strict'; /** @@ -30,11 +32,13 @@ define([ /** * Computes the heading, pitch and roll from a quaternion (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles ) * + * @deprecated since V1.38. An optional boolean flag can be supplied to this function that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40 * @param {Quaternion} quaternion The quaternion from which to retrieve heading, pitch, and roll, all expressed in radians. * @param {HeadingPitchRoll} [result] The object in which to store the result. If not provided, a new instance is created and returned. + * @param {Boolean} [false] Indicates if the function uses the classical orientation of heading and pitch (counter-clockwise). * @returns {HeadingPitchRoll} The modified result parameter or a new HeadingPitchRoll instance if one was not provided. */ - HeadingPitchRoll.fromQuaternion = function(quaternion, result) { + HeadingPitchRoll.fromQuaternion = function(quaternion, result, classical) { //>>includeStart('debug', pragmas.debug); if (!defined(quaternion)) { throw new DeveloperError('quaternion is required'); @@ -43,14 +47,24 @@ define([ if (!defined(result)) { result = new HeadingPitchRoll(); } + classical = defaultValue(classical, false); var test = 2 * (quaternion.w * quaternion.y - quaternion.z * quaternion.x); var denominatorRoll = 1 - 2 * (quaternion.x * quaternion.x + quaternion.y * quaternion.y); var numeratorRoll = 2 * (quaternion.w * quaternion.x + quaternion.y * quaternion.z); var denominatorHeading = 1 - 2 * (quaternion.y * quaternion.y + quaternion.z * quaternion.z); var numeratorHeading = 2 * (quaternion.w * quaternion.z + quaternion.x * quaternion.y); - result.heading = -Math.atan2(numeratorHeading, denominatorHeading); - result.roll = Math.atan2(numeratorRoll, denominatorRoll); - result.pitch = -Math.asin(test); + + if(classical === true){ + result.heading = Math.atan2(numeratorHeading, denominatorHeading); + result.roll = Math.atan2(numeratorRoll, denominatorRoll); + result.pitch = Math.asin(test); + } else { + deprecationWarning('HeadingPitchRoll.fromQuaternion', 'This HeadingPitchRoll.fromQuaternion works in the Cesium legacy fashion which means that heading and pitch is opposite of the classical interpretation used in mathematics. This behavior will be corrected in 1.40 in order to be classical. The new behavior can be evaluate using parameter classical setted to true'); + result.heading = -Math.atan2(numeratorHeading, denominatorHeading); + result.roll = Math.atan2(numeratorRoll, denominatorRoll); + result.pitch = -Math.asin(test); + } + return result; }; diff --git a/Source/Core/Matrix3.js b/Source/Core/Matrix3.js index 23e9b6c21376..47112adbe19d 100644 --- a/Source/Core/Matrix3.js +++ b/Source/Core/Matrix3.js @@ -6,7 +6,8 @@ define([ './defineProperties', './DeveloperError', './freezeObject', - './Math' + './Math', + './deprecationWarning' ], function( Cartesian3, Check, @@ -15,7 +16,8 @@ define([ defineProperties, DeveloperError, freezeObject, - CesiumMath) { + CesiumMath, + deprecationWarning) { 'use strict'; /** @@ -295,21 +297,41 @@ define([ /** * Computes a 3x3 rotation matrix from the provided headingPitchRoll. (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles ) * + * @deprecated since V1.38. An optional boolean flag can be supplied to this function that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40 * @param {HeadingPitchRoll} headingPitchRoll the headingPitchRoll to use. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. + * @param {Boolean} [false] Indicates if the function uses the classical orientation of heading and pitch (counter-clockwise). * @returns {Matrix3} The 3x3 rotation matrix from this headingPitchRoll. */ - Matrix3.fromHeadingPitchRoll = function(headingPitchRoll, result) { + Matrix3.fromHeadingPitchRoll = function(headingPitchRoll, result, classical) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object('headingPitchRoll', headingPitchRoll); //>>includeEnd('debug'); - - var cosTheta = Math.cos(-headingPitchRoll.pitch); - var cosPsi = Math.cos(-headingPitchRoll.heading); - var cosPhi = Math.cos(headingPitchRoll.roll); - var sinTheta = Math.sin(-headingPitchRoll.pitch); - var sinPsi = Math.sin(-headingPitchRoll.heading); - var sinPhi = Math.sin(headingPitchRoll.roll); + classical = defaultValue(classical, false); + + var cosTheta; + var cosPsi; + var cosPhi; + var sinTheta; + var sinPsi; + var sinPhi; + + if(classical === true){ + cosTheta = Math.cos(headingPitchRoll.pitch); + cosPsi = Math.cos(headingPitchRoll.heading); + cosPhi = Math.cos(headingPitchRoll.roll); + sinTheta = Math.sin(headingPitchRoll.pitch); + sinPsi = Math.sin(headingPitchRoll.heading); + sinPhi = Math.sin(headingPitchRoll.roll); + } else { + deprecationWarning('Matrix3.fromHeadingPitchRoll', 'This Matrix3.fromHeadingPitchRoll works in the Cesium legacy fashion which means that heading and pitch is opposite of the classical interpretation used in mathematics. This behavior will be corrected in 1.40 in order to be classical. The new behavior can be evaluate using parameter classical setted to true'); + cosTheta = Math.cos(-headingPitchRoll.pitch); + cosPsi = Math.cos(-headingPitchRoll.heading); + cosPhi = Math.cos(headingPitchRoll.roll); + sinTheta = Math.sin(-headingPitchRoll.pitch); + sinPsi = Math.sin(-headingPitchRoll.heading); + sinPhi = Math.sin(headingPitchRoll.roll); + } var m00 = cosTheta * cosPsi; var m01 = -cosPhi * sinPsi + sinPhi * sinTheta * cosPsi; diff --git a/Source/Core/Quaternion.js b/Source/Core/Quaternion.js index 346c135d71d9..babf555a4e17 100644 --- a/Source/Core/Quaternion.js +++ b/Source/Core/Quaternion.js @@ -7,7 +7,8 @@ define([ './freezeObject', './HeadingPitchRoll', './Math', - './Matrix3' + './Matrix3', + './deprecationWarning' ], function( Cartesian3, Check, @@ -17,7 +18,8 @@ define([ freezeObject, HeadingPitchRoll, CesiumMath, - Matrix3) { + Matrix3, + deprecationWarning) { 'use strict'; /** @@ -179,20 +181,32 @@ define([ * Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the * negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about * the positive x axis. + * @deprecated since V1.38. An optional boolean flag can be supplied to this function that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40 * * @param {HeadingPitchRoll} headingPitchRoll The rotation expressed as a heading, pitch and roll. * @param {Quaternion} [result] The object onto which to store the result. + * @param {Boolean} [false] Indicates if the function uses the classical orientation of heading and pitch (counter-clockwise). * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided. */ - Quaternion.fromHeadingPitchRoll = function(headingPitchRoll, result) { + Quaternion.fromHeadingPitchRoll = function(headingPitchRoll, result, classical) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object('headingPitchRoll', headingPitchRoll); //>>includeEnd('debug'); + classical = defaultValue(classical, false); + + if(classical === true){ + scratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion); + scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, headingPitchRoll.pitch, result); + result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion); + scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, headingPitchRoll.heading, scratchHPRQuaternion); + }else{ + deprecationWarning('Quaternion.fromHeadingPitchRoll', 'This Quaternion.fromHeadingPitchRoll works in the Cesium legacy fashion which means that heading and pitch is opposite of the classical interpretation used in mathematics. This behavior will be corrected in 1.40 in order to be classical. The new behavior can be evaluate using parameter classical setted to true'); + scratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion); + scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -headingPitchRoll.pitch, result); + result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion); + scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -headingPitchRoll.heading, scratchHPRQuaternion); + } - scratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion); - scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -headingPitchRoll.pitch, result); - result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion); - scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -headingPitchRoll.heading, scratchHPRQuaternion); return Quaternion.multiply(scratchHeadingQuaternion, result, result); }; diff --git a/Source/Core/Transforms.js b/Source/Core/Transforms.js index ef3ce08a0cbe..4d5a489f3669 100644 --- a/Source/Core/Transforms.js +++ b/Source/Core/Transforms.js @@ -18,7 +18,8 @@ define([ './Matrix3', './Matrix4', './Quaternion', - './TimeConstants' + './TimeConstants', + './deprecationWarning' ], function( when, Cartesian2, @@ -39,7 +40,8 @@ define([ Matrix3, Matrix4, Quaternion, - TimeConstants) { + TimeConstants, + deprecationWarning) { 'use strict'; /** @@ -311,6 +313,7 @@ define([ * centered at the provided origin to the provided ellipsoid's fixed reference frame. Heading is the rotation from the local north * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis. + * @deprecated since V1.38 An optional boolean flag can be supplied to this function that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40 * * @param {Cartesian3} origin The center point of the local reference frame. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll. @@ -318,6 +321,7 @@ define([ * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransform=Transforms.eastNorthUpToFixedFrame] A 4x4 transformation * matrix from a reference frame to the provided ellipsoid's fixed reference frame * @param {Matrix4} [result] The object onto which to store the result. + * @param {Boolean} [false] Indicates if the function uses the classical orientation of heading and pitch (counter-clockwise). * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided. * * @example @@ -329,14 +333,20 @@ define([ * var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); * var transform = Cesium.Transforms.headingPitchRollToFixedFrame(center, hpr); */ - Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) { + Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result, classical) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll); //>>includeEnd('debug'); - + classical = defaultValue(classical, false); fixedFrameTransform = defaultValue(fixedFrameTransform, Transforms.eastNorthUpToFixedFrame); - var hprQuaternion = Quaternion.fromHeadingPitchRoll(headingPitchRoll, scratchHPRQuaternion); - var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4); + + if(classical === true){ + Quaternion.fromHeadingPitchRoll(headingPitchRoll, scratchHPRQuaternion, true); + } else { + deprecationWarning('Transforms.headingPitchRollToFixedFrame', 'This Transforms.headingPitchRollToFixedFrame works in the Cesium legacy fashion which means that heading and pitch is opposite of the classical interpretation used in mathematics. This behavior will be corrected in 1.40 in order to be classical. The new behavior can be evaluate using parameter classical setted to true'); + Quaternion.fromHeadingPitchRoll(headingPitchRoll, scratchHPRQuaternion, false); + } + var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, scratchHPRQuaternion, scratchScale, scratchHPRMatrix4); result = fixedFrameTransform(origin, ellipsoid, result); return Matrix4.multiply(result, hprMatrix, result); }; @@ -349,6 +359,7 @@ define([ * centered at the provided origin. Heading is the rotation from the local north * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis. + * @deprecated since V1.38. An optional boolean flag can be supplied to this function that, if true, uses the classical orientation of heading and pitch calculated counter-clockwise. The flag will be removed and the new behavior made default in 1.40 * * @param {Cartesian3} origin The center point of the local reference frame. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll. @@ -356,6 +367,7 @@ define([ * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransform=Transforms.eastNorthUpToFixedFrame] A 4x4 transformation * matrix from a reference frame to the provided ellipsoid's fixed reference frame * @param {Quaternion} [result] The object onto which to store the result. + * @param {Boolean} [false] Indicates if the function uses the classical orientation of heading and pitch (counter-clockwise). * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided. * * @example @@ -367,14 +379,21 @@ define([ * var hpr = new HeadingPitchRoll(heading, pitch, roll); * var quaternion = Cesium.Transforms.headingPitchRollQuaternion(center, hpr); */ - Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) { + Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result, classical) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll); //>>includeEnd('debug'); + classical = defaultValue(classical, false); + if(classical === true){ + scratchENUMatrix4 = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, scratchENUMatrix4, true); + Matrix4.getRotation(scratchENUMatrix4, scratchHPRMatrix3); + } else { + deprecationWarning('Transforms.headingPitchRollQuaternion', 'This Transforms.headingPitchRollQuaternion works in the Cesium legacy fashion which means that heading and pitch is opposite of the classical interpretation used in mathematics. This behavior will be corrected in 1.40 in order to be classical. The new behavior can be evaluate using parameter classical setted to true'); + scratchENUMatrix4 = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, scratchENUMatrix4, false); + Matrix4.getRotation(scratchENUMatrix4, scratchHPRMatrix3); + } - var transform = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, scratchENUMatrix4); - var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3); - return Quaternion.fromRotationMatrix(rotation, result); + return Quaternion.fromRotationMatrix(scratchHPRMatrix3, result); }; var gmstConstant0 = 6 * 3600 + 41 * 60 + 50.54841; diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index f7155fc5c35e..f7fb64e07396 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -1039,7 +1039,6 @@ define([ var scratchSetViewCartesian = new Cartesian3(); var scratchSetViewTransform1 = new Matrix4(); var scratchSetViewTransform2 = new Matrix4(); - var scratchSetViewQuaternion = new Quaternion(); var scratchSetViewMatrix3 = new Matrix3(); var scratchSetViewCartographic = new Cartographic(); @@ -1049,10 +1048,10 @@ define([ camera._setTransform(localTransform); Cartesian3.clone(Cartesian3.ZERO, camera.position); - hpr.heading = hpr.heading - CesiumMath.PI_OVER_TWO; + hpr.heading = -hpr.heading + CesiumMath.PI_OVER_TWO; + hpr.pitch = -hpr.pitch; - var rotQuat = Quaternion.fromHeadingPitchRoll(hpr, scratchSetViewQuaternion); - var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3); + var rotMat = Matrix3.fromHeadingPitchRoll(hpr, scratchSetViewMatrix3, true); Matrix3.getColumn(rotMat, 0, camera.direction); Matrix3.getColumn(rotMat, 2, camera.up); @@ -1075,10 +1074,10 @@ define([ } Cartesian3.clone(position, camera.position); } - hpr.heading = hpr.heading - CesiumMath.PI_OVER_TWO; + hpr.heading = -hpr.heading + CesiumMath.PI_OVER_TWO; + hpr.pitch = -hpr.pitch; - var rotQuat = Quaternion.fromHeadingPitchRoll(hpr, scratchSetViewQuaternion); - var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3); + var rotMat = Matrix3.fromHeadingPitchRoll(hpr, scratchSetViewMatrix3, true); Matrix3.getColumn(rotMat, 0, camera.direction); Matrix3.getColumn(rotMat, 2, camera.up); @@ -1116,11 +1115,10 @@ define([ } if (camera._scene.mapMode2D === MapMode2D.ROTATE) { - hpr.heading = hpr.heading - CesiumMath.PI_OVER_TWO; - hpr.pitch = -CesiumMath.PI_OVER_TWO; + hpr.heading = -hpr.heading + CesiumMath.PI_OVER_TWO; + hpr.pitch = CesiumMath.PI_OVER_TWO; hpr.roll = 0.0; - var rotQuat = Quaternion.fromHeadingPitchRoll(hpr, scratchSetViewQuaternion); - var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3); + var rotMat = Matrix3.fromHeadingPitchRoll(hpr, scratchSetViewMatrix3, true); Matrix3.getColumn(rotMat, 2, camera.up); Cartesian3.cross(camera.direction, camera.up, camera.right); diff --git a/Specs/Core/HeadingPitchRollSpec.js b/Specs/Core/HeadingPitchRollSpec.js index 96642a9d99cd..f0b3466af9f0 100644 --- a/Specs/Core/HeadingPitchRollSpec.js +++ b/Specs/Core/HeadingPitchRollSpec.js @@ -51,6 +51,32 @@ defineSuite([ } }); + it('conversion from quaternion', function() { + var testingTab = [ + [0, 0, 0], + [90 * deg2rad, 0, 0], + [-90 * deg2rad, 0, 0], + [0, 89 * deg2rad, 0], + [0, -89 * deg2rad, 0], + [0, 0, 90 * deg2rad], + [0, 0, -90 * deg2rad], + [30 * deg2rad, 30 * deg2rad, 30 * deg2rad], + [-30 * deg2rad, -30 * deg2rad, 45 * deg2rad] + ]; + var hpr = new HeadingPitchRoll(); + for (var i = 0; i < testingTab.length; i++) { + var init = testingTab[i]; + hpr.heading = init[0]; + hpr.pitch = init[1]; + hpr.roll = init[2]; + + var result = HeadingPitchRoll.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true), undefined, true); + expect(init[0]).toEqualEpsilon(result.heading, CesiumMath.EPSILON11); + expect(init[1]).toEqualEpsilon(result.pitch, CesiumMath.EPSILON11); + expect(init[2]).toEqualEpsilon(result.roll, CesiumMath.EPSILON11); + } + }); + it('conversion from degrees', function() { var testingTab = [ [0, 0, 0], diff --git a/Specs/Core/Matrix3Spec.js b/Specs/Core/Matrix3Spec.js index b87c0775d199..1fedc4554ec0 100644 --- a/Specs/Core/Matrix3Spec.js +++ b/Specs/Core/Matrix3Spec.js @@ -161,6 +161,51 @@ defineSuite([ expect(returnedResult).toEqualEpsilon(expected, CesiumMath.EPSILON15); }); + it('fromHeadingPitchRoll works without a result parameter', function() { + var sPiOver4 = Math.sin(CesiumMath.PI_OVER_FOUR); + var cPiOver4 = Math.cos(CesiumMath.PI_OVER_FOUR); + var sPiOver2 = Math.sin(CesiumMath.PI_OVER_TWO); + var cPiOver2 = Math.cos(CesiumMath.PI_OVER_TWO); + + var tmp = Cartesian3.multiplyByScalar(new Cartesian3(0.0, 0.0, 1.0), sPiOver4, new Cartesian3()); + var quaternion = new Quaternion(tmp.x, tmp.y, tmp.z, cPiOver4); + var headingPitchRoll = HeadingPitchRoll.fromQuaternion(quaternion, undefined, true); + var expected = new Matrix3(cPiOver2, -sPiOver2, 0.0, sPiOver2, cPiOver2, 0.0, 0.0, 0.0, 1.0); + + var returnedResult = Matrix3.fromHeadingPitchRoll(headingPitchRoll, undefined, true); + expect(returnedResult).toEqualEpsilon(expected, CesiumMath.EPSILON15); + }); + + it('fromHeadingPitchRoll works with a result parameter', function() { + var sPiOver4 = Math.sin(CesiumMath.PI_OVER_FOUR); + var cPiOver4 = Math.cos(CesiumMath.PI_OVER_FOUR); + var sPiOver2 = Math.sin(CesiumMath.PI_OVER_TWO); + var cPiOver2 = Math.cos(CesiumMath.PI_OVER_TWO); + + var tmp = Cartesian3.multiplyByScalar(new Cartesian3(0.0, 0.0, 1.0), sPiOver4, new Cartesian3()); + var quaternion = new Quaternion(tmp.x, tmp.y, tmp.z, cPiOver4); + var headingPitchRoll = HeadingPitchRoll.fromQuaternion(quaternion, undefined, true); + var expected = new Matrix3(cPiOver2, -sPiOver2, 0.0, sPiOver2, cPiOver2, 0.0, 0.0, 0.0, 1.0); + var result = new Matrix3(); + var returnedResult = Matrix3.fromHeadingPitchRoll(headingPitchRoll, result, true); + expect(result).toBe(returnedResult); + expect(returnedResult).toEqualEpsilon(expected, CesiumMath.EPSILON15); + }); + + it('fromHeadingPitchRoll computed correctly', function() { + // Expected generated via STK Components + var expected = new Matrix3( + 0.754406506735489, 0.418940943945763, 0.505330889696038, + 0.133022221559489, 0.656295369162553, -0.742685314912828, + -0.642787609686539, 0.627506871597133, 0.439385041770705); + + var headingPitchRoll = new HeadingPitchRoll(CesiumMath.toRadians(10), CesiumMath.toRadians(40), CesiumMath.toRadians(55)); + var result = new Matrix3(); + var returnedResult = Matrix3.fromHeadingPitchRoll(headingPitchRoll, result, true); + expect(result).toBe(returnedResult); + expect(returnedResult).toEqualEpsilon(expected, CesiumMath.EPSILON15); + }); + it('fromScale works without a result parameter', function() { var expected = new Matrix3( diff --git a/Specs/Core/QuaternionSpec.js b/Specs/Core/QuaternionSpec.js index c969f95f690c..db9c7ac2703a 100644 --- a/Specs/Core/QuaternionSpec.js +++ b/Specs/Core/QuaternionSpec.js @@ -157,6 +157,59 @@ defineSuite([ expect(quaternion).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); + it('fromDirectHeadingPitchRoll with just heading', function() { + var angle = CesiumMath.toRadians(20.0); + var hpr = new HeadingPitchRoll(angle, 0.0, 0.0); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, undefined, true); + expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationZ(angle), CesiumMath.EPSILON11); + }); + + it('fromDirectHeadingPitchRoll with just pitch', function() { + var angle = CesiumMath.toRadians(20.0); + var hpr = new HeadingPitchRoll(0.0, angle, 0.0); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, undefined, true); + expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationY(angle), CesiumMath.EPSILON11); + }); + + it('fromDirectHeadingPitchRoll with just roll', function() { + var angle = CesiumMath.toRadians(20.0); + var hpr = new HeadingPitchRoll( 0.0, 0.0, angle); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, undefined, true); + expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationX(angle), CesiumMath.EPSILON11); + }); + + it('fromDirectHeadingPitchRoll with all angles (1)', function() { + var angle = CesiumMath.toRadians(20.0); + var hpr = new HeadingPitchRoll( angle, angle, angle); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, undefined, true); + var expected = Matrix3.fromRotationX(angle); + Matrix3.multiply(Matrix3.fromRotationY(angle), expected, expected); + Matrix3.multiply(Matrix3.fromRotationZ(angle), expected, expected); + expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + + it('fromDirectHeadingPitchRoll with all angles (2)', function() { + var heading = CesiumMath.toRadians(180.0); + var pitch = CesiumMath.toRadians(-45.0); + var roll = CesiumMath.toRadians(45.0); + var hpr = new HeadingPitchRoll( heading, pitch, roll); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, undefined, true); + var expected = Matrix3.fromRotationX(roll); + Matrix3.multiply(Matrix3.fromRotationY(pitch), expected, expected); + Matrix3.multiply(Matrix3.fromRotationZ(heading), expected, expected); + expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + + it('fromDirectHeadingPitchRoll works with result parameter', function() { + var angle = CesiumMath.toRadians(20.0); + var hpr = new HeadingPitchRoll(0.0, 0.0, angle); + var result = new Quaternion(); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, result, true); + var expected = Quaternion.fromRotationMatrix(Matrix3.fromRotationX(angle)); + expect(quaternion).toBe(result); + expect(quaternion).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + it('clone without a result parameter', function() { var quaternion = new Quaternion(1.0, 2.0, 3.0, 4.0); var result = quaternion.clone(); diff --git a/Specs/Core/TransformsSpec.js b/Specs/Core/TransformsSpec.js index 07a702507f56..f4905106fc73 100644 --- a/Specs/Core/TransformsSpec.js +++ b/Specs/Core/TransformsSpec.js @@ -538,6 +538,169 @@ defineSuite([ expect(actualTranslation).toEqual(origin); }); + it('directHeadingPitchRollToFixedFrame works without a result parameter', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true)); + var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); + var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); + var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); + + Cartesian3.fromElements(expectedX.z, expectedX.x, expectedX.y, expectedX); + Cartesian3.fromElements(expectedY.z, expectedY.x, expectedY.y, expectedY); + Cartesian3.fromElements(expectedZ.z, expectedZ.x, expectedZ.y, expectedZ); + + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, undefined, true); + var actualX = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); + var actualY = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); + var actualZ = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); + var actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(actualX).toEqual(expectedX); + expect(actualY).toEqual(expectedY); + expect(actualZ).toEqual(expectedZ); + expect(actualTranslation).toEqual(origin); + }); + + it('directHeadingPitchRollToFixedFrame works with a HeadingPitchRoll object and without a result parameter and a fixedFrameTransform', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true)); + var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); + var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); + var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); + + Cartesian3.fromElements(expectedX.z, expectedX.x, expectedX.y, expectedX); + Cartesian3.fromElements(expectedY.z, expectedY.x, expectedY.y, expectedY); + Cartesian3.fromElements(expectedZ.z, expectedZ.x, expectedZ.y, expectedZ); + + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, undefined, true); + var actualX = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); + var actualY = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); + var actualZ = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); + var actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(actualX).toEqual(expectedX); + expect(actualY).toEqual(expectedY); + expect(actualZ).toEqual(expectedZ); + expect(actualTranslation).toEqual(origin); + }); + + it('directHeadingPitchRollToFixedFrame works with a HeadingPitchRoll object and without a result parameter', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true)); + var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); + var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); + var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); + + Cartesian3.fromElements(expectedX.z, expectedX.x, expectedX.y, expectedX); + Cartesian3.fromElements(expectedY.z, expectedY.x, expectedY.y, expectedY); + Cartesian3.fromElements(expectedZ.z, expectedZ.x, expectedZ.y, expectedZ); + + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, undefined, true); + var actualX = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); + var actualY = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); + var actualZ = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); + var actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(actualX).toEqual(expectedX); + expect(actualY).toEqual(expectedY); + expect(actualZ).toEqual(expectedZ); + expect(actualTranslation).toEqual(origin); + }); + + it('directHeadingPitchRollToFixedFrame works with a result parameter', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true)); + var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); + var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); + var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); + + Cartesian3.fromElements(expectedX.z, expectedX.x, expectedX.y, expectedX); + Cartesian3.fromElements(expectedY.z, expectedY.x, expectedY.y, expectedY); + Cartesian3.fromElements(expectedZ.z, expectedZ.x, expectedZ.y, expectedZ); + + var result = new Matrix4(); + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, result, true); + var actualX = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); + var actualY = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); + var actualZ = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); + var actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(returnedResult).toBe(result); + expect(actualX).toEqual(expectedX); + expect(actualY).toEqual(expectedY); + expect(actualZ).toEqual(expectedZ); + expect(actualTranslation).toEqual(origin); + }); + + it('directHeadingPitchRollToFixedFrame works with a custom fixedFrameTransform', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr, undefined, true)); + var expectedEast = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); // east + var expectedNorth = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); // north + var expectedUp = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); // up + + Cartesian3.fromElements(expectedEast.z, expectedEast.x, expectedEast.y, expectedEast); + Cartesian3.fromElements(expectedNorth.z, expectedNorth.x, expectedNorth.y, expectedNorth); + Cartesian3.fromElements(expectedUp.z, expectedUp.x, expectedUp.y, expectedUp); + + var result = new Matrix4(); + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, result, true); + var actualEast = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); // east + var actualNorth = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); // north + var actualUp = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); // up + var actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(returnedResult).toBe(result); + expect(actualEast).toEqual(expectedEast); + expect(actualNorth).toEqual(expectedNorth); + expect(actualUp).toEqual(expectedUp); + expect(actualTranslation).toEqual(origin); + + var UNEFixedFrameConverter = Transforms.localFrameToFixedFrameGenerator('west','south'); // up north east + returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, UNEFixedFrameConverter, result, true); + actualEast = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 0, new Cartesian4())); // east + actualEast.y = -actualEast.y; + actualEast.z= -actualEast.z; + actualNorth = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 1, new Cartesian4())); // north + actualNorth.y = -actualNorth.y; + actualNorth.z= -actualNorth.z; + actualUp = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 2, new Cartesian4())); // up + actualUp.y = -actualUp.y; + actualUp.z= -actualUp.z; + actualTranslation = Cartesian3.fromCartesian4(Matrix4.getColumn(returnedResult, 3, new Cartesian4())); + + expect(returnedResult).toBe(result); + expect(actualEast).toEqual(expectedEast); + expect(actualNorth).toEqual(expectedNorth); + expect(actualUp).toEqual(expectedUp); + expect(actualTranslation).toEqual(origin); + }); + it('headingPitchRollQuaternion works without a result parameter', function() { var origin = new Cartesian3(1.0, 0.0, 0.0); var heading = CesiumMath.toRadians(20.0); @@ -606,6 +769,74 @@ defineSuite([ expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); + it('directHeadingPitchRollQuaternion works without a result parameter', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, undefined, true); + var expected = Matrix4.getRotation(transform, new Matrix3()); + + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, undefined, true); + var actual = Matrix3.fromQuaternion(quaternion); + expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + + it('directHeadingPitchRollQuaternion works with a result parameter', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, undefined, true); + var expected = Matrix4.getRotation(transform, new Matrix3()); + + var result = new Quaternion(); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, result, true); + var actual = Matrix3.fromQuaternion(quaternion); + expect(quaternion).toBe(result); + expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + + it('directHeadingPitchRollQuaternion works without a custom fixedFrameTransform', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + + var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, undefined, true); + var expected = Matrix4.getRotation(transform, new Matrix3()); + + var result = new Quaternion(); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, result, true); + var actual = Matrix3.fromQuaternion(quaternion); + expect(quaternion).toBe(result); + expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + + + it('directHeadingPitchRollQuaternion works with a custom fixedFrameTransform', function() { + var origin = new Cartesian3(1.0, 0.0, 0.0); + var heading = CesiumMath.toRadians(20.0); + var pitch = CesiumMath.toRadians(30.0); + var roll = CesiumMath.toRadians(40.0); + var hpr = new HeadingPitchRoll(heading, pitch, roll); + var fixedFrameTransform = Transforms.localFrameToFixedFrameGenerator('west','south'); + + var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, fixedFrameTransform, undefined, true); + var expected = Matrix4.getRotation(transform, new Matrix3()); + + var result = new Quaternion(); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, fixedFrameTransform, result, true); + var actual = Matrix3.fromQuaternion(quaternion); + expect(quaternion).toBe(result); + expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); + }); + it('computeTemeToPseudoFixedMatrix works before noon', function() { var time = JulianDate.fromDate(new Date('June 29, 2015 12:00:00 UTC')); var t = Transforms.computeTemeToPseudoFixedMatrix(time); @@ -1048,9 +1279,9 @@ defineSuite([ var heading = CesiumMath.toRadians(90.0); var pitch = CesiumMath.toRadians(45.0); var roll = 0.0; - var hpr = new HeadingPitchRoll(heading, pitch, roll); + var hpr = new HeadingPitchRoll(-heading, -pitch, roll); - var modelMatrix = Transforms.headingPitchRollToFixedFrame(origin, hpr, ellipsoid); + var modelMatrix = Transforms.headingPitchRollToFixedFrame(origin, hpr, ellipsoid, undefined, undefined, true); var modelMatrix2D = Transforms.basisTo2D(projection, modelMatrix, new Matrix4()); var translation2D = Cartesian3.fromCartesian4(Matrix4.getColumn(modelMatrix2D, 3, new Cartesian4())); @@ -1069,7 +1300,7 @@ defineSuite([ var heading = CesiumMath.toRadians(90.0); var pitch = CesiumMath.toRadians(45.0); var roll = 0.0; - var hpr = new HeadingPitchRoll(heading, pitch, roll); + var hpr = new HeadingPitchRoll(-heading, -pitch, roll); var modelMatrix = Transforms.headingPitchRollToFixedFrame(origin, hpr, ellipsoid); var modelMatrix2D = Transforms.basisTo2D(projection, modelMatrix, new Matrix4()); diff --git a/Specs/Scene/ModelInstanceCollectionSpec.js b/Specs/Scene/ModelInstanceCollectionSpec.js index 1b493721d190..adaaeceecb21 100644 --- a/Specs/Scene/ModelInstanceCollectionSpec.js +++ b/Specs/Scene/ModelInstanceCollectionSpec.js @@ -133,8 +133,8 @@ defineSuite([ var heading = Math.PI/2.0; var pitch = 0.0; var roll = 0.0; - var hpr = new HeadingPitchRoll(heading, pitch, roll); - var modelMatrix = Transforms.headingPitchRollToFixedFrame(position, hpr); + var hpr = new HeadingPitchRoll(-heading, -pitch, roll); + var modelMatrix = Transforms.headingPitchRollToFixedFrame(position, hpr, undefined, undefined, undefined, true); instances.push({ modelMatrix : modelMatrix });