UNPKG

cesium

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

349 lines (311 loc) 12.8 kB
define([ './AxisAlignedBoundingBox', './Cartesian2', './Cartesian3', './Cartesian4', './defaultValue', './defined', './defineProperties', './DeveloperError', './Ellipsoid', './IntersectionTests', './Matrix4', './Plane', './Ray', './Transforms' ], function( AxisAlignedBoundingBox, Cartesian2, Cartesian3, Cartesian4, defaultValue, defined, defineProperties, DeveloperError, Ellipsoid, IntersectionTests, Matrix4, Plane, Ray, Transforms) { 'use strict'; var scratchCart4 = new Cartesian4(); /** * A plane tangent to the provided ellipsoid at the provided origin. * If origin is not on the surface of the ellipsoid, it's surface projection will be used. * If origin is at the center of the ellipsoid, an exception will be thrown. * @alias EllipsoidTangentPlane * @constructor * * @param {Cartesian3} origin The point on the surface of the ellipsoid where the tangent plane touches. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use. * * @exception {DeveloperError} origin must not be at the center of the ellipsoid. */ function EllipsoidTangentPlane(origin, ellipsoid) { //>>includeStart('debug', pragmas.debug); if (!defined(origin)) { throw new DeveloperError('origin is required.'); } //>>includeEnd('debug'); ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84); origin = ellipsoid.scaleToGeodeticSurface(origin); //>>includeStart('debug', pragmas.debug); if (!defined(origin)) { throw new DeveloperError('origin must not be at the center of the ellipsoid.'); } //>>includeEnd('debug'); var eastNorthUp = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid); this._ellipsoid = ellipsoid; this._origin = origin; this._xAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 0, scratchCart4)); this._yAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 1, scratchCart4)); var normal = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 2, scratchCart4)); this._plane = Plane.fromPointNormal(origin, normal); } defineProperties(EllipsoidTangentPlane.prototype, { /** * Gets the ellipsoid. * @memberof EllipsoidTangentPlane.prototype * @type {Ellipsoid} */ ellipsoid : { get : function() { return this._ellipsoid; } }, /** * Gets the origin. * @memberof EllipsoidTangentPlane.prototype * @type {Cartesian3} */ origin : { get : function() { return this._origin; } }, /** * Gets the plane which is tangent to the ellipsoid. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Plane} */ plane : { get : function() { return this._plane; } }, /** * Gets the local X-axis (east) of the tangent plane. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ xAxis : { get : function() { return this._xAxis; } }, /** * Gets the local Y-axis (north) of the tangent plane. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ yAxis : { get : function() { return this._yAxis; } }, /** * Gets the local Z-axis (up) of the tangent plane. * @member EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ zAxis : { get : function() { return this._plane.normal; } } }); var tmp = new AxisAlignedBoundingBox(); /** * Creates a new instance from the provided ellipsoid and the center * point of the provided Cartesians. * * @param {Ellipsoid} ellipsoid The ellipsoid to use. * @param {Cartesian3} cartesians The list of positions surrounding the center point. */ EllipsoidTangentPlane.fromPoints = function(cartesians, ellipsoid) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesians)) { throw new DeveloperError('cartesians is required.'); } //>>includeEnd('debug'); var box = AxisAlignedBoundingBox.fromPoints(cartesians, tmp); return new EllipsoidTangentPlane(box.center, ellipsoid); }; var scratchProjectPointOntoPlaneRay = new Ray(); var scratchProjectPointOntoPlaneCartesian3 = new Cartesian3(); /** * Computes the projection of the provided 3D position onto the 2D plane, radially outward from the {@link EllipsoidTangentPlane.ellipsoid} coordinate system origin. * * @param {Cartesian3} cartesian The point to project. * @param {Cartesian2} [result] The object onto which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided. Undefined if there is no intersection point */ EllipsoidTangentPlane.prototype.projectPointOntoPlane = function(cartesian, result) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesian)) { throw new DeveloperError('cartesian is required.'); } //>>includeEnd('debug'); var ray = scratchProjectPointOntoPlaneRay; ray.origin = cartesian; Cartesian3.normalize(cartesian, ray.direction); var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3); if (!defined(intersectionPoint)) { Cartesian3.negate(ray.direction, ray.direction); intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3); } if (defined(intersectionPoint)) { var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint); var x = Cartesian3.dot(this._xAxis, v); var y = Cartesian3.dot(this._yAxis, v); if (!defined(result)) { return new Cartesian2(x, y); } result.x = x; result.y = y; return result; } return undefined; }; /** * Computes the projection of the provided 3D positions onto the 2D plane (where possible), radially outward from the global origin. * The resulting array may be shorter than the input array - if a single projection is impossible it will not be included. * * @see EllipsoidTangentPlane.projectPointOntoPlane * * @param {Cartesian3[]} cartesians The array of points to project. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results. * @returns {Cartesian2[]} The modified result parameter or a new array of Cartesian2 instances if none was provided. */ EllipsoidTangentPlane.prototype.projectPointsOntoPlane = function(cartesians, result) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesians)) { throw new DeveloperError('cartesians is required.'); } //>>includeEnd('debug'); if (!defined(result)) { result = []; } var count = 0; var length = cartesians.length; for ( var i = 0; i < length; i++) { var p = this.projectPointOntoPlane(cartesians[i], result[count]); if (defined(p)) { result[count] = p; count++; } } result.length = count; return result; }; /** * Computes the projection of the provided 3D position onto the 2D plane, along the plane normal. * * @param {Cartesian3} cartesian The point to project. * @param {Cartesian2} [result] The object onto which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided. */ EllipsoidTangentPlane.prototype.projectPointToNearestOnPlane = function(cartesian, result) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesian)) { throw new DeveloperError('cartesian is required.'); } //>>includeEnd('debug'); if (!defined(result)) { result = new Cartesian2(); } var ray = scratchProjectPointOntoPlaneRay; ray.origin = cartesian; Cartesian3.clone(this._plane.normal, ray.direction); var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3); if (!defined(intersectionPoint)) { Cartesian3.negate(ray.direction, ray.direction); intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3); } var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint); var x = Cartesian3.dot(this._xAxis, v); var y = Cartesian3.dot(this._yAxis, v); result.x = x; result.y = y; return result; }; /** * Computes the projection of the provided 3D positions onto the 2D plane, along the plane normal. * * @see EllipsoidTangentPlane.projectPointToNearestOnPlane * * @param {Cartesian3[]} cartesians The array of points to project. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results. * @returns {Cartesian2[]} The modified result parameter or a new array of Cartesian2 instances if none was provided. This will have the same length as <code>cartesians</code>. */ EllipsoidTangentPlane.prototype.projectPointsToNearestOnPlane = function(cartesians, result) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesians)) { throw new DeveloperError('cartesians is required.'); } //>>includeEnd('debug'); if (!defined(result)) { result = []; } var length = cartesians.length; result.length = length; for (var i = 0; i < length; i++) { result[i] = this.projectPointToNearestOnPlane(cartesians[i], result[i]); } return result; }; var projectPointsOntoEllipsoidScratch = new Cartesian3(); /** * Computes the projection of the provided 2D positions onto the 3D ellipsoid. * * @param {Cartesian2[]} cartesians The array of points to project. * @param {Cartesian3[]} [result] The array of Cartesian3 instances onto which to store results. * @returns {Cartesian3[]} The modified result parameter or a new array of Cartesian3 instances if none was provided. */ EllipsoidTangentPlane.prototype.projectPointsOntoEllipsoid = function(cartesians, result) { //>>includeStart('debug', pragmas.debug); if (!defined(cartesians)) { throw new DeveloperError('cartesians is required.'); } //>>includeEnd('debug'); var length = cartesians.length; if (!defined(result)) { result = new Array(length); } else { result.length = length; } var ellipsoid = this._ellipsoid; var origin = this._origin; var xAxis = this._xAxis; var yAxis = this._yAxis; var tmp = projectPointsOntoEllipsoidScratch; for ( var i = 0; i < length; ++i) { var position = cartesians[i]; Cartesian3.multiplyByScalar(xAxis, position.x, tmp); if (!defined(result[i])) { result[i] = new Cartesian3(); } var point = Cartesian3.add(origin, tmp, result[i]); Cartesian3.multiplyByScalar(yAxis, position.y, tmp); Cartesian3.add(point, tmp, point); ellipsoid.scaleToGeocentricSurface(point, point); } return result; }; return EllipsoidTangentPlane; });