EllipsoidTangentPlane.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import AxisAlignedBoundingBox from './AxisAlignedBoundingBox.js';
  2. import Cartesian2 from './Cartesian2.js';
  3. import Cartesian3 from './Cartesian3.js';
  4. import Cartesian4 from './Cartesian4.js';
  5. import Check from './Check.js';
  6. import defaultValue from './defaultValue.js';
  7. import defined from './defined.js';
  8. import defineProperties from './defineProperties.js';
  9. import DeveloperError from './DeveloperError.js';
  10. import Ellipsoid from './Ellipsoid.js';
  11. import IntersectionTests from './IntersectionTests.js';
  12. import Matrix4 from './Matrix4.js';
  13. import Plane from './Plane.js';
  14. import Ray from './Ray.js';
  15. import Transforms from './Transforms.js';
  16. var scratchCart4 = new Cartesian4();
  17. /**
  18. * A plane tangent to the provided ellipsoid at the provided origin.
  19. * If origin is not on the surface of the ellipsoid, it's surface projection will be used.
  20. * If origin is at the center of the ellipsoid, an exception will be thrown.
  21. * @alias EllipsoidTangentPlane
  22. * @constructor
  23. *
  24. * @param {Cartesian3} origin The point on the surface of the ellipsoid where the tangent plane touches.
  25. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
  26. *
  27. * @exception {DeveloperError} origin must not be at the center of the ellipsoid.
  28. */
  29. function EllipsoidTangentPlane(origin, ellipsoid) {
  30. //>>includeStart('debug', pragmas.debug);
  31. Check.defined('origin', origin);
  32. //>>includeEnd('debug');
  33. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  34. origin = ellipsoid.scaleToGeodeticSurface(origin);
  35. //>>includeStart('debug', pragmas.debug);
  36. if (!defined(origin)) {
  37. throw new DeveloperError('origin must not be at the center of the ellipsoid.');
  38. }
  39. //>>includeEnd('debug');
  40. var eastNorthUp = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid);
  41. this._ellipsoid = ellipsoid;
  42. this._origin = origin;
  43. this._xAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 0, scratchCart4));
  44. this._yAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 1, scratchCart4));
  45. var normal = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 2, scratchCart4));
  46. this._plane = Plane.fromPointNormal(origin, normal);
  47. }
  48. defineProperties(EllipsoidTangentPlane.prototype, {
  49. /**
  50. * Gets the ellipsoid.
  51. * @memberof EllipsoidTangentPlane.prototype
  52. * @type {Ellipsoid}
  53. */
  54. ellipsoid : {
  55. get : function() {
  56. return this._ellipsoid;
  57. }
  58. },
  59. /**
  60. * Gets the origin.
  61. * @memberof EllipsoidTangentPlane.prototype
  62. * @type {Cartesian3}
  63. */
  64. origin : {
  65. get : function() {
  66. return this._origin;
  67. }
  68. },
  69. /**
  70. * Gets the plane which is tangent to the ellipsoid.
  71. * @memberof EllipsoidTangentPlane.prototype
  72. * @readonly
  73. * @type {Plane}
  74. */
  75. plane : {
  76. get : function() {
  77. return this._plane;
  78. }
  79. },
  80. /**
  81. * Gets the local X-axis (east) of the tangent plane.
  82. * @memberof EllipsoidTangentPlane.prototype
  83. * @readonly
  84. * @type {Cartesian3}
  85. */
  86. xAxis : {
  87. get : function() {
  88. return this._xAxis;
  89. }
  90. },
  91. /**
  92. * Gets the local Y-axis (north) of the tangent plane.
  93. * @memberof EllipsoidTangentPlane.prototype
  94. * @readonly
  95. * @type {Cartesian3}
  96. */
  97. yAxis : {
  98. get : function() {
  99. return this._yAxis;
  100. }
  101. },
  102. /**
  103. * Gets the local Z-axis (up) of the tangent plane.
  104. * @member EllipsoidTangentPlane.prototype
  105. * @readonly
  106. * @type {Cartesian3}
  107. */
  108. zAxis : {
  109. get : function() {
  110. return this._plane.normal;
  111. }
  112. }
  113. });
  114. var tmp = new AxisAlignedBoundingBox();
  115. /**
  116. * Creates a new instance from the provided ellipsoid and the center
  117. * point of the provided Cartesians.
  118. *
  119. * @param {Cartesian3} cartesians The list of positions surrounding the center point.
  120. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
  121. */
  122. EllipsoidTangentPlane.fromPoints = function(cartesians, ellipsoid) {
  123. //>>includeStart('debug', pragmas.debug);
  124. Check.defined('cartesians', cartesians);
  125. //>>includeEnd('debug');
  126. var box = AxisAlignedBoundingBox.fromPoints(cartesians, tmp);
  127. return new EllipsoidTangentPlane(box.center, ellipsoid);
  128. };
  129. var scratchProjectPointOntoPlaneRay = new Ray();
  130. var scratchProjectPointOntoPlaneCartesian3 = new Cartesian3();
  131. /**
  132. * Computes the projection of the provided 3D position onto the 2D plane, radially outward from the {@link EllipsoidTangentPlane.ellipsoid} coordinate system origin.
  133. *
  134. * @param {Cartesian3} cartesian The point to project.
  135. * @param {Cartesian2} [result] The object onto which to store the result.
  136. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided. Undefined if there is no intersection point
  137. */
  138. EllipsoidTangentPlane.prototype.projectPointOntoPlane = function(cartesian, result) {
  139. //>>includeStart('debug', pragmas.debug);
  140. Check.defined('cartesian', cartesian);
  141. //>>includeEnd('debug');
  142. var ray = scratchProjectPointOntoPlaneRay;
  143. ray.origin = cartesian;
  144. Cartesian3.normalize(cartesian, ray.direction);
  145. var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  146. if (!defined(intersectionPoint)) {
  147. Cartesian3.negate(ray.direction, ray.direction);
  148. intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  149. }
  150. if (defined(intersectionPoint)) {
  151. var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint);
  152. var x = Cartesian3.dot(this._xAxis, v);
  153. var y = Cartesian3.dot(this._yAxis, v);
  154. if (!defined(result)) {
  155. return new Cartesian2(x, y);
  156. }
  157. result.x = x;
  158. result.y = y;
  159. return result;
  160. }
  161. return undefined;
  162. };
  163. /**
  164. * Computes the projection of the provided 3D positions onto the 2D plane (where possible), radially outward from the global origin.
  165. * The resulting array may be shorter than the input array - if a single projection is impossible it will not be included.
  166. *
  167. * @see EllipsoidTangentPlane.projectPointOntoPlane
  168. *
  169. * @param {Cartesian3[]} cartesians The array of points to project.
  170. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results.
  171. * @returns {Cartesian2[]} The modified result parameter or a new array of Cartesian2 instances if none was provided.
  172. */
  173. EllipsoidTangentPlane.prototype.projectPointsOntoPlane = function(cartesians, result) {
  174. //>>includeStart('debug', pragmas.debug);
  175. Check.defined('cartesians', cartesians);
  176. //>>includeEnd('debug');
  177. if (!defined(result)) {
  178. result = [];
  179. }
  180. var count = 0;
  181. var length = cartesians.length;
  182. for ( var i = 0; i < length; i++) {
  183. var p = this.projectPointOntoPlane(cartesians[i], result[count]);
  184. if (defined(p)) {
  185. result[count] = p;
  186. count++;
  187. }
  188. }
  189. result.length = count;
  190. return result;
  191. };
  192. /**
  193. * Computes the projection of the provided 3D position onto the 2D plane, along the plane normal.
  194. *
  195. * @param {Cartesian3} cartesian The point to project.
  196. * @param {Cartesian2} [result] The object onto which to store the result.
  197. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided.
  198. */
  199. EllipsoidTangentPlane.prototype.projectPointToNearestOnPlane = function(cartesian, result) {
  200. //>>includeStart('debug', pragmas.debug);
  201. Check.defined('cartesian', cartesian);
  202. //>>includeEnd('debug');
  203. if (!defined(result)) {
  204. result = new Cartesian2();
  205. }
  206. var ray = scratchProjectPointOntoPlaneRay;
  207. ray.origin = cartesian;
  208. Cartesian3.clone(this._plane.normal, ray.direction);
  209. var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  210. if (!defined(intersectionPoint)) {
  211. Cartesian3.negate(ray.direction, ray.direction);
  212. intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  213. }
  214. var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint);
  215. var x = Cartesian3.dot(this._xAxis, v);
  216. var y = Cartesian3.dot(this._yAxis, v);
  217. result.x = x;
  218. result.y = y;
  219. return result;
  220. };
  221. /**
  222. * Computes the projection of the provided 3D positions onto the 2D plane, along the plane normal.
  223. *
  224. * @see EllipsoidTangentPlane.projectPointToNearestOnPlane
  225. *
  226. * @param {Cartesian3[]} cartesians The array of points to project.
  227. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results.
  228. * @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>.
  229. */
  230. EllipsoidTangentPlane.prototype.projectPointsToNearestOnPlane = function(cartesians, result) {
  231. //>>includeStart('debug', pragmas.debug);
  232. Check.defined('cartesians', cartesians);
  233. //>>includeEnd('debug');
  234. if (!defined(result)) {
  235. result = [];
  236. }
  237. var length = cartesians.length;
  238. result.length = length;
  239. for (var i = 0; i < length; i++) {
  240. result[i] = this.projectPointToNearestOnPlane(cartesians[i], result[i]);
  241. }
  242. return result;
  243. };
  244. var projectPointsOntoEllipsoidScratch = new Cartesian3();
  245. /**
  246. * Computes the projection of the provided 2D position onto the 3D ellipsoid.
  247. *
  248. * @param {Cartesian2} cartesian The points to project.
  249. * @param {Cartesian3} [result] The Cartesian3 instance to store result.
  250. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  251. */
  252. EllipsoidTangentPlane.prototype.projectPointOntoEllipsoid = function(cartesian, result) {
  253. //>>includeStart('debug', pragmas.debug);
  254. Check.defined('cartesian', cartesian);
  255. //>>includeEnd('debug');
  256. if (!defined(result)) {
  257. result = new Cartesian3();
  258. }
  259. var ellipsoid = this._ellipsoid;
  260. var origin = this._origin;
  261. var xAxis = this._xAxis;
  262. var yAxis = this._yAxis;
  263. var tmp = projectPointsOntoEllipsoidScratch;
  264. Cartesian3.multiplyByScalar(xAxis, cartesian.x, tmp);
  265. result = Cartesian3.add(origin, tmp, result);
  266. Cartesian3.multiplyByScalar(yAxis, cartesian.y, tmp);
  267. Cartesian3.add(result, tmp, result);
  268. ellipsoid.scaleToGeocentricSurface(result, result);
  269. return result;
  270. };
  271. /**
  272. * Computes the projection of the provided 2D positions onto the 3D ellipsoid.
  273. *
  274. * @param {Cartesian2[]} cartesians The array of points to project.
  275. * @param {Cartesian3[]} [result] The array of Cartesian3 instances onto which to store results.
  276. * @returns {Cartesian3[]} The modified result parameter or a new array of Cartesian3 instances if none was provided.
  277. */
  278. EllipsoidTangentPlane.prototype.projectPointsOntoEllipsoid = function(cartesians, result) {
  279. //>>includeStart('debug', pragmas.debug);
  280. Check.defined('cartesians', cartesians);
  281. //>>includeEnd('debug');
  282. var length = cartesians.length;
  283. if (!defined(result)) {
  284. result = new Array(length);
  285. } else {
  286. result.length = length;
  287. }
  288. for ( var i = 0; i < length; ++i) {
  289. result[i] = this.projectPointOntoEllipsoid(cartesians[i], result[i]);
  290. }
  291. return result;
  292. };
  293. export default EllipsoidTangentPlane;