diff --git a/packages/engine/Source/Core/EllipsoidRhumbLine.js b/packages/engine/Source/Core/EllipsoidRhumbLine.js index 047d48e87961..51b410622677 100644 --- a/packages/engine/Source/Core/EllipsoidRhumbLine.js +++ b/packages/engine/Source/Core/EllipsoidRhumbLine.js @@ -333,10 +333,16 @@ function interpolateUsingSurfaceDistance( latitude = calculateInverseM(M2, ellipticity, major); //Now find the longitude of the second point - const sigma1 = calculateSigma(ellipticity, start.latitude); - const sigma2 = calculateSigma(ellipticity, latitude); - deltaLongitude = Math.tan(heading) * (sigma2 - sigma1); - longitude = CesiumMath.negativePiToPi(start.longitude + deltaLongitude); + + // Check to see if the rhumb line has constant longitude + if (Math.abs(heading) < CesiumMath.EPSILON10) { + longitude = CesiumMath.negativePiToPi(start.longitude); + } else { + const sigma1 = calculateSigma(ellipticity, start.latitude); + const sigma2 = calculateSigma(ellipticity, latitude); + deltaLongitude = Math.tan(heading) * (sigma2 - sigma1); + longitude = CesiumMath.negativePiToPi(start.longitude + deltaLongitude); + } } else { //If heading is close to 90 degrees latitude = start.latitude; diff --git a/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js b/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js index f56803e3f411..87157adea73d 100644 --- a/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js +++ b/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js @@ -13,6 +13,7 @@ describe("Core/EllipsoidRhumbLine", function () { const fifteenDegrees = Math.PI / 12; const thirtyDegrees = Math.PI / 6; const fortyfiveDegrees = Math.PI / 4; + const threeHundredDegrees = (5 * Math.PI) / 6; it("throws without start", function () { expect(function () { @@ -749,6 +750,46 @@ describe("Core/EllipsoidRhumbLine", function () { ); }); + it("interpolates when heading is near 90 degrees", function () { + const start = new Cartographic(0.0, 0.0); + const end = new Cartographic(Math.PI / 2, 0.0); + const expectedMid = new Cartographic(fortyfiveDegrees, 0.0); + + const rhumb = new EllipsoidRhumbLine(start, end); + expect(rhumb.heading).toEqualEpsilon(Math.PI / 2, CesiumMath.EPSILON12); + + const midpoint = rhumb.interpolateUsingFraction(0.5); + + expect(expectedMid.longitude).toEqualEpsilon( + midpoint.longitude, + CesiumMath.EPSILON12 + ); + expect(expectedMid.latitude).toEqualEpsilon( + midpoint.latitude, + CesiumMath.EPSILON12 + ); + }); + + it("interpolates when heading is near 0 degrees", function () { + const start = new Cartographic(-threeHundredDegrees, fifteenDegrees); + const end = new Cartographic(-threeHundredDegrees, fortyfiveDegrees); + const expectedMid = new Cartographic(-threeHundredDegrees, thirtyDegrees); + + const rhumb = new EllipsoidRhumbLine(start, end); + expect(rhumb.heading).toEqualEpsilon(0, CesiumMath.EPSILON12); + + const midpoint = rhumb.interpolateUsingFraction(0.5); + + expect(expectedMid.longitude).toEqualEpsilon( + midpoint.longitude, + CesiumMath.EPSILON12 + ); + expect(expectedMid.latitude).toEqualEpsilon( + midpoint.latitude, + CesiumMath.EPSILON3 + ); + }); + it("interpolates midpoint fraction using result parameter", function () { const start = new Cartographic(fifteenDegrees, 0.0); const end = new Cartographic(fortyfiveDegrees, 0.0);