import AxisAlignedBoundingBox from "./AxisAlignedBoundingBox.js";
|
import Cartesian2 from "./Cartesian2.js";
|
import Cartesian3 from "./Cartesian3.js";
|
import Cartesian4 from "./Cartesian4.js";
|
import Check from "./Check.js";
|
import defaultValue from "./defaultValue.js";
|
import defined from "./defined.js";
|
import DeveloperError from "./DeveloperError.js";
|
import Ellipsoid from "./Ellipsoid.js";
|
import IntersectionTests from "./IntersectionTests.js";
|
import Matrix4 from "./Matrix4.js";
|
import Plane from "./Plane.js";
|
import Ray from "./Ray.js";
|
import Transforms from "./Transforms.js";
|
|
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);
|
Check.defined("origin", origin);
|
//>>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);
|
}
|
|
Object.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.
|
* @memberof 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 {Cartesian3[]} cartesians The list of positions surrounding the center point.
|
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
|
* @returns {EllipsoidTangentPlane} The new instance of EllipsoidTangentPlane.
|
*/
|
EllipsoidTangentPlane.fromPoints = function (cartesians, ellipsoid) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined("cartesians", cartesians);
|
//>>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);
|
Check.defined("cartesian", cartesian);
|
//>>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);
|
Check.defined("cartesians", cartesians);
|
//>>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);
|
Check.defined("cartesian", cartesian);
|
//>>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);
|
Check.defined("cartesians", cartesians);
|
//>>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 position onto the 3D ellipsoid.
|
*
|
* @param {Cartesian2} cartesian The points to project.
|
* @param {Cartesian3} [result] The Cartesian3 instance to store result.
|
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
|
*/
|
EllipsoidTangentPlane.prototype.projectPointOntoEllipsoid = function (
|
cartesian,
|
result
|
) {
|
//>>includeStart('debug', pragmas.debug);
|
Check.defined("cartesian", cartesian);
|
//>>includeEnd('debug');
|
|
if (!defined(result)) {
|
result = new Cartesian3();
|
}
|
|
var ellipsoid = this._ellipsoid;
|
var origin = this._origin;
|
var xAxis = this._xAxis;
|
var yAxis = this._yAxis;
|
var tmp = projectPointsOntoEllipsoidScratch;
|
|
Cartesian3.multiplyByScalar(xAxis, cartesian.x, tmp);
|
result = Cartesian3.add(origin, tmp, result);
|
Cartesian3.multiplyByScalar(yAxis, cartesian.y, tmp);
|
Cartesian3.add(result, tmp, result);
|
ellipsoid.scaleToGeocentricSurface(result, result);
|
|
return result;
|
};
|
|
/**
|
* 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);
|
Check.defined("cartesians", cartesians);
|
//>>includeEnd('debug');
|
|
var length = cartesians.length;
|
if (!defined(result)) {
|
result = new Array(length);
|
} else {
|
result.length = length;
|
}
|
|
for (var i = 0; i < length; ++i) {
|
result[i] = this.projectPointOntoEllipsoid(cartesians[i], result[i]);
|
}
|
|
return result;
|
};
|
export default EllipsoidTangentPlane;
|