itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
316 lines (279 loc) • 10.9 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var THREE = _interopRequireWildcard(require("three"));
var _proj = _interopRequireDefault(require("proj4"));
var _Crs = _interopRequireDefault(require("./Crs"));
var _Ellipsoid = _interopRequireDefault(require("../Math/Ellipsoid"));
_proj["default"].defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs');
var ellipsoid = new _Ellipsoid["default"]();
var vectorPivot = new THREE.Vector3();
var coordPivot;
var projectionCache = {};
function proj4cache(crsIn, crsOut) {
if (!projectionCache[crsIn]) {
projectionCache[crsIn] = {};
}
if (!projectionCache[crsIn][crsOut]) {
projectionCache[crsIn][crsOut] = (0, _proj["default"])(crsIn, crsOut);
}
return projectionCache[crsIn][crsOut];
} // Internal method, takes a coord and put some proj4 values in it
function setFromProj4(coord, proj4value, z) {
return coord.setFromValues(proj4value[0], proj4value[1], z);
}
/**
* A Coordinates object, defined by a [crs]{@link http://inspire.ec.europa.eu/theme/rs}
* and three values. These values are accessible through `x`, `y` and `z`,
* although it can also be accessible through `latitude`, `longitude` and
* `altitude`. To change a value, prefer the `set()` method below.
*
* @property {boolean} isCoordinates - Used to checkout whether this coordinates
* is a Coordinates. Default is true. You should not change this, as it is used
* internally for optimisation.
* @property {string} crs - A supported crs by default in
* [`proj4js`](https://github.com/proj4js/proj4js#named-projections), or an
* added crs to `proj4js` (using `proj4.defs`). Note that `EPSG:4978` is also
* supported by default in itowns.
* @property {number} x - The first value of the coordinate.
* @property {number} y - The second value of the coordinate.
* @property {number} z - The third value of the coordinate.
* @property {number} latitude - The first value of the coordinate.
* @property {number} longitude - The second value of the coordinate.
* @property {number} altitude - The third value of the coordinate.
* @property {THREE.Vector3} geodesicNormal - The geodesic normal of the
* coordinate.
*
* @example
* new Coordinates('EPSG:4978', 20885167, 849862, 23385912); //Geocentric coordinates
*
* @example
* new Coordinates('EPSG:4326', 2.33, 48.24, 24999549); //Geographic coordinates
*/
var Coordinates =
/*#__PURE__*/
function () {
/**
* @constructor
*
* @param {string} crs - A supported crs (see the `crs` property below).
* @param {number|Array<number>|Coordinates|THREE.Vector3} [v0=0] -
* x or longitude value, or a more complex one: it can be an array of three
* numbers, being x/lon, x/lat, z/alt, or it can be `THREE.Vector3`. It can
* also simply be a Coordinates.
* @param {number} [v1=0] - y or latitude value.
* @param {number} [v2=0] - z or altitude value.
*/
function Coordinates(crs) {
var v0 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var v1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var v2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
(0, _classCallCheck2["default"])(this, Coordinates);
this.isCoordinates = true;
_Crs["default"].isValid(crs);
this.crs = crs; // Storing the coordinates as is, not in arrays, as it is
// slower (see https://jsbench.me/40jumfag6g/1)
this.x = 0;
this.y = 0;
this.z = 0; // Normal
this._normal = new THREE.Vector3();
if (v0.length > 0) {
this.setFromArray(v0);
} else if (v0.isVector3 || v0.isCoordinates) {
this.setFromVector3(v0);
} else {
this.setFromValues(v0, v1, v2);
}
this._normalNeedsUpdate = true;
}
/**
* Set the values of this Coordinates.
*
* @param {number} [v0=0] - x or longitude value.
* @param {number} [v1=0] - y or latitude value.
* @param {number} [v2=0] - z or altitude value.
*
* @return {Coordinates} This Coordinates.
*/
(0, _createClass2["default"])(Coordinates, [{
key: "setFromValues",
value: function setFromValues() {
var v0 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var v1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var v2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
this.x = v0 == undefined ? 0 : v0;
this.y = v1 == undefined ? 0 : v1;
this.z = v2 == undefined ? 0 : v2;
this._normalNeedsUpdate = true;
return this;
}
/**
* Set the values of this Coordinates from an array.
*
* @param {Array<number>} array - An array of number to assign to the
* Coordinates.
* @param {number} [offset] - Optional offset into the array.
*
* @return {Coordinates} This Coordinates.
*/
}, {
key: "setFromArray",
value: function setFromArray(array) {
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
return this.setFromValues(array[offset], array[offset + 1], array[offset + 2]);
}
/**
* Set the values of this Coordinates from a `THREE.Vector3` or an `Object`
* having `x/y/z` properties, like a `Coordinates`.
*
* @param {THREE.Vector3|Coordinates} v0 - The object to read the values
* from.
*
* @return {Coordinates} This Coordinates.
*/
}, {
key: "setFromVector3",
value: function setFromVector3(v0) {
return this.setFromValues(v0.x, v0.y, v0.z);
}
/**
* Returns a new Coordinates with the same values as this one. It will
* instantiate a new Coordinates with the same CRS as this one.
*
* @return {Coordinates} The target with its new coordinates.
*/
}, {
key: "clone",
value: function clone() {
return new Coordinates(this.crs, this);
}
/**
* Copies the values of the passed Coordinates to this one. The CRS is
* however not copied.
*
* @param {Coordinates} src - The source to copy from.
*
* @return {Coordinates} This Coordinates.
*/
}, {
key: "copy",
value: function copy(src) {
this.crs = src.crs;
return this.setFromVector3(src);
}
}, {
key: "toVector3",
/**
* Return this Coordinates values into a `THREE.Vector3`.
*
* @param {THREE.Vector3} [target] - The target to put the values in. If not
* specified, a new vector will be created.
*
* @return {THREE.Vector3}
*/
value: function toVector3() {
var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new THREE.Vector3();
return target.copy(this);
}
/**
* Returns coordinates in the wanted [CRS]{@link http://inspire.ec.europa.eu/theme/rs}.
*
* @param {string} crs - The CRS to convert the Coordinates into.
* @param {Coordinates} [target] - The target to put the converted
* Coordinates into. If not specified a new one will be created.
*
* @return {Coordinates} - The resulting Coordinates after the conversion.
*
* @example
* const position = { longitude: 2.33, latitude: 48.24, altitude: 24999549 };
* const coords = new Coordinates('EPSG:4326', position.longitude, position.latitude, position.altitude); // Geographic system
* const coordinates = coords.as('EPSG:4978'); // Geocentric system
*
* @example
* const position = { x: 20885167, y: 849862, z: 23385912 };
* const coords = new Coordinates('EPSG:4978', position.x, position.y, position.z); // Geocentric system
* const coordinates = coords.as('EPSG:4326'); // Geographic system
*
* @example
* new Coordinates('EPSG:4326', longitude: 2.33, latitude: 48.24, altitude: 24999549).as('EPSG:4978'); // Geocentric system
*
* @example
* new Coordinates('EPSG:4978', x: 20885167, y: 849862, z: 23385912).as('EPSG:4326'); // Geographic system
*/
}, {
key: "as",
value: function as(crs) {
var target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Coordinates(crs);
if (this.crs == crs) {
target.copy(this); // there is a bug for converting anything from and to 4978 with proj4
// https://github.com/proj4js/proj4js/issues/195
// the workaround is to use an intermediate projection, like EPSG:4326
} else if (crs == 'EPSG:4978') {
if (_Crs["default"].is4326(this.crs)) {
ellipsoid.cartographicToCartesian(this, vectorPivot);
target.setFromVector3(vectorPivot);
} else {
setFromProj4(coordPivot, proj4cache(this.crs, 'EPSG:4326').forward([this.x, this.y]), this.z);
coordPivot.as('EPSG:4978', target);
}
} else if (this.crs == 'EPSG:4978') {
if (_Crs["default"].is4326(crs)) {
ellipsoid.cartesianToCartographic(this, target);
} else {
this.as('EPSG:4326', coordPivot);
setFromProj4(target, proj4cache('EPSG:4326', crs).forward([coordPivot.x, coordPivot.y]), coordPivot.z);
}
} else if (_Crs["default"].is4326(this.crs) && crs == 'EPSG:3857') {
this.y = THREE.Math.clamp(this.y, -89.999999, 89.999999);
setFromProj4(target, proj4cache(this.crs, crs).forward([this.x, this.y]), this.z);
} else {
setFromProj4(target, proj4cache(this.crs, crs).forward([this.x, this.y]), this.z);
}
target.crs = crs;
return target;
}
}, {
key: "longitude",
get: function get() {
return this.x;
}
}, {
key: "latitude",
get: function get() {
return this.y;
}
}, {
key: "altitude",
get: function get() {
return this.z;
},
set: function set(value) {
this.z = value;
}
}, {
key: "geodesicNormal",
get: function get() {
if (this._normalNeedsUpdate) {
this._normalNeedsUpdate = false;
if (_Crs["default"].is4326(this.crs)) {
ellipsoid.geodeticSurfaceNormalCartographic(this, this._normal);
} else if (this.crs == 'EPSG:4978') {
ellipsoid.geodeticSurfaceNormal(this, this._normal);
} else {
this._normal.set(0, 0, 1);
}
}
return this._normal;
}
}]);
return Coordinates;
}();
coordPivot = new Coordinates('EPSG:4326');
var _default = Coordinates;
exports["default"] = _default;