import Cartesian3 from "./Cartesian3.js";
import Check from "./Check.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import CesiumMath from "./Math.js";
import scaleToGeodeticSurface from "./scaleToGeodeticSurface.js";
/**
* A position defined by longitude, latitude, and height.
* @alias Cartographic
* @constructor
*
* @param {Number} [longitude=0.0] The longitude, in radians.
* @param {Number} [latitude=0.0] The latitude, in radians.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
*
* @see Ellipsoid
*/
function Cartographic(longitude, latitude, height) {
/**
* The longitude, in radians.
* @type {Number}
* @default 0.0
*/
this.longitude = defaultValue(longitude, 0.0);
/**
* The latitude, in radians.
* @type {Number}
* @default 0.0
*/
this.latitude = defaultValue(latitude, 0.0);
/**
* The height, in meters, above the ellipsoid.
* @type {Number}
* @default 0.0
*/
this.height = defaultValue(height, 0.0);
}
/**
* Creates a new Cartographic instance from longitude and latitude
* specified in radians.
*
* @param {Number} longitude The longitude, in radians.
* @param {Number} latitude The latitude, in radians.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.fromRadians = function (longitude, latitude, height, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
height = defaultValue(height, 0.0);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* Creates a new Cartographic instance from longitude and latitude
* specified in degrees. The values in the resulting object will
* be in radians.
*
* @param {Number} longitude The longitude, in degrees.
* @param {Number} latitude The latitude, in degrees.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.fromDegrees = function (longitude, latitude, height, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
longitude = CesiumMath.toRadians(longitude);
latitude = CesiumMath.toRadians(latitude);
return Cartographic.fromRadians(longitude, latitude, height, result);
};
const cartesianToCartographicN = new Cartesian3();
const cartesianToCartographicP = new Cartesian3();
const cartesianToCartographicH = new Cartesian3();
const wgs84OneOverRadii = new Cartesian3(
1.0 / 6378137.0,
1.0 / 6378137.0,
1.0 / 6356752.3142451793
);
const wgs84OneOverRadiiSquared = new Cartesian3(
1.0 / (6378137.0 * 6378137.0),
1.0 / (6378137.0 * 6378137.0),
1.0 / (6356752.3142451793 * 6356752.3142451793)
);
const wgs84CenterToleranceSquared = CesiumMath.EPSILON1;
/**
* Creates a new Cartographic instance from a Cartesian position. The values in the
* resulting object will be in radians.
*
* @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartographic} [result] The object onto which to store the result.
* @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.
*/
Cartographic.fromCartesian = function (cartesian, ellipsoid, result) {
const oneOverRadii = defined(ellipsoid)
? ellipsoid.oneOverRadii
: wgs84OneOverRadii;
const oneOverRadiiSquared = defined(ellipsoid)
? ellipsoid.oneOverRadiiSquared
: wgs84OneOverRadiiSquared;
const centerToleranceSquared = defined(ellipsoid)
? ellipsoid._centerToleranceSquared
: wgs84CenterToleranceSquared;
//`cartesian is required.` is thrown from scaleToGeodeticSurface
const p = scaleToGeodeticSurface(
cartesian,
oneOverRadii,
oneOverRadiiSquared,
centerToleranceSquared,
cartesianToCartographicP
);
if (!defined(p)) {
return undefined;
}
let n = Cartesian3.multiplyComponents(
p,
oneOverRadiiSquared,
cartesianToCartographicN
);
n = Cartesian3.normalize(n, n);
const h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
const longitude = Math.atan2(n.y, n.x);
const latitude = Math.asin(n.z);
const height =
CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* Creates a new Cartesian3 instance from a Cartographic input. The values in the inputted
* object should be in radians.
*
* @param {Cartographic} cartographic Input to be converted into a Cartesian3 output.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The position
*/
Cartographic.toCartesian = function (cartographic, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartographic", cartographic);
//>>includeEnd('debug');
return Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
cartographic.height,
ellipsoid,
result
);
};
/**
* Duplicates a Cartographic instance.
*
* @param {Cartographic} cartographic The cartographic to duplicate.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined)
*/
Cartographic.clone = function (cartographic, result) {
if (!defined(cartographic)) {
return undefined;
}
if (!defined(result)) {
return new Cartographic(
cartographic.longitude,
cartographic.latitude,
cartographic.height
);
}
result.longitude = cartographic.longitude;
result.latitude = cartographic.latitude;
result.height = cartographic.height;
return result;
};
/**
* Compares the provided cartographics componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartographic} [left] The first cartographic.
* @param {Cartographic} [right] The second cartographic.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartographic.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.longitude === right.longitude &&
left.latitude === right.latitude &&
left.height === right.height)
);
};
/**
* Compares the provided cartographics componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Cartographic} [left] The first cartographic.
* @param {Cartographic} [right] The second cartographic.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartographic.equalsEpsilon = function (left, right, epsilon) {
epsilon = defaultValue(epsilon, 0);
return (
left === right ||
(defined(left) &&
defined(right) &&
Math.abs(left.longitude - right.longitude) <= epsilon &&
Math.abs(left.latitude - right.latitude) <= epsilon &&
Math.abs(left.height - right.height) <= epsilon)
);
};
/**
* An immutable Cartographic instance initialized to (0.0, 0.0, 0.0).
*
* @type {Cartographic}
* @constant
*/
Cartographic.ZERO = Object.freeze(new Cartographic(0.0, 0.0, 0.0));
/**
* Duplicates this instance.
*
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.prototype.clone = function (result) {
return Cartographic.clone(this, result);
};
/**
* Compares the provided against this cartographic componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartographic} [right] The second cartographic.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartographic.prototype.equals = function (right) {
return Cartographic.equals(this, right);
};
/**
* Compares the provided against this cartographic componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Cartographic} [right] The second cartographic.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartographic.prototype.equalsEpsilon = function (right, epsilon) {
return Cartographic.equalsEpsilon(this, right, epsilon);
};
/**
* Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
*
* @returns {String} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
*/
Cartographic.prototype.toString = function () {
return `(${this.longitude}, ${this.latitude}, ${this.height})`;
};
export default Cartographic;