diff --git a/CHANGES.md b/CHANGES.md index 888bf37ee814..179aa7c095cf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,20 +30,21 @@ Change Log * Added `Globe.showSkirts` to support the ability to hide terrain skirts when viewing terrain from below the surface. [#8489](https://github.com/AnalyticalGraphicsInc/cesium/pull/8489) * Fixed `BoundingSphere.projectTo2D` when the bounding sphere’s center is at the origin. [#8482](https://github.com/AnalyticalGraphicsInc/cesium/pull/8482) * Added `minificationFilter` and `magnificationFilter` options to `Material` to control texture filtering. [#8473](https://github.com/AnalyticalGraphicsInc/cesium/pull/8473) -* Update [earcut](https://github.com/mapbox/earcut) to 2.2.1 [#8528](https://github.com/AnalyticalGraphicsInc/cesium/pull/8528) +* Update [earcut](https://github.com/mapbox/earcut) to 2.2.1. [#8528](https://github.com/AnalyticalGraphicsInc/cesium/pull/8528) ##### Fixes :wrench: * Fixed issue where `RequestScheduler` double-counted image requests made via `createImageBitmap`. [#8162](https://github.com/AnalyticalGraphicsInc/cesium/issues/8162) * Fixed a bug where the camera could go underground during mouse navigation. [#8504](https://github.com/AnalyticalGraphicsInc/cesium/pull/8504) * Fixed a bug where files with backslashes were not loaded in KMZ files. [#8533](https://github.com/AnalyticalGraphicsInc/cesium/pull/8533) -* Reduced Cesium bundle size by avoiding unnecessarily importing `Cesium3DTileset` in `Picking.js` [#8532](https://github.com/AnalyticalGraphicsInc/cesium/pull/8532) +* Reduced Cesium bundle size by avoiding unnecessarily importing `Cesium3DTileset` in `Picking.js`. [#8532](https://github.com/AnalyticalGraphicsInc/cesium/pull/8532) * Fixed WebGL warning message about `EXT_float_blend` being implicitly enabled. [#8534](https://github.com/AnalyticalGraphicsInc/cesium/pull/8534) * Updated SampleData models to glTF 2.0. [#7802](https://github.com/AnalyticalGraphicsInc/cesium/issues/7802) -* Fixed a bug where toggling point cloud classification visibility would result in a grey screen on Linux / Nvidia [#8538](https://github.com/AnalyticalGraphicsInc/cesium/pull/8538) +* Fixed a bug where toggling point cloud classification visibility would result in a grey screen on Linux / Nvidia. [#8538](https://github.com/AnalyticalGraphicsInc/cesium/pull/8538) * Fixed a bug where a point in a `PointPrimitiveCollection` is rendered in the middle of the screen instead of being clipped. [#8542](https://github.com/AnalyticalGraphicsInc/cesium/pull/8542) * Fixed a crash when deleting and re-creating polylines from CZML. `ReferenceProperty` now returns undefined when the target entity or property does not exist, instead of throwing. [#8544](https://github.com/AnalyticalGraphicsInc/cesium/pull/8544) * Fixed a bug where rapidly updating a `PolylineCollection` could result in an instanceIndex is out of range error. [#8546](https://github.com/AnalyticalGraphicsInc/cesium/pull/8546) * Fixed a crash that could occur when an entity was deleted while the corresponding `Primitive` was being created asynchronously. [#8569](https://github.com/AnalyticalGraphicsInc/cesium/pull/8569) +* Fixed a crash when calling `camera.lookAt` with the origin as the target. This could happen when looking at a tileset with the origin as its center. [#8571](https://github.com/AnalyticalGraphicsInc/cesium/pull/8571) ### 1.65.0 - 2020-01-06 diff --git a/Source/Core/Transforms.js b/Source/Core/Transforms.js index ca9c7c86716f..0b775c2f97c7 100644 --- a/Source/Core/Transforms.js +++ b/Source/Core/Transforms.js @@ -128,8 +128,13 @@ import TimeConstants from './TimeConstants.js'; 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)) { + if (Cartesian3.equalsEpsilon(origin, Cartesian3.ZERO, CesiumMath.EPSILON14)) { + // If x, y, and z are zero, use the degenerate local frame, which is a special case + Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian); + Cartesian3.unpack(degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian); + Cartesian3.unpack(degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian); + } else if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) { + // If x and y are zero, assume origin is at a pole, which is a special case. var sign = CesiumMath.sign(origin.z); Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian); diff --git a/Specs/Core/TransformsSpec.js b/Specs/Core/TransformsSpec.js index 8576a226e7e0..4b617118be1c 100644 --- a/Specs/Core/TransformsSpec.js +++ b/Specs/Core/TransformsSpec.js @@ -69,6 +69,17 @@ describe('Core/Transforms', function() { expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation }); + it('eastNorthUpToFixedFrame works at the origin', function() { + var origin = Cartesian3.ZERO; + var expectedTranslation = new Cartesian4(0.0, 0.0, 0.0, 1.0); + + var returnedResult = Transforms.eastNorthUpToFixedFrame(origin, Ellipsoid.WGS84); + expect(Matrix4.getColumn(returnedResult, 0, new Cartesian4())).toEqual(Cartesian4.UNIT_Y); // east + expect(Matrix4.getColumn(returnedResult, 1, new Cartesian4())).toEqual(negativeX); // north + expect(Matrix4.getColumn(returnedResult, 2, new Cartesian4())).toEqual(Cartesian4.UNIT_Z); // up + expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation + }); + it('northEastDownToFixedFrame works without a result parameter', function() { var origin = new Cartesian3(1.0, 0.0, 0.0); var expectedTranslation = new Cartesian4(origin.x, origin.y, origin.z, 1.0); @@ -117,6 +128,17 @@ describe('Core/Transforms', function() { expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation }); + it('northEastDownToFixedFrame works at the origin', function() { + var origin = Cartesian3.ZERO; + var expectedTranslation = new Cartesian4(0.0, 0.0, 0.0, 1.0); + + var returnedResult = Transforms.northEastDownToFixedFrame(origin, Ellipsoid.UNIT_SPHERE); + expect(Matrix4.getColumn(returnedResult, 0, new Cartesian4())).toEqual(negativeX); // north + expect(Matrix4.getColumn(returnedResult, 1, new Cartesian4())).toEqual(Cartesian4.UNIT_Y); // east + expect(Matrix4.getColumn(returnedResult, 2, new Cartesian4())).toEqual(negativeZ); // down + expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation + }); + it('northUpEastToFixedFrame works without a result parameter', function() { var origin = new Cartesian3(1.0, 0.0, 0.0); var expectedTranslation = new Cartesian4(origin.x, origin.y, origin.z, 1.0); @@ -165,6 +187,17 @@ describe('Core/Transforms', function() { expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation }); + it('northUpEastToFixedFrame works at the origin', function() { + var origin = Cartesian3.ZERO; + var expectedTranslation = new Cartesian4(0.0, 0.0, 0.0, 1.0); + + var returnedResult = Transforms.northUpEastToFixedFrame(origin, Ellipsoid.UNIT_SPHERE); + expect(Matrix4.getColumn(returnedResult, 0, new Cartesian4())).toEqual(negativeX); // north + expect(Matrix4.getColumn(returnedResult, 1, new Cartesian4())).toEqual(Cartesian4.UNIT_Z); // up + expect(Matrix4.getColumn(returnedResult, 2, new Cartesian4())).toEqual(Cartesian4.UNIT_Y); // east + expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation + }); + it('northWestUpToFixedFrame works without a result parameter', function() { var origin = new Cartesian3(1.0, 0.0, 0.0); var expectedTranslation = new Cartesian4(origin.x, origin.y, origin.z, 1.0); @@ -213,6 +246,17 @@ describe('Core/Transforms', function() { expect(Matrix4.getColumn(returnedResult, 3, new Cartesian4())).toEqual(expectedTranslation); // translation }); + it('northWestUpToFixedFrame works at the origin', function() { + var origin = Cartesian3.ZERO; + var expectedTranslation = new Cartesian4(0.0, 0.0, 0.0, 1.0); + + var returnedResult = Transforms.northWestUpToFixedFrame(origin, Ellipsoid.UNIT_SPHERE); + expect(Matrix4.getColumn(returnedResult, 0, new Cartesian4())).toEqual(negativeX); // north + expect(Matrix4.getColumn(returnedResult, 1, new Cartesian4())).toEqual(negativeY); // west + expect(Matrix4.getColumn(returnedResult, 2, new Cartesian4())).toEqual(Cartesian4.UNIT_Z); // up + 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), diff --git a/Specs/Scene/CameraSpec.js b/Specs/Scene/CameraSpec.js index 0baa4642be56..17ec181357b0 100644 --- a/Specs/Scene/CameraSpec.js +++ b/Specs/Scene/CameraSpec.js @@ -1499,6 +1499,33 @@ describe('Scene/Camera', function() { expect(1.0 - Cartesian3.magnitude(tempCamera.right)).toBeLessThan(CesiumMath.EPSILON14); }); + it('lookAt when target is zero', function() { + var target = Cartesian3.clone(Cartesian3.ZERO); + var offset = new Cartesian3(0.0, -1.0, 0.0); + + var tempCamera = Camera.clone(camera); + tempCamera.lookAt(target, offset); + + expect(tempCamera.position).toEqualEpsilon(offset, CesiumMath.EPSILON11); + expect(tempCamera.direction).toEqualEpsilon(Cartesian3.negate(Cartesian3.normalize(offset, new Cartesian3()), new Cartesian3()), CesiumMath.EPSILON11); + expect(tempCamera.right).toEqualEpsilon(Cartesian3.cross(tempCamera.direction, Cartesian3.UNIT_Z, new Cartesian3()), CesiumMath.EPSILON11); + expect(tempCamera.up).toEqualEpsilon(Cartesian3.cross(tempCamera.right, tempCamera.direction, new Cartesian3()), CesiumMath.EPSILON11); + }); + + it('lookAt when target and camera are zero', function() { + var target = Cartesian3.clone(Cartesian3.ZERO); + var offset = new Cartesian3(0.0, -1.0, 0.0); + + var tempCamera = Camera.clone(camera); + tempCamera.position = Cartesian3.clone(Cartesian3.ZERO); + tempCamera.lookAt(target, offset); + + expect(tempCamera.position).toEqualEpsilon(offset, CesiumMath.EPSILON11); + expect(tempCamera.direction).toEqualEpsilon(Cartesian3.negate(Cartesian3.normalize(offset, new Cartesian3()), new Cartesian3()), CesiumMath.EPSILON11); + expect(tempCamera.right).toEqualEpsilon(Cartesian3.cross(tempCamera.direction, Cartesian3.UNIT_Z, new Cartesian3()), CesiumMath.EPSILON11); + expect(tempCamera.up).toEqualEpsilon(Cartesian3.cross(tempCamera.right, tempCamera.direction, new Cartesian3()), CesiumMath.EPSILON11); + }); + it('lookAt throws with no target parameter', function() { expect(function() { camera.lookAt(undefined, Cartesian3.ZERO);