| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 | 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";const 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');  const 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)  );  const 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;    },  },});const 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');  const box = AxisAlignedBoundingBox.fromPoints(cartesians, tmp);  return new EllipsoidTangentPlane(box.center, ellipsoid);};const scratchProjectPointOntoPlaneRay = new Ray();const 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');  const ray = scratchProjectPointOntoPlaneRay;  ray.origin = cartesian;  Cartesian3.normalize(cartesian, ray.direction);  let 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)) {    const v = Cartesian3.subtract(      intersectionPoint,      this._origin,      intersectionPoint    );    const x = Cartesian3.dot(this._xAxis, v);    const 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 = [];  }  let count = 0;  const length = cartesians.length;  for (let i = 0; i < length; i++) {    const 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();  }  const ray = scratchProjectPointOntoPlaneRay;  ray.origin = cartesian;  Cartesian3.clone(this._plane.normal, ray.direction);  let intersectionPoint = IntersectionTests.rayPlane(    ray,    this._plane,    scratchProjectPointOntoPlaneCartesian3  );  if (!defined(intersectionPoint)) {    Cartesian3.negate(ray.direction, ray.direction);    intersectionPoint = IntersectionTests.rayPlane(      ray,      this._plane,      scratchProjectPointOntoPlaneCartesian3    );  }  const v = Cartesian3.subtract(    intersectionPoint,    this._origin,    intersectionPoint  );  const x = Cartesian3.dot(this._xAxis, v);  const 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 = [];  }  const length = cartesians.length;  result.length = length;  for (let i = 0; i < length; i++) {    result[i] = this.projectPointToNearestOnPlane(cartesians[i], result[i]);  }  return result;};const 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();  }  const ellipsoid = this._ellipsoid;  const origin = this._origin;  const xAxis = this._xAxis;  const yAxis = this._yAxis;  const 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');  const length = cartesians.length;  if (!defined(result)) {    result = new Array(length);  } else {    result.length = length;  }  for (let i = 0; i < length; ++i) {    result[i] = this.projectPointOntoEllipsoid(cartesians[i], result[i]);  }  return result;};export default EllipsoidTangentPlane;
 |