EllipsoidRhumbLine-5f1ab81f.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['exports', './when-e6985d2a', './Check-24cae389', './Math-392d0035', './Cartesian2-a5d6dde9'], function (exports, when, Check, _Math, Cartesian2) { 'use strict';
  3. function calculateM(ellipticity, major, latitude) {
  4. if (ellipticity === 0.0) {
  5. // sphere
  6. return major * latitude;
  7. }
  8. var e2 = ellipticity * ellipticity;
  9. var e4 = e2 * e2;
  10. var e6 = e4 * e2;
  11. var e8 = e6 * e2;
  12. var e10 = e8 * e2;
  13. var e12 = e10 * e2;
  14. var phi = latitude;
  15. var sin2Phi = Math.sin(2 * phi);
  16. var sin4Phi = Math.sin(4 * phi);
  17. var sin6Phi = Math.sin(6 * phi);
  18. var sin8Phi = Math.sin(8 * phi);
  19. var sin10Phi = Math.sin(10 * phi);
  20. var sin12Phi = Math.sin(12 * phi);
  21. return (
  22. major *
  23. ((1 -
  24. e2 / 4 -
  25. (3 * e4) / 64 -
  26. (5 * e6) / 256 -
  27. (175 * e8) / 16384 -
  28. (441 * e10) / 65536 -
  29. (4851 * e12) / 1048576) *
  30. phi -
  31. ((3 * e2) / 8 +
  32. (3 * e4) / 32 +
  33. (45 * e6) / 1024 +
  34. (105 * e8) / 4096 +
  35. (2205 * e10) / 131072 +
  36. (6237 * e12) / 524288) *
  37. sin2Phi +
  38. ((15 * e4) / 256 +
  39. (45 * e6) / 1024 +
  40. (525 * e8) / 16384 +
  41. (1575 * e10) / 65536 +
  42. (155925 * e12) / 8388608) *
  43. sin4Phi -
  44. ((35 * e6) / 3072 +
  45. (175 * e8) / 12288 +
  46. (3675 * e10) / 262144 +
  47. (13475 * e12) / 1048576) *
  48. sin6Phi +
  49. ((315 * e8) / 131072 + (2205 * e10) / 524288 + (43659 * e12) / 8388608) *
  50. sin8Phi -
  51. ((693 * e10) / 1310720 + (6237 * e12) / 5242880) * sin10Phi +
  52. ((1001 * e12) / 8388608) * sin12Phi)
  53. );
  54. }
  55. function calculateInverseM(M, ellipticity, major) {
  56. var d = M / major;
  57. if (ellipticity === 0.0) {
  58. // sphere
  59. return d;
  60. }
  61. var d2 = d * d;
  62. var d3 = d2 * d;
  63. var d4 = d3 * d;
  64. var e = ellipticity;
  65. var e2 = e * e;
  66. var e4 = e2 * e2;
  67. var e6 = e4 * e2;
  68. var e8 = e6 * e2;
  69. var e10 = e8 * e2;
  70. var e12 = e10 * e2;
  71. var sin2D = Math.sin(2 * d);
  72. var cos2D = Math.cos(2 * d);
  73. var sin4D = Math.sin(4 * d);
  74. var cos4D = Math.cos(4 * d);
  75. var sin6D = Math.sin(6 * d);
  76. var cos6D = Math.cos(6 * d);
  77. var sin8D = Math.sin(8 * d);
  78. var cos8D = Math.cos(8 * d);
  79. var sin10D = Math.sin(10 * d);
  80. var cos10D = Math.cos(10 * d);
  81. var sin12D = Math.sin(12 * d);
  82. return (
  83. d +
  84. (d * e2) / 4 +
  85. (7 * d * e4) / 64 +
  86. (15 * d * e6) / 256 +
  87. (579 * d * e8) / 16384 +
  88. (1515 * d * e10) / 65536 +
  89. (16837 * d * e12) / 1048576 +
  90. ((3 * d * e4) / 16 +
  91. (45 * d * e6) / 256 -
  92. (d * (32 * d2 - 561) * e8) / 4096 -
  93. (d * (232 * d2 - 1677) * e10) / 16384 +
  94. (d * (399985 - 90560 * d2 + 512 * d4) * e12) / 5242880) *
  95. cos2D +
  96. ((21 * d * e6) / 256 +
  97. (483 * d * e8) / 4096 -
  98. (d * (224 * d2 - 1969) * e10) / 16384 -
  99. (d * (33152 * d2 - 112599) * e12) / 1048576) *
  100. cos4D +
  101. ((151 * d * e8) / 4096 +
  102. (4681 * d * e10) / 65536 +
  103. (1479 * d * e12) / 16384 -
  104. (453 * d3 * e12) / 32768) *
  105. cos6D +
  106. ((1097 * d * e10) / 65536 + (42783 * d * e12) / 1048576) * cos8D +
  107. ((8011 * d * e12) / 1048576) * cos10D +
  108. ((3 * e2) / 8 +
  109. (3 * e4) / 16 +
  110. (213 * e6) / 2048 -
  111. (3 * d2 * e6) / 64 +
  112. (255 * e8) / 4096 -
  113. (33 * d2 * e8) / 512 +
  114. (20861 * e10) / 524288 -
  115. (33 * d2 * e10) / 512 +
  116. (d4 * e10) / 1024 +
  117. (28273 * e12) / 1048576 -
  118. (471 * d2 * e12) / 8192 +
  119. (9 * d4 * e12) / 4096) *
  120. sin2D +
  121. ((21 * e4) / 256 +
  122. (21 * e6) / 256 +
  123. (533 * e8) / 8192 -
  124. (21 * d2 * e8) / 512 +
  125. (197 * e10) / 4096 -
  126. (315 * d2 * e10) / 4096 +
  127. (584039 * e12) / 16777216 -
  128. (12517 * d2 * e12) / 131072 +
  129. (7 * d4 * e12) / 2048) *
  130. sin4D +
  131. ((151 * e6) / 6144 +
  132. (151 * e8) / 4096 +
  133. (5019 * e10) / 131072 -
  134. (453 * d2 * e10) / 16384 +
  135. (26965 * e12) / 786432 -
  136. (8607 * d2 * e12) / 131072) *
  137. sin6D +
  138. ((1097 * e8) / 131072 +
  139. (1097 * e10) / 65536 +
  140. (225797 * e12) / 10485760 -
  141. (1097 * d2 * e12) / 65536) *
  142. sin8D +
  143. ((8011 * e10) / 2621440 + (8011 * e12) / 1048576) * sin10D +
  144. ((293393 * e12) / 251658240) * sin12D
  145. );
  146. }
  147. function calculateSigma(ellipticity, latitude) {
  148. if (ellipticity === 0.0) {
  149. // sphere
  150. return Math.log(Math.tan(0.5 * (_Math.CesiumMath.PI_OVER_TWO + latitude)));
  151. }
  152. var eSinL = ellipticity * Math.sin(latitude);
  153. return (
  154. Math.log(Math.tan(0.5 * (_Math.CesiumMath.PI_OVER_TWO + latitude))) -
  155. (ellipticity / 2.0) * Math.log((1 + eSinL) / (1 - eSinL))
  156. );
  157. }
  158. function calculateHeading(
  159. ellipsoidRhumbLine,
  160. firstLongitude,
  161. firstLatitude,
  162. secondLongitude,
  163. secondLatitude
  164. ) {
  165. var sigma1 = calculateSigma(ellipsoidRhumbLine._ellipticity, firstLatitude);
  166. var sigma2 = calculateSigma(ellipsoidRhumbLine._ellipticity, secondLatitude);
  167. return Math.atan2(
  168. _Math.CesiumMath.negativePiToPi(secondLongitude - firstLongitude),
  169. sigma2 - sigma1
  170. );
  171. }
  172. function calculateArcLength(
  173. ellipsoidRhumbLine,
  174. major,
  175. minor,
  176. firstLongitude,
  177. firstLatitude,
  178. secondLongitude,
  179. secondLatitude
  180. ) {
  181. var heading = ellipsoidRhumbLine._heading;
  182. var deltaLongitude = secondLongitude - firstLongitude;
  183. var distance = 0.0;
  184. //Check to see if the rhumb line has constant latitude
  185. //This equation will diverge if heading gets close to 90 degrees
  186. if (
  187. _Math.CesiumMath.equalsEpsilon(
  188. Math.abs(heading),
  189. _Math.CesiumMath.PI_OVER_TWO,
  190. _Math.CesiumMath.EPSILON8
  191. )
  192. ) {
  193. //If heading is close to 90 degrees
  194. if (major === minor) {
  195. distance =
  196. major *
  197. Math.cos(firstLatitude) *
  198. _Math.CesiumMath.negativePiToPi(deltaLongitude);
  199. } else {
  200. var sinPhi = Math.sin(firstLatitude);
  201. distance =
  202. (major *
  203. Math.cos(firstLatitude) *
  204. _Math.CesiumMath.negativePiToPi(deltaLongitude)) /
  205. Math.sqrt(1 - ellipsoidRhumbLine._ellipticitySquared * sinPhi * sinPhi);
  206. }
  207. } else {
  208. var M1 = calculateM(ellipsoidRhumbLine._ellipticity, major, firstLatitude);
  209. var M2 = calculateM(ellipsoidRhumbLine._ellipticity, major, secondLatitude);
  210. distance = (M2 - M1) / Math.cos(heading);
  211. }
  212. return Math.abs(distance);
  213. }
  214. var scratchCart1 = new Cartesian2.Cartesian3();
  215. var scratchCart2 = new Cartesian2.Cartesian3();
  216. function computeProperties(ellipsoidRhumbLine, start, end, ellipsoid) {
  217. var firstCartesian = Cartesian2.Cartesian3.normalize(
  218. ellipsoid.cartographicToCartesian(start, scratchCart2),
  219. scratchCart1
  220. );
  221. var lastCartesian = Cartesian2.Cartesian3.normalize(
  222. ellipsoid.cartographicToCartesian(end, scratchCart2),
  223. scratchCart2
  224. );
  225. //>>includeStart('debug', pragmas.debug);
  226. Check.Check.typeOf.number.greaterThanOrEquals(
  227. "value",
  228. Math.abs(
  229. Math.abs(Cartesian2.Cartesian3.angleBetween(firstCartesian, lastCartesian)) - Math.PI
  230. ),
  231. 0.0125
  232. );
  233. //>>includeEnd('debug');
  234. var major = ellipsoid.maximumRadius;
  235. var minor = ellipsoid.minimumRadius;
  236. var majorSquared = major * major;
  237. var minorSquared = minor * minor;
  238. ellipsoidRhumbLine._ellipticitySquared =
  239. (majorSquared - minorSquared) / majorSquared;
  240. ellipsoidRhumbLine._ellipticity = Math.sqrt(
  241. ellipsoidRhumbLine._ellipticitySquared
  242. );
  243. ellipsoidRhumbLine._start = Cartesian2.Cartographic.clone(
  244. start,
  245. ellipsoidRhumbLine._start
  246. );
  247. ellipsoidRhumbLine._start.height = 0;
  248. ellipsoidRhumbLine._end = Cartesian2.Cartographic.clone(end, ellipsoidRhumbLine._end);
  249. ellipsoidRhumbLine._end.height = 0;
  250. ellipsoidRhumbLine._heading = calculateHeading(
  251. ellipsoidRhumbLine,
  252. start.longitude,
  253. start.latitude,
  254. end.longitude,
  255. end.latitude
  256. );
  257. ellipsoidRhumbLine._distance = calculateArcLength(
  258. ellipsoidRhumbLine,
  259. ellipsoid.maximumRadius,
  260. ellipsoid.minimumRadius,
  261. start.longitude,
  262. start.latitude,
  263. end.longitude,
  264. end.latitude
  265. );
  266. }
  267. function interpolateUsingSurfaceDistance(
  268. start,
  269. heading,
  270. distance,
  271. major,
  272. ellipticity,
  273. result
  274. ) {
  275. var ellipticitySquared = ellipticity * ellipticity;
  276. var longitude;
  277. var latitude;
  278. var deltaLongitude;
  279. //Check to see if the rhumb line has constant latitude
  280. //This won't converge if heading is close to 90 degrees
  281. if (
  282. Math.abs(_Math.CesiumMath.PI_OVER_TWO - Math.abs(heading)) > _Math.CesiumMath.EPSILON8
  283. ) {
  284. //Calculate latitude of the second point
  285. var M1 = calculateM(ellipticity, major, start.latitude);
  286. var deltaM = distance * Math.cos(heading);
  287. var M2 = M1 + deltaM;
  288. latitude = calculateInverseM(M2, ellipticity, major);
  289. //Now find the longitude of the second point
  290. var sigma1 = calculateSigma(ellipticity, start.latitude);
  291. var sigma2 = calculateSigma(ellipticity, latitude);
  292. deltaLongitude = Math.tan(heading) * (sigma2 - sigma1);
  293. longitude = _Math.CesiumMath.negativePiToPi(start.longitude + deltaLongitude);
  294. } else {
  295. //If heading is close to 90 degrees
  296. latitude = start.latitude;
  297. var localRad;
  298. if (ellipticity === 0.0) {
  299. // sphere
  300. localRad = major * Math.cos(start.latitude);
  301. } else {
  302. var sinPhi = Math.sin(start.latitude);
  303. localRad =
  304. (major * Math.cos(start.latitude)) /
  305. Math.sqrt(1 - ellipticitySquared * sinPhi * sinPhi);
  306. }
  307. deltaLongitude = distance / localRad;
  308. if (heading > 0.0) {
  309. longitude = _Math.CesiumMath.negativePiToPi(start.longitude + deltaLongitude);
  310. } else {
  311. longitude = _Math.CesiumMath.negativePiToPi(start.longitude - deltaLongitude);
  312. }
  313. }
  314. if (when.defined(result)) {
  315. result.longitude = longitude;
  316. result.latitude = latitude;
  317. result.height = 0;
  318. return result;
  319. }
  320. return new Cartesian2.Cartographic(longitude, latitude, 0);
  321. }
  322. /**
  323. * Initializes a rhumb line on the ellipsoid connecting the two provided planetodetic points.
  324. *
  325. * @alias EllipsoidRhumbLine
  326. * @constructor
  327. *
  328. * @param {Cartographic} [start] The initial planetodetic point on the path.
  329. * @param {Cartographic} [end] The final planetodetic point on the path.
  330. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rhumb line lies.
  331. *
  332. * @exception {DeveloperError} angle between start and end must be at least 0.0125 radians.
  333. */
  334. function EllipsoidRhumbLine(start, end, ellipsoid) {
  335. var e = when.defaultValue(ellipsoid, Cartesian2.Ellipsoid.WGS84);
  336. this._ellipsoid = e;
  337. this._start = new Cartesian2.Cartographic();
  338. this._end = new Cartesian2.Cartographic();
  339. this._heading = undefined;
  340. this._distance = undefined;
  341. this._ellipticity = undefined;
  342. this._ellipticitySquared = undefined;
  343. if (when.defined(start) && when.defined(end)) {
  344. computeProperties(this, start, end, e);
  345. }
  346. }
  347. Object.defineProperties(EllipsoidRhumbLine.prototype, {
  348. /**
  349. * Gets the ellipsoid.
  350. * @memberof EllipsoidRhumbLine.prototype
  351. * @type {Ellipsoid}
  352. * @readonly
  353. */
  354. ellipsoid: {
  355. get: function () {
  356. return this._ellipsoid;
  357. },
  358. },
  359. /**
  360. * Gets the surface distance between the start and end point
  361. * @memberof EllipsoidRhumbLine.prototype
  362. * @type {Number}
  363. * @readonly
  364. */
  365. surfaceDistance: {
  366. get: function () {
  367. //>>includeStart('debug', pragmas.debug);
  368. Check.Check.defined("distance", this._distance);
  369. //>>includeEnd('debug');
  370. return this._distance;
  371. },
  372. },
  373. /**
  374. * Gets the initial planetodetic point on the path.
  375. * @memberof EllipsoidRhumbLine.prototype
  376. * @type {Cartographic}
  377. * @readonly
  378. */
  379. start: {
  380. get: function () {
  381. return this._start;
  382. },
  383. },
  384. /**
  385. * Gets the final planetodetic point on the path.
  386. * @memberof EllipsoidRhumbLine.prototype
  387. * @type {Cartographic}
  388. * @readonly
  389. */
  390. end: {
  391. get: function () {
  392. return this._end;
  393. },
  394. },
  395. /**
  396. * Gets the heading from the start point to the end point.
  397. * @memberof EllipsoidRhumbLine.prototype
  398. * @type {Number}
  399. * @readonly
  400. */
  401. heading: {
  402. get: function () {
  403. //>>includeStart('debug', pragmas.debug);
  404. Check.Check.defined("distance", this._distance);
  405. //>>includeEnd('debug');
  406. return this._heading;
  407. },
  408. },
  409. });
  410. /**
  411. * Create a rhumb line using an initial position with a heading and distance.
  412. *
  413. * @param {Cartographic} start The initial planetodetic point on the path.
  414. * @param {Number} heading The heading in radians.
  415. * @param {Number} distance The rhumb line distance between the start and end point.
  416. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rhumb line lies.
  417. * @param {EllipsoidRhumbLine} [result] The object in which to store the result.
  418. * @returns {EllipsoidRhumbLine} The EllipsoidRhumbLine object.
  419. */
  420. EllipsoidRhumbLine.fromStartHeadingDistance = function (
  421. start,
  422. heading,
  423. distance,
  424. ellipsoid,
  425. result
  426. ) {
  427. //>>includeStart('debug', pragmas.debug);
  428. Check.Check.defined("start", start);
  429. Check.Check.defined("heading", heading);
  430. Check.Check.defined("distance", distance);
  431. Check.Check.typeOf.number.greaterThan("distance", distance, 0.0);
  432. //>>includeEnd('debug');
  433. var e = when.defaultValue(ellipsoid, Cartesian2.Ellipsoid.WGS84);
  434. var major = e.maximumRadius;
  435. var minor = e.minimumRadius;
  436. var majorSquared = major * major;
  437. var minorSquared = minor * minor;
  438. var ellipticity = Math.sqrt((majorSquared - minorSquared) / majorSquared);
  439. heading = _Math.CesiumMath.negativePiToPi(heading);
  440. var end = interpolateUsingSurfaceDistance(
  441. start,
  442. heading,
  443. distance,
  444. e.maximumRadius,
  445. ellipticity
  446. );
  447. if (
  448. !when.defined(result) ||
  449. (when.defined(ellipsoid) && !ellipsoid.equals(result.ellipsoid))
  450. ) {
  451. return new EllipsoidRhumbLine(start, end, e);
  452. }
  453. result.setEndPoints(start, end);
  454. return result;
  455. };
  456. /**
  457. * Sets the start and end points of the rhumb line.
  458. *
  459. * @param {Cartographic} start The initial planetodetic point on the path.
  460. * @param {Cartographic} end The final planetodetic point on the path.
  461. */
  462. EllipsoidRhumbLine.prototype.setEndPoints = function (start, end) {
  463. //>>includeStart('debug', pragmas.debug);
  464. Check.Check.defined("start", start);
  465. Check.Check.defined("end", end);
  466. //>>includeEnd('debug');
  467. computeProperties(this, start, end, this._ellipsoid);
  468. };
  469. /**
  470. * Provides the location of a point at the indicated portion along the rhumb line.
  471. *
  472. * @param {Number} fraction The portion of the distance between the initial and final points.
  473. * @param {Cartographic} [result] The object in which to store the result.
  474. * @returns {Cartographic} The location of the point along the rhumb line.
  475. */
  476. EllipsoidRhumbLine.prototype.interpolateUsingFraction = function (
  477. fraction,
  478. result
  479. ) {
  480. return this.interpolateUsingSurfaceDistance(
  481. fraction * this._distance,
  482. result
  483. );
  484. };
  485. /**
  486. * Provides the location of a point at the indicated distance along the rhumb line.
  487. *
  488. * @param {Number} distance The distance from the inital point to the point of interest along the rhumbLine.
  489. * @param {Cartographic} [result] The object in which to store the result.
  490. * @returns {Cartographic} The location of the point along the rhumb line.
  491. *
  492. * @exception {DeveloperError} start and end must be set before calling function interpolateUsingSurfaceDistance
  493. */
  494. EllipsoidRhumbLine.prototype.interpolateUsingSurfaceDistance = function (
  495. distance,
  496. result
  497. ) {
  498. //>>includeStart('debug', pragmas.debug);
  499. Check.Check.typeOf.number("distance", distance);
  500. if (!when.defined(this._distance) || this._distance === 0.0) {
  501. throw new Check.DeveloperError(
  502. "EllipsoidRhumbLine must have distinct start and end set."
  503. );
  504. }
  505. //>>includeEnd('debug');
  506. return interpolateUsingSurfaceDistance(
  507. this._start,
  508. this._heading,
  509. distance,
  510. this._ellipsoid.maximumRadius,
  511. this._ellipticity,
  512. result
  513. );
  514. };
  515. /**
  516. * Provides the location of a point at the indicated longitude along the rhumb line.
  517. * If the longitude is outside the range of start and end points, the first intersection with the longitude from the start point in the direction of the heading is returned. This follows the spiral property of a rhumb line.
  518. *
  519. * @param {Number} intersectionLongitude The longitude, in radians, at which to find the intersection point from the starting point using the heading.
  520. * @param {Cartographic} [result] The object in which to store the result.
  521. * @returns {Cartographic} The location of the intersection point along the rhumb line, undefined if there is no intersection or infinite intersections.
  522. *
  523. * @exception {DeveloperError} start and end must be set before calling function findIntersectionWithLongitude.
  524. */
  525. EllipsoidRhumbLine.prototype.findIntersectionWithLongitude = function (
  526. intersectionLongitude,
  527. result
  528. ) {
  529. //>>includeStart('debug', pragmas.debug);
  530. Check.Check.typeOf.number("intersectionLongitude", intersectionLongitude);
  531. if (!when.defined(this._distance) || this._distance === 0.0) {
  532. throw new Check.DeveloperError(
  533. "EllipsoidRhumbLine must have distinct start and end set."
  534. );
  535. }
  536. //>>includeEnd('debug');
  537. var ellipticity = this._ellipticity;
  538. var heading = this._heading;
  539. var absHeading = Math.abs(heading);
  540. var start = this._start;
  541. intersectionLongitude = _Math.CesiumMath.negativePiToPi(intersectionLongitude);
  542. if (
  543. _Math.CesiumMath.equalsEpsilon(
  544. Math.abs(intersectionLongitude),
  545. Math.PI,
  546. _Math.CesiumMath.EPSILON14
  547. )
  548. ) {
  549. intersectionLongitude = _Math.CesiumMath.sign(start.longitude) * Math.PI;
  550. }
  551. if (!when.defined(result)) {
  552. result = new Cartesian2.Cartographic();
  553. }
  554. // If heading is -PI/2 or PI/2, this is an E-W rhumb line
  555. // If heading is 0 or PI, this is an N-S rhumb line
  556. if (Math.abs(_Math.CesiumMath.PI_OVER_TWO - absHeading) <= _Math.CesiumMath.EPSILON8) {
  557. result.longitude = intersectionLongitude;
  558. result.latitude = start.latitude;
  559. result.height = 0;
  560. return result;
  561. } else if (
  562. _Math.CesiumMath.equalsEpsilon(
  563. Math.abs(_Math.CesiumMath.PI_OVER_TWO - absHeading),
  564. _Math.CesiumMath.PI_OVER_TWO,
  565. _Math.CesiumMath.EPSILON8
  566. )
  567. ) {
  568. if (
  569. _Math.CesiumMath.equalsEpsilon(
  570. intersectionLongitude,
  571. start.longitude,
  572. _Math.CesiumMath.EPSILON12
  573. )
  574. ) {
  575. return undefined;
  576. }
  577. result.longitude = intersectionLongitude;
  578. result.latitude =
  579. _Math.CesiumMath.PI_OVER_TWO *
  580. _Math.CesiumMath.sign(_Math.CesiumMath.PI_OVER_TWO - heading);
  581. result.height = 0;
  582. return result;
  583. }
  584. // Use iterative solver from Equation 9 from http://edwilliams.org/ellipsoid/ellipsoid.pdf
  585. var phi1 = start.latitude;
  586. var eSinPhi1 = ellipticity * Math.sin(phi1);
  587. var leftComponent =
  588. Math.tan(0.5 * (_Math.CesiumMath.PI_OVER_TWO + phi1)) *
  589. Math.exp((intersectionLongitude - start.longitude) / Math.tan(heading));
  590. var denominator = (1 + eSinPhi1) / (1 - eSinPhi1);
  591. var newPhi = start.latitude;
  592. var phi;
  593. do {
  594. phi = newPhi;
  595. var eSinPhi = ellipticity * Math.sin(phi);
  596. var numerator = (1 + eSinPhi) / (1 - eSinPhi);
  597. newPhi =
  598. 2 *
  599. Math.atan(
  600. leftComponent * Math.pow(numerator / denominator, ellipticity / 2)
  601. ) -
  602. _Math.CesiumMath.PI_OVER_TWO;
  603. } while (!_Math.CesiumMath.equalsEpsilon(newPhi, phi, _Math.CesiumMath.EPSILON12));
  604. result.longitude = intersectionLongitude;
  605. result.latitude = newPhi;
  606. result.height = 0;
  607. return result;
  608. };
  609. /**
  610. * Provides the location of a point at the indicated latitude along the rhumb line.
  611. * If the latitude is outside the range of start and end points, the first intersection with the latitude from that start point in the direction of the heading is returned. This follows the spiral property of a rhumb line.
  612. *
  613. * @param {Number} intersectionLatitude The latitude, in radians, at which to find the intersection point from the starting point using the heading.
  614. * @param {Cartographic} [result] The object in which to store the result.
  615. * @returns {Cartographic} The location of the intersection point along the rhumb line, undefined if there is no intersection or infinite intersections.
  616. *
  617. * @exception {DeveloperError} start and end must be set before calling function findIntersectionWithLongitude.
  618. */
  619. EllipsoidRhumbLine.prototype.findIntersectionWithLatitude = function (
  620. intersectionLatitude,
  621. result
  622. ) {
  623. //>>includeStart('debug', pragmas.debug);
  624. Check.Check.typeOf.number("intersectionLatitude", intersectionLatitude);
  625. if (!when.defined(this._distance) || this._distance === 0.0) {
  626. throw new Check.DeveloperError(
  627. "EllipsoidRhumbLine must have distinct start and end set."
  628. );
  629. }
  630. //>>includeEnd('debug');
  631. var ellipticity = this._ellipticity;
  632. var heading = this._heading;
  633. var start = this._start;
  634. // If start and end have same latitude, return undefined since it's either no intersection or infinite intersections
  635. if (
  636. _Math.CesiumMath.equalsEpsilon(
  637. Math.abs(heading),
  638. _Math.CesiumMath.PI_OVER_TWO,
  639. _Math.CesiumMath.EPSILON8
  640. )
  641. ) {
  642. return;
  643. }
  644. // Can be solved using the same equations from interpolateUsingSurfaceDistance
  645. var sigma1 = calculateSigma(ellipticity, start.latitude);
  646. var sigma2 = calculateSigma(ellipticity, intersectionLatitude);
  647. var deltaLongitude = Math.tan(heading) * (sigma2 - sigma1);
  648. var longitude = _Math.CesiumMath.negativePiToPi(start.longitude + deltaLongitude);
  649. if (when.defined(result)) {
  650. result.longitude = longitude;
  651. result.latitude = intersectionLatitude;
  652. result.height = 0;
  653. return result;
  654. }
  655. return new Cartesian2.Cartographic(longitude, intersectionLatitude, 0);
  656. };
  657. exports.EllipsoidRhumbLine = EllipsoidRhumbLine;
  658. });