OrientedBoundingBox-a786ab5d.js 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['exports', './defined-26bd4a03', './Check-da037458', './defaultValue-f2e68450', './Math-fa6e45cb', './Cartesian2-2a723276', './Transforms-65aba0a4', './Plane-a1a3fd52', './EllipsoidTangentPlane-10c6053a'], function (exports, defined, Check, defaultValue, _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(defaultValue.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(defaultValue.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 = Cartesian2.Cartesian3.packedLength + Transforms.Matrix3.packedLength;
  44. /**
  45. * Stores the provided instance into the provided array.
  46. *
  47. * @param {OrientedBoundingBox} value The value to pack.
  48. * @param {Number[]} array The array to pack into.
  49. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  50. *
  51. * @returns {Number[]} The array that was packed into
  52. */
  53. OrientedBoundingBox.pack = function(value, array, startingIndex) {
  54. //>>includeStart('debug', pragmas.debug);
  55. Check.Check.typeOf.object('value', value);
  56. Check.Check.defined('array', array);
  57. //>>includeEnd('debug');
  58. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  59. Cartesian2.Cartesian3.pack(value.center, array, startingIndex);
  60. Transforms.Matrix3.pack(value.halfAxes, array, startingIndex + Cartesian2.Cartesian3.packedLength);
  61. return array;
  62. };
  63. /**
  64. * Retrieves an instance from a packed array.
  65. *
  66. * @param {Number[]} array The packed array.
  67. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  68. * @param {OrientedBoundingBox} [result] The object into which to store the result.
  69. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  70. */
  71. OrientedBoundingBox.unpack = function(array, startingIndex, result) {
  72. //>>includeStart('debug', pragmas.debug);
  73. Check.Check.defined('array', array);
  74. //>>includeEnd('debug');
  75. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  76. if (!defined.defined(result)) {
  77. result = new OrientedBoundingBox();
  78. }
  79. Cartesian2.Cartesian3.unpack(array, startingIndex, result.center);
  80. Transforms.Matrix3.unpack(array, startingIndex + Cartesian2.Cartesian3.packedLength, result.halfAxes);
  81. return result;
  82. };
  83. var scratchCartesian1 = new Cartesian2.Cartesian3();
  84. var scratchCartesian2 = new Cartesian2.Cartesian3();
  85. var scratchCartesian3 = new Cartesian2.Cartesian3();
  86. var scratchCartesian4 = new Cartesian2.Cartesian3();
  87. var scratchCartesian5 = new Cartesian2.Cartesian3();
  88. var scratchCartesian6 = new Cartesian2.Cartesian3();
  89. var scratchCovarianceResult = new Transforms.Matrix3();
  90. var scratchEigenResult = {
  91. unitary : new Transforms.Matrix3(),
  92. diagonal : new Transforms.Matrix3()
  93. };
  94. /**
  95. * Computes an instance of an OrientedBoundingBox of the given positions.
  96. * This is an implementation of Stefan Gottschalk's Collision Queries using Oriented Bounding Boxes solution (PHD thesis).
  97. * Reference: http://gamma.cs.unc.edu/users/gottschalk/main.pdf
  98. *
  99. * @param {Cartesian3[]} [positions] List of {@link Cartesian3} points that the bounding box will enclose.
  100. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  101. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  102. *
  103. * @example
  104. * // Compute an object oriented bounding box enclosing two points.
  105. * var box = Cesium.OrientedBoundingBox.fromPoints([new Cesium.Cartesian3(2, 0, 0), new Cesium.Cartesian3(-2, 0, 0)]);
  106. */
  107. OrientedBoundingBox.fromPoints = function(positions, result) {
  108. if (!defined.defined(result)) {
  109. result = new OrientedBoundingBox();
  110. }
  111. if (!defined.defined(positions) || positions.length === 0) {
  112. result.halfAxes = Transforms.Matrix3.ZERO;
  113. result.center = Cartesian2.Cartesian3.ZERO;
  114. return result;
  115. }
  116. var i;
  117. var length = positions.length;
  118. var meanPoint = Cartesian2.Cartesian3.clone(positions[0], scratchCartesian1);
  119. for (i = 1; i < length; i++) {
  120. Cartesian2.Cartesian3.add(meanPoint, positions[i], meanPoint);
  121. }
  122. var invLength = 1.0 / length;
  123. Cartesian2.Cartesian3.multiplyByScalar(meanPoint, invLength, meanPoint);
  124. var exx = 0.0;
  125. var exy = 0.0;
  126. var exz = 0.0;
  127. var eyy = 0.0;
  128. var eyz = 0.0;
  129. var ezz = 0.0;
  130. var p;
  131. for (i = 0; i < length; i++) {
  132. p = Cartesian2.Cartesian3.subtract(positions[i], meanPoint, scratchCartesian2);
  133. exx += p.x * p.x;
  134. exy += p.x * p.y;
  135. exz += p.x * p.z;
  136. eyy += p.y * p.y;
  137. eyz += p.y * p.z;
  138. ezz += p.z * p.z;
  139. }
  140. exx *= invLength;
  141. exy *= invLength;
  142. exz *= invLength;
  143. eyy *= invLength;
  144. eyz *= invLength;
  145. ezz *= invLength;
  146. var covarianceMatrix = scratchCovarianceResult;
  147. covarianceMatrix[0] = exx;
  148. covarianceMatrix[1] = exy;
  149. covarianceMatrix[2] = exz;
  150. covarianceMatrix[3] = exy;
  151. covarianceMatrix[4] = eyy;
  152. covarianceMatrix[5] = eyz;
  153. covarianceMatrix[6] = exz;
  154. covarianceMatrix[7] = eyz;
  155. covarianceMatrix[8] = ezz;
  156. var eigenDecomposition = Transforms.Matrix3.computeEigenDecomposition(covarianceMatrix, scratchEigenResult);
  157. var rotation = Transforms.Matrix3.clone(eigenDecomposition.unitary, result.halfAxes);
  158. var v1 = Transforms.Matrix3.getColumn(rotation, 0, scratchCartesian4);
  159. var v2 = Transforms.Matrix3.getColumn(rotation, 1, scratchCartesian5);
  160. var v3 = Transforms.Matrix3.getColumn(rotation, 2, scratchCartesian6);
  161. var u1 = -Number.MAX_VALUE;
  162. var u2 = -Number.MAX_VALUE;
  163. var u3 = -Number.MAX_VALUE;
  164. var l1 = Number.MAX_VALUE;
  165. var l2 = Number.MAX_VALUE;
  166. var l3 = Number.MAX_VALUE;
  167. for (i = 0; i < length; i++) {
  168. p = positions[i];
  169. u1 = Math.max(Cartesian2.Cartesian3.dot(v1, p), u1);
  170. u2 = Math.max(Cartesian2.Cartesian3.dot(v2, p), u2);
  171. u3 = Math.max(Cartesian2.Cartesian3.dot(v3, p), u3);
  172. l1 = Math.min(Cartesian2.Cartesian3.dot(v1, p), l1);
  173. l2 = Math.min(Cartesian2.Cartesian3.dot(v2, p), l2);
  174. l3 = Math.min(Cartesian2.Cartesian3.dot(v3, p), l3);
  175. }
  176. v1 = Cartesian2.Cartesian3.multiplyByScalar(v1, 0.5 * (l1 + u1), v1);
  177. v2 = Cartesian2.Cartesian3.multiplyByScalar(v2, 0.5 * (l2 + u2), v2);
  178. v3 = Cartesian2.Cartesian3.multiplyByScalar(v3, 0.5 * (l3 + u3), v3);
  179. var center = Cartesian2.Cartesian3.add(v1, v2, result.center);
  180. Cartesian2.Cartesian3.add(center, v3, center);
  181. var scale = scratchCartesian3;
  182. scale.x = u1 - l1;
  183. scale.y = u2 - l2;
  184. scale.z = u3 - l3;
  185. Cartesian2.Cartesian3.multiplyByScalar(scale, 0.5, scale);
  186. Transforms.Matrix3.multiplyByScale(result.halfAxes, scale, result.halfAxes);
  187. return result;
  188. };
  189. var scratchOffset = new Cartesian2.Cartesian3();
  190. var scratchScale = new Cartesian2.Cartesian3();
  191. function fromTangentPlaneExtents(tangentPlane, minimumX, maximumX, minimumY, maximumY, minimumZ, maximumZ, result) {
  192. //>>includeStart('debug', pragmas.debug);
  193. if (!defined.defined(minimumX) ||
  194. !defined.defined(maximumX) ||
  195. !defined.defined(minimumY) ||
  196. !defined.defined(maximumY) ||
  197. !defined.defined(minimumZ) ||
  198. !defined.defined(maximumZ)) {
  199. throw new Check.DeveloperError('all extents (minimum/maximum X/Y/Z) are required.');
  200. }
  201. //>>includeEnd('debug');
  202. if (!defined.defined(result)) {
  203. result = new OrientedBoundingBox();
  204. }
  205. var halfAxes = result.halfAxes;
  206. Transforms.Matrix3.setColumn(halfAxes, 0, tangentPlane.xAxis, halfAxes);
  207. Transforms.Matrix3.setColumn(halfAxes, 1, tangentPlane.yAxis, halfAxes);
  208. Transforms.Matrix3.setColumn(halfAxes, 2, tangentPlane.zAxis, halfAxes);
  209. var centerOffset = scratchOffset;
  210. centerOffset.x = (minimumX + maximumX) / 2.0;
  211. centerOffset.y = (minimumY + maximumY) / 2.0;
  212. centerOffset.z = (minimumZ + maximumZ) / 2.0;
  213. var scale = scratchScale;
  214. scale.x = (maximumX - minimumX) / 2.0;
  215. scale.y = (maximumY - minimumY) / 2.0;
  216. scale.z = (maximumZ - minimumZ) / 2.0;
  217. var center = result.center;
  218. centerOffset = Transforms.Matrix3.multiplyByVector(halfAxes, centerOffset, centerOffset);
  219. Cartesian2.Cartesian3.add(tangentPlane.origin, centerOffset, center);
  220. Transforms.Matrix3.multiplyByScale(halfAxes, scale, halfAxes);
  221. return result;
  222. }
  223. var scratchRectangleCenterCartographic = new Cartesian2.Cartographic();
  224. var scratchRectangleCenter = new Cartesian2.Cartesian3();
  225. var perimeterCartographicScratch = [new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic(), new Cartesian2.Cartographic()];
  226. var perimeterCartesianScratch = [new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3(), new Cartesian2.Cartesian3()];
  227. var perimeterProjectedScratch = [new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2(), new Cartesian2.Cartesian2()];
  228. /**
  229. * Computes an OrientedBoundingBox that bounds a {@link Rectangle} on the surface of an {@link Ellipsoid}.
  230. * There are no guarantees about the orientation of the bounding box.
  231. *
  232. * @param {Rectangle} rectangle The cartographic rectangle on the surface of the ellipsoid.
  233. * @param {Number} [minimumHeight=0.0] The minimum height (elevation) within the tile.
  234. * @param {Number} [maximumHeight=0.0] The maximum height (elevation) within the tile.
  235. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle is defined.
  236. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  237. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided.
  238. *
  239. * @exception {DeveloperError} rectangle.width must be between 0 and pi.
  240. * @exception {DeveloperError} rectangle.height must be between 0 and pi.
  241. * @exception {DeveloperError} ellipsoid must be an ellipsoid of revolution (<code>radii.x == radii.y</code>)
  242. */
  243. OrientedBoundingBox.fromRectangle = function(rectangle, minimumHeight, maximumHeight, ellipsoid, result) {
  244. //>>includeStart('debug', pragmas.debug);
  245. if (!defined.defined(rectangle)) {
  246. throw new Check.DeveloperError('rectangle is required');
  247. }
  248. if (rectangle.width < 0.0 || rectangle.width > _Math.CesiumMath.TWO_PI) {
  249. throw new Check.DeveloperError('Rectangle width must be between 0 and 2*pi');
  250. }
  251. if (rectangle.height < 0.0 || rectangle.height > _Math.CesiumMath.PI) {
  252. throw new Check.DeveloperError('Rectangle height must be between 0 and pi');
  253. }
  254. if (defined.defined(ellipsoid) && !_Math.CesiumMath.equalsEpsilon(ellipsoid.radii.x, ellipsoid.radii.y, _Math.CesiumMath.EPSILON15)) {
  255. throw new Check.DeveloperError('Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)');
  256. }
  257. //>>includeEnd('debug');
  258. minimumHeight = defaultValue.defaultValue(minimumHeight, 0.0);
  259. maximumHeight = defaultValue.defaultValue(maximumHeight, 0.0);
  260. ellipsoid = defaultValue.defaultValue(ellipsoid, Cartesian2.Ellipsoid.WGS84);
  261. // The bounding box will be aligned with the tangent plane at the center of the rectangle.
  262. var tangentPointCartographic = Cartesian2.Rectangle.center(rectangle, scratchRectangleCenterCartographic);
  263. var tangentPoint = ellipsoid.cartographicToCartesian(tangentPointCartographic, scratchRectangleCenter);
  264. var tangentPlane = new EllipsoidTangentPlane.EllipsoidTangentPlane(tangentPoint, ellipsoid);
  265. var plane = tangentPlane.plane;
  266. // Corner arrangement:
  267. // N/+y
  268. // [0] [1] [2]
  269. // W/-x [7] [3] E/+x
  270. // [6] [5] [4]
  271. // S/-y
  272. // "C" refers to the central lat/long, which by default aligns with the tangent point (above).
  273. // If the rectangle spans the equator, CW and CE are instead aligned with the equator.
  274. var perimeterNW = perimeterCartographicScratch[0];
  275. var perimeterNC = perimeterCartographicScratch[1];
  276. var perimeterNE = perimeterCartographicScratch[2];
  277. var perimeterCE = perimeterCartographicScratch[3];
  278. var perimeterSE = perimeterCartographicScratch[4];
  279. var perimeterSC = perimeterCartographicScratch[5];
  280. var perimeterSW = perimeterCartographicScratch[6];
  281. var perimeterCW = perimeterCartographicScratch[7];
  282. var lonCenter = tangentPointCartographic.longitude;
  283. var latCenter = (rectangle.south < 0.0 && rectangle.north > 0.0) ? 0.0 : tangentPointCartographic.latitude;
  284. perimeterSW.latitude = perimeterSC.latitude = perimeterSE.latitude = rectangle.south;
  285. perimeterCW.latitude = perimeterCE.latitude = latCenter;
  286. perimeterNW.latitude = perimeterNC.latitude = perimeterNE.latitude = rectangle.north;
  287. perimeterSW.longitude = perimeterCW.longitude = perimeterNW.longitude = rectangle.west;
  288. perimeterSC.longitude = perimeterNC.longitude = lonCenter;
  289. perimeterSE.longitude = perimeterCE.longitude = perimeterNE.longitude = rectangle.east;
  290. // Compute XY extents using the rectangle at maximum height
  291. perimeterNE.height = perimeterNC.height = perimeterNW.height = perimeterCW.height = perimeterSW.height = perimeterSC.height = perimeterSE.height = perimeterCE.height = maximumHeight;
  292. ellipsoid.cartographicArrayToCartesianArray(perimeterCartographicScratch, perimeterCartesianScratch);
  293. tangentPlane.projectPointsToNearestOnPlane(perimeterCartesianScratch, perimeterProjectedScratch);
  294. // See the `perimeterXX` definitions above for what these are
  295. var minX = Math.min(perimeterProjectedScratch[6].x, perimeterProjectedScratch[7].x, perimeterProjectedScratch[0].x);
  296. var maxX = Math.max(perimeterProjectedScratch[2].x, perimeterProjectedScratch[3].x, perimeterProjectedScratch[4].x);
  297. var minY = Math.min(perimeterProjectedScratch[4].y, perimeterProjectedScratch[5].y, perimeterProjectedScratch[6].y);
  298. var maxY = Math.max(perimeterProjectedScratch[0].y, perimeterProjectedScratch[1].y, perimeterProjectedScratch[2].y);
  299. // Compute minimum Z using the rectangle at minimum height
  300. perimeterNE.height = perimeterNW.height = perimeterSE.height = perimeterSW.height = minimumHeight;
  301. ellipsoid.cartographicArrayToCartesianArray(perimeterCartographicScratch, perimeterCartesianScratch);
  302. var minZ = Math.min(Plane.Plane.getPointDistance(plane, perimeterCartesianScratch[0]),
  303. Plane.Plane.getPointDistance(plane, perimeterCartesianScratch[2]),
  304. Plane.Plane.getPointDistance(plane, perimeterCartesianScratch[4]),
  305. Plane.Plane.getPointDistance(plane, perimeterCartesianScratch[6]));
  306. var maxZ = maximumHeight; // Since the tangent plane touches the surface at height = 0, this is okay
  307. return fromTangentPlaneExtents(tangentPlane, minX, maxX, minY, maxY, minZ, maxZ, result);
  308. };
  309. /**
  310. * Duplicates a OrientedBoundingBox instance.
  311. *
  312. * @param {OrientedBoundingBox} box The bounding box to duplicate.
  313. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  314. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided. (Returns undefined if box is undefined)
  315. */
  316. OrientedBoundingBox.clone = function(box, result) {
  317. if (!defined.defined(box)) {
  318. return undefined;
  319. }
  320. if (!defined.defined(result)) {
  321. return new OrientedBoundingBox(box.center, box.halfAxes);
  322. }
  323. Cartesian2.Cartesian3.clone(box.center, result.center);
  324. Transforms.Matrix3.clone(box.halfAxes, result.halfAxes);
  325. return result;
  326. };
  327. /**
  328. * Determines which side of a plane the oriented bounding box is located.
  329. *
  330. * @param {OrientedBoundingBox} box The oriented bounding box to test.
  331. * @param {Plane} plane The plane to test against.
  332. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  333. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  334. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  335. * intersects the plane.
  336. */
  337. OrientedBoundingBox.intersectPlane = function(box, plane) {
  338. //>>includeStart('debug', pragmas.debug);
  339. if (!defined.defined(box)) {
  340. throw new Check.DeveloperError('box is required.');
  341. }
  342. if (!defined.defined(plane)) {
  343. throw new Check.DeveloperError('plane is required.');
  344. }
  345. //>>includeEnd('debug');
  346. var center = box.center;
  347. var normal = plane.normal;
  348. var halfAxes = box.halfAxes;
  349. var normalX = normal.x, normalY = normal.y, normalZ = normal.z;
  350. // plane is used as if it is its normal; the first three components are assumed to be normalized
  351. var radEffective = Math.abs(normalX * halfAxes[Transforms.Matrix3.COLUMN0ROW0] + normalY * halfAxes[Transforms.Matrix3.COLUMN0ROW1] + normalZ * halfAxes[Transforms.Matrix3.COLUMN0ROW2]) +
  352. Math.abs(normalX * halfAxes[Transforms.Matrix3.COLUMN1ROW0] + normalY * halfAxes[Transforms.Matrix3.COLUMN1ROW1] + normalZ * halfAxes[Transforms.Matrix3.COLUMN1ROW2]) +
  353. Math.abs(normalX * halfAxes[Transforms.Matrix3.COLUMN2ROW0] + normalY * halfAxes[Transforms.Matrix3.COLUMN2ROW1] + normalZ * halfAxes[Transforms.Matrix3.COLUMN2ROW2]);
  354. var distanceToPlane = Cartesian2.Cartesian3.dot(normal, center) + plane.distance;
  355. if (distanceToPlane <= -radEffective) {
  356. // The entire box is on the negative side of the plane normal
  357. return Transforms.Intersect.OUTSIDE;
  358. } else if (distanceToPlane >= radEffective) {
  359. // The entire box is on the positive side of the plane normal
  360. return Transforms.Intersect.INSIDE;
  361. }
  362. return Transforms.Intersect.INTERSECTING;
  363. };
  364. var scratchCartesianU = new Cartesian2.Cartesian3();
  365. var scratchCartesianV = new Cartesian2.Cartesian3();
  366. var scratchCartesianW = new Cartesian2.Cartesian3();
  367. var scratchPPrime = new Cartesian2.Cartesian3();
  368. /**
  369. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  370. *
  371. * @param {OrientedBoundingBox} box The box.
  372. * @param {Cartesian3} cartesian The point
  373. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  374. *
  375. * @example
  376. * // Sort bounding boxes from back to front
  377. * boxes.sort(function(a, b) {
  378. * return Cesium.OrientedBoundingBox.distanceSquaredTo(b, camera.positionWC) - Cesium.OrientedBoundingBox.distanceSquaredTo(a, camera.positionWC);
  379. * });
  380. */
  381. OrientedBoundingBox.distanceSquaredTo = function(box, cartesian) {
  382. // See Geometric Tools for Computer Graphics 10.4.2
  383. //>>includeStart('debug', pragmas.debug);
  384. if (!defined.defined(box)) {
  385. throw new Check.DeveloperError('box is required.');
  386. }
  387. if (!defined.defined(cartesian)) {
  388. throw new Check.DeveloperError('cartesian is required.');
  389. }
  390. //>>includeEnd('debug');
  391. var offset = Cartesian2.Cartesian3.subtract(cartesian, box.center, scratchOffset);
  392. var halfAxes = box.halfAxes;
  393. var u = Transforms.Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  394. var v = Transforms.Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  395. var w = Transforms.Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  396. var uHalf = Cartesian2.Cartesian3.magnitude(u);
  397. var vHalf = Cartesian2.Cartesian3.magnitude(v);
  398. var wHalf = Cartesian2.Cartesian3.magnitude(w);
  399. Cartesian2.Cartesian3.normalize(u, u);
  400. Cartesian2.Cartesian3.normalize(v, v);
  401. Cartesian2.Cartesian3.normalize(w, w);
  402. var pPrime = scratchPPrime;
  403. pPrime.x = Cartesian2.Cartesian3.dot(offset, u);
  404. pPrime.y = Cartesian2.Cartesian3.dot(offset, v);
  405. pPrime.z = Cartesian2.Cartesian3.dot(offset, w);
  406. var distanceSquared = 0.0;
  407. var d;
  408. if (pPrime.x < -uHalf) {
  409. d = pPrime.x + uHalf;
  410. distanceSquared += d * d;
  411. } else if (pPrime.x > uHalf) {
  412. d = pPrime.x - uHalf;
  413. distanceSquared += d * d;
  414. }
  415. if (pPrime.y < -vHalf) {
  416. d = pPrime.y + vHalf;
  417. distanceSquared += d * d;
  418. } else if (pPrime.y > vHalf) {
  419. d = pPrime.y - vHalf;
  420. distanceSquared += d * d;
  421. }
  422. if (pPrime.z < -wHalf) {
  423. d = pPrime.z + wHalf;
  424. distanceSquared += d * d;
  425. } else if (pPrime.z > wHalf) {
  426. d = pPrime.z - wHalf;
  427. distanceSquared += d * d;
  428. }
  429. return distanceSquared;
  430. };
  431. var scratchCorner = new Cartesian2.Cartesian3();
  432. var scratchToCenter = new Cartesian2.Cartesian3();
  433. /**
  434. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  435. * <br>
  436. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  437. * closest and farthest planes from position that intersect the bounding box.
  438. *
  439. * @param {OrientedBoundingBox} box The bounding box to calculate the distance to.
  440. * @param {Cartesian3} position The position to calculate the distance from.
  441. * @param {Cartesian3} direction The direction from position.
  442. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  443. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  444. */
  445. OrientedBoundingBox.computePlaneDistances = function(box, position, direction, result) {
  446. //>>includeStart('debug', pragmas.debug);
  447. if (!defined.defined(box)) {
  448. throw new Check.DeveloperError('box is required.');
  449. }
  450. if (!defined.defined(position)) {
  451. throw new Check.DeveloperError('position is required.');
  452. }
  453. if (!defined.defined(direction)) {
  454. throw new Check.DeveloperError('direction is required.');
  455. }
  456. //>>includeEnd('debug');
  457. if (!defined.defined(result)) {
  458. result = new Transforms.Interval();
  459. }
  460. var minDist = Number.POSITIVE_INFINITY;
  461. var maxDist = Number.NEGATIVE_INFINITY;
  462. var center = box.center;
  463. var halfAxes = box.halfAxes;
  464. var u = Transforms.Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  465. var v = Transforms.Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  466. var w = Transforms.Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  467. // project first corner
  468. var corner = Cartesian2.Cartesian3.add(u, v, scratchCorner);
  469. Cartesian2.Cartesian3.add(corner, w, corner);
  470. Cartesian2.Cartesian3.add(corner, center, corner);
  471. var toCenter = Cartesian2.Cartesian3.subtract(corner, position, scratchToCenter);
  472. var mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  473. minDist = Math.min(mag, minDist);
  474. maxDist = Math.max(mag, maxDist);
  475. // project second corner
  476. Cartesian2.Cartesian3.add(center, u, corner);
  477. Cartesian2.Cartesian3.add(corner, v, corner);
  478. Cartesian2.Cartesian3.subtract(corner, w, corner);
  479. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  480. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  481. minDist = Math.min(mag, minDist);
  482. maxDist = Math.max(mag, maxDist);
  483. // project third corner
  484. Cartesian2.Cartesian3.add(center, u, corner);
  485. Cartesian2.Cartesian3.subtract(corner, v, corner);
  486. Cartesian2.Cartesian3.add(corner, w, corner);
  487. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  488. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  489. minDist = Math.min(mag, minDist);
  490. maxDist = Math.max(mag, maxDist);
  491. // project fourth corner
  492. Cartesian2.Cartesian3.add(center, u, corner);
  493. Cartesian2.Cartesian3.subtract(corner, v, corner);
  494. Cartesian2.Cartesian3.subtract(corner, w, corner);
  495. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  496. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  497. minDist = Math.min(mag, minDist);
  498. maxDist = Math.max(mag, maxDist);
  499. // project fifth corner
  500. Cartesian2.Cartesian3.subtract(center, u, corner);
  501. Cartesian2.Cartesian3.add(corner, v, corner);
  502. Cartesian2.Cartesian3.add(corner, w, corner);
  503. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  504. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  505. minDist = Math.min(mag, minDist);
  506. maxDist = Math.max(mag, maxDist);
  507. // project sixth corner
  508. Cartesian2.Cartesian3.subtract(center, u, corner);
  509. Cartesian2.Cartesian3.add(corner, v, corner);
  510. Cartesian2.Cartesian3.subtract(corner, w, corner);
  511. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  512. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  513. minDist = Math.min(mag, minDist);
  514. maxDist = Math.max(mag, maxDist);
  515. // project seventh corner
  516. Cartesian2.Cartesian3.subtract(center, u, corner);
  517. Cartesian2.Cartesian3.subtract(corner, v, corner);
  518. Cartesian2.Cartesian3.add(corner, w, corner);
  519. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  520. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  521. minDist = Math.min(mag, minDist);
  522. maxDist = Math.max(mag, maxDist);
  523. // project eighth corner
  524. Cartesian2.Cartesian3.subtract(center, u, corner);
  525. Cartesian2.Cartesian3.subtract(corner, v, corner);
  526. Cartesian2.Cartesian3.subtract(corner, w, corner);
  527. Cartesian2.Cartesian3.subtract(corner, position, toCenter);
  528. mag = Cartesian2.Cartesian3.dot(direction, toCenter);
  529. minDist = Math.min(mag, minDist);
  530. maxDist = Math.max(mag, maxDist);
  531. result.start = minDist;
  532. result.stop = maxDist;
  533. return result;
  534. };
  535. var scratchBoundingSphere = new Transforms.BoundingSphere();
  536. /**
  537. * Determines whether or not a bounding box is hidden from view by the occluder.
  538. *
  539. * @param {OrientedBoundingBox} box The bounding box surrounding the occludee object.
  540. * @param {Occluder} occluder The occluder.
  541. * @returns {Boolean} <code>true</code> if the box is not visible; otherwise <code>false</code>.
  542. */
  543. OrientedBoundingBox.isOccluded = function(box, occluder) {
  544. //>>includeStart('debug', pragmas.debug);
  545. if (!defined.defined(box)) {
  546. throw new Check.DeveloperError('box is required.');
  547. }
  548. if (!defined.defined(occluder)) {
  549. throw new Check.DeveloperError('occluder is required.');
  550. }
  551. //>>includeEnd('debug');
  552. var sphere = Transforms.BoundingSphere.fromOrientedBoundingBox(box, scratchBoundingSphere);
  553. return !occluder.isBoundingSphereVisible(sphere);
  554. };
  555. /**
  556. * Determines which side of a plane the oriented bounding box is located.
  557. *
  558. * @param {Plane} plane The plane to test against.
  559. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  560. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  561. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  562. * intersects the plane.
  563. */
  564. OrientedBoundingBox.prototype.intersectPlane = function(plane) {
  565. return OrientedBoundingBox.intersectPlane(this, plane);
  566. };
  567. /**
  568. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  569. *
  570. * @param {Cartesian3} cartesian The point
  571. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  572. *
  573. * @example
  574. * // Sort bounding boxes from back to front
  575. * boxes.sort(function(a, b) {
  576. * return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC);
  577. * });
  578. */
  579. OrientedBoundingBox.prototype.distanceSquaredTo = function(cartesian) {
  580. return OrientedBoundingBox.distanceSquaredTo(this, cartesian);
  581. };
  582. /**
  583. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  584. * <br>
  585. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  586. * closest and farthest planes from position that intersect the bounding box.
  587. *
  588. * @param {Cartesian3} position The position to calculate the distance from.
  589. * @param {Cartesian3} direction The direction from position.
  590. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  591. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  592. */
  593. OrientedBoundingBox.prototype.computePlaneDistances = function(position, direction, result) {
  594. return OrientedBoundingBox.computePlaneDistances(this, position, direction, result);
  595. };
  596. /**
  597. * Determines whether or not a bounding box is hidden from view by the occluder.
  598. *
  599. * @param {Occluder} occluder The occluder.
  600. * @returns {Boolean} <code>true</code> if the sphere is not visible; otherwise <code>false</code>.
  601. */
  602. OrientedBoundingBox.prototype.isOccluded = function(occluder) {
  603. return OrientedBoundingBox.isOccluded(this, occluder);
  604. };
  605. /**
  606. * Compares the provided OrientedBoundingBox componentwise and returns
  607. * <code>true</code> if they are equal, <code>false</code> otherwise.
  608. *
  609. * @param {OrientedBoundingBox} left The first OrientedBoundingBox.
  610. * @param {OrientedBoundingBox} right The second OrientedBoundingBox.
  611. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  612. */
  613. OrientedBoundingBox.equals = function(left, right) {
  614. return (left === right) ||
  615. ((defined.defined(left)) &&
  616. (defined.defined(right)) &&
  617. Cartesian2.Cartesian3.equals(left.center, right.center) &&
  618. Transforms.Matrix3.equals(left.halfAxes, right.halfAxes));
  619. };
  620. /**
  621. * Duplicates this OrientedBoundingBox instance.
  622. *
  623. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  624. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  625. */
  626. OrientedBoundingBox.prototype.clone = function(result) {
  627. return OrientedBoundingBox.clone(this, result);
  628. };
  629. /**
  630. * Compares this OrientedBoundingBox against the provided OrientedBoundingBox componentwise and returns
  631. * <code>true</code> if they are equal, <code>false</code> otherwise.
  632. *
  633. * @param {OrientedBoundingBox} [right] The right hand side OrientedBoundingBox.
  634. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  635. */
  636. OrientedBoundingBox.prototype.equals = function(right) {
  637. return OrientedBoundingBox.equals(this, right);
  638. };
  639. exports.OrientedBoundingBox = OrientedBoundingBox;
  640. });