diff --git a/Apps/Sandcastle/gallery/development/HeadingPitchRoll.html b/Apps/Sandcastle/gallery/HeadingPitchRoll.html similarity index 91% rename from Apps/Sandcastle/gallery/development/HeadingPitchRoll.html rename to Apps/Sandcastle/gallery/HeadingPitchRoll.html index a58c6fae485e..7597de58a5fc 100644 --- a/Apps/Sandcastle/gallery/development/HeadingPitchRoll.html +++ b/Apps/Sandcastle/gallery/HeadingPitchRoll.html @@ -4,8 +4,8 @@ - - + + Cesium Demo @@ -70,9 +70,10 @@

Loading...

var viewer = new Cesium.Viewer('cesiumContainer'); var canvas = viewer.canvas; canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas -canvas.onclick = function() { - canvas.focus(); -}; +canvas.addEventListener('click', function() { + canvas.focus(); +}); +canvas.focus(); var scene = viewer.scene; @@ -101,13 +102,15 @@

Loading...

var hpRoll = new Cesium.HeadingPitchRoll(); var hpRange = new Cesium.HeadingPitchRange(); var speed = 10; +var deltaRadians = Cesium.Math.toRadians(3.0); var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 5000.0); var speedVector = new Cesium.Cartesian3(); +var fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west'); var planePrimitive = scene.primitives.add(Cesium.Model.fromGltf({ url : '../../SampleData/models/CesiumAir/Cesium_Air.glb', - modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll), + modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform), minimumPixelSize : 128 })); @@ -128,19 +131,16 @@

Loading...

