OrientedBoundingBox-d8219c10.js 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['exports', './when-e6985d2a', './Check-24cae389', './Math-392d0035', './Cartesian2-a5d6dde9', './Transforms-81680c41', './Plane-ac6a1d3e', './EllipsoidTangentPlane-85280670'], function (exports, when, Check, _Math, Cartesian2, Transforms, Plane, EllipsoidTangentPlane) { 'use strict';
  3. /**
  4. * Creates an instance of an OrientedBoundingBox.
  5. * An OrientedBoundingBox of some object is a closed and convex cuboid. It can provide a tighter bounding volume than {@link BoundingSphere} or {@link AxisAlignedBoundingBox} in many cases.
  6. * @alias OrientedBoundingBox
  7. * @constructor
  8. *
  9. * @param {Cartesian3} [center=Cartesian3.ZERO] The center of the box.
  10. * @param {Matrix3} [halfAxes=Matrix3.ZERO] The three orthogonal half-axes of the bounding box.
  11. * Equivalently, the transformation matrix, to rotate and scale a 0x0x0
  12. * cube centered at the origin.
  13. *
  14. *
  15. * @example
  16. * // Create an OrientedBoundingBox using a transformation matrix, a position where the box will be translated, and a scale.
  17. * var center = new Cesium.Cartesian3(1.0, 0.0, 0.0);
  18. * var halfAxes = Cesium.Matrix3.fromScale(new Cesium.Cartesian3(1.0, 3.0, 2.0), new Cesium.Matrix3());
  19. *
  20. * var obb = new Cesium.OrientedBoundingBox(center, halfAxes);
  21. *
  22. * @see BoundingSphere
  23. * @see BoundingRectangle
  24. */
  25. function OrientedBoundingBox(center, halfAxes) {
  26. /**
  27. * The center of the box.
  28. * @type {Cartesian3}
  29. * @default {@link Cartesian3.ZERO}
  30. */
  31. this.center = Cartesian2.Cartesian3.clone(when.defaultValue(center, Cartesian2.Cartesian3.ZERO));
  32. /**
  33. * The transformation matrix, to rotate the box to the right position.
  34. * @type {Matrix3}
  35. * @default {@link Matrix3.ZERO}
  36. */
  37. this.halfAxes = Transforms.Matrix3.clone(when.defaultValue(halfAxes, Transforms.Matrix3.ZERO));
  38. }
  39. /**
  40. * The number of elements used to pack the object into an array.
  41. * @type {Number}
  42. */
  43. OrientedBoundingBox.packedLength =
  44. Cartesian2.Cartesian3.packedLength + Transforms.Matrix3.packedLength;
  45. /**
  46. * Stores the provided instance into the provided array.
  47. *
  48. * @param {OrientedBoundingBox} value The value to pack.
  49. * @param {Number[]} array The array to pack into.
  50. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  51. *
  52. * @returns {Number[]} The array that was packed into
  53. */
  54. OrientedBoundingBox.pack = function (value, array, startingIndex) {
  55. //>>includeStart('debug', pragmas.debug);
  56. Check.Check.typeOf.object("value", value);
  57. Check.Check.defined("array", array);
  58. //>>includeEnd('debug');
  59. startingIndex = when.defaultValue(startingIndex, 0);
  60. Cartesian2.Cartesian3.pack(value.center, array, startingIndex);
  61. Transforms.Matrix3.pack(value.halfAxes, array, startingIndex + Cartesian2.Cartesian3.packedLength);
  62. return array;
  63. };
  64. /**
  65. * Retrieves an instance from a packed array.
  66. *
  67. * @param {Number[]} array The packed array.
  68. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  69. * @param {OrientedBoundingBox} [result] The object into which to store the result.
  70. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  71. */
  72. OrientedBoundingBox.unpack = function (array, startingIndex, result) {
  73. //>>includeStart('debug', pragmas.debug);
  74. Check.Check.defined("array", array);
  75. //>>includeEnd('debug');
  76. startingIndex = when.defaultValue(startingIndex, 0);
  77. if (!when.defined(result)) {
  78. result = new OrientedBoundingBox();
  79. }
  80. Cartesian2.Cartesian3.unpack(array, startingIndex, result.center);
  81. Transforms.Matrix3.unpack(
  82. array,
  83. startingIndex + Cartesian2.Cartesian3.packedLength,
  84. result.halfAxes
  85. );
  86. return result;
  87. };
  88. var scratchCartesian1 = new Cartesian2.Cartesian3();
  89. var scratchCartesian2 = new Cartesian2.Cartesian3();
  90. var scratchCartesian3 = new Cartesian2.Cartesian3();
  91. var scratchCartesian4 = new Cartesian2.Cartesian3();
  92. var scratchCartesian5 = new Cartesian2.Cartesian3();
  93. var scratchCartesian6 = new Cartesian2.Cartesian3();
  94. var scratchCovarianceResult = new Transforms.Matrix3();
  95. var scratchEigenResult = {
  96. unitary: new Transforms.Matrix3(),
  97. diagonal: new Transforms.Matrix3(),
  98. };
  99. /**
  100. * Computes an instance of an OrientedBoundingBox of the given positions.
  101. * This is an implementation of Stefan Gottschalk's Collision Queries using Oriented Bounding Boxes solution (PHD thesis).
  102. * Reference: http://gamma.cs.unc.edu/users/gottschalk/main.pdf
  103. *
  104. * @param {Cartesian3[]} [positions] List of {@link Cartesian3} points that the bounding box will enclose.
  105. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  106. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  107. *
  108. * @example
  109. * // Compute an object oriented bounding box enclosing two points.
  110. * var box = Cesium.OrientedBoundingBox.fromPoints([new Cesium.Cartesian3(2, 0, 0), new Cesium.Cartesian3(-2, 0, 0)]);
  111. */
  112. OrientedBoundingBox.fromPoints = function (positions, result) {
  113. if (!when.defined(result)) {
  114. result = new OrientedBoundingBox();
  115. }
  116. if (!when.defined(positions) || positions.length === 0) {
  117. result.halfAxes = Transforms.Matrix3.ZERO;
  118. result.center = Cartesian2.Cartesian3.ZERO;
  119. return result;
  120. }
  121. var i;
  122. var length = positions.length;
  123. var meanPoint = Cartesian2.Cartesian3.clone(positions[0], scratchCartesian1);
  124. for (i = 1; i < length; i++) {
  125. Cartesian2.Cartesian3.add(meanPoint, positions[i], meanPoint);
  126. }
  127. var invLength = 1.0 / length;
  128. Cartesian2.Cartesian3.multiplyByScalar(meanPoint, invLength, meanPoint);
  129. var exx = 0.0;
  130. var exy = 0.0;
  131. var exz = 0.0;
  132. var eyy = 0.0;
  133. var eyz = 0.0;
  134. var ezz = 0.0;
  135. var p;
  136. for (i = 0; i < length; i++) {
  137. p = Cartesian2.Cartesian3.subtract(positions[i], meanPoint, scratchCartesian2);
  138. exx += p.x * p.x;
  139. exy += p.x * p.y;
  140. exz += p.x * p.z;
  141. eyy += p.y * p.y;
  142. eyz += p.y * p.z;
  143. ezz += p.z * p.z;
  144. }
  145. exx *= invLength;
  146. exy *= invLength;
  147. exz *= invLength;
  148. eyy *= invLength;
  149. eyz *= invLength;
  150. ezz *= invLength;
  151. var covarianceMatrix = scratchCovarianceResult;
  152. covarianceMatrix[0] = exx;
  153. covarianceMatrix[1] = exy;
  154. covarianceMatrix[2] = exz;
  155. covarianceMatrix[3] = exy;
  156. covarianceMatrix[4] = eyy;
  157. covarianceMatrix[5] = eyz;
  158. covarianceMatrix[6] = exz;
  159. covarianceMatrix[7] = eyz;
  160. covarianceMatrix[8] = ezz;
  161. var eigenDecomposition = Transforms.Matrix3.computeEigenDecomposition(
  162. covarianceMatrix,
  163. scratchEigenResult
  164. );
  165. var rotation = Transforms.Matrix3.clone(eigenDecomposition.unitary, result.halfAxes);
  166. var v1 = Transforms.Matrix3.getColumn(rotation, 0, scratchCartesian4);
  167. var v2 = Transforms.Matrix3.getColumn(rotation, 1, scratchCartesian5);
  168. var v3 = Transforms.Matrix3.getColumn(rotation, 2, scratchCartesian6);
  169. var u1 = -Number.MAX_VALUE;
  170. var u2 = -Number.MAX_VALUE;
  171. var u3 = -Number.MAX_VALUE;
  172. var l1 = Number.MAX_VALUE;
  173. var l2 = Number.MAX_VALUE;
  174. var l3 = Number.MAX_VALUE;
  175. for (i = 0; i < length; i++) {
  176. p = positions[i];
  177. u1 = Math.max(Cartesian2.Cartesian3.dot(v1, p), u1);
  178. u2 = Math.max(Cartesian2.Cartesian3.dot(v2, p), u2);
  179. u3 = Math.max(Cartesian2.Cartesian3.dot(v3, p), u3);
  180. l1 = Math.min(Cartesian2.Cartesian3.dot(v1, p), l1);
  181. l2 = Math.min(Cartesian2.Cartesian3.dot(v2, p), l2);
  182. l3 = Math.min(Cartesian2.Cartesian3.dot(v3, p), l3);
  183. }
  184. v1 = Cartesian2.Cartesian3.multiplyByScalar(v1, 0.5 * (l1 + u1), v1);
  185. v2 = Cartesian2.Cartesian3.multiplyByScalar(v2, 0.5 * (l2 + u2), v2);
  186. v3 = Cartesian2.Cartesian3.multiplyByScalar(v3, 0.5 * (l3 + u3), v3);
  187. var center = Cartesian2.Cartesian3.add(v1, v2, result.center);
  188. Cartesian2.Cartesian3.add(center, v3, center);
  189. var scale = scratchCartesian3;
  190. scale.x = u1 - l1;
  191. scale.y = u2 - l2;
  192. scale.z = u3 - l3;
  193. Cartesian2.Cartesian3.multiplyByScalar(scale, 0.5, scale);
  194. Transforms.Matrix3.multiplyByScale(result.halfAxes, scale, result.halfAxes);
  195. return result;
  196. };
  197. var scratchOffset = new Cartesian2.Cartesian3();
  198. var scratchScale = new Cartesian2.Cartesian3();
  199. function fromPlaneExtents(
  200. planeOrigin,
  201. planeXAxis,
  202. planeYAxis,
  203. planeZAxis,
  204. minimumX,
  205. maximumX,
  206. minimumY,
  207. maximumY,
  208. minimumZ,
  209. maximumZ,
  210. result
  211. ) {
  212. //>>includeStart('debug', pragmas.debug);
  213. if (
  214. !when.defined(minimumX) ||
  215. !when.defined(maximumX) ||
  216. !when.defined(minimumY) ||
  217. !when.defined(maximumY) ||
  218. !when.defined(minimumZ) ||
  219. !when.defined(maximumZ)
  220. ) {
  221. throw new Check.DeveloperError(
  222. "all extents (minimum/maximum X/Y/Z) are required."
  223. );
  224. }
  225. //>>includeEnd('debug');
  226. if (!when.defined(result)) {
  227. result = new OrientedBoundingBox();
  228. }
  229. var halfAxes = result.halfAxes;
  230. Transforms.Matrix3.setColumn(halfAxes, 0, planeXAxis, halfAxes);
  231. Transforms.Matrix3.setColumn(halfAxes, 1, planeYAxis, halfAxes);
  232. Transforms.Matrix3.setColumn(halfAxes, 2, planeZAxis, halfAxes);
  233. var centerOffset = scratchOffset;
  234. centerOffset.x = (minimumX + maximumX) / 2.0;
  235. centerOffset.y = (minimumY + maximumY) / 2.0;
  236. centerOffset.z = (minimumZ + maximumZ) / 2.0;
  237. var scale = scratchScale;
  238. scale.x = (maximumX - minimumX) / 2.0;
  239. scale.y = (maximumY - minimumY) / 2.0;
  240. scale.z = (maximumZ - minimumZ) / 2.0;
  241. var center = result.center;
  242. centerOffset = Transforms.Matrix3.multiplyByVector(halfAxes, centerOffset, centerOffset);
  243. Cartesian2.Cartesian3.add(planeOrigin, centerOffset, center);
  244. Transforms.Matrix3.multiplyByScale(halfAxes, scale, halfAxes);
  245. return result;
  246. }
  247. var scratchRectangleCenterCartographic = new Cartesian2.Cartographic();
  248. var scratchRectangleCenter = new Cartesian2.Cartesian3();
  249. var scratchPerimeterCartographicNC = new Cartesian2.Cartographic();
  250. var scratchPerimeterCartographicNW = new Cartesian2.Cartographic();
  251. var scratchPerimeterCartographicCW = new Cartesian2.Cartographic();
  252. var scratchPerimeterCartographicSW = new Cartesian2.Cartographic();
  253. var scratchPerimeterCartographicSC = new Cartesian2.Cartographic();
  254. var scratchPerimeterCartesianNC = new Cartesian2.Cartesian3();
  255. var scratchPerimeterCartesianNW = new Cartesian2.Cartesian3();
  256. var scratchPerimeterCartesianCW = new Cartesian2.Cartesian3();
  257. var scratchPerimeterCartesianSW = new Cartesian2.Cartesian3();
  258. var scratchPerimeterCartesianSC = new Cartesian2.Cartesian3();
  259. var scratchPerimeterProjectedNC = new Cartesian2.Cartesian2();
  260. var scratchPerimeterProjectedNW = new Cartesian2.Cartesian2();
  261. var scratchPerimeterProjectedCW = new Cartesian2.Cartesian2();
  262. var scratchPerimeterProjectedSW = new Cartesian2.Cartesian2();
  263. var scratchPerimeterProjectedSC = new Cartesian2.Cartesian2();
  264. var scratchPlaneOrigin = new Cartesian2.Cartesian3();
  265. var scratchPlaneNormal = new Cartesian2.Cartesian3();
  266. var scratchPlaneXAxis = new Cartesian2.Cartesian3();
  267. var scratchHorizonCartesian = new Cartesian2.Cartesian3();
  268. var scratchHorizonProjected = new Cartesian2.Cartesian2();
  269. var scratchMaxY = new Cartesian2.Cartesian3();
  270. var scratchMinY = new Cartesian2.Cartesian3();
  271. var scratchZ = new Cartesian2.Cartesian3();
  272. var scratchPlane = new Plane.Plane(Cartesian2.Cartesian3.UNIT_X, 0.0);
  273. /**
  274. * Computes an OrientedBoundingBox that bounds a {@link Rectangle} on the surface of an {@link Ellipsoid}.
  275. * There are no guarantees about the orientation of the bounding box.
  276. *
  277. * @param {Rectangle} rectangle The cartographic rectangle on the surface of the ellipsoid.
  278. * @param {Number} [minimumHeight=0.0] The minimum height (elevation) within the tile.
  279. * @param {Number} [maximumHeight=0.0] The maximum height (elevation) within the tile.
  280. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle is defined.
  281. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  282. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided.
  283. *
  284. * @exception {DeveloperError} rectangle.width must be between 0 and pi.
  285. * @exception {DeveloperError} rectangle.height must be between 0 and pi.
  286. * @exception {DeveloperError} ellipsoid must be an ellipsoid of revolution (<code>radii.x == radii.y</code>)
  287. */
  288. OrientedBoundingBox.fromRectangle = function (
  289. rectangle,
  290. minimumHeight,
  291. maximumHeight,
  292. ellipsoid,
  293. result
  294. ) {
  295. //>>includeStart('debug', pragmas.debug);
  296. if (!when.defined(rectangle)) {
  297. throw new Check.DeveloperError("rectangle is required");
  298. }
  299. if (rectangle.width < 0.0 || rectangle.width > _Math.CesiumMath.TWO_PI) {
  300. throw new Check.DeveloperError("Rectangle width must be between 0 and 2*pi");
  301. }
  302. if (rectangle.height < 0.0 || rectangle.height > _Math.CesiumMath.PI) {
  303. throw new Check.DeveloperError("Rectangle height must be between 0 and pi");
  304. }
  305. if (
  306. when.defined(ellipsoid) &&
  307. !_Math.CesiumMath.equalsEpsilon(
  308. ellipsoid.radii.x,
  309. ellipsoid.radii.y,
  310. _Math.CesiumMath.EPSILON15
  311. )
  312. ) {
  313. throw new Check.DeveloperError(
  314. "Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)"
  315. );
  316. }
  317. //>>includeEnd('debug');
  318. minimumHeight = when.defaultValue(minimumHeight, 0.0);
  319. maximumHeight = when.defaultValue(maximumHeight, 0.0);
  320. ellipsoid = when.defaultValue(ellipsoid, Cartesian2.Ellipsoid.WGS84);
  321. var minX, maxX, minY, maxY, minZ, maxZ, plane;
  322. if (rectangle.width <= _Math.CesiumMath.PI) {
  323. // The bounding box will be aligned with the tangent plane at the center of the rectangle.
  324. var tangentPointCartographic = Cartesian2.Rectangle.center(
  325. rectangle,
  326. scratchRectangleCenterCartographic
  327. );
  328. var tangentPoint = ellipsoid.cartographicToCartesian(
  329. tangentPointCartographic,
  330. scratchRectangleCenter
  331. );
  332. var tangentPlane = new EllipsoidTangentPlane.EllipsoidTangentPlane(tangentPoint, ellipsoid);
  333. plane = tangentPlane.plane;
  334. // If the rectangle spans the equator, CW is instead aligned with the equator (because it sticks out the farthest at the equator).
  335. var lonCenter = tangentPointCartographic.longitude;
  336. var latCenter =
  337. rectangle.south < 0.0 && rectangle.north > 0.0
  338. ? 0.0
  339. : tangentPointCartographic.latitude;
  340. // Compute XY extents using the rectangle at maximum height
  341. var perimeterCartographicNC = Cartesian2.Cartographic.fromRadians(
  342. lonCenter,
  343. rectangle.north,
  344. maximumHeight,
  345. scratchPerimeterCartographicNC
  346. );
  347. var perimeterCartographicNW = Cartesian2.Cartographic.fromRadians(
  348. rectangle.west,
  349. rectangle.north,
  350. maximumHeight,
  351. scratchPerimeterCartographicNW
  352. );
  353. var perimeterCartographicCW = Cartesian2.Cartographic.fromRadians(
  354. rectangle.west,
  355. latCenter,
  356. maximumHeight,
  357. scratchPerimeterCartographicCW
  358. );
  359. var perimeterCartographicSW = Cartesian2.Cartographic.fromRadians(
  360. rectangle.west,
  361. rectangle.south,
  362. maximumHeight,
  363. scratchPerimeterCartographicSW
  364. );
  365. var perimeterCartographicSC = Cartesian2.Cartographic.fromRadians(
  366. lonCenter,
  367. rectangle.south,
  368. maximumHeight,
  369. scratchPerimeterCartographicSC
  370. );
  371. var perimeterCartesianNC = ellipsoid.cartographicToCartesian(
  372. perimeterCartographicNC,
  373. scratchPerimeterCartesianNC
  374. );
  375. var perimeterCartesianNW = ellipsoid.cartographicToCartesian(
  376. perimeterCartographicNW,
  377. scratchPerimeterCartesianNW
  378. );
  379. var perimeterCartesianCW = ellipsoid.cartographicToCartesian(
  380. perimeterCartographicCW,
  381. scratchPerimeterCartesianCW
  382. );
  383. var perimeterCartesianSW = ellipsoid.cartographicToCartesian(
  384. perimeterCartographicSW,
  385. scratchPerimeterCartesianSW
  386. );
  387. var perimeterCartesianSC = ellipsoid.cartographicToCartesian(
  388. perimeterCartographicSC,
  389. scratchPerimeterCartesianSC
  390. );
  391. var perimeterProjectedNC = tangentPlane.projectPointToNearestOnPlane(
  392. perimeterCartesianNC,
  393. scratchPerimeterProjectedNC
  394. );
  395. var perimeterProjectedNW = tangentPlane.projectPointToNearestOnPlane(
  396. perimeterCartesianNW,
  397. scratchPerimeterProjectedNW
  398. );
  399. var perimeterProjectedCW = tangentPlane.projectPointToNearestOnPlane(
  400. perimeterCartesianCW,
  401. scratchPerimeterProjectedCW
  402. );
  403. var perimeterProjectedSW = tangentPlane.projectPointToNearestOnPlane(
  404. perimeterCartesianSW,
  405. scratchPerimeterProjectedSW
  406. );
  407. var perimeterProjectedSC = tangentPlane.projectPointToNearestOnPlane(
  408. perimeterCartesianSC,
  409. scratchPerimeterProjectedSC
  410. );
  411. minX = Math.min(
  412. perimeterProjectedNW.x,
  413. perimeterProjectedCW.x,
  414. perimeterProjectedSW.x
  415. );
  416. maxX = -minX; // symmetrical
  417. maxY = Math.max(perimeterProjectedNW.y, perimeterProjectedNC.y);
  418. minY = Math.min(perimeterProjectedSW.y, perimeterProjectedSC.y);
  419. // Compute minimum Z using the rectangle at minimum height, since it will be deeper than the maximum height
  420. perimeterCartographicNW.height = perimeterCartographicSW.height = minimumHeight;
  421. perimeterCartesianNW = ellipsoid.cartographicToCartesian(
  422. perimeterCartographicNW,
  423. scratchPerimeterCartesianNW
  424. );
  425. perimeterCartesianSW = ellipsoid.cartographicToCartesian(
  426. perimeterCartographicSW,
  427. scratchPerimeterCartesianSW
  428. );
  429. minZ = Math.min(
  430. Plane.Plane.getPointDistance(plane, perimeterCartesianNW),
  431. Plane.Plane.getPointDistance(plane, perimeterCartesianSW)
  432. );
  433. maxZ = maximumHeight; // Since the tangent plane touches the surface at height = 0, this is okay
  434. return fromPlaneExtents(
  435. tangentPlane.origin,
  436. tangentPlane.xAxis,
  437. tangentPlane.yAxis,
  438. tangentPlane.zAxis,
  439. minX,
  440. maxX,
  441. minY,
  442. maxY,
  443. minZ,
  444. maxZ,
  445. result
  446. );
  447. }
  448. // Handle the case where rectangle width is greater than PI (wraps around more than half the ellipsoid).
  449. var fullyAboveEquator = rectangle.south > 0.0;
  450. var fullyBelowEquator = rectangle.north < 0.0;
  451. var latitudeNearestToEquator = fullyAboveEquator
  452. ? rectangle.south
  453. : fullyBelowEquator
  454. ? rectangle.north
  455. : 0.0;
  456. var centerLongitude = Cartesian2.Rectangle.center(
  457. rectangle,
  458. scratchRectangleCenterCartographic
  459. ).longitude;
  460. // Plane is located at the rectangle's center longitude and the rectangle's latitude that is closest to the equator. It rotates around the Z axis.
  461. // This results in a better fit than the obb approach for smaller rectangles, which orients with the rectangle's center normal.
  462. var planeOrigin = Cartesian2.Cartesian3.fromRadians(
  463. centerLongitude,
  464. latitudeNearestToEquator,
  465. maximumHeight,
  466. ellipsoid,
  467. scratchPlaneOrigin
  468. );
  469. planeOrigin.z = 0.0; // center the plane on the equator to simpify plane normal calculation
  470. var isPole =
  471. Math.abs(planeOrigin.x) < _Math.CesiumMath.EPSILON10 &&
  472. Math.abs(planeOrigin.y) < _Math.CesiumMath.EPSILON10;
  473. var planeNormal = !isPole
  474. ? Cartesian2.Cartesian3.normalize(planeOrigin, scratchPlaneNormal)
  475. : Cartesian2.Cartesian3.UNIT_X;
  476. var planeYAxis = Cartesian2.Cartesian3.UNIT_Z;
  477. var planeXAxis = Cartesian2.Cartesian3.cross(planeNormal, planeYAxis, scratchPlaneXAxis);
  478. plane = Plane.Plane.fromPointNormal(planeOrigin, planeNormal, scratchPlane);
  479. // Get the horizon point relative to the center. This will be the farthest extent in the plane's X dimension.
  480. var horizonCartesian = Cartesian2.Cartesian3.fromRadians(
  481. centerLongitude + _Math.CesiumMath.PI_OVER_TWO,
  482. latitudeNearestToEquator,
  483. maximumHeight,
  484. ellipsoid,
  485. scratchHorizonCartesian
  486. );
  487. maxX = Cartesian2.Cartesian3.dot(
  488. Plane.Plane.projectPointOntoPlane(
  489. plane,
  490. horizonCartesian,
  491. scratchHorizonProjected
  492. ),
  493. planeXAxis
  494. );
  495. minX = -maxX; // symmetrical
  496. // Get the min and max Y, using the height that will give the largest extent
  497. maxY = Cartesian2.Cartesian3.fromRadians(
  498. 0.0,
  499. rectangle.north,
  500. fullyBelowEquator ? minimumHeight : maximumHeight,
  501. ellipsoid,
  502. scratchMaxY
  503. ).z;
  504. minY = Cartesian2.Cartesian3.fromRadians(
  505. 0.0,
  506. rectangle.south,
  507. fullyAboveEquator ? minimumHeight : maximumHeight,
  508. ellipsoid,
  509. scratchMinY
  510. ).z;
  511. var farZ = Cartesian2.Cartesian3.fromRadians(
  512. rectangle.east,
  513. latitudeNearestToEquator,
  514. maximumHeight,
  515. ellipsoid,
  516. scratchZ
  517. );
  518. minZ = Plane.Plane.getPointDistance(plane, farZ);
  519. maxZ = 0.0; // plane origin starts at maxZ already
  520. // min and max are local to the plane axes
  521. return fromPlaneExtents(
  522. planeOrigin,
  523. planeXAxis,
  524. planeYAxis,
  525. planeNormal,
  526. minX,
  527. maxX,
  528. minY,
  529. maxY,
  530. minZ,
  531. maxZ,
  532. result
  533. );
  534. };
  535. /**
  536. * Duplicates a OrientedBoundingBox instance.
  537. *
  538. * @param {OrientedBoundingBox} box The bounding box to duplicate.
  539. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  540. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided. (Returns undefined if box is undefined)
  541. */
  542. OrientedBoundingBox.clone = function (box, result) {
  543. if (!when.defined(box)) {
  544. return undefined;
  545. }
  546. if (!when.defined(result)) {
  547. return new OrientedBoundingBox(box.center, box.halfAxes);
  548. }
  549. Cartesian2.Cartesian3.clone(box.center, result.center);
  550. Transforms.Matrix3.clone(box.halfAxes, result.halfAxes);
  551. return result;
  552. };
  553. /**
  554. * Determines which side of a plane the oriented bounding box is located.
  555. *
  556. * @param {OrientedBoundingBox} box The oriented bounding box to test.
  557. * @param {Plane} plane The plane to test against.
  558. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  559. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  560. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  561. * intersects the plane.
  562. */
  563. OrientedBoundingBox.intersectPlane = function (box, plane) {
  564. //>>includeStart('debug', pragmas.debug);
  565. if (!when.defined(box)) {
  566. throw new Check.DeveloperError("box is required.");
  567. }
  568. if (!when.defined(plane)) {
  569. throw new Check.DeveloperError("plane is required.");
  570. }
  571. //>>includeEnd('debug');
  572. var center = box.center;
  573. var normal = plane.normal;
  574. var halfAxes = box.halfAxes;
  575. var normalX = normal.x,
  576. normalY = normal.y,
  577. normalZ = normal.z;
  578. // plane is used as if it is its normal; the first three components are assumed to be normalized
  579. var radEffective =
  580. Math.abs(
  581. normalX * halfAxes[Transforms.Matrix3.COLUMN0ROW0] +
  582. normalY * halfAxes[Transforms.Matrix3.COLUMN0ROW1] +
  583. normalZ * halfAxes[Transforms.Matrix3.COLUMN0ROW2]
  584. ) +
  585. Math.abs(
  586. normalX * halfAxes[Transforms.Matrix3.COLUMN1ROW0] +
  587. normalY * halfAxes[Transforms.Matrix3.COLUMN1ROW1] +
  588. normalZ * halfAxes[Transforms.Matrix3.COLUMN1ROW2]
  589. ) +
  590. Math.abs(
  591. normalX * halfAxes[Transforms.Matrix3.COLUMN2ROW0] +
  592. normalY * halfAxes[Transforms.Matrix3.COLUMN2ROW1] +
  593. normalZ * halfAxes[Transforms.Matrix3.COLUMN2ROW2]
  594. );
  595. var distanceToPlane = Cartesian2.Cartesian3.dot(normal, center) + plane.distance;
  596. if (distanceToPlane <= -radEffective) {
  597. // The entire box is on the negative side of the plane normal
  598. return Transforms.Intersect.OUTSIDE;
  599. } else if (distanceToPlane >= radEffective) {
  600. // The entire box is on the positive side of the plane normal
  601. return Transforms.Intersect.INSIDE;
  602. }
  603. return Transforms.Intersect.INTERSECTING;
  604. };
  605. var scratchCartesianU = new Cartesian2.Cartesian3();
  606. var scratchCartesianV = new Cartesian2.Cartesian3();
  607. var scratchCartesianW = new Cartesian2.Cartesian3();
  608. var scratchPPrime = new Cartesian2.Cartesian3();
  609. /**
  610. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  611. *
  612. * @param {OrientedBoundingBox} box The box.
  613. * @param {Cartesian3} cartesian The point
  614. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  615. *
  616. * @example
  617. * // Sort bounding boxes from back to front
  618. * boxes.sort(function(a, b) {
  619. * return Cesium.OrientedBoundingBox.distanceSquaredTo(b, camera.positionWC) - Cesium.OrientedBoundingBox.distanceSquaredTo(a, camera.positionWC);
  620. * });
  621. */
  622. OrientedBoundingBox.distanceSquaredTo = function (box, cartesian) {
  623. // See Geometric Tools for Computer Graphics 10.4.2
  624. //>>includeStart('debug', pragmas.debug);
  625. if (!when.defined(box)) {
  626. throw new Check.DeveloperError("box is required.");
  627. }
  628. if (!when.defined(cartesian)) {
  629. throw new Check.DeveloperError("cartesian is required.");
  630. }
  631. //>>includeEnd('debug');
  632. var offset = Cartesian2.Cartesian3.subtract(cartesian, box.center, scratchOffset);
  633. var halfAxes = box.halfAxes;
  634. var u = Transforms.Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  635. var v = Transforms.Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  636. var w = Transforms.Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  637. var uHalf = Cartesian2.Cartesian3.magnitude(u);
  638. var vHalf = Cartesian2.Cartesian3.magnitude(v);
  639. var wHalf = Cartesian2.Cartesian3.magnitude(w);
  640. Cartesian2.Cartesian3.normalize(u, u);
  641. Cartesian2.Cartesian3.normalize(v, v);
  642. Cartesian2.Cartesian3.normalize(w, w);
  643. var pPrime = scratchPPrime;
  644. pPrime.x = Cartesian2.Cartesian3.dot(offset, u);
  645. pPrime.y = Cartesian2.Cartesian3.dot(offset, v);
  646. pPrime.z = Cartesian2.Cartesian3.dot(offset, w);
  647. var distanceSquared = 0.0;
  648. var d;
  649. if (pPrime.x < -uHalf) {
  650. d = pPrime.x + uHalf;
  651. distanceSquared += d * d;
  652. } else if (pPrime.x > uHalf) {
  653. d = pPrime.x - uHalf;
  654. distanceSquared += d * d;
  655. }
  656. if (pPrime.y < -vHalf) {
  657. d = pPrime.y + vHalf;
  658. distanceSquared += d * d;
  659. } else if (pPrime.y > vHalf) {
  660. d = pPrime.y - vHalf;
  661. distanceSquared += d * d;
  662. }
  663. if (pPrime.z < -wHalf) {
  664. d = pPrime.z + wHalf;
  665. distanceSquared += d * d;
  666. } else if (pPrime.z > wHalf) {
  667. d = pPrime.z - wHalf;
  668. distanceSquared += d * d;
  669. }
  670. return distanceSquared;
  671. };
  672. var scratchCorner = new Cartesian2.Cartesian3();
  673. var scratchToCenter = new Cartesian2.Cartesian3();
  674. /**
  675. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  676. * <br>
  677. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  678. * closest and farthest planes from position that intersect the bounding box.
  679. *
  680. * @param {OrientedBoundingBox} box The bounding box to calculate the distance to.
  681. * @param {Cartesian3} position The position to calculate the distance from.
  682. * @param {Cartesian3} direction The direction from position.
  683. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  684. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  685. */
  686. OrientedBoundingBox.computePlaneDistances = function (
  687. box,
  688. position,
  689. direction,
  690. result
  691. ) {
  692. //>>includeStart('debug', pragmas.debug);
  693. if (!when.defined(box)) {
  694. throw new Check.DeveloperError("box is required.");
  695. }
  696. if (!when.defined(position)) {
  697. throw new Check.DeveloperError("position is required.");
  698. }
  699. if (!when.defined(direction)) {
  700. throw new Check.DeveloperError("direction is required.");
  701. }
  702. //>>includeEnd('debug');
  703. if (!when.defined(result)) {
  704. result = new Transforms.Interval();
  705. }
  706. var minDist = Number.POSITIVE_INFINITY;
  707. var maxDist = Number.NEGATIVE_INFINITY;
  708. var center = box.center;
  709. var halfAxes = box.halfAxes;
  710. var u = Transforms.Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  711. var v = Transforms.Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  712. var w = Transforms.Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  713. // project first corner
  714. var corner = Cartesian2.Cartesian3.add(u, v, scratchCorner);
  715. Cartesian2.Cartesian3.add(corner, w, corner);
  716. Cartesian2.Cartesian3.add(corner, center, corner);
  717. var toCenter = Cartesian2.Cartesian3.subtract(corner, position, scratchToCenter);
  718. var mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  719. minDist = Math.min(mag, minDist);
  720. maxDist = Math.max(mag, maxDist);
  721. // project second corner
  722. Cartesian2.Cartesian3.add(center, u, corner);
  723. Cartesian2.Cartesian3.add(corner, v, corner);
  724. Cartesian2.Cartesian3.subtract(corner, w, corner);
  725. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  726. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  727. minDist = Math.min(mag, minDist);
  728. maxDist = Math.max(mag, maxDist);
  729. // project third corner
  730. Cartesian2.Cartesian3.add(center, u, corner);
  731. Cartesian2.Cartesian3.subtract(corner, v, corner);
  732. Cartesian2.Cartesian3.add(corner, w, corner);
  733. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  734. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  735. minDist = Math.min(mag, minDist);
  736. maxDist = Math.max(mag, maxDist);
  737. // project fourth corner
  738. Cartesian2.Cartesian3.add(center, u, corner);
  739. Cartesian2.Cartesian3.subtract(corner, v, corner);
  740. Cartesian2.Cartesian3.subtract(corner, w, corner);
  741. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  742. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  743. minDist = Math.min(mag, minDist);
  744. maxDist = Math.max(mag, maxDist);
  745. // project fifth corner
  746. Cartesian2.Cartesian3.subtract(center, u, corner);
  747. Cartesian2.Cartesian3.add(corner, v, corner);
  748. Cartesian2.Cartesian3.add(corner, w, corner);
  749. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  750. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  751. minDist = Math.min(mag, minDist);
  752. maxDist = Math.max(mag, maxDist);
  753. // project sixth corner
  754. Cartesian2.Cartesian3.subtract(center, u, corner);
  755. Cartesian2.Cartesian3.add(corner, v, corner);
  756. Cartesian2.Cartesian3.subtract(corner, w, corner);
  757. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  758. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  759. minDist = Math.min(mag, minDist);
  760. maxDist = Math.max(mag, maxDist);
  761. // project seventh corner
  762. Cartesian2.Cartesian3.subtract(center, u, corner);
  763. Cartesian2.Cartesian3.subtract(corner, v, corner);
  764. Cartesian2.Cartesian3.add(corner, w, corner);
  765. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  766. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  767. minDist = Math.min(mag, minDist);
  768. maxDist = Math.max(mag, maxDist);
  769. // project eighth corner
  770. Cartesian2.Cartesian3.subtract(center, u, corner);
  771. Cartesian2.Cartesian3.subtract(corner, v, corner);
  772. Cartesian2.Cartesian3.subtract(corner, w, corner);
  773. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  774. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  775. minDist = Math.min(mag, minDist);
  776. maxDist = Math.max(mag, maxDist);
  777. result.start = minDist;
  778. result.stop = maxDist;
  779. return result;
  780. };
  781. var scratchBoundingSphere = new Transforms.BoundingSphere();
  782. /**
  783. * Determines whether or not a bounding box is hidden from view by the occluder.
  784. *
  785. * @param {OrientedBoundingBox} box The bounding box surrounding the occludee object.
  786. * @param {Occluder} occluder The occluder.
  787. * @returns {Boolean} <code>true</code> if the box is not visible; otherwise <code>false</code>.
  788. */
  789. OrientedBoundingBox.isOccluded = function (box, occluder) {
  790. //>>includeStart('debug', pragmas.debug);
  791. if (!when.defined(box)) {
  792. throw new Check.DeveloperError("box is required.");
  793. }
  794. if (!when.defined(occluder)) {
  795. throw new Check.DeveloperError("occluder is required.");
  796. }
  797. //>>includeEnd('debug');
  798. var sphere = Transforms.BoundingSphere.fromOrientedBoundingBox(
  799. box,
  800. scratchBoundingSphere
  801. );
  802. return !occluder.isBoundingSphereVisible(sphere);
  803. };
  804. /**
  805. * Determines which side of a plane the oriented bounding box is located.
  806. *
  807. * @param {Plane} plane The plane to test against.
  808. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  809. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  810. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  811. * intersects the plane.
  812. */
  813. OrientedBoundingBox.prototype.intersectPlane = function (plane) {
  814. return OrientedBoundingBox.intersectPlane(this, plane);
  815. };
  816. /**
  817. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  818. *
  819. * @param {Cartesian3} cartesian The point
  820. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  821. *
  822. * @example
  823. * // Sort bounding boxes from back to front
  824. * boxes.sort(function(a, b) {
  825. * return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC);
  826. * });
  827. */
  828. OrientedBoundingBox.prototype.distanceSquaredTo = function (cartesian) {
  829. return OrientedBoundingBox.distanceSquaredTo(this, cartesian);
  830. };
  831. /**
  832. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  833. * <br>
  834. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  835. * closest and farthest planes from position that intersect the bounding box.
  836. *
  837. * @param {Cartesian3} position The position to calculate the distance from.
  838. * @param {Cartesian3} direction The direction from position.
  839. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  840. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  841. */
  842. OrientedBoundingBox.prototype.computePlaneDistances = function (
  843. position,
  844. direction,
  845. result
  846. ) {
  847. return OrientedBoundingBox.computePlaneDistances(
  848. this,
  849. position,
  850. direction,
  851. result
  852. );
  853. };
  854. /**
  855. * Determines whether or not a bounding box is hidden from view by the occluder.
  856. *
  857. * @param {Occluder} occluder The occluder.
  858. * @returns {Boolean} <code>true</code> if the sphere is not visible; otherwise <code>false</code>.
  859. */
  860. OrientedBoundingBox.prototype.isOccluded = function (occluder) {
  861. return OrientedBoundingBox.isOccluded(this, occluder);
  862. };
  863. /**
  864. * Compares the provided OrientedBoundingBox componentwise and returns
  865. * <code>true</code> if they are equal, <code>false</code> otherwise.
  866. *
  867. * @param {OrientedBoundingBox} left The first OrientedBoundingBox.
  868. * @param {OrientedBoundingBox} right The second OrientedBoundingBox.
  869. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  870. */
  871. OrientedBoundingBox.equals = function (left, right) {
  872. return (
  873. left === right ||
  874. (when.defined(left) &&
  875. when.defined(right) &&
  876. Cartesian2.Cartesian3.equals(left.center, right.center) &&
  877. Transforms.Matrix3.equals(left.halfAxes, right.halfAxes))
  878. );
  879. };
  880. /**
  881. * Duplicates this OrientedBoundingBox instance.
  882. *
  883. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  884. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  885. */
  886. OrientedBoundingBox.prototype.clone = function (result) {
  887. return OrientedBoundingBox.clone(this, result);
  888. };
  889. /**
  890. * Compares this OrientedBoundingBox against the provided OrientedBoundingBox componentwise and returns
  891. * <code>true</code> if they are equal, <code>false</code> otherwise.
  892. *
  893. * @param {OrientedBoundingBox} [right] The right hand side OrientedBoundingBox.
  894. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  895. */
  896. OrientedBoundingBox.prototype.equals = function (right) {
  897. return OrientedBoundingBox.equals(this, right);
  898. };
  899. exports.OrientedBoundingBox = OrientedBoundingBox;
  900. });