Cartographic.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. import Cartesian3 from "./Cartesian3.js";
  2. import Check from "./Check.js";
  3. import defaultValue from "./defaultValue.js";
  4. import defined from "./defined.js";
  5. import CesiumMath from "./Math.js";
  6. import scaleToGeodeticSurface from "./scaleToGeodeticSurface.js";
  7. /**
  8. * A position defined by longitude, latitude, and height.
  9. * @alias Cartographic
  10. * @constructor
  11. *
  12. * @param {number} [longitude=0.0] The longitude, in radians.
  13. * @param {number} [latitude=0.0] The latitude, in radians.
  14. * @param {number} [height=0.0] The height, in meters, above the ellipsoid.
  15. *
  16. * @see Ellipsoid
  17. */
  18. function Cartographic(longitude, latitude, height) {
  19. /**
  20. * The longitude, in radians.
  21. * @type {number}
  22. * @default 0.0
  23. */
  24. this.longitude = defaultValue(longitude, 0.0);
  25. /**
  26. * The latitude, in radians.
  27. * @type {number}
  28. * @default 0.0
  29. */
  30. this.latitude = defaultValue(latitude, 0.0);
  31. /**
  32. * The height, in meters, above the ellipsoid.
  33. * @type {number}
  34. * @default 0.0
  35. */
  36. this.height = defaultValue(height, 0.0);
  37. }
  38. /**
  39. * Creates a new Cartographic instance from longitude and latitude
  40. * specified in radians.
  41. *
  42. * @param {number} longitude The longitude, in radians.
  43. * @param {number} latitude The latitude, in radians.
  44. * @param {number} [height=0.0] The height, in meters, above the ellipsoid.
  45. * @param {Cartographic} [result] The object onto which to store the result.
  46. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  47. */
  48. Cartographic.fromRadians = function (longitude, latitude, height, result) {
  49. //>>includeStart('debug', pragmas.debug);
  50. Check.typeOf.number("longitude", longitude);
  51. Check.typeOf.number("latitude", latitude);
  52. //>>includeEnd('debug');
  53. height = defaultValue(height, 0.0);
  54. if (!defined(result)) {
  55. return new Cartographic(longitude, latitude, height);
  56. }
  57. result.longitude = longitude;
  58. result.latitude = latitude;
  59. result.height = height;
  60. return result;
  61. };
  62. /**
  63. * Creates a new Cartographic instance from longitude and latitude
  64. * specified in degrees. The values in the resulting object will
  65. * be in radians.
  66. *
  67. * @param {number} longitude The longitude, in degrees.
  68. * @param {number} latitude The latitude, in degrees.
  69. * @param {number} [height=0.0] The height, in meters, above the ellipsoid.
  70. * @param {Cartographic} [result] The object onto which to store the result.
  71. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  72. */
  73. Cartographic.fromDegrees = function (longitude, latitude, height, result) {
  74. //>>includeStart('debug', pragmas.debug);
  75. Check.typeOf.number("longitude", longitude);
  76. Check.typeOf.number("latitude", latitude);
  77. //>>includeEnd('debug');
  78. longitude = CesiumMath.toRadians(longitude);
  79. latitude = CesiumMath.toRadians(latitude);
  80. return Cartographic.fromRadians(longitude, latitude, height, result);
  81. };
  82. const cartesianToCartographicN = new Cartesian3();
  83. const cartesianToCartographicP = new Cartesian3();
  84. const cartesianToCartographicH = new Cartesian3();
  85. const wgs84OneOverRadii = new Cartesian3(
  86. 1.0 / 6378137.0,
  87. 1.0 / 6378137.0,
  88. 1.0 / 6356752.3142451793
  89. );
  90. const wgs84OneOverRadiiSquared = new Cartesian3(
  91. 1.0 / (6378137.0 * 6378137.0),
  92. 1.0 / (6378137.0 * 6378137.0),
  93. 1.0 / (6356752.3142451793 * 6356752.3142451793)
  94. );
  95. const wgs84CenterToleranceSquared = CesiumMath.EPSILON1;
  96. /**
  97. * Creates a new Cartographic instance from a Cartesian position. The values in the
  98. * resulting object will be in radians.
  99. *
  100. * @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
  101. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  102. * @param {Cartographic} [result] The object onto which to store the result.
  103. * @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
  104. */
  105. Cartographic.fromCartesian = function (cartesian, ellipsoid, result) {
  106. const oneOverRadii = defined(ellipsoid)
  107. ? ellipsoid.oneOverRadii
  108. : wgs84OneOverRadii;
  109. const oneOverRadiiSquared = defined(ellipsoid)
  110. ? ellipsoid.oneOverRadiiSquared
  111. : wgs84OneOverRadiiSquared;
  112. const centerToleranceSquared = defined(ellipsoid)
  113. ? ellipsoid._centerToleranceSquared
  114. : wgs84CenterToleranceSquared;
  115. //`cartesian is required.` is thrown from scaleToGeodeticSurface
  116. const p = scaleToGeodeticSurface(
  117. cartesian,
  118. oneOverRadii,
  119. oneOverRadiiSquared,
  120. centerToleranceSquared,
  121. cartesianToCartographicP
  122. );
  123. if (!defined(p)) {
  124. return undefined;
  125. }
  126. let n = Cartesian3.multiplyComponents(
  127. p,
  128. oneOverRadiiSquared,
  129. cartesianToCartographicN
  130. );
  131. n = Cartesian3.normalize(n, n);
  132. const h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
  133. const longitude = Math.atan2(n.y, n.x);
  134. const latitude = Math.asin(n.z);
  135. const height =
  136. CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
  137. if (!defined(result)) {
  138. return new Cartographic(longitude, latitude, height);
  139. }
  140. result.longitude = longitude;
  141. result.latitude = latitude;
  142. result.height = height;
  143. return result;
  144. };
  145. /**
  146. * Creates a new Cartesian3 instance from a Cartographic input. The values in the inputted
  147. * object should be in radians.
  148. *
  149. * @param {Cartographic} cartographic Input to be converted into a Cartesian3 output.
  150. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  151. * @param {Cartesian3} [result] The object onto which to store the result.
  152. * @returns {Cartesian3} The position
  153. */
  154. Cartographic.toCartesian = function (cartographic, ellipsoid, result) {
  155. //>>includeStart('debug', pragmas.debug);
  156. Check.defined("cartographic", cartographic);
  157. //>>includeEnd('debug');
  158. return Cartesian3.fromRadians(
  159. cartographic.longitude,
  160. cartographic.latitude,
  161. cartographic.height,
  162. ellipsoid,
  163. result
  164. );
  165. };
  166. /**
  167. * Duplicates a Cartographic instance.
  168. *
  169. * @param {Cartographic} cartographic The cartographic to duplicate.
  170. * @param {Cartographic} [result] The object onto which to store the result.
  171. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined)
  172. */
  173. Cartographic.clone = function (cartographic, result) {
  174. if (!defined(cartographic)) {
  175. return undefined;
  176. }
  177. if (!defined(result)) {
  178. return new Cartographic(
  179. cartographic.longitude,
  180. cartographic.latitude,
  181. cartographic.height
  182. );
  183. }
  184. result.longitude = cartographic.longitude;
  185. result.latitude = cartographic.latitude;
  186. result.height = cartographic.height;
  187. return result;
  188. };
  189. /**
  190. * Compares the provided cartographics componentwise and returns
  191. * <code>true</code> if they are equal, <code>false</code> otherwise.
  192. *
  193. * @param {Cartographic} [left] The first cartographic.
  194. * @param {Cartographic} [right] The second cartographic.
  195. * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  196. */
  197. Cartographic.equals = function (left, right) {
  198. return (
  199. left === right ||
  200. (defined(left) &&
  201. defined(right) &&
  202. left.longitude === right.longitude &&
  203. left.latitude === right.latitude &&
  204. left.height === right.height)
  205. );
  206. };
  207. /**
  208. * Compares the provided cartographics componentwise and returns
  209. * <code>true</code> if they are within the provided epsilon,
  210. * <code>false</code> otherwise.
  211. *
  212. * @param {Cartographic} [left] The first cartographic.
  213. * @param {Cartographic} [right] The second cartographic.
  214. * @param {number} [epsilon=0] The epsilon to use for equality testing.
  215. * @returns {boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  216. */
  217. Cartographic.equalsEpsilon = function (left, right, epsilon) {
  218. epsilon = defaultValue(epsilon, 0);
  219. return (
  220. left === right ||
  221. (defined(left) &&
  222. defined(right) &&
  223. Math.abs(left.longitude - right.longitude) <= epsilon &&
  224. Math.abs(left.latitude - right.latitude) <= epsilon &&
  225. Math.abs(left.height - right.height) <= epsilon)
  226. );
  227. };
  228. /**
  229. * An immutable Cartographic instance initialized to (0.0, 0.0, 0.0).
  230. *
  231. * @type {Cartographic}
  232. * @constant
  233. */
  234. Cartographic.ZERO = Object.freeze(new Cartographic(0.0, 0.0, 0.0));
  235. /**
  236. * Duplicates this instance.
  237. *
  238. * @param {Cartographic} [result] The object onto which to store the result.
  239. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  240. */
  241. Cartographic.prototype.clone = function (result) {
  242. return Cartographic.clone(this, result);
  243. };
  244. /**
  245. * Compares the provided against this cartographic componentwise and returns
  246. * <code>true</code> if they are equal, <code>false</code> otherwise.
  247. *
  248. * @param {Cartographic} [right] The second cartographic.
  249. * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  250. */
  251. Cartographic.prototype.equals = function (right) {
  252. return Cartographic.equals(this, right);
  253. };
  254. /**
  255. * Compares the provided against this cartographic componentwise and returns
  256. * <code>true</code> if they are within the provided epsilon,
  257. * <code>false</code> otherwise.
  258. *
  259. * @param {Cartographic} [right] The second cartographic.
  260. * @param {number} [epsilon=0] The epsilon to use for equality testing.
  261. * @returns {boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  262. */
  263. Cartographic.prototype.equalsEpsilon = function (right, epsilon) {
  264. return Cartographic.equalsEpsilon(this, right, epsilon);
  265. };
  266. /**
  267. * Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
  268. *
  269. * @returns {string} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
  270. */
  271. Cartographic.prototype.toString = function () {
  272. return `(${this.longitude}, ${this.latitude}, ${this.height})`;
  273. };
  274. export default Cartographic;