hpRange.pitch = pitch; hpRange.range = r * 50.0; camera.lookAt(center, hpRange); - update(); }); -document.addEventListener('keyup', function(e) { - var deltaRadians = Cesium.Math.toRadians(3.0); - +document.addEventListener('keydown', function(e) { switch (e.keyCode) { case 40: if (e.shiftKey) { // speed down speed = Math.max(--speed, 1); } else { - // pitch down until + // pitch down hpRoll.pitch -= deltaRadians; if (hpRoll.pitch < -Cesium.Math.TWO_PI) { hpRoll.pitch += Cesium.Math.TWO_PI; @@ -150,9 +150,9 @@

Loading...

case 38: if (e.shiftKey) { // speed up - speed = Math.max(speed++, 100); + speed = Math.min(++speed, 100); } else { - // pitch up until Math.PI/2 + // pitch up hpRoll.pitch += deltaRadians; if (hpRoll.pitch > Cesium.Math.TWO_PI) { hpRoll.pitch -= Cesium.Math.TWO_PI; @@ -161,7 +161,7 @@

Loading...

break; case 39: if (e.shiftKey) { - // roll right until Math.PI/2 + // roll right hpRoll.roll += deltaRadians; if (hpRoll.roll > Cesium.Math.TWO_PI) { hpRoll.roll -= Cesium.Math.TWO_PI; @@ -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, undefined, planePrimitive.modelMatrix); + Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, planePrimitive.modelMatrix); if (fromBehind.checked) { // Zoom to model @@ -217,7 +217,8 @@

Loading...

hpRange.pitch = hpRoll.pitch; camera.lookAt(center, hpRange); } -});//Sandcastle_End +}); +//Sandcastle_End Sandcastle.finishedLoading(); } if (typeof Cesium !== "undefined") { diff --git a/Apps/Sandcastle/gallery/HeadingPitchRoll.jpg b/Apps/Sandcastle/gallery/HeadingPitchRoll.jpg new file mode 100644 index 000000000000..6074ed758ac5 Binary files /dev/null and b/Apps/Sandcastle/gallery/HeadingPitchRoll.jpg differ diff --git a/Apps/Sandcastle/gallery/LocalToFixedFrame.html b/Apps/Sandcastle/gallery/LocalToFixedFrame.html new file mode 100644 index 000000000000..744e647fa37a --- /dev/null +++ b/Apps/Sandcastle/gallery/LocalToFixedFrame.html @@ -0,0 +1,237 @@ + + + + + + + + + Cesium Demo + + + + + + +
+
+

Loading...

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Click on the 3D window then use the keyboard to change settings.
Heading: °
← to left/→ to right
Pitch: °
↑ to up/↓ to down
roll: °
← + ⇧ left/→ + ⇧ right
+
+ + + diff --git a/Apps/Sandcastle/gallery/LocalToFixedFrame.jpg b/Apps/Sandcastle/gallery/LocalToFixedFrame.jpg new file mode 100644 index 000000000000..9d3771e9a4e2 Binary files /dev/null and b/Apps/Sandcastle/gallery/LocalToFixedFrame.jpg differ diff --git a/Apps/Sandcastle/gallery/development/3D Models Node Explorer.html b/Apps/Sandcastle/gallery/development/3D Models Node Explorer.html index e9bf3a982bcf..f17078d6a602 100644 --- a/Apps/Sandcastle/gallery/development/3D Models Node Explorer.html +++ b/Apps/Sandcastle/gallery/development/3D Models Node Explorer.html @@ -146,7 +146,7 @@ return transformations[nodeName]; }); -// these writable computed properties produce individual values for use in the UI +// these writable computed properties produce individual values for use in the UI ['translationX', 'translationY', 'translationZ', 'rotationHeading', 'rotationPitch', 'rotationRoll', 'scaleX', 'scaleY', 'scaleZ'].forEach(function(p) { Cesium.knockout.defineProperty(viewModel, p, { get: function() { @@ -155,7 +155,7 @@ set: function(value) { // coerce values to number viewModel.transformation[p] = +value; - } + } }); }); @@ -164,7 +164,8 @@ return new Cesium.Cartesian3(viewModel.translationX, viewModel.translationY, viewModel.translationZ); }); Cesium.knockout.defineProperty(viewModel, 'rotation', function() { - return Cesium.Quaternion.fromHeadingPitchRoll(viewModel.rotationHeading, viewModel.rotationPitch, viewModel.rotationRoll); + var hpr = new Cesium.HeadingPitchRoll(viewModel.rotationHeading, viewModel.rotationPitch, viewModel.rotationRoll); + return Cesium.Quaternion.fromHeadingPitchRoll(hpr); }); Cesium.knockout.defineProperty(viewModel, 'scale', function() { return new Cesium.Cartesian3(viewModel.scaleX, viewModel.scaleY, viewModel.scaleZ); @@ -192,17 +193,17 @@ model.readyPromise.then(function(model) { var camera = viewer.camera; - + // Zoom to model var controller = scene.screenSpaceCameraController; var r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near); controller.minimumZoomDistance = r * 0.5; - + var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cesium.Cartesian3()); var heading = Cesium.Math.toRadians(230.0); var pitch = Cesium.Math.toRadians(-20.0); camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0)); - + // enumerate nodes and add options var options = Object.keys(model._runtime.nodesByName).map(function(nodeName) { return { @@ -214,7 +215,7 @@ }); options[0].onselect(); Sandcastle.addToolbarMenu(options); - + // respond to viewmodel changes by applying the computed matrix Cesium.knockout.getObservable(viewModel, 'matrix').subscribe(function(newValue) { var node = model.getNode(viewModel.nodeName); diff --git a/Apps/Sandcastle/gallery/development/HeadingPitchRoll.jpg b/Apps/Sandcastle/gallery/development/HeadingPitchRoll.jpg deleted file mode 100644 index b06301c8a0a4..000000000000 Binary files a/Apps/Sandcastle/gallery/development/HeadingPitchRoll.jpg and /dev/null differ diff --git a/CHANGES.md b/CHANGES.md index bc0c9136fc5e..f8a4db7ca6f1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,9 @@ Change Log ### 1.31 - 2017-03-01 * Deprecated + * The function `Quaternion.fromHeadingPitchRoll(heading, pitch, roll,result)` will be removed in 1.33. Use `Quaternion.fromHeadingPitchRoll(hpr,result)` instead where hpr is a HeadingPitchRoll. + * The function `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator). + * The function `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator). * `ArcGisImageServerTerrainProvider` will be removed in 1.32 due to missing TIFF support in web browsers. * Breaking changes * Corrected spelling of `Color.FUCHSIA` from `Color.FUSCHIA`. [#4977](https://github.com/AnalyticalGraphicsInc/cesium/pull/4977) @@ -15,6 +18,7 @@ Change Log * Added new `PixelFormat` and `WebGLConstants` enums from WebGL extensions `WEBGL_compressed_s3tc`, `WEBGL_compressed_texture_pvrtc`, and `WEBGL_compressed_texture_etc1`. * Added `CompressedTextureBuffer`. * Improved `RectangleGeometry` by skipping unecessary logic in the code [#4948](https://github.com/AnalyticalGraphicsInc/cesium/pull/4948) +* Added `Transforms.localFrameToFixedFrameGenerator` to generate a function that computes a 4x4 transformation matrix from a local reference frame to fixed reference frame. * Fixed an issue where the camera would zoom past an object and flip to the other side of the globe. [#4967](https://github.com/AnalyticalGraphicsInc/cesium/pull/4967) and [#4982](https://github.com/AnalyticalGraphicsInc/cesium/pull/4982) ### 1.30 - 2017-02-01 diff --git a/Source/Core/Quaternion.js b/Source/Core/Quaternion.js index de7f28e57961..cd19446e2fc8 100644 --- a/Source/Core/Quaternion.js +++ b/Source/Core/Quaternion.js @@ -4,9 +4,11 @@ define([ './Check', './defaultValue', './defined', + './deprecationWarning', './DeveloperError', './FeatureDetection', './freezeObject', + './HeadingPitchRoll', './Math', './Matrix3' ], function( @@ -14,9 +16,11 @@ define([ Check, defaultValue, defined, + deprecationWarning, DeveloperError, FeatureDetection, freezeObject, + HeadingPitchRoll, CesiumMath, Matrix3) { 'use strict'; @@ -172,6 +176,9 @@ define([ }; var scratchHPRQuaternion = new Quaternion(); + var scratchHeadingQuaternion = new Quaternion(); + var scratchPitchQuaternion = new Quaternion(); + var scratchRollQuaternion = new Quaternion(); /** * Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the @@ -184,18 +191,29 @@ define([ * @param {Quaternion} [result] The object onto which to store the result. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided. */ - Quaternion.fromHeadingPitchRoll = function(heading, pitch, roll, result) { + Quaternion.fromHeadingPitchRoll = function(headingOrHeadingPitchRoll, pitchOrResult, roll, result) { //>>includeStart('debug', pragmas.debug); - Check.typeOf.number('heading', heading); - Check.typeOf.number('pitch', pitch); - Check.typeOf.number('roll', roll); + if (headingOrHeadingPitchRoll instanceof HeadingPitchRoll) { + Check.typeOf.object('headingPitchRoll', headingOrHeadingPitchRoll); + } else { + Check.typeOf.number(headingOrHeadingPitchRoll, 'heading'); + Check.typeOf.number(pitchOrResult, 'pitch'); + Check.typeOf.number(roll, 'roll'); + } //>>includeEnd('debug'); - - var rollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, roll, scratchHPRQuaternion); - var pitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -pitch, result); - result = Quaternion.multiply(pitchQuaternion, rollQuaternion, pitchQuaternion); - var headingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -heading, scratchHPRQuaternion); - return Quaternion.multiply(headingQuaternion, result, result); + var hpr; + if (headingOrHeadingPitchRoll instanceof HeadingPitchRoll) { + hpr = headingOrHeadingPitchRoll; + result = pitchOrResult; + } else { + deprecationWarning('Quaternion.fromHeadingPitchRoll(heading, pitch, roll,result)', 'The method was deprecated in Cesium 1.32 and will be removed in version 1.33. ' + 'Use Quaternion.fromHeadingPitchRoll(hpr,result) where hpr is a HeadingPitchRoll'); + hpr = new HeadingPitchRoll(headingOrHeadingPitchRoll, pitchOrResult, roll); + } + scratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, hpr.roll, scratchHPRQuaternion); + scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -hpr.pitch, result); + result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion); + scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -hpr.heading, scratchHPRQuaternion); + return Quaternion.multiply(scratchHeadingQuaternion, result, result); }; var sampledQuaternionAxis = new Cartesian3(); diff --git a/Source/Core/Transforms.js b/Source/Core/Transforms.js index e6a561adf9a2..75547a76aa2f 100644 --- a/Source/Core/Transforms.js +++ b/Source/Core/Transforms.js @@ -8,6 +8,7 @@ define([ './Check', './defaultValue', './defined', + './deprecationWarning', './DeveloperError', './EarthOrientationParameters', './EarthOrientationParametersSample', @@ -30,6 +31,7 @@ define([ Check, defaultValue, defined, + deprecationWarning, DeveloperError, EarthOrientationParameters, EarthOrientationParametersSample, @@ -52,9 +54,166 @@ define([ */ var Transforms = {}; - var eastNorthUpToFixedFrameNormal = new Cartesian3(); - var eastNorthUpToFixedFrameTangent = new Cartesian3(); - var eastNorthUpToFixedFrameBitangent = new Cartesian3(); + var vectorProductLocalFrame = { + up : { + south : 'east', + north : 'west', + west : 'south', + east : 'north' + }, + down : { + south : 'west', + north : 'east', + west : 'north', + east : 'south' + }, + south : { + up : 'west', + down : 'east', + west : 'down', + east : 'up' + }, + north : { + up : 'east', + down : 'west', + west : 'up', + east : 'down' + }, + west : { + up : 'north', + down : 'south', + north : 'down', + south : 'up' + }, + east : { + up : 'south', + down : 'north', + north : 'up', + south : 'down' + } + }; + + var degeneratePositionLocalFrame = { + north : [-1, 0, 0], + east : [0, 1, 0], + up : [0, 0, 1], + south : [1, 0, 0], + west : [0, -1, 0], + down : [0, 0, -1] + }; + + var localFrameToFixedFrameCache = {}; + + var scratchCalculateCartesian = { + east : new Cartesian3(), + north : new Cartesian3(), + up : new Cartesian3(), + west : new Cartesian3(), + south : new Cartesian3(), + down : new Cartesian3() + }; + var scratchFirstCartesian = new Cartesian3(); + var scratchSecondCartesian = new Cartesian3(); + var scratchThirdCartesian = new Cartesian3(); + /** + * Generates a function that computes a 4x4 transformation matrix from a reference frame + * centered at the provided origin to the provided ellipsoid's fixed reference frame. + * @param {String} firstAxis name of the first axis of the local reference frame. Must be + * 'east', 'north', 'up', 'west', 'south' or 'down'. + * @param {String} secondAxis name of the second axis of the local reference frame. Must be + * 'east', 'north', 'up', 'west', 'south' or 'down'. + * @return {localFrameToFixedFrameGenerator~resultat} The function that will computes a + * 4x4 transformation matrix from a reference frame, with first axis and second axis compliant with the parameters, + */ + Transforms.localFrameToFixedFrameGenerator = function( firstAxis, secondAxis) { + if (!vectorProductLocalFrame.hasOwnProperty(firstAxis) || !vectorProductLocalFrame[firstAxis].hasOwnProperty(secondAxis)) { + throw new DeveloperError('firstAxis and secondAxis must be east, north, up, west, south or down.'); + } + var thirdAxis = vectorProductLocalFrame[firstAxis][secondAxis]; + + /** + * Computes a 4x4 transformation matrix from a reference frame + * centered at the provided origin to the provided ellipsoid's fixed reference frame. + * @callback Transforms~LocalFrameToFixedFrame + * @param {Cartesian3} origin The center point of the local reference frame. + * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation. + * @param {Matrix4} [result] The object onto which to store the result. + * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided. + */ + var resultat; + var hashAxis = firstAxis + secondAxis; + if (defined(localFrameToFixedFrameCache[hashAxis])) { + resultat = localFrameToFixedFrameCache[hashAxis]; + } else { + resultat = function(origin, ellipsoid, result) { + //>>includeStart('debug', pragmas.debug); + if (!defined(origin)) { + throw new DeveloperError('origin is required.'); + } + //>>includeEnd('debug'); + if (!defined(result)) { + result = new Matrix4(); + } + // If x and y are zero, assume origin is at a pole, which is a special case. + if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { + var sign = CesiumMath.sign(origin.z); + + Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian); + if (firstAxis !== 'east' && firstAxis !== 'west') { + Cartesian3.multiplyByScalar(scratchFirstCartesian, sign, scratchFirstCartesian); + } + + Cartesian3.unpack(degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian); + if (secondAxis !== 'east' && secondAxis !== 'west') { + Cartesian3.multiplyByScalar(scratchSecondCartesian, sign, scratchSecondCartesian); + } + + Cartesian3.unpack(degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian); + if (thirdAxis !== 'east' && thirdAxis !== 'west') { + Cartesian3.multiplyByScalar(scratchThirdCartesian, sign, scratchThirdCartesian); + } + } else { + ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); + ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up); + + var up = scratchCalculateCartesian.up; + var east = scratchCalculateCartesian.east; + east.x = -origin.y; + east.y = origin.x; + east.z = 0.0; + Cartesian3.normalize(east, scratchCalculateCartesian.east); + Cartesian3.cross(up, east, scratchCalculateCartesian.north); + + Cartesian3.multiplyByScalar(scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down); + Cartesian3.multiplyByScalar(scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west); + Cartesian3.multiplyByScalar(scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south); + + scratchFirstCartesian = scratchCalculateCartesian[firstAxis]; + scratchSecondCartesian = scratchCalculateCartesian[secondAxis]; + scratchThirdCartesian = scratchCalculateCartesian[thirdAxis]; + } + result[0] = scratchFirstCartesian.x; + result[1] = scratchFirstCartesian.y; + result[2] = scratchFirstCartesian.z; + result[3] = 0.0; + result[4] = scratchSecondCartesian.x; + result[5] = scratchSecondCartesian.y; + result[6] = scratchSecondCartesian.z; + result[7] = 0.0; + result[8] = scratchThirdCartesian.x; + result[9] = scratchThirdCartesian.y; + result[10] = scratchThirdCartesian.z; + result[11] = 0.0; + result[12] = origin.x; + result[13] = origin.y; + result[14] = origin.z; + result[15] = 1.0; + return result; + }; + localFrameToFixedFrameCache[hashAxis] = resultat; + } + return resultat; + }; /** * Computes a 4x4 transformation matrix from a reference frame with an east-north-up axes @@ -76,86 +235,7 @@ define([ * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0); * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center); */ - Transforms.eastNorthUpToFixedFrame = function(origin, ellipsoid, result) { - //>>includeStart('debug', pragmas.debug); - if (!defined(origin)) { - throw new DeveloperError('origin is required.'); - } - //>>includeEnd('debug'); - - // If x and y are zero, assume origin is at a pole, which is a special case. - if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && - CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { - var sign = CesiumMath.sign(origin.z); - if (!defined(result)) { - return new Matrix4( - 0.0, -sign, 0.0, origin.x, - 1.0, 0.0, 0.0, origin.y, - 0.0, 0.0, sign, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = 0.0; - result[1] = 1.0; - result[2] = 0.0; - result[3] = 0.0; - result[4] = -sign; - result[5] = 0.0; - result[6] = 0.0; - result[7] = 0.0; - result[8] = 0.0; - result[9] = 0.0; - result[10] = sign; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - } - - var normal = eastNorthUpToFixedFrameNormal; - var tangent = eastNorthUpToFixedFrameTangent; - var bitangent = eastNorthUpToFixedFrameBitangent; - - ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); - ellipsoid.geodeticSurfaceNormal(origin, normal); - - tangent.x = -origin.y; - tangent.y = origin.x; - tangent.z = 0.0; - Cartesian3.normalize(tangent, tangent); - - Cartesian3.cross(normal, tangent, bitangent); - - if (!defined(result)) { - return new Matrix4( - tangent.x, bitangent.x, normal.x, origin.x, - tangent.y, bitangent.y, normal.y, origin.y, - tangent.z, bitangent.z, normal.z, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = tangent.x; - result[1] = tangent.y; - result[2] = tangent.z; - result[3] = 0.0; - result[4] = bitangent.x; - result[5] = bitangent.y; - result[6] = bitangent.z; - result[7] = 0.0; - result[8] = normal.x; - result[9] = normal.y; - result[10] = normal.z; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - }; - - var northEastDownToFixedFrameNormal = new Cartesian3(); - var northEastDownToFixedFrameTangent = new Cartesian3(); - var northEastDownToFixedFrameBitangent = new Cartesian3(); + Transforms.eastNorthUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator('east','north'); /** * Computes a 4x4 transformation matrix from a reference frame with an north-east-down axes @@ -177,82 +257,7 @@ define([ * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0); * var transform = Cesium.Transforms.northEastDownToFixedFrame(center); */ - Transforms.northEastDownToFixedFrame = function(origin, ellipsoid, result) { - //>>includeStart('debug', pragmas.debug); - if (!defined(origin)) { - throw new DeveloperError('origin is required.'); - } - //>>includeEnd('debug'); - - if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && - CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { - // The poles are special cases. If x and y are zero, assume origin is at a pole. - var sign = CesiumMath.sign(origin.z); - if (!defined(result)) { - return new Matrix4( - -sign, 0.0, 0.0, origin.x, - 0.0, 1.0, 0.0, origin.y, - 0.0, 0.0, -sign, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = -sign; - result[1] = 0.0; - result[2] = 0.0; - result[3] = 0.0; - result[4] = 0.0; - result[5] = 1.0; - result[6] = 0.0; - result[7] = 0.0; - result[8] = 0.0; - result[9] = 0.0; - result[10] = -sign; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - } - - var normal = northEastDownToFixedFrameNormal; - var tangent = northEastDownToFixedFrameTangent; - var bitangent = northEastDownToFixedFrameBitangent; - - ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); - ellipsoid.geodeticSurfaceNormal(origin, normal); - - tangent.x = -origin.y; - tangent.y = origin.x; - tangent.z = 0.0; - Cartesian3.normalize(tangent, tangent); - - Cartesian3.cross(normal, tangent, bitangent); - - if (!defined(result)) { - return new Matrix4( - bitangent.x, tangent.x, -normal.x, origin.x, - bitangent.y, tangent.y, -normal.y, origin.y, - bitangent.z, tangent.z, -normal.z, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = bitangent.x; - result[1] = bitangent.y; - result[2] = bitangent.z; - result[3] = 0.0; - result[4] = tangent.x; - result[5] = tangent.y; - result[6] = tangent.z; - result[7] = 0.0; - result[8] = -normal.x; - result[9] = -normal.y; - result[10] = -normal.z; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - }; + Transforms.northEastDownToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','east'); /** * Computes a 4x4 transformation matrix from a reference frame with an north-up-east axes @@ -274,82 +279,7 @@ define([ * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0); * var transform = Cesium.Transforms.northUpEastToFixedFrame(center); */ - Transforms.northUpEastToFixedFrame = function(origin, ellipsoid, result) { - //>>includeStart('debug', pragmas.debug); - if (!defined(origin)) { - throw new DeveloperError('origin is required.'); - } - //>>includeEnd('debug'); - - // If x and y are zero, assume origin is at a pole, which is a special case. - if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && - CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { - var sign = CesiumMath.sign(origin.z); - if (!defined(result)) { - return new Matrix4( - -sign, 0.0, 0.0, origin.x, - 0.0, 0.0, 1.0, origin.y, - 0.0, sign, 0.0, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = -sign; - result[1] = 0.0; - result[2] = 0.0; - result[3] = 0.0; - result[4] = 0.0; - result[5] = 0.0; - result[6] = sign; - result[7] = 0.0; - result[8] = 0.0; - result[9] = 1.0; - result[10] = 0.0; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - } - - var normal = eastNorthUpToFixedFrameNormal; - var tangent = eastNorthUpToFixedFrameTangent; - var bitangent = eastNorthUpToFixedFrameBitangent; - - ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); - ellipsoid.geodeticSurfaceNormal(origin, normal); - - tangent.x = -origin.y; - tangent.y = origin.x; - tangent.z = 0.0; - Cartesian3.normalize(tangent, tangent); - - Cartesian3.cross(normal, tangent, bitangent); - - if (!defined(result)) { - return new Matrix4( - bitangent.x, normal.x, tangent.x, origin.x, - bitangent.y, normal.y, tangent.y, origin.y, - bitangent.z, normal.z, tangent.z, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = bitangent.x; - result[1] = bitangent.y; - result[2] = bitangent.z; - result[3] = 0.0; - result[4] = normal.x; - result[5] = normal.y; - result[6] = normal.z; - result[7] = 0.0; - result[8] = tangent.x; - result[9] = tangent.y; - result[10] = tangent.z; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - }; + Transforms.northUpEastToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','up'); /** * Computes a 4x4 transformation matrix from a reference frame with an north-west-up axes @@ -371,82 +301,7 @@ define([ * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0); * var transform = Cesium.Transforms.northWestUpToFixedFrame(center); */ - Transforms.northWestUpToFixedFrame = function(origin, ellipsoid, result) { - //>>includeStart('debug', pragmas.debug); - if (!defined(origin)) { - throw new DeveloperError('origin is required.'); - } - //>>includeEnd('debug'); - - // If x and y are zero, assume origin is at a pole, which is a special case. - if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && - CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { - var sign = CesiumMath.sign(origin.z); - if (!defined(result)) { - return new Matrix4( - -sign, 0.0, 0.0, origin.x, - 0.0, -1.0, 0.0, origin.y, - 0.0, 0.0, sign, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = -sign; - result[1] = 0.0; - result[2] = 0.0; - result[3] = 0.0; - result[4] = 0.0; - result[5] = -1.0; - result[6] = 0.0; - result[7] = 0.0; - result[8] = 0.0; - result[9] = 0.0; - result[10] = sign; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; - } - - var normal = eastNorthUpToFixedFrameNormal;//Up - var tangent = eastNorthUpToFixedFrameTangent;//East - var bitangent = eastNorthUpToFixedFrameBitangent;//North - - ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); - ellipsoid.geodeticSurfaceNormal(origin, normal); - - tangent.x = -origin.y; - tangent.y = origin.x; - tangent.z = 0.0; - Cartesian3.normalize(tangent, tangent); - - Cartesian3.cross(normal, tangent, bitangent); - - if (!defined(result)) { - return new Matrix4( - bitangent.x, -tangent.x, normal.x, origin.x, - bitangent.y, -tangent.y, normal.y, origin.y, - bitangent.z, -tangent.z, normal.z, origin.z, - 0.0, 0.0, 0.0, 1.0); - } - result[0] = bitangent.x; - result[1] = bitangent.y; - result[2] = bitangent.z; - result[3] = 0.0; - result[4] = -tangent.x; - result[5] = -tangent.y; - result[6] = -tangent.z; - result[7] = 0.0; - result[8] = normal.x; - result[9] = normal.y; - result[10] = normal.z; - result[11] = 0.0; - result[12] = origin.x; - result[13] = origin.y; - result[14] = origin.z; - result[15] = 1.0; - return result; -}; + Transforms.northWestUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','west'); var scratchHPRQuaternion = new Quaternion(); var scratchScale = new Cartesian3(1.0, 1.0, 1.0); @@ -461,6 +316,8 @@ define([ * @param {Cartesian3} origin The center point of the local reference frame. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation. + * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransformOrResult=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. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided. * @@ -473,16 +330,21 @@ define([ * var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); * var transform = Cesium.Transforms.headingPitchRollToFixedFrame(center, hpr); */ - Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, result) { - Check.typeOf.object('headingPitchRoll', headingPitchRoll); - var heading = headingPitchRoll.heading; - var pitch = headingPitchRoll.pitch; - var roll = headingPitchRoll.roll; + Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransformOrResult, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll); + //>>includeEnd('debug'); // checks for required parameters happen in the called functions - var hprQuaternion = Quaternion.fromHeadingPitchRoll(heading, pitch, roll, scratchHPRQuaternion); + if(fixedFrameTransformOrResult instanceof Matrix4){ + result = fixedFrameTransformOrResult; + fixedFrameTransformOrResult = undefined; + deprecationWarning('Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, result)', 'The method was deprecated in Cesium 1.31 and will be removed in version 1.33. Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator)'); + } + fixedFrameTransformOrResult = defaultValue(fixedFrameTransformOrResult,Transforms.eastNorthUpToFixedFrame); + var hprQuaternion = Quaternion.fromHeadingPitchRoll(headingPitchRoll, scratchHPRQuaternion); var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4); - result = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, result); + result = fixedFrameTransformOrResult(origin, ellipsoid, result); return Matrix4.multiply(result, hprMatrix, result); }; @@ -498,6 +360,8 @@ define([ * @param {Cartesian3} origin The center point of the local reference frame. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation. + * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransformOrResult=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. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided. * @@ -510,10 +374,16 @@ define([ * var hpr = new HeadingPitchRoll(heading, pitch, roll); * var quaternion = Cesium.Transforms.headingPitchRollQuaternion(center, hpr); */ - Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, result) { - // checks for required parameters happen in the called functions - Check.typeOf.object('headingPitchRoll', headingPitchRoll); - var transform = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, scratchENUMatrix4); + Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransformOrResult, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll); + //>>includeEnd('debug'); + if (fixedFrameTransformOrResult instanceof Quaternion) { + result = fixedFrameTransformOrResult; + fixedFrameTransformOrResult = undefined; + deprecationWarning('Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, result)', 'The method was deprecated in Cesium 1.31 and will be removed in version 1.33. Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator)'); + } + var transform = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid,fixedFrameTransformOrResult, scratchENUMatrix4); var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3); return Quaternion.fromRotationMatrix(rotation, result); }; diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 66ea1413be01..d2ee120847fc 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -14,6 +14,7 @@ define([ '../Core/EllipsoidGeodesic', '../Core/Event', '../Core/HeadingPitchRange', + '../Core/HeadingPitchRoll', '../Core/Intersect', '../Core/IntersectionTests', '../Core/Math', @@ -42,6 +43,7 @@ define([ EllipsoidGeodesic, Event, HeadingPitchRange, + HeadingPitchRoll, Intersect, IntersectionTests, CesiumMath, @@ -963,14 +965,15 @@ define([ var scratchSetViewMatrix3 = new Matrix3(); var scratchSetViewCartographic = new Cartographic(); - function setView3D(camera, position, heading, pitch, roll) { + function setView3D(camera, position, hpr) { var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1); var localTransform = Transforms.eastNorthUpToFixedFrame(position, camera._projection.ellipsoid, scratchSetViewTransform2); camera._setTransform(localTransform); Cartesian3.clone(Cartesian3.ZERO, camera.position); + hpr.heading = hpr.heading - CesiumMath.PI_OVER_TWO; - var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion); + var rotQuat = Quaternion.fromHeadingPitchRoll(hpr, scratchSetViewQuaternion); var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3); Matrix3.getColumn(rotMat, 0, camera.direction); @@ -980,7 +983,7 @@ define([ camera._setTransform(currentTransform); } - function setViewCV(camera, position, heading, pitch, roll, convert) { + function setViewCV(camera, position,hpr, convert) { var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1); camera._setTransform(Matrix4.IDENTITY); @@ -992,8 +995,9 @@ define([ } Cartesian3.clone(position, camera.position); } + hpr.heading = hpr.heading - CesiumMath.PI_OVER_TWO; - var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion); + var rotQuat = Quaternion.fromHeadingPitchRoll(hpr, scratchSetViewQuaternion); var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3); Matrix3.getColumn(rotMat, 0, camera.direction); @@ -1003,10 +1007,7 @@ define([ camera._setTransform(currentTransform); } - function setView2D(camera, position, heading, convert) { - var pitch = -CesiumMath.PI_OVER_TWO; - var roll = 0.0; - + function setView2D(camera, position, hpr, convert) { var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1); camera._setTransform(Matrix4.IDENTITY); @@ -1033,7 +1034,10 @@ define([ } if (camera._scene.mapMode2D === MapMode2D.ROTATE) { - var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion); + 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); Matrix3.getColumn(rotMat, 2, camera.up); @@ -1082,6 +1086,7 @@ define([ endTransform : undefined }; + var scratchHpr = new HeadingPitchRoll(); /** * Sets the camera position, orientation and transform. * @@ -1156,18 +1161,18 @@ define([ orientation = directionUpToHeadingPitchRoll(this, destination, orientation, scratchSetViewOptions.orientation); } - var heading = defaultValue(orientation.heading, 0.0); - var pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO); - var roll = defaultValue(orientation.roll, 0.0); + scratchHpr.heading = defaultValue(orientation.heading, 0.0); + scratchHpr.pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO); + scratchHpr.roll = defaultValue(orientation.roll, 0.0); this._suspendTerrainAdjustment = true; if (mode === SceneMode.SCENE3D) { - setView3D(this, destination, heading, pitch, roll); + setView3D(this, destination, scratchHpr); } else if (mode === SceneMode.SCENE2D) { - setView2D(this, destination, heading, convert); + setView2D(this, destination, scratchHpr, convert); } else { - setViewCV(this, destination, heading, pitch, roll, convert); + setViewCV(this, destination, scratchHpr, convert); } }; diff --git a/Specs/Core/HeadingPitchRollSpec.js b/Specs/Core/HeadingPitchRollSpec.js index 93c150ea666e..920b4c05896c 100644 --- a/Specs/Core/HeadingPitchRollSpec.js +++ b/Specs/Core/HeadingPitchRollSpec.js @@ -38,9 +38,14 @@ defineSuite([ [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]; - var result = HeadingPitchRoll.fromQuaternion(Quaternion.fromHeadingPitchRoll(init[0], init[1], init[2])); + hpr.heading = init[0]; + hpr.pitch = init[1]; + hpr.roll = init[2]; + + var result = HeadingPitchRoll.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr)); expect(init[0]).toEqualEpsilon(result.heading, CesiumMath.EPSILON11); expect(init[1]).toEqualEpsilon(result.pitch, CesiumMath.EPSILON11); expect(init[2]).toEqualEpsilon(result.roll, CesiumMath.EPSILON11); diff --git a/Specs/Core/QuaternionSpec.js b/Specs/Core/QuaternionSpec.js index 7310a599acc0..ca4861320cab 100644 --- a/Specs/Core/QuaternionSpec.js +++ b/Specs/Core/QuaternionSpec.js @@ -2,12 +2,14 @@ defineSuite([ 'Core/Quaternion', 'Core/Cartesian3', + 'Core/HeadingPitchRoll', 'Core/Math', 'Core/Matrix3', 'Specs/createPackableSpecs' ], function( Quaternion, Cartesian3, + HeadingPitchRoll, CesiumMath, Matrix3, createPackableSpecs) { @@ -105,25 +107,29 @@ defineSuite([ it('fromHeadingPitchRoll with just heading', function() { var angle = CesiumMath.toRadians(20.0); - var quaternion = Quaternion.fromHeadingPitchRoll(angle, 0.0, 0.0); + var hpr = new HeadingPitchRoll(angle, 0.0, 0.0); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationZ(-angle), CesiumMath.EPSILON11); }); it('fromHeadingPitchRoll with just pitch', function() { var angle = CesiumMath.toRadians(20.0); - var quaternion = Quaternion.fromHeadingPitchRoll(0.0, angle, 0.0); + var hpr = new HeadingPitchRoll(0.0, angle, 0.0); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationY(-angle), CesiumMath.EPSILON11); }); it('fromHeadingPitchRoll with just roll', function() { var angle = CesiumMath.toRadians(20.0); - var quaternion = Quaternion.fromHeadingPitchRoll(0.0, 0.0, angle); + var hpr = new HeadingPitchRoll( 0.0, 0.0, angle); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr); expect(Matrix3.fromQuaternion(quaternion)).toEqualEpsilon(Matrix3.fromRotationX(angle), CesiumMath.EPSILON11); }); it('fromHeadingPitchRoll with all angles (1)', function() { var angle = CesiumMath.toRadians(20.0); - var quaternion = Quaternion.fromHeadingPitchRoll(angle, angle, angle); + var hpr = new HeadingPitchRoll( angle, angle, angle); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr); var expected = Matrix3.fromRotationX(angle); Matrix3.multiply(Matrix3.fromRotationY(-angle), expected, expected); Matrix3.multiply(Matrix3.fromRotationZ(-angle), expected, expected); @@ -134,7 +140,8 @@ defineSuite([ var heading = CesiumMath.toRadians(180.0); var pitch = CesiumMath.toRadians(-45.0); var roll = CesiumMath.toRadians(45.0); - var quaternion = Quaternion.fromHeadingPitchRoll(heading, pitch, roll); + var hpr = new HeadingPitchRoll( heading, pitch, roll); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr); var expected = Matrix3.fromRotationX(roll); Matrix3.multiply(Matrix3.fromRotationY(-pitch), expected, expected); Matrix3.multiply(Matrix3.fromRotationZ(-heading), expected, expected); @@ -143,8 +150,9 @@ defineSuite([ it('fromHeadingPitchRoll 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(0.0, 0.0, angle, result); + var quaternion = Quaternion.fromHeadingPitchRoll(hpr, result); var expected = Quaternion.fromRotationMatrix(Matrix3.fromRotationX(angle)); expect(quaternion).toBe(result); expect(quaternion).toEqualEpsilon(expected, CesiumMath.EPSILON11); @@ -653,24 +661,6 @@ defineSuite([ }).toThrowDeveloperError(); }); - it('fromHeadingPitchRoll throws with undefined heading', function() { - expect(function() { - Quaternion.fromHeadingPitchRoll(undefined, 0.0, 0.0); - }).toThrowDeveloperError(); - }); - - it('fromHeadingPitchRoll throws with undefined pitch', function() { - expect(function() { - Quaternion.fromHeadingPitchRoll(0.0, undefined, 0.0); - }).toThrowDeveloperError(); - }); - - it('fromHeadingPitchRoll throws with undefined roll', function() { - expect(function() { - Quaternion.fromHeadingPitchRoll(0.0, 0.0, undefined); - }).toThrowDeveloperError(); - }); - it('clone returns undefined with no parameter', function() { expect(Quaternion.clone()).toBeUndefined(); }); diff --git a/Specs/Core/TransformsSpec.js b/Specs/Core/TransformsSpec.js index da6f5de0943e..365f6dad36d6 100644 --- a/Specs/Core/TransformsSpec.js +++ b/Specs/Core/TransformsSpec.js @@ -231,6 +231,151 @@ defineSuite([ expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation }); + it('normal use of localFrameToFixedFrameGenerator', function() { + var cartesianTab = [ + new Cartesian3(0.0, 0.0, 1.0), + new Cartesian3(0.0, 0.0, -1.0), + new Cartesian3(10.0, 20.0, 30.0), + new Cartesian3(-10.0, -20.0, -30.0), + new Cartesian3(-25.0, 60.0, -1.0), + new Cartesian3(9.0, 0.0, -7.0) + ]; + + var converterTab = [ + { + converter : Transforms.localFrameToFixedFrameGenerator('north', 'east'), + order : ['north', 'east', 'down'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('north', 'west'), + order : ['north', 'west', 'up'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('north', 'up'), + order : ['north', 'up', 'east'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('north', 'down'), + order : ['north', 'down', 'west'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('south', 'east'), + order : ['south', 'east', 'up'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('south', 'west'), + order : ['south', 'west', 'down'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('south', 'up'), + order : ['south', 'up', 'west'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('south', 'down'), + order : ['south', 'down', 'east'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('east', 'north'), + order : ['east', 'north', 'up'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('east', 'south'), + order : ['east', 'south', 'down'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('east', 'up'), + order : ['east', 'up', 'south'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('east', 'down'), + order : ['east', 'down', 'north'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('west', 'north'), + order : ['west', 'north', 'down'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('west', 'south'), + order : ['west', 'south', 'up'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('west', 'up'), + order : ['west', 'up', 'north'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('west', 'down'), + order : ['west', 'down', 'south'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('up', 'north'), + order : ['up', 'north', 'west'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('up', 'south'), + order : ['up', 'south', 'east'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('up', 'east'), + order : ['up', 'east', 'north'] + }, { + converter : Transforms.localFrameToFixedFrameGenerator('up', 'west'), + order : ['up', 'west', 'south'] + } + ]; + + function testAllLocalFrame(classicalENUMatrix, position) { + var ENUColumn = new Cartesian4(); + var converterColumn = new Cartesian4(); + for (var i = 0; i < converterTab.length; i++) { + var converterMatrix = (converterTab[i].converter)(position, Ellipsoid.UNIT_SPHERE); + var order = converterTab[i].order; + // check translation + Matrix4.getColumn(classicalENUMatrix, 3, ENUColumn); + Matrix4.getColumn(converterMatrix, 3, converterColumn); + expect(ENUColumn).toEqual(converterColumn); + // check axis + for (var j = 0; j < 3; j++) { + Matrix4.getColumn(converterMatrix, j, converterColumn); + var axisName = order[j]; + if (axisName === 'east') { + Matrix4.getColumn(classicalENUMatrix, 0, ENUColumn); + } else if (axisName === 'west') { + Matrix4.getColumn(classicalENUMatrix, 0, ENUColumn); + Cartesian4.negate(ENUColumn, ENUColumn); + } else if (axisName === 'north') { + Matrix4.getColumn(classicalENUMatrix, 1, ENUColumn); + } else if (axisName === 'south') { + Matrix4.getColumn(classicalENUMatrix, 1, ENUColumn); + Cartesian4.negate(ENUColumn, ENUColumn); + } else if (axisName === 'up') { + Matrix4.getColumn(classicalENUMatrix, 2, ENUColumn); + } else if (axisName === 'down') { + Matrix4.getColumn(classicalENUMatrix, 2, ENUColumn); + Cartesian4.negate(ENUColumn, ENUColumn); + } + expect(ENUColumn).toEqual(converterColumn); + } + } + } + + for (var i = 0; i < cartesianTab.length; i++) { + var cartesian = cartesianTab[i]; + var classicalEastNorthUpReferential = Transforms.eastNorthUpToFixedFrame(cartesian, Ellipsoid.UNIT_SPHERE); + testAllLocalFrame(classicalEastNorthUpReferential, cartesian); + } + }); + + it('abnormal use of localFrameToFixedFrameGenerator', function() { + function checkDeveloperError(firstAxis, secondAxis) { + expect(function() { + Transforms.localFrameToFixedFrameGenerator(firstAxis, secondAxis); + }).toThrowDeveloperError(); + } + + checkDeveloperError(undefined, undefined); + checkDeveloperError('north', undefined); + checkDeveloperError(undefined, 'north'); + checkDeveloperError('south', undefined); + checkDeveloperError('northe', 'southe'); + + checkDeveloperError('north', 'north'); + checkDeveloperError('north', 'south'); + checkDeveloperError('south', 'north'); + checkDeveloperError('south', 'south'); + + checkDeveloperError('up', 'up'); + checkDeveloperError('up', 'down'); + checkDeveloperError('down', 'up'); + checkDeveloperError('down', 'down'); + + checkDeveloperError('east', 'east'); + checkDeveloperError('east', 'west'); + checkDeveloperError('west', 'east'); + checkDeveloperError('west', 'west'); + }); + it('headingPitchRollToFixedFrame works without a result parameter', function() { var origin = new Cartesian3(1.0, 0.0, 0.0); var heading = CesiumMath.toRadians(20.0); @@ -238,7 +383,7 @@ defineSuite([ var roll = CesiumMath.toRadians(40.0); var hpr = new HeadingPitchRoll(heading, pitch, roll); - var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(heading, pitch, roll)); + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr)); var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); @@ -259,14 +404,14 @@ defineSuite([ expect(actualTranslation).toEqual(origin); }); - it('headingPitchRollToFixedFrame works with a HeadingPitchRoll object and without a result parameter', function() { + it('headingPitchRollToFixedFrame 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(heading, pitch, roll)); + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr)); var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); @@ -287,14 +432,14 @@ defineSuite([ expect(actualTranslation).toEqual(origin); }); - it('headingPitchRollToFixedFrame works with a result parameter', function() { + it('headingPitchRollToFixedFrame 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(heading, pitch, roll)); + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr)); var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); @@ -303,28 +448,26 @@ defineSuite([ 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, result); + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame); 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('headingPitchRollToFixedFrame works with a HeadingPitchRoll object and a result parameter', function() { + it('headingPitchRollToFixedFrame 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(heading, pitch, roll)); + var expectedRotation = Matrix3.fromQuaternion(Quaternion.fromHeadingPitchRoll(hpr)); var expectedX = Matrix3.getColumn(expectedRotation, 0, new Cartesian3()); var expectedY = Matrix3.getColumn(expectedRotation, 1, new Cartesian3()); var expectedZ = Matrix3.getColumn(expectedRotation, 2, new Cartesian3()); @@ -334,7 +477,7 @@ defineSuite([ Cartesian3.fromElements(expectedZ.z, expectedZ.x, expectedZ.y, expectedZ); var result = new Matrix4(); - var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, result); + var returnedResult = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, result); 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())); @@ -347,6 +490,55 @@ defineSuite([ expect(actualTranslation).toEqual(origin); }); + it('headingPitchRollToFixedFrame 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)); + 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); + 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); + 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); @@ -357,12 +549,12 @@ defineSuite([ var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE); var expected = Matrix4.getRotation(transform, new Matrix3()); - var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame); var actual = Matrix3.fromQuaternion(quaternion); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); - it('headingPitchRollQuaternion works with a HeadingPitchRoll object and without a result parameter', function() { + it('headingPitchRollQuaternion 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); @@ -372,12 +564,14 @@ defineSuite([ var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE); var expected = Matrix4.getRotation(transform, new Matrix3()); - var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE); + var result = new Quaternion(); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, Transforms.eastNorthUpToFixedFrame, result); var actual = Matrix3.fromQuaternion(quaternion); + expect(quaternion).toBe(result); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); - it('headingPitchRollQuaternion works with a result parameter', function() { + it('headingPitchRollQuaternion 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); @@ -388,24 +582,26 @@ defineSuite([ var expected = Matrix4.getRotation(transform, new Matrix3()); var result = new Quaternion(); - var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, result); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, undefined, result); var actual = Matrix3.fromQuaternion(quaternion); expect(quaternion).toBe(result); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); }); - it('headingPitchRollQuaternion works with a HeadingPitchRoll object and a result parameter', function() { + + it('headingPitchRollQuaternion 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); + var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, Ellipsoid.UNIT_SPHERE, fixedFrameTransform); var expected = Matrix4.getRotation(transform, new Matrix3()); var result = new Quaternion(); - var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, result); + var quaternion = Transforms.headingPitchRollQuaternion(origin, hpr, Ellipsoid.UNIT_SPHERE, fixedFrameTransform, result); var actual = Matrix3.fromQuaternion(quaternion); expect(quaternion).toBe(result); expect(actual).toEqualEpsilon(expected, CesiumMath.EPSILON11); @@ -947,7 +1143,7 @@ defineSuite([ it('headingPitchRollToFixedFrame throws without an origin', function() { expect(function() { - Transforms.headingPitchRollToFixedFrame(undefined, 0.0, 0.0, 0.0); + Transforms.headingPitchRollToFixedFrame(undefined, new HeadingPitchRoll()); }).toThrowDeveloperError(); });