FrustumGeometry-fcb367ee.js 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232
  1. /**
  2. * Cesium - https://github.com/CesiumGS/cesium
  3. *
  4. * Copyright 2011-2020 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/CesiumGS/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['exports', './when-8d13db60', './Check-70bec281', './Math-61ede240', './Cartographic-fe4be337', './Cartesian4-5af5bb24', './BoundingSphere-8f8a682c', './ComponentDatatype-5862616f', './GeometryAttribute-ed9d707f', './PrimitiveType-97893bc7', './Transforms-878b6816', './GeometryAttributes-aacecde6', './VertexFormat-fe4db402', './Plane-b1361c67'], function (exports, when, Check, _Math, Cartographic, Cartesian4, BoundingSphere, ComponentDatatype, GeometryAttribute, PrimitiveType, Transforms, GeometryAttributes, VertexFormat, Plane) { 'use strict';
  24. /**
  25. * The culling volume defined by planes.
  26. *
  27. * @alias CullingVolume
  28. * @constructor
  29. *
  30. * @param {Cartesian4[]} [planes] An array of clipping planes.
  31. */
  32. function CullingVolume(planes) {
  33. /**
  34. * Each plane is represented by a Cartesian4 object, where the x, y, and z components
  35. * define the unit vector normal to the plane, and the w component is the distance of the
  36. * plane from the origin.
  37. * @type {Cartesian4[]}
  38. * @default []
  39. */
  40. this.planes = when.defaultValue(planes, []);
  41. }
  42. var faces = [new Cartographic.Cartesian3(), new Cartographic.Cartesian3(), new Cartographic.Cartesian3()];
  43. Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_X, faces[0]);
  44. Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Y, faces[1]);
  45. Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Z, faces[2]);
  46. var scratchPlaneCenter = new Cartographic.Cartesian3();
  47. var scratchPlaneNormal = new Cartographic.Cartesian3();
  48. var scratchPlane = new Plane.Plane(new Cartographic.Cartesian3(1.0, 0.0, 0.0), 0.0);
  49. /**
  50. * Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.
  51. * The planes are aligned to the x, y, and z axes in world coordinates.
  52. *
  53. * @param {BoundingSphere} boundingSphere The bounding sphere used to create the culling volume.
  54. * @param {CullingVolume} [result] The object onto which to store the result.
  55. * @returns {CullingVolume} The culling volume created from the bounding sphere.
  56. */
  57. CullingVolume.fromBoundingSphere = function(boundingSphere, result) {
  58. //>>includeStart('debug', pragmas.debug);
  59. if (!when.defined(boundingSphere)) {
  60. throw new Check.DeveloperError('boundingSphere is required.');
  61. }
  62. //>>includeEnd('debug');
  63. if (!when.defined(result)) {
  64. result = new CullingVolume();
  65. }
  66. var length = faces.length;
  67. var planes = result.planes;
  68. planes.length = 2 * length;
  69. var center = boundingSphere.center;
  70. var radius = boundingSphere.radius;
  71. var planeIndex = 0;
  72. for (var i = 0; i < length; ++i) {
  73. var faceNormal = faces[i];
  74. var plane0 = planes[planeIndex];
  75. var plane1 = planes[planeIndex + 1];
  76. if (!when.defined(plane0)) {
  77. plane0 = planes[planeIndex] = new Cartesian4.Cartesian4();
  78. }
  79. if (!when.defined(plane1)) {
  80. plane1 = planes[planeIndex + 1] = new Cartesian4.Cartesian4();
  81. }
  82. Cartographic.Cartesian3.multiplyByScalar(faceNormal, -radius, scratchPlaneCenter);
  83. Cartographic.Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
  84. plane0.x = faceNormal.x;
  85. plane0.y = faceNormal.y;
  86. plane0.z = faceNormal.z;
  87. plane0.w = -Cartographic.Cartesian3.dot(faceNormal, scratchPlaneCenter);
  88. Cartographic.Cartesian3.multiplyByScalar(faceNormal, radius, scratchPlaneCenter);
  89. Cartographic.Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
  90. plane1.x = -faceNormal.x;
  91. plane1.y = -faceNormal.y;
  92. plane1.z = -faceNormal.z;
  93. plane1.w = -Cartographic.Cartesian3.dot(Cartographic.Cartesian3.negate(faceNormal, scratchPlaneNormal), scratchPlaneCenter);
  94. planeIndex += 2;
  95. }
  96. return result;
  97. };
  98. /**
  99. * Determines whether a bounding volume intersects the culling volume.
  100. *
  101. * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
  102. * @returns {Intersect} Intersect.OUTSIDE, Intersect.INTERSECTING, or Intersect.INSIDE.
  103. */
  104. CullingVolume.prototype.computeVisibility = function(boundingVolume) {
  105. //>>includeStart('debug', pragmas.debug);
  106. if (!when.defined(boundingVolume)) {
  107. throw new Check.DeveloperError('boundingVolume is required.');
  108. }
  109. //>>includeEnd('debug');
  110. var planes = this.planes;
  111. var intersecting = false;
  112. for (var k = 0, len = planes.length; k < len; ++k) {
  113. var result = boundingVolume.intersectPlane(Plane.Plane.fromCartesian4(planes[k], scratchPlane));
  114. if (result === BoundingSphere.Intersect.OUTSIDE) {
  115. return BoundingSphere.Intersect.OUTSIDE;
  116. } else if (result === BoundingSphere.Intersect.INTERSECTING) {
  117. intersecting = true;
  118. }
  119. }
  120. return intersecting ? BoundingSphere.Intersect.INTERSECTING : BoundingSphere.Intersect.INSIDE;
  121. };
  122. /**
  123. * Determines whether a bounding volume intersects the culling volume.
  124. *
  125. * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
  126. * @param {Number} parentPlaneMask A bit mask from the boundingVolume's parent's check against the same culling
  127. * volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then
  128. * the parent (and therefore this) volume is completely inside plane[planeIndex]
  129. * and that plane check can be skipped.
  130. * @returns {Number} A plane mask as described above (which can be applied to this boundingVolume's children).
  131. *
  132. * @private
  133. */
  134. CullingVolume.prototype.computeVisibilityWithPlaneMask = function(boundingVolume, parentPlaneMask) {
  135. //>>includeStart('debug', pragmas.debug);
  136. if (!when.defined(boundingVolume)) {
  137. throw new Check.DeveloperError('boundingVolume is required.');
  138. }
  139. if (!when.defined(parentPlaneMask)) {
  140. throw new Check.DeveloperError('parentPlaneMask is required.');
  141. }
  142. //>>includeEnd('debug');
  143. if (parentPlaneMask === CullingVolume.MASK_OUTSIDE || parentPlaneMask === CullingVolume.MASK_INSIDE) {
  144. // parent is completely outside or completely inside, so this child is as well.
  145. return parentPlaneMask;
  146. }
  147. // Start with MASK_INSIDE (all zeros) so that after the loop, the return value can be compared with MASK_INSIDE.
  148. // (Because if there are fewer than 31 planes, the upper bits wont be changed.)
  149. var mask = CullingVolume.MASK_INSIDE;
  150. var planes = this.planes;
  151. for (var k = 0, len = planes.length; k < len; ++k) {
  152. // For k greater than 31 (since 31 is the maximum number of INSIDE/INTERSECTING bits we can store), skip the optimization.
  153. var flag = (k < 31) ? (1 << k) : 0;
  154. if (k < 31 && (parentPlaneMask & flag) === 0) {
  155. // boundingVolume is known to be INSIDE this plane.
  156. continue;
  157. }
  158. var result = boundingVolume.intersectPlane(Plane.Plane.fromCartesian4(planes[k], scratchPlane));
  159. if (result === BoundingSphere.Intersect.OUTSIDE) {
  160. return CullingVolume.MASK_OUTSIDE;
  161. } else if (result === BoundingSphere.Intersect.INTERSECTING) {
  162. mask |= flag;
  163. }
  164. }
  165. return mask;
  166. };
  167. /**
  168. * For plane masks (as used in {@link CullingVolume#computeVisibilityWithPlaneMask}), this special value
  169. * represents the case where the object bounding volume is entirely outside the culling volume.
  170. *
  171. * @type {Number}
  172. * @private
  173. */
  174. CullingVolume.MASK_OUTSIDE = 0xffffffff;
  175. /**
  176. * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
  177. * represents the case where the object bounding volume is entirely inside the culling volume.
  178. *
  179. * @type {Number}
  180. * @private
  181. */
  182. CullingVolume.MASK_INSIDE = 0x00000000;
  183. /**
  184. * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
  185. * represents the case where the object bounding volume (may) intersect all planes of the culling volume.
  186. *
  187. * @type {Number}
  188. * @private
  189. */
  190. CullingVolume.MASK_INDETERMINATE = 0x7fffffff;
  191. /**
  192. * The viewing frustum is defined by 6 planes.
  193. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  194. * define the unit vector normal to the plane, and the w component is the distance of the
  195. * plane from the origin/camera position.
  196. *
  197. * @alias OrthographicOffCenterFrustum
  198. * @constructor
  199. *
  200. * @param {Object} [options] An object with the following properties:
  201. * @param {Number} [options.left] The left clipping plane distance.
  202. * @param {Number} [options.right] The right clipping plane distance.
  203. * @param {Number} [options.top] The top clipping plane distance.
  204. * @param {Number} [options.bottom] The bottom clipping plane distance.
  205. * @param {Number} [options.near=1.0] The near clipping plane distance.
  206. * @param {Number} [options.far=500000000.0] The far clipping plane distance.
  207. *
  208. * @example
  209. * var maxRadii = ellipsoid.maximumRadius;
  210. *
  211. * var frustum = new Cesium.OrthographicOffCenterFrustum();
  212. * frustum.right = maxRadii * Cesium.Math.PI;
  213. * frustum.left = -c.frustum.right;
  214. * frustum.top = c.frustum.right * (canvas.clientHeight / canvas.clientWidth);
  215. * frustum.bottom = -c.frustum.top;
  216. * frustum.near = 0.01 * maxRadii;
  217. * frustum.far = 50.0 * maxRadii;
  218. */
  219. function OrthographicOffCenterFrustum(options) {
  220. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  221. /**
  222. * The left clipping plane.
  223. * @type {Number}
  224. * @default undefined
  225. */
  226. this.left = options.left;
  227. this._left = undefined;
  228. /**
  229. * The right clipping plane.
  230. * @type {Number}
  231. * @default undefined
  232. */
  233. this.right = options.right;
  234. this._right = undefined;
  235. /**
  236. * The top clipping plane.
  237. * @type {Number}
  238. * @default undefined
  239. */
  240. this.top = options.top;
  241. this._top = undefined;
  242. /**
  243. * The bottom clipping plane.
  244. * @type {Number}
  245. * @default undefined
  246. */
  247. this.bottom = options.bottom;
  248. this._bottom = undefined;
  249. /**
  250. * The distance of the near plane.
  251. * @type {Number}
  252. * @default 1.0
  253. */
  254. this.near = when.defaultValue(options.near, 1.0);
  255. this._near = this.near;
  256. /**
  257. * The distance of the far plane.
  258. * @type {Number}
  259. * @default 500000000.0;
  260. */
  261. this.far = when.defaultValue(options.far, 500000000.0);
  262. this._far = this.far;
  263. this._cullingVolume = new CullingVolume();
  264. this._orthographicMatrix = new BoundingSphere.Matrix4();
  265. }
  266. function update(frustum) {
  267. //>>includeStart('debug', pragmas.debug);
  268. if (!when.defined(frustum.right) || !when.defined(frustum.left) ||
  269. !when.defined(frustum.top) || !when.defined(frustum.bottom) ||
  270. !when.defined(frustum.near) || !when.defined(frustum.far)) {
  271. throw new Check.DeveloperError('right, left, top, bottom, near, or far parameters are not set.');
  272. }
  273. //>>includeEnd('debug');
  274. if (frustum.top !== frustum._top || frustum.bottom !== frustum._bottom ||
  275. frustum.left !== frustum._left || frustum.right !== frustum._right ||
  276. frustum.near !== frustum._near || frustum.far !== frustum._far) {
  277. //>>includeStart('debug', pragmas.debug);
  278. if (frustum.left > frustum.right) {
  279. throw new Check.DeveloperError('right must be greater than left.');
  280. }
  281. if (frustum.bottom > frustum.top) {
  282. throw new Check.DeveloperError('top must be greater than bottom.');
  283. }
  284. if (frustum.near <= 0 || frustum.near > frustum.far) {
  285. throw new Check.DeveloperError('near must be greater than zero and less than far.');
  286. }
  287. //>>includeEnd('debug');
  288. frustum._left = frustum.left;
  289. frustum._right = frustum.right;
  290. frustum._top = frustum.top;
  291. frustum._bottom = frustum.bottom;
  292. frustum._near = frustum.near;
  293. frustum._far = frustum.far;
  294. frustum._orthographicMatrix = BoundingSphere.Matrix4.computeOrthographicOffCenter(frustum.left, frustum.right, frustum.bottom, frustum.top, frustum.near, frustum.far, frustum._orthographicMatrix);
  295. }
  296. }
  297. Object.defineProperties(OrthographicOffCenterFrustum.prototype, {
  298. /**
  299. * Gets the orthographic projection matrix computed from the view frustum.
  300. * @memberof OrthographicOffCenterFrustum.prototype
  301. * @type {Matrix4}
  302. * @readonly
  303. */
  304. projectionMatrix : {
  305. get : function() {
  306. update(this);
  307. return this._orthographicMatrix;
  308. }
  309. }
  310. });
  311. var getPlanesRight = new Cartographic.Cartesian3();
  312. var getPlanesNearCenter = new Cartographic.Cartesian3();
  313. var getPlanesPoint = new Cartographic.Cartesian3();
  314. var negateScratch = new Cartographic.Cartesian3();
  315. /**
  316. * Creates a culling volume for this frustum.
  317. *
  318. * @param {Cartesian3} position The eye position.
  319. * @param {Cartesian3} direction The view direction.
  320. * @param {Cartesian3} up The up direction.
  321. * @returns {CullingVolume} A culling volume at the given position and orientation.
  322. *
  323. * @example
  324. * // Check if a bounding volume intersects the frustum.
  325. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  326. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  327. */
  328. OrthographicOffCenterFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  329. //>>includeStart('debug', pragmas.debug);
  330. if (!when.defined(position)) {
  331. throw new Check.DeveloperError('position is required.');
  332. }
  333. if (!when.defined(direction)) {
  334. throw new Check.DeveloperError('direction is required.');
  335. }
  336. if (!when.defined(up)) {
  337. throw new Check.DeveloperError('up is required.');
  338. }
  339. //>>includeEnd('debug');
  340. var planes = this._cullingVolume.planes;
  341. var t = this.top;
  342. var b = this.bottom;
  343. var r = this.right;
  344. var l = this.left;
  345. var n = this.near;
  346. var f = this.far;
  347. var right = Cartographic.Cartesian3.cross(direction, up, getPlanesRight);
  348. Cartographic.Cartesian3.normalize(right, right);
  349. var nearCenter = getPlanesNearCenter;
  350. Cartographic.Cartesian3.multiplyByScalar(direction, n, nearCenter);
  351. Cartographic.Cartesian3.add(position, nearCenter, nearCenter);
  352. var point = getPlanesPoint;
  353. // Left plane
  354. Cartographic.Cartesian3.multiplyByScalar(right, l, point);
  355. Cartographic.Cartesian3.add(nearCenter, point, point);
  356. var plane = planes[0];
  357. if (!when.defined(plane)) {
  358. plane = planes[0] = new Cartesian4.Cartesian4();
  359. }
  360. plane.x = right.x;
  361. plane.y = right.y;
  362. plane.z = right.z;
  363. plane.w = -Cartographic.Cartesian3.dot(right, point);
  364. // Right plane
  365. Cartographic.Cartesian3.multiplyByScalar(right, r, point);
  366. Cartographic.Cartesian3.add(nearCenter, point, point);
  367. plane = planes[1];
  368. if (!when.defined(plane)) {
  369. plane = planes[1] = new Cartesian4.Cartesian4();
  370. }
  371. plane.x = -right.x;
  372. plane.y = -right.y;
  373. plane.z = -right.z;
  374. plane.w = -Cartographic.Cartesian3.dot(Cartographic.Cartesian3.negate(right, negateScratch), point);
  375. // Bottom plane
  376. Cartographic.Cartesian3.multiplyByScalar(up, b, point);
  377. Cartographic.Cartesian3.add(nearCenter, point, point);
  378. plane = planes[2];
  379. if (!when.defined(plane)) {
  380. plane = planes[2] = new Cartesian4.Cartesian4();
  381. }
  382. plane.x = up.x;
  383. plane.y = up.y;
  384. plane.z = up.z;
  385. plane.w = -Cartographic.Cartesian3.dot(up, point);
  386. // Top plane
  387. Cartographic.Cartesian3.multiplyByScalar(up, t, point);
  388. Cartographic.Cartesian3.add(nearCenter, point, point);
  389. plane = planes[3];
  390. if (!when.defined(plane)) {
  391. plane = planes[3] = new Cartesian4.Cartesian4();
  392. }
  393. plane.x = -up.x;
  394. plane.y = -up.y;
  395. plane.z = -up.z;
  396. plane.w = -Cartographic.Cartesian3.dot(Cartographic.Cartesian3.negate(up, negateScratch), point);
  397. // Near plane
  398. plane = planes[4];
  399. if (!when.defined(plane)) {
  400. plane = planes[4] = new Cartesian4.Cartesian4();
  401. }
  402. plane.x = direction.x;
  403. plane.y = direction.y;
  404. plane.z = direction.z;
  405. plane.w = -Cartographic.Cartesian3.dot(direction, nearCenter);
  406. // Far plane
  407. Cartographic.Cartesian3.multiplyByScalar(direction, f, point);
  408. Cartographic.Cartesian3.add(position, point, point);
  409. plane = planes[5];
  410. if (!when.defined(plane)) {
  411. plane = planes[5] = new Cartesian4.Cartesian4();
  412. }
  413. plane.x = -direction.x;
  414. plane.y = -direction.y;
  415. plane.z = -direction.z;
  416. plane.w = -Cartographic.Cartesian3.dot(Cartographic.Cartesian3.negate(direction, negateScratch), point);
  417. return this._cullingVolume;
  418. };
  419. /**
  420. * Returns the pixel's width and height in meters.
  421. *
  422. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  423. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  424. * @param {Number} distance The distance to the near plane in meters.
  425. * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.
  426. * @param {Cartesian2} result The object onto which to store the result.
  427. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  428. *
  429. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  430. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  431. * @exception {DeveloperError} pixelRatio must be greater than zero.
  432. *
  433. * @example
  434. * // Example 1
  435. * // Get the width and height of a pixel.
  436. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 0.0, scene.pixelRatio, new Cesium.Cartesian2());
  437. */
  438. OrthographicOffCenterFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result) {
  439. update(this);
  440. //>>includeStart('debug', pragmas.debug);
  441. if (!when.defined(drawingBufferWidth) || !when.defined(drawingBufferHeight)) {
  442. throw new Check.DeveloperError('Both drawingBufferWidth and drawingBufferHeight are required.');
  443. }
  444. if (drawingBufferWidth <= 0) {
  445. throw new Check.DeveloperError('drawingBufferWidth must be greater than zero.');
  446. }
  447. if (drawingBufferHeight <= 0) {
  448. throw new Check.DeveloperError('drawingBufferHeight must be greater than zero.');
  449. }
  450. if (!when.defined(distance)) {
  451. throw new Check.DeveloperError('distance is required.');
  452. }
  453. if (!when.defined(pixelRatio)) {
  454. throw new Check.DeveloperError('pixelRatio is required.');
  455. }
  456. if (pixelRatio <= 0) {
  457. throw new Check.DeveloperError('pixelRatio must be greater than zero.');
  458. }
  459. if (!when.defined(result)) {
  460. throw new Check.DeveloperError('A result object is required.');
  461. }
  462. //>>includeEnd('debug');
  463. var frustumWidth = this.right - this.left;
  464. var frustumHeight = this.top - this.bottom;
  465. var pixelWidth = pixelRatio * frustumWidth / drawingBufferWidth;
  466. var pixelHeight = pixelRatio * frustumHeight / drawingBufferHeight;
  467. result.x = pixelWidth;
  468. result.y = pixelHeight;
  469. return result;
  470. };
  471. /**
  472. * Returns a duplicate of a OrthographicOffCenterFrustum instance.
  473. *
  474. * @param {OrthographicOffCenterFrustum} [result] The object onto which to store the result.
  475. * @returns {OrthographicOffCenterFrustum} The modified result parameter or a new OrthographicOffCenterFrustum instance if one was not provided.
  476. */
  477. OrthographicOffCenterFrustum.prototype.clone = function(result) {
  478. if (!when.defined(result)) {
  479. result = new OrthographicOffCenterFrustum();
  480. }
  481. result.left = this.left;
  482. result.right = this.right;
  483. result.top = this.top;
  484. result.bottom = this.bottom;
  485. result.near = this.near;
  486. result.far = this.far;
  487. // force update of clone to compute matrices
  488. result._left = undefined;
  489. result._right = undefined;
  490. result._top = undefined;
  491. result._bottom = undefined;
  492. result._near = undefined;
  493. result._far = undefined;
  494. return result;
  495. };
  496. /**
  497. * Compares the provided OrthographicOffCenterFrustum componentwise and returns
  498. * <code>true</code> if they are equal, <code>false</code> otherwise.
  499. *
  500. * @param {OrthographicOffCenterFrustum} [other] The right hand side OrthographicOffCenterFrustum.
  501. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  502. */
  503. OrthographicOffCenterFrustum.prototype.equals = function(other) {
  504. return (when.defined(other) && other instanceof OrthographicOffCenterFrustum &&
  505. this.right === other.right &&
  506. this.left === other.left &&
  507. this.top === other.top &&
  508. this.bottom === other.bottom &&
  509. this.near === other.near &&
  510. this.far === other.far);
  511. };
  512. /**
  513. * Compares the provided OrthographicOffCenterFrustum componentwise and returns
  514. * <code>true</code> if they pass an absolute or relative tolerance test,
  515. * <code>false</code> otherwise.
  516. *
  517. * @param {OrthographicOffCenterFrustum} other The right hand side OrthographicOffCenterFrustum.
  518. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  519. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  520. * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.
  521. */
  522. OrthographicOffCenterFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) {
  523. return (other === this) ||
  524. (when.defined(other) &&
  525. other instanceof OrthographicOffCenterFrustum &&
  526. _Math.CesiumMath.equalsEpsilon(this.right, other.right, relativeEpsilon, absoluteEpsilon) &&
  527. _Math.CesiumMath.equalsEpsilon(this.left, other.left, relativeEpsilon, absoluteEpsilon) &&
  528. _Math.CesiumMath.equalsEpsilon(this.top, other.top, relativeEpsilon, absoluteEpsilon) &&
  529. _Math.CesiumMath.equalsEpsilon(this.bottom, other.bottom, relativeEpsilon, absoluteEpsilon) &&
  530. _Math.CesiumMath.equalsEpsilon(this.near, other.near, relativeEpsilon, absoluteEpsilon) &&
  531. _Math.CesiumMath.equalsEpsilon(this.far, other.far, relativeEpsilon, absoluteEpsilon));
  532. };
  533. /**
  534. * The viewing frustum is defined by 6 planes.
  535. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  536. * define the unit vector normal to the plane, and the w component is the distance of the
  537. * plane from the origin/camera position.
  538. *
  539. * @alias OrthographicFrustum
  540. * @constructor
  541. *
  542. * @param {Object} [options] An object with the following properties:
  543. * @param {Number} [options.width] The width of the frustum in meters.
  544. * @param {Number} [options.aspectRatio] The aspect ratio of the frustum's width to it's height.
  545. * @param {Number} [options.near=1.0] The distance of the near plane.
  546. * @param {Number} [options.far=500000000.0] The distance of the far plane.
  547. *
  548. * @example
  549. * var maxRadii = ellipsoid.maximumRadius;
  550. *
  551. * var frustum = new Cesium.OrthographicFrustum();
  552. * frustum.near = 0.01 * maxRadii;
  553. * frustum.far = 50.0 * maxRadii;
  554. */
  555. function OrthographicFrustum(options) {
  556. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  557. this._offCenterFrustum = new OrthographicOffCenterFrustum();
  558. /**
  559. * The horizontal width of the frustum in meters.
  560. * @type {Number}
  561. * @default undefined
  562. */
  563. this.width = options.width;
  564. this._width = undefined;
  565. /**
  566. * The aspect ratio of the frustum's width to it's height.
  567. * @type {Number}
  568. * @default undefined
  569. */
  570. this.aspectRatio = options.aspectRatio;
  571. this._aspectRatio = undefined;
  572. /**
  573. * The distance of the near plane.
  574. * @type {Number}
  575. * @default 1.0
  576. */
  577. this.near = when.defaultValue(options.near, 1.0);
  578. this._near = this.near;
  579. /**
  580. * The distance of the far plane.
  581. * @type {Number}
  582. * @default 500000000.0;
  583. */
  584. this.far = when.defaultValue(options.far, 500000000.0);
  585. this._far = this.far;
  586. }
  587. /**
  588. * The number of elements used to pack the object into an array.
  589. * @type {Number}
  590. */
  591. OrthographicFrustum.packedLength = 4;
  592. /**
  593. * Stores the provided instance into the provided array.
  594. *
  595. * @param {OrthographicFrustum} value The value to pack.
  596. * @param {Number[]} array The array to pack into.
  597. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  598. *
  599. * @returns {Number[]} The array that was packed into
  600. */
  601. OrthographicFrustum.pack = function(value, array, startingIndex) {
  602. //>>includeStart('debug', pragmas.debug);
  603. Check.Check.typeOf.object('value', value);
  604. Check.Check.defined('array', array);
  605. //>>includeEnd('debug');
  606. startingIndex = when.defaultValue(startingIndex, 0);
  607. array[startingIndex++] = value.width;
  608. array[startingIndex++] = value.aspectRatio;
  609. array[startingIndex++] = value.near;
  610. array[startingIndex] = value.far;
  611. return array;
  612. };
  613. /**
  614. * Retrieves an instance from a packed array.
  615. *
  616. * @param {Number[]} array The packed array.
  617. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  618. * @param {OrthographicFrustum} [result] The object into which to store the result.
  619. * @returns {OrthographicFrustum} The modified result parameter or a new OrthographicFrustum instance if one was not provided.
  620. */
  621. OrthographicFrustum.unpack = function(array, startingIndex, result) {
  622. //>>includeStart('debug', pragmas.debug);
  623. Check.Check.defined('array', array);
  624. //>>includeEnd('debug');
  625. startingIndex = when.defaultValue(startingIndex, 0);
  626. if (!when.defined(result)) {
  627. result = new OrthographicFrustum();
  628. }
  629. result.width = array[startingIndex++];
  630. result.aspectRatio = array[startingIndex++];
  631. result.near = array[startingIndex++];
  632. result.far = array[startingIndex];
  633. return result;
  634. };
  635. function update$1(frustum) {
  636. //>>includeStart('debug', pragmas.debug);
  637. if (!when.defined(frustum.width) || !when.defined(frustum.aspectRatio) || !when.defined(frustum.near) || !when.defined(frustum.far)) {
  638. throw new Check.DeveloperError('width, aspectRatio, near, or far parameters are not set.');
  639. }
  640. //>>includeEnd('debug');
  641. var f = frustum._offCenterFrustum;
  642. if (frustum.width !== frustum._width || frustum.aspectRatio !== frustum._aspectRatio ||
  643. frustum.near !== frustum._near || frustum.far !== frustum._far) {
  644. //>>includeStart('debug', pragmas.debug);
  645. if (frustum.aspectRatio < 0) {
  646. throw new Check.DeveloperError('aspectRatio must be positive.');
  647. }
  648. if (frustum.near < 0 || frustum.near > frustum.far) {
  649. throw new Check.DeveloperError('near must be greater than zero and less than far.');
  650. }
  651. //>>includeEnd('debug');
  652. frustum._aspectRatio = frustum.aspectRatio;
  653. frustum._width = frustum.width;
  654. frustum._near = frustum.near;
  655. frustum._far = frustum.far;
  656. var ratio = 1.0 / frustum.aspectRatio;
  657. f.right = frustum.width * 0.5;
  658. f.left = -f.right;
  659. f.top = ratio * f.right;
  660. f.bottom = -f.top;
  661. f.near = frustum.near;
  662. f.far = frustum.far;
  663. }
  664. }
  665. Object.defineProperties(OrthographicFrustum.prototype, {
  666. /**
  667. * Gets the orthographic projection matrix computed from the view frustum.
  668. * @memberof OrthographicFrustum.prototype
  669. * @type {Matrix4}
  670. * @readonly
  671. */
  672. projectionMatrix : {
  673. get : function() {
  674. update$1(this);
  675. return this._offCenterFrustum.projectionMatrix;
  676. }
  677. }
  678. });
  679. /**
  680. * Creates a culling volume for this frustum.
  681. *
  682. * @param {Cartesian3} position The eye position.
  683. * @param {Cartesian3} direction The view direction.
  684. * @param {Cartesian3} up The up direction.
  685. * @returns {CullingVolume} A culling volume at the given position and orientation.
  686. *
  687. * @example
  688. * // Check if a bounding volume intersects the frustum.
  689. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  690. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  691. */
  692. OrthographicFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  693. update$1(this);
  694. return this._offCenterFrustum.computeCullingVolume(position, direction, up);
  695. };
  696. /**
  697. * Returns the pixel's width and height in meters.
  698. *
  699. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  700. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  701. * @param {Number} distance The distance to the near plane in meters.
  702. * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.
  703. * @param {Cartesian2} result The object onto which to store the result.
  704. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  705. *
  706. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  707. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  708. * @exception {DeveloperError} pixelRatio must be greater than zero.
  709. *
  710. * @example
  711. * // Example 1
  712. * // Get the width and height of a pixel.
  713. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 0.0, scene.pixelRatio, new Cesium.Cartesian2());
  714. */
  715. OrthographicFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result) {
  716. update$1(this);
  717. return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result);
  718. };
  719. /**
  720. * Returns a duplicate of a OrthographicFrustum instance.
  721. *
  722. * @param {OrthographicFrustum} [result] The object onto which to store the result.
  723. * @returns {OrthographicFrustum} The modified result parameter or a new OrthographicFrustum instance if one was not provided.
  724. */
  725. OrthographicFrustum.prototype.clone = function(result) {
  726. if (!when.defined(result)) {
  727. result = new OrthographicFrustum();
  728. }
  729. result.aspectRatio = this.aspectRatio;
  730. result.width = this.width;
  731. result.near = this.near;
  732. result.far = this.far;
  733. // force update of clone to compute matrices
  734. result._aspectRatio = undefined;
  735. result._width = undefined;
  736. result._near = undefined;
  737. result._far = undefined;
  738. this._offCenterFrustum.clone(result._offCenterFrustum);
  739. return result;
  740. };
  741. /**
  742. * Compares the provided OrthographicFrustum componentwise and returns
  743. * <code>true</code> if they are equal, <code>false</code> otherwise.
  744. *
  745. * @param {OrthographicFrustum} [other] The right hand side OrthographicFrustum.
  746. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  747. */
  748. OrthographicFrustum.prototype.equals = function(other) {
  749. if (!when.defined(other) || !(other instanceof OrthographicFrustum)) {
  750. return false;
  751. }
  752. update$1(this);
  753. update$1(other);
  754. return (this.width === other.width &&
  755. this.aspectRatio === other.aspectRatio &&
  756. this._offCenterFrustum.equals(other._offCenterFrustum));
  757. };
  758. /**
  759. * Compares the provided OrthographicFrustum componentwise and returns
  760. * <code>true</code> if they pass an absolute or relative tolerance test,
  761. * <code>false</code> otherwise.
  762. *
  763. * @param {OrthographicFrustum} other The right hand side OrthographicFrustum.
  764. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  765. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  766. * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.
  767. */
  768. OrthographicFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) {
  769. if (!when.defined(other) || !(other instanceof OrthographicFrustum)) {
  770. return false;
  771. }
  772. update$1(this);
  773. update$1(other);
  774. return (_Math.CesiumMath.equalsEpsilon(this.width, other.width, relativeEpsilon, absoluteEpsilon) &&
  775. _Math.CesiumMath.equalsEpsilon(this.aspectRatio, other.aspectRatio, relativeEpsilon, absoluteEpsilon) &&
  776. this._offCenterFrustum.equalsEpsilon(other._offCenterFrustum, relativeEpsilon, absoluteEpsilon));
  777. };
  778. /**
  779. * The viewing frustum is defined by 6 planes.
  780. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  781. * define the unit vector normal to the plane, and the w component is the distance of the
  782. * plane from the origin/camera position.
  783. *
  784. * @alias PerspectiveOffCenterFrustum
  785. * @constructor
  786. *
  787. * @param {Object} [options] An object with the following properties:
  788. * @param {Number} [options.left] The left clipping plane distance.
  789. * @param {Number} [options.right] The right clipping plane distance.
  790. * @param {Number} [options.top] The top clipping plane distance.
  791. * @param {Number} [options.bottom] The bottom clipping plane distance.
  792. * @param {Number} [options.near=1.0] The near clipping plane distance.
  793. * @param {Number} [options.far=500000000.0] The far clipping plane distance.
  794. *
  795. * @example
  796. * var frustum = new Cesium.PerspectiveOffCenterFrustum({
  797. * left : -1.0,
  798. * right : 1.0,
  799. * top : 1.0,
  800. * bottom : -1.0,
  801. * near : 1.0,
  802. * far : 100.0
  803. * });
  804. *
  805. * @see PerspectiveFrustum
  806. */
  807. function PerspectiveOffCenterFrustum(options) {
  808. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  809. /**
  810. * Defines the left clipping plane.
  811. * @type {Number}
  812. * @default undefined
  813. */
  814. this.left = options.left;
  815. this._left = undefined;
  816. /**
  817. * Defines the right clipping plane.
  818. * @type {Number}
  819. * @default undefined
  820. */
  821. this.right = options.right;
  822. this._right = undefined;
  823. /**
  824. * Defines the top clipping plane.
  825. * @type {Number}
  826. * @default undefined
  827. */
  828. this.top = options.top;
  829. this._top = undefined;
  830. /**
  831. * Defines the bottom clipping plane.
  832. * @type {Number}
  833. * @default undefined
  834. */
  835. this.bottom = options.bottom;
  836. this._bottom = undefined;
  837. /**
  838. * The distance of the near plane.
  839. * @type {Number}
  840. * @default 1.0
  841. */
  842. this.near = when.defaultValue(options.near, 1.0);
  843. this._near = this.near;
  844. /**
  845. * The distance of the far plane.
  846. * @type {Number}
  847. * @default 500000000.0
  848. */
  849. this.far = when.defaultValue(options.far, 500000000.0);
  850. this._far = this.far;
  851. this._cullingVolume = new CullingVolume();
  852. this._perspectiveMatrix = new BoundingSphere.Matrix4();
  853. this._infinitePerspective = new BoundingSphere.Matrix4();
  854. }
  855. function update$2(frustum) {
  856. //>>includeStart('debug', pragmas.debug);
  857. if (!when.defined(frustum.right) || !when.defined(frustum.left) ||
  858. !when.defined(frustum.top) || !when.defined(frustum.bottom) ||
  859. !when.defined(frustum.near) || !when.defined(frustum.far)) {
  860. throw new Check.DeveloperError('right, left, top, bottom, near, or far parameters are not set.');
  861. }
  862. //>>includeEnd('debug');
  863. var t = frustum.top;
  864. var b = frustum.bottom;
  865. var r = frustum.right;
  866. var l = frustum.left;
  867. var n = frustum.near;
  868. var f = frustum.far;
  869. if (t !== frustum._top || b !== frustum._bottom ||
  870. l !== frustum._left || r !== frustum._right ||
  871. n !== frustum._near || f !== frustum._far) {
  872. //>>includeStart('debug', pragmas.debug);
  873. if (frustum.near <= 0 || frustum.near > frustum.far) {
  874. throw new Check.DeveloperError('near must be greater than zero and less than far.');
  875. }
  876. //>>includeEnd('debug');
  877. frustum._left = l;
  878. frustum._right = r;
  879. frustum._top = t;
  880. frustum._bottom = b;
  881. frustum._near = n;
  882. frustum._far = f;
  883. frustum._perspectiveMatrix = BoundingSphere.Matrix4.computePerspectiveOffCenter(l, r, b, t, n, f, frustum._perspectiveMatrix);
  884. frustum._infinitePerspective = BoundingSphere.Matrix4.computeInfinitePerspectiveOffCenter(l, r, b, t, n, frustum._infinitePerspective);
  885. }
  886. }
  887. Object.defineProperties(PerspectiveOffCenterFrustum.prototype, {
  888. /**
  889. * Gets the perspective projection matrix computed from the view frustum.
  890. * @memberof PerspectiveOffCenterFrustum.prototype
  891. * @type {Matrix4}
  892. * @readonly
  893. *
  894. * @see PerspectiveOffCenterFrustum#infiniteProjectionMatrix
  895. */
  896. projectionMatrix : {
  897. get : function() {
  898. update$2(this);
  899. return this._perspectiveMatrix;
  900. }
  901. },
  902. /**
  903. * Gets the perspective projection matrix computed from the view frustum with an infinite far plane.
  904. * @memberof PerspectiveOffCenterFrustum.prototype
  905. * @type {Matrix4}
  906. * @readonly
  907. *
  908. * @see PerspectiveOffCenterFrustum#projectionMatrix
  909. */
  910. infiniteProjectionMatrix : {
  911. get : function() {
  912. update$2(this);
  913. return this._infinitePerspective;
  914. }
  915. }
  916. });
  917. var getPlanesRight$1 = new Cartographic.Cartesian3();
  918. var getPlanesNearCenter$1 = new Cartographic.Cartesian3();
  919. var getPlanesFarCenter = new Cartographic.Cartesian3();
  920. var getPlanesNormal = new Cartographic.Cartesian3();
  921. PerspectiveOffCenterFrustum.prototype.resetProjectionMatrix = function() {
  922. //>>includeStart('debug', pragmas.debug);
  923. if (!when.defined(this.right) || !when.defined(this.left) ||
  924. !when.defined(this.top) || !when.defined(this.bottom) ||
  925. !when.defined(this.near) || !when.defined(this.far)) {
  926. throw new Check.DeveloperError('right, left, top, bottom, near, or far parameters are not set.');
  927. }
  928. //>>includeEnd('debug');
  929. var t = this.top;
  930. var b = this.bottom;
  931. var r = this.right;
  932. var l = this.left;
  933. var n = this.near;
  934. var f = this.far;
  935. //>>includeStart('debug', pragmas.debug);
  936. if (this.near <= 0 || this.near > this.far) {
  937. throw new Check.DeveloperError('near must be greater than zero and less than far.');
  938. }
  939. //>>includeEnd('debug');
  940. this._left = l;
  941. this._right = r;
  942. this._top = t;
  943. this._bottom = b;
  944. this._near = n;
  945. this._far = f;
  946. this._perspectiveMatrix = BoundingSphere.Matrix4.computePerspectiveOffCenter(l, r, b, t, n, f, this._perspectiveMatrix);
  947. this._infinitePerspective = BoundingSphere.Matrix4.computeInfinitePerspectiveOffCenter(l, r, b, t, n, this._infinitePerspective);
  948. };
  949. /**
  950. * Creates a culling volume for this frustum.
  951. *
  952. * @param {Cartesian3} position The eye position.
  953. * @param {Cartesian3} direction The view direction.
  954. * @param {Cartesian3} up The up direction.
  955. * @returns {CullingVolume} A culling volume at the given position and orientation.
  956. *
  957. * @example
  958. * // Check if a bounding volume intersects the frustum.
  959. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  960. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  961. */
  962. PerspectiveOffCenterFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  963. //>>includeStart('debug', pragmas.debug);
  964. if (!when.defined(position)) {
  965. throw new Check.DeveloperError('position is required.');
  966. }
  967. if (!when.defined(direction)) {
  968. throw new Check.DeveloperError('direction is required.');
  969. }
  970. if (!when.defined(up)) {
  971. throw new Check.DeveloperError('up is required.');
  972. }
  973. //>>includeEnd('debug');
  974. var planes = this._cullingVolume.planes;
  975. var t = this.top;
  976. var b = this.bottom;
  977. var r = this.right;
  978. var l = this.left;
  979. var n = this.near;
  980. var f = this.far;
  981. var right = Cartographic.Cartesian3.cross(direction, up, getPlanesRight$1);
  982. var nearCenter = getPlanesNearCenter$1;
  983. Cartographic.Cartesian3.multiplyByScalar(direction, n, nearCenter);
  984. Cartographic.Cartesian3.add(position, nearCenter, nearCenter);
  985. var farCenter = getPlanesFarCenter;
  986. Cartographic.Cartesian3.multiplyByScalar(direction, f, farCenter);
  987. Cartographic.Cartesian3.add(position, farCenter, farCenter);
  988. var normal = getPlanesNormal;
  989. //Left plane computation
  990. Cartographic.Cartesian3.multiplyByScalar(right, l, normal);
  991. Cartographic.Cartesian3.add(nearCenter, normal, normal);
  992. Cartographic.Cartesian3.subtract(normal, position, normal);
  993. Cartographic.Cartesian3.normalize(normal, normal);
  994. Cartographic.Cartesian3.cross(normal, up, normal);
  995. Cartographic.Cartesian3.normalize(normal, normal);
  996. var plane = planes[0];
  997. if (!when.defined(plane)) {
  998. plane = planes[0] = new Cartesian4.Cartesian4();
  999. }
  1000. plane.x = normal.x;
  1001. plane.y = normal.y;
  1002. plane.z = normal.z;
  1003. plane.w = -Cartographic.Cartesian3.dot(normal, position);
  1004. //Right plane computation
  1005. Cartographic.Cartesian3.multiplyByScalar(right, r, normal);
  1006. Cartographic.Cartesian3.add(nearCenter, normal, normal);
  1007. Cartographic.Cartesian3.subtract(normal, position, normal);
  1008. Cartographic.Cartesian3.cross(up, normal, normal);
  1009. Cartographic.Cartesian3.normalize(normal, normal);
  1010. plane = planes[1];
  1011. if (!when.defined(plane)) {
  1012. plane = planes[1] = new Cartesian4.Cartesian4();
  1013. }
  1014. plane.x = normal.x;
  1015. plane.y = normal.y;
  1016. plane.z = normal.z;
  1017. plane.w = -Cartographic.Cartesian3.dot(normal, position);
  1018. //Bottom plane computation
  1019. Cartographic.Cartesian3.multiplyByScalar(up, b, normal);
  1020. Cartographic.Cartesian3.add(nearCenter, normal, normal);
  1021. Cartographic.Cartesian3.subtract(normal, position, normal);
  1022. Cartographic.Cartesian3.cross(right, normal, normal);
  1023. Cartographic.Cartesian3.normalize(normal, normal);
  1024. plane = planes[2];
  1025. if (!when.defined(plane)) {
  1026. plane = planes[2] = new Cartesian4.Cartesian4();
  1027. }
  1028. plane.x = normal.x;
  1029. plane.y = normal.y;
  1030. plane.z = normal.z;
  1031. plane.w = -Cartographic.Cartesian3.dot(normal, position);
  1032. //Top plane computation
  1033. Cartographic.Cartesian3.multiplyByScalar(up, t, normal);
  1034. Cartographic.Cartesian3.add(nearCenter, normal, normal);
  1035. Cartographic.Cartesian3.subtract(normal, position, normal);
  1036. Cartographic.Cartesian3.cross(normal, right, normal);
  1037. Cartographic.Cartesian3.normalize(normal, normal);
  1038. plane = planes[3];
  1039. if (!when.defined(plane)) {
  1040. plane = planes[3] = new Cartesian4.Cartesian4();
  1041. }
  1042. plane.x = normal.x;
  1043. plane.y = normal.y;
  1044. plane.z = normal.z;
  1045. plane.w = -Cartographic.Cartesian3.dot(normal, position);
  1046. //Near plane computation
  1047. plane = planes[4];
  1048. if (!when.defined(plane)) {
  1049. plane = planes[4] = new Cartesian4.Cartesian4();
  1050. }
  1051. plane.x = direction.x;
  1052. plane.y = direction.y;
  1053. plane.z = direction.z;
  1054. plane.w = -Cartographic.Cartesian3.dot(direction, nearCenter);
  1055. //Far plane computation
  1056. Cartographic.Cartesian3.negate(direction, normal);
  1057. plane = planes[5];
  1058. if (!when.defined(plane)) {
  1059. plane = planes[5] = new Cartesian4.Cartesian4();
  1060. }
  1061. plane.x = normal.x;
  1062. plane.y = normal.y;
  1063. plane.z = normal.z;
  1064. plane.w = -Cartographic.Cartesian3.dot(normal, farCenter);
  1065. return this._cullingVolume;
  1066. };
  1067. /**
  1068. * Returns the pixel's width and height in meters.
  1069. *
  1070. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  1071. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  1072. * @param {Number} distance The distance to the near plane in meters.
  1073. * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.
  1074. * @param {Cartesian2} result The object onto which to store the result.
  1075. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  1076. *
  1077. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  1078. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  1079. * @exception {DeveloperError} pixelRatio must be greater than zero.
  1080. *
  1081. * @example
  1082. * // Example 1
  1083. * // Get the width and height of a pixel.
  1084. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, scene.pixelRatio, new Cesium.Cartesian2());
  1085. *
  1086. * @example
  1087. * // Example 2
  1088. * // Get the width and height of a pixel if the near plane was set to 'distance'.
  1089. * // For example, get the size of a pixel of an image on a billboard.
  1090. * var position = camera.position;
  1091. * var direction = camera.direction;
  1092. * var toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3()); // vector from camera to a primitive
  1093. * var toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector
  1094. * var distance = Cesium.Cartesian3.magnitude(toCenterProj);
  1095. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, scene.pixelRatio, new Cesium.Cartesian2());
  1096. */
  1097. PerspectiveOffCenterFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result) {
  1098. update$2(this);
  1099. //>>includeStart('debug', pragmas.debug);
  1100. if (!when.defined(drawingBufferWidth) || !when.defined(drawingBufferHeight)) {
  1101. throw new Check.DeveloperError('Both drawingBufferWidth and drawingBufferHeight are required.');
  1102. }
  1103. if (drawingBufferWidth <= 0) {
  1104. throw new Check.DeveloperError('drawingBufferWidth must be greater than zero.');
  1105. }
  1106. if (drawingBufferHeight <= 0) {
  1107. throw new Check.DeveloperError('drawingBufferHeight must be greater than zero.');
  1108. }
  1109. if (!when.defined(distance)) {
  1110. throw new Check.DeveloperError('distance is required.');
  1111. }
  1112. if (!when.defined(pixelRatio)) {
  1113. throw new Check.DeveloperError('pixelRatio is required');
  1114. }
  1115. if (pixelRatio <= 0) {
  1116. throw new Check.DeveloperError('pixelRatio must be greater than zero.');
  1117. }
  1118. if (!when.defined(result)) {
  1119. throw new Check.DeveloperError('A result object is required.');
  1120. }
  1121. //>>includeEnd('debug');
  1122. var inverseNear = 1.0 / this.near;
  1123. var tanTheta = this.top * inverseNear;
  1124. var pixelHeight = 2.0 * pixelRatio * distance * tanTheta / drawingBufferHeight;
  1125. tanTheta = this.right * inverseNear;
  1126. var pixelWidth = 2.0 * pixelRatio * distance * tanTheta / drawingBufferWidth;
  1127. result.x = pixelWidth;
  1128. result.y = pixelHeight;
  1129. return result;
  1130. };
  1131. /**
  1132. * Returns a duplicate of a PerspectiveOffCenterFrustum instance.
  1133. *
  1134. * @param {PerspectiveOffCenterFrustum} [result] The object onto which to store the result.
  1135. * @returns {PerspectiveOffCenterFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  1136. */
  1137. PerspectiveOffCenterFrustum.prototype.clone = function(result) {
  1138. if (!when.defined(result)) {
  1139. result = new PerspectiveOffCenterFrustum();
  1140. }
  1141. result.right = this.right;
  1142. result.left = this.left;
  1143. result.top = this.top;
  1144. result.bottom = this.bottom;
  1145. result.near = this.near;
  1146. result.far = this.far;
  1147. // force update of clone to compute matrices
  1148. result._left = undefined;
  1149. result._right = undefined;
  1150. result._top = undefined;
  1151. result._bottom = undefined;
  1152. result._near = undefined;
  1153. result._far = undefined;
  1154. return result;
  1155. };
  1156. /**
  1157. * Compares the provided PerspectiveOffCenterFrustum componentwise and returns
  1158. * <code>true</code> if they are equal, <code>false</code> otherwise.
  1159. *
  1160. * @param {PerspectiveOffCenterFrustum} [other] The right hand side PerspectiveOffCenterFrustum.
  1161. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  1162. */
  1163. PerspectiveOffCenterFrustum.prototype.equals = function(other) {
  1164. return (when.defined(other) && other instanceof PerspectiveOffCenterFrustum &&
  1165. this.right === other.right &&
  1166. this.left === other.left &&
  1167. this.top === other.top &&
  1168. this.bottom === other.bottom &&
  1169. this.near === other.near &&
  1170. this.far === other.far);
  1171. };
  1172. /**
  1173. * Compares the provided PerspectiveOffCenterFrustum componentwise and returns
  1174. * <code>true</code> if they pass an absolute or relative tolerance test,
  1175. * <code>false</code> otherwise.
  1176. *
  1177. * @param {PerspectiveOffCenterFrustum} other The right hand side PerspectiveOffCenterFrustum.
  1178. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  1179. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  1180. * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.
  1181. */
  1182. PerspectiveOffCenterFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) {
  1183. return (other === this) ||
  1184. (when.defined(other) &&
  1185. other instanceof PerspectiveOffCenterFrustum &&
  1186. _Math.CesiumMath.equalsEpsilon(this.right, other.right, relativeEpsilon, absoluteEpsilon) &&
  1187. _Math.CesiumMath.equalsEpsilon(this.left, other.left, relativeEpsilon, absoluteEpsilon) &&
  1188. _Math.CesiumMath.equalsEpsilon(this.top, other.top, relativeEpsilon, absoluteEpsilon) &&
  1189. _Math.CesiumMath.equalsEpsilon(this.bottom, other.bottom, relativeEpsilon, absoluteEpsilon) &&
  1190. _Math.CesiumMath.equalsEpsilon(this.near, other.near, relativeEpsilon, absoluteEpsilon) &&
  1191. _Math.CesiumMath.equalsEpsilon(this.far, other.far, relativeEpsilon, absoluteEpsilon));
  1192. };
  1193. /**
  1194. * The viewing frustum is defined by 6 planes.
  1195. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  1196. * define the unit vector normal to the plane, and the w component is the distance of the
  1197. * plane from the origin/camera position.
  1198. *
  1199. * @alias PerspectiveFrustum
  1200. * @constructor
  1201. *
  1202. * @param {Object} [options] An object with the following properties:
  1203. * @param {Number} [options.fov] The angle of the field of view (FOV), in radians.
  1204. * @param {Number} [options.aspectRatio] The aspect ratio of the frustum's width to it's height.
  1205. * @param {Number} [options.near=1.0] The distance of the near plane.
  1206. * @param {Number} [options.far=500000000.0] The distance of the far plane.
  1207. * @param {Number} [options.xOffset=0.0] The offset in the x direction.
  1208. * @param {Number} [options.yOffset=0.0] The offset in the y direction.
  1209. *
  1210. * @example
  1211. * var frustum = new Cesium.PerspectiveFrustum({
  1212. * fov : Cesium.Math.PI_OVER_THREE,
  1213. * aspectRatio : canvas.clientWidth / canvas.clientHeight
  1214. * near : 1.0,
  1215. * far : 1000.0
  1216. * });
  1217. *
  1218. * @see PerspectiveOffCenterFrustum
  1219. */
  1220. function PerspectiveFrustum(options) {
  1221. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  1222. this._offCenterFrustum = new PerspectiveOffCenterFrustum();
  1223. /**
  1224. * The angle of the field of view (FOV), in radians. This angle will be used
  1225. * as the horizontal FOV if the width is greater than the height, otherwise
  1226. * it will be the vertical FOV.
  1227. * @type {Number}
  1228. * @default undefined
  1229. */
  1230. this.fov = options.fov;
  1231. this._fov = undefined;
  1232. this._fovy = undefined;
  1233. this._sseDenominator = undefined;
  1234. /**
  1235. * The aspect ratio of the frustum's width to it's height.
  1236. * @type {Number}
  1237. * @default undefined
  1238. */
  1239. this.aspectRatio = options.aspectRatio;
  1240. this._aspectRatio = undefined;
  1241. /**
  1242. * The distance of the near plane.
  1243. * @type {Number}
  1244. * @default 1.0
  1245. */
  1246. this.near = when.defaultValue(options.near, 1.0);
  1247. this._near = this.near;
  1248. /**
  1249. * The distance of the far plane.
  1250. * @type {Number}
  1251. * @default 500000000.0
  1252. */
  1253. this.far = when.defaultValue(options.far, 500000000.0);
  1254. this._far = this.far;
  1255. /**
  1256. * Offsets the frustum in the x direction.
  1257. * @type {Number}
  1258. * @default 0.0
  1259. */
  1260. this.xOffset = when.defaultValue(options.xOffset, 0.0);
  1261. this._xOffset = this.xOffset;
  1262. /**
  1263. * Offsets the frustum in the y direction.
  1264. * @type {Number}
  1265. * @default 0.0
  1266. */
  1267. this.yOffset = when.defaultValue(options.yOffset, 0.0);
  1268. this._yOffset = this.yOffset;
  1269. this.reflect = false;
  1270. }
  1271. /**
  1272. * The number of elements used to pack the object into an array.
  1273. * @type {Number}
  1274. */
  1275. PerspectiveFrustum.packedLength = 6;
  1276. /**
  1277. * Stores the provided instance into the provided array.
  1278. *
  1279. * @param {PerspectiveFrustum} value The value to pack.
  1280. * @param {Number[]} array The array to pack into.
  1281. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  1282. *
  1283. * @returns {Number[]} The array that was packed into
  1284. */
  1285. PerspectiveFrustum.pack = function(value, array, startingIndex) {
  1286. //>>includeStart('debug', pragmas.debug);
  1287. Check.Check.typeOf.object('value', value);
  1288. Check.Check.defined('array', array);
  1289. //>>includeEnd('debug');
  1290. startingIndex = when.defaultValue(startingIndex, 0);
  1291. array[startingIndex++] = value.fov;
  1292. array[startingIndex++] = value.aspectRatio;
  1293. array[startingIndex++] = value.near;
  1294. array[startingIndex++] = value.far;
  1295. array[startingIndex++] = value.xOffset;
  1296. array[startingIndex] = value.yOffset;
  1297. return array;
  1298. };
  1299. /**
  1300. * Retrieves an instance from a packed array.
  1301. *
  1302. * @param {Number[]} array The packed array.
  1303. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  1304. * @param {PerspectiveFrustum} [result] The object into which to store the result.
  1305. * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  1306. */
  1307. PerspectiveFrustum.unpack = function(array, startingIndex, result) {
  1308. //>>includeStart('debug', pragmas.debug);
  1309. Check.Check.defined('array', array);
  1310. //>>includeEnd('debug');
  1311. startingIndex = when.defaultValue(startingIndex, 0);
  1312. if (!when.defined(result)) {
  1313. result = new PerspectiveFrustum();
  1314. }
  1315. result.fov = array[startingIndex++];
  1316. result.aspectRatio = array[startingIndex++];
  1317. result.near = array[startingIndex++];
  1318. result.far = array[startingIndex++];
  1319. result.xOffset = array[startingIndex++];
  1320. result.yOffset = array[startingIndex];
  1321. return result;
  1322. };
  1323. function update$3(frustum) {
  1324. //>>includeStart('debug', pragmas.debug);
  1325. if (!when.defined(frustum.fov) || !when.defined(frustum.aspectRatio) || !when.defined(frustum.near) || !when.defined(frustum.far)) {
  1326. throw new Check.DeveloperError('fov, aspectRatio, near, or far parameters are not set.');
  1327. }
  1328. //>>includeEnd('debug');
  1329. var f = frustum._offCenterFrustum;
  1330. if (frustum.fov !== frustum._fov || frustum.aspectRatio !== frustum._aspectRatio ||
  1331. frustum.near !== frustum._near || frustum.far !== frustum._far ||
  1332. frustum.xOffset !== frustum._xOffset || frustum.yOffset !== frustum._yOffset) {
  1333. //>>includeStart('debug', pragmas.debug);
  1334. if (frustum.fov < 0 || frustum.fov >= Math.PI) {
  1335. throw new Check.DeveloperError('fov must be in the range [0, PI).');
  1336. }
  1337. if (frustum.aspectRatio < 0) {
  1338. throw new Check.DeveloperError('aspectRatio must be positive.');
  1339. }
  1340. if (frustum.near < 0 || frustum.near > frustum.far) {
  1341. throw new Check.DeveloperError('near must be greater than zero and less than far.');
  1342. }
  1343. //>>includeEnd('debug');
  1344. frustum._aspectRatio = frustum.aspectRatio;
  1345. frustum._fov = frustum.fov;
  1346. frustum._fovy = (frustum.aspectRatio <= 1) ? frustum.fov : Math.atan(Math.tan(frustum.fov * 0.5) / frustum.aspectRatio) * 2.0;
  1347. frustum._near = frustum.near;
  1348. frustum._far = frustum.far;
  1349. frustum._sseDenominator = 2.0 * Math.tan(0.5 * frustum._fovy);
  1350. frustum._xOffset = frustum.xOffset;
  1351. frustum._yOffset = frustum.yOffset;
  1352. f.top = frustum.near * Math.tan(0.5 * frustum._fovy);
  1353. f.bottom = -f.top;
  1354. f.right = frustum.aspectRatio * f.top;
  1355. f.left = -f.right;
  1356. f.near = frustum.near;
  1357. f.far = frustum.far;
  1358. f.right += frustum.xOffset;
  1359. f.left += frustum.xOffset;
  1360. f.top += frustum.yOffset;
  1361. f.bottom += frustum.yOffset;
  1362. }
  1363. }
  1364. Object.defineProperties(PerspectiveFrustum.prototype, {
  1365. /**
  1366. * Gets the perspective projection matrix computed from the view frustum.
  1367. * @memberof PerspectiveFrustum.prototype
  1368. * @type {Matrix4}
  1369. * @readonly
  1370. *
  1371. * @see PerspectiveFrustum#infiniteProjectionMatrix
  1372. */
  1373. projectionMatrix : {
  1374. get : function() {
  1375. update$3(this);
  1376. if(this.reflect){
  1377. modifyProjectionMatrix(this);
  1378. }
  1379. return this._offCenterFrustum.projectionMatrix;
  1380. }
  1381. },
  1382. /**
  1383. * The perspective projection matrix computed from the view frustum with an infinite far plane.
  1384. * @memberof PerspectiveFrustum.prototype
  1385. * @type {Matrix4}
  1386. * @readonly
  1387. *
  1388. * @see PerspectiveFrustum#projectionMatrix
  1389. */
  1390. infiniteProjectionMatrix : {
  1391. get : function() {
  1392. update$3(this);
  1393. return this._offCenterFrustum.infiniteProjectionMatrix;
  1394. }
  1395. },
  1396. /**
  1397. * Gets the angle of the vertical field of view, in radians.
  1398. * @memberof PerspectiveFrustum.prototype
  1399. * @type {Number}
  1400. * @readonly
  1401. * @default undefined
  1402. */
  1403. fovy : {
  1404. get : function() {
  1405. update$3(this);
  1406. return this._fovy;
  1407. }
  1408. },
  1409. /**
  1410. * @readonly
  1411. * @private
  1412. */
  1413. sseDenominator : {
  1414. get : function () {
  1415. update$3(this);
  1416. return this._sseDenominator;
  1417. }
  1418. }
  1419. });
  1420. PerspectiveFrustum.prototype.resetProjectionMatrix = function() {
  1421. return this._offCenterFrustum.resetProjectionMatrix();
  1422. };
  1423. /**
  1424. * Creates a culling volume for this frustum.
  1425. *
  1426. * @param {Cartesian3} position The eye position.
  1427. * @param {Cartesian3} direction The view direction.
  1428. * @param {Cartesian3} up The up direction.
  1429. * @returns {CullingVolume} A culling volume at the given position and orientation.
  1430. *
  1431. * @example
  1432. * // Check if a bounding volume intersects the frustum.
  1433. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  1434. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  1435. */
  1436. PerspectiveFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  1437. update$3(this);
  1438. return this._offCenterFrustum.computeCullingVolume(position, direction, up);
  1439. };
  1440. /**
  1441. * Returns the pixel's width and height in meters.
  1442. *
  1443. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  1444. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  1445. * @param {Number} distance The distance to the near plane in meters.
  1446. * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.
  1447. * @param {Cartesian2} result The object onto which to store the result.
  1448. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  1449. *
  1450. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  1451. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  1452. * @exception {DeveloperError} pixelRatio must be greater than zero.
  1453. *
  1454. * @example
  1455. * // Example 1
  1456. * // Get the width and height of a pixel.
  1457. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, scene.pixelRatio, new Cesium.Cartesian2());
  1458. *
  1459. * @example
  1460. * // Example 2
  1461. * // Get the width and height of a pixel if the near plane was set to 'distance'.
  1462. * // For example, get the size of a pixel of an image on a billboard.
  1463. * var position = camera.position;
  1464. * var direction = camera.direction;
  1465. * var toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3()); // vector from camera to a primitive
  1466. * var toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector
  1467. * var distance = Cesium.Cartesian3.magnitude(toCenterProj);
  1468. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, scene.pixelRatio, new Cesium.Cartesian2());
  1469. */
  1470. PerspectiveFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result) {
  1471. update$3(this);
  1472. return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, pixelRatio, result);
  1473. };
  1474. /**
  1475. * Returns a duplicate of a PerspectiveFrustum instance.
  1476. *
  1477. * @param {PerspectiveFrustum} [result] The object onto which to store the result.
  1478. * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  1479. */
  1480. PerspectiveFrustum.prototype.clone = function(result) {
  1481. if (!when.defined(result)) {
  1482. result = new PerspectiveFrustum();
  1483. }
  1484. result.aspectRatio = this.aspectRatio;
  1485. result.fov = this.fov;
  1486. result.near = this.near;
  1487. result.far = this.far;
  1488. result.reflect = this.reflect;
  1489. result.clipPlane = this.clipPlane;
  1490. result.currentViewMatrix = this.currentViewMatrix;
  1491. // force update of clone to compute matrices
  1492. result._aspectRatio = undefined;
  1493. result._fov = undefined;
  1494. result._near = undefined;
  1495. result._far = undefined;
  1496. this._offCenterFrustum.clone(result._offCenterFrustum);
  1497. return result;
  1498. };
  1499. /**
  1500. * Compares the provided PerspectiveFrustum componentwise and returns
  1501. * <code>true</code> if they are equal, <code>false</code> otherwise.
  1502. *
  1503. * @param {PerspectiveFrustum} [other] The right hand side PerspectiveFrustum.
  1504. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  1505. */
  1506. PerspectiveFrustum.prototype.equals = function(other) {
  1507. if (!when.defined(other) || !(other instanceof PerspectiveFrustum)) {
  1508. return false;
  1509. }
  1510. update$3(this);
  1511. update$3(other);
  1512. return (this.fov === other.fov &&
  1513. this.aspectRatio === other.aspectRatio &&
  1514. this._offCenterFrustum.equals(other._offCenterFrustum));
  1515. };
  1516. /**
  1517. * Compares the provided PerspectiveFrustum componentwise and returns
  1518. * <code>true</code> if they pass an absolute or relative tolerance test,
  1519. * <code>false</code> otherwise.
  1520. *
  1521. * @param {PerspectiveFrustum} other The right hand side PerspectiveFrustum.
  1522. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  1523. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  1524. * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.
  1525. */
  1526. PerspectiveFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) {
  1527. if (!when.defined(other) || !(other instanceof PerspectiveFrustum)) {
  1528. return false;
  1529. }
  1530. update$3(this);
  1531. update$3(other);
  1532. return (_Math.CesiumMath.equalsEpsilon(this.fov, other.fov, relativeEpsilon, absoluteEpsilon) &&
  1533. _Math.CesiumMath.equalsEpsilon(this.aspectRatio, other.aspectRatio, relativeEpsilon, absoluteEpsilon) &&
  1534. this._offCenterFrustum.equalsEpsilon(other._offCenterFrustum, relativeEpsilon, absoluteEpsilon));
  1535. };
  1536. var scratchViewPlane = new Plane.Plane(Cartographic.Cartesian3.UNIT_Z, 1.0);
  1537. var scratchQVec = new Cartesian4.Cartesian4();
  1538. var scratchClipPlane4d = new Cartesian4.Cartesian4();
  1539. var scratchResult4 = new Cartesian4.Cartesian4();
  1540. /**
  1541. * modify the near clip plane for reflection
  1542. */
  1543. function modifyProjectionMatrix(frustum) {
  1544. if(!when.defined(frustum.clipPlane) || !when.defined(frustum.currentViewMatrix)){
  1545. return;
  1546. }
  1547. var viewMatrix = frustum.currentViewMatrix;
  1548. var projectionMatrix = frustum._offCenterFrustum.projectionMatrix;
  1549. BoundingSphere.Matrix4.multiplyByPlane(viewMatrix, frustum.clipPlane, scratchViewPlane);
  1550. scratchQVec.x = (_Math.CesiumMath.sign(scratchViewPlane.normal.x) + projectionMatrix[8]) / projectionMatrix[0];
  1551. scratchQVec.y = (_Math.CesiumMath.sign(scratchViewPlane.normal.y) + projectionMatrix[9]) / projectionMatrix[5];
  1552. scratchQVec.z = -1.0;
  1553. scratchQVec.w = (1 + projectionMatrix[10]) / projectionMatrix[14];
  1554. scratchClipPlane4d.x = scratchViewPlane.normal.x;
  1555. scratchClipPlane4d.y = scratchViewPlane.normal.y;
  1556. scratchClipPlane4d.z = scratchViewPlane.normal.z;
  1557. scratchClipPlane4d.w = scratchViewPlane.distance;
  1558. Cartesian4.Cartesian4.multiplyByScalar(scratchClipPlane4d, 2.0 / Cartesian4.Cartesian4.dot(scratchClipPlane4d, scratchQVec), scratchResult4);
  1559. projectionMatrix[2] = scratchResult4.x;
  1560. projectionMatrix[6] = scratchResult4.y;
  1561. projectionMatrix[10] = scratchResult4.z + 1.0;
  1562. projectionMatrix[14] = scratchResult4.w;
  1563. }
  1564. var PERSPECTIVE = 0;
  1565. var ORTHOGRAPHIC = 1;
  1566. /**
  1567. * Describes a frustum at the given the origin and orientation.
  1568. *
  1569. * @alias FrustumGeometry
  1570. * @constructor
  1571. *
  1572. * @param {Object} options Object with the following properties:
  1573. * @param {PerspectiveFrustum|OrthographicFrustum} options.frustum The frustum.
  1574. * @param {Cartesian3} options.origin The origin of the frustum.
  1575. * @param {Quaternion} options.orientation The orientation of the frustum.
  1576. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  1577. */
  1578. function FrustumGeometry(options) {
  1579. //>>includeStart('debug', pragmas.debug);
  1580. Check.Check.typeOf.object('options', options);
  1581. Check.Check.typeOf.object('options.frustum', options.frustum);
  1582. Check.Check.typeOf.object('options.origin', options.origin);
  1583. Check.Check.typeOf.object('options.orientation', options.orientation);
  1584. //>>includeEnd('debug');
  1585. var frustum = options.frustum;
  1586. var orientation = options.orientation;
  1587. var origin = options.origin;
  1588. var vertexFormat = when.defaultValue(options.vertexFormat, VertexFormat.VertexFormat.DEFAULT);
  1589. // This is private because it is used by DebugCameraPrimitive to draw a multi-frustum by
  1590. // creating multiple FrustumGeometrys. This way the near plane of one frustum doesn't overlap
  1591. // the far plane of another.
  1592. var drawNearPlane = when.defaultValue(options._drawNearPlane, true);
  1593. var frustumType;
  1594. var frustumPackedLength;
  1595. if (frustum instanceof PerspectiveFrustum) {
  1596. frustumType = PERSPECTIVE;
  1597. frustumPackedLength = PerspectiveFrustum.packedLength;
  1598. } else if (frustum instanceof OrthographicFrustum) {
  1599. frustumType = ORTHOGRAPHIC;
  1600. frustumPackedLength = OrthographicFrustum.packedLength;
  1601. }
  1602. this._frustumType = frustumType;
  1603. this._frustum = frustum.clone();
  1604. this._origin = Cartographic.Cartesian3.clone(origin);
  1605. this._orientation = Transforms.Quaternion.clone(orientation);
  1606. this._drawNearPlane = drawNearPlane;
  1607. this._vertexFormat = vertexFormat;
  1608. this._workerName = 'createFrustumGeometry';
  1609. /**
  1610. * The number of elements used to pack the object into an array.
  1611. * @type {Number}
  1612. */
  1613. this.packedLength = 2 + frustumPackedLength + Cartographic.Cartesian3.packedLength + Transforms.Quaternion.packedLength + VertexFormat.VertexFormat.packedLength;
  1614. }
  1615. /**
  1616. * Stores the provided instance into the provided array.
  1617. *
  1618. * @param {FrustumGeometry} value The value to pack.
  1619. * @param {Number[]} array The array to pack into.
  1620. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  1621. *
  1622. * @returns {Number[]} The array that was packed into
  1623. */
  1624. FrustumGeometry.pack = function(value, array, startingIndex) {
  1625. //>>includeStart('debug', pragmas.debug);
  1626. Check.Check.typeOf.object('value', value);
  1627. Check.Check.defined('array', array);
  1628. //>>includeEnd('debug');
  1629. startingIndex = when.defaultValue(startingIndex, 0);
  1630. var frustumType = value._frustumType;
  1631. var frustum = value._frustum;
  1632. array[startingIndex++] = frustumType;
  1633. if (frustumType === PERSPECTIVE) {
  1634. PerspectiveFrustum.pack(frustum, array, startingIndex);
  1635. startingIndex += PerspectiveFrustum.packedLength;
  1636. } else {
  1637. OrthographicFrustum.pack(frustum, array, startingIndex);
  1638. startingIndex += OrthographicFrustum.packedLength;
  1639. }
  1640. Cartographic.Cartesian3.pack(value._origin, array, startingIndex);
  1641. startingIndex += Cartographic.Cartesian3.packedLength;
  1642. Transforms.Quaternion.pack(value._orientation, array, startingIndex);
  1643. startingIndex += Transforms.Quaternion.packedLength;
  1644. VertexFormat.VertexFormat.pack(value._vertexFormat, array, startingIndex);
  1645. startingIndex += VertexFormat.VertexFormat.packedLength;
  1646. array[startingIndex] = value._drawNearPlane ? 1.0 : 0.0;
  1647. return array;
  1648. };
  1649. var scratchPackPerspective = new PerspectiveFrustum();
  1650. var scratchPackOrthographic = new OrthographicFrustum();
  1651. var scratchPackQuaternion = new Transforms.Quaternion();
  1652. var scratchPackorigin = new Cartographic.Cartesian3();
  1653. var scratchVertexFormat = new VertexFormat.VertexFormat();
  1654. /**
  1655. * Retrieves an instance from a packed array.
  1656. *
  1657. * @param {Number[]} array The packed array.
  1658. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  1659. * @param {FrustumGeometry} [result] The object into which to store the result.
  1660. */
  1661. FrustumGeometry.unpack = function(array, startingIndex, result) {
  1662. //>>includeStart('debug', pragmas.debug);
  1663. Check.Check.defined('array', array);
  1664. //>>includeEnd('debug');
  1665. startingIndex = when.defaultValue(startingIndex, 0);
  1666. var frustumType = array[startingIndex++];
  1667. var frustum;
  1668. if (frustumType === PERSPECTIVE) {
  1669. frustum = PerspectiveFrustum.unpack(array, startingIndex, scratchPackPerspective);
  1670. startingIndex += PerspectiveFrustum.packedLength;
  1671. } else {
  1672. frustum = OrthographicFrustum.unpack(array, startingIndex, scratchPackOrthographic);
  1673. startingIndex += OrthographicFrustum.packedLength;
  1674. }
  1675. var origin = Cartographic.Cartesian3.unpack(array, startingIndex, scratchPackorigin);
  1676. startingIndex += Cartographic.Cartesian3.packedLength;
  1677. var orientation = Transforms.Quaternion.unpack(array, startingIndex, scratchPackQuaternion);
  1678. startingIndex += Transforms.Quaternion.packedLength;
  1679. var vertexFormat = VertexFormat.VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  1680. startingIndex += VertexFormat.VertexFormat.packedLength;
  1681. var drawNearPlane = array[startingIndex] === 1.0;
  1682. if (!when.defined(result)) {
  1683. return new FrustumGeometry({
  1684. frustum : frustum,
  1685. origin : origin,
  1686. orientation : orientation,
  1687. vertexFormat : vertexFormat,
  1688. _drawNearPlane : drawNearPlane
  1689. });
  1690. }
  1691. var frustumResult = frustumType === result._frustumType ? result._frustum : undefined;
  1692. result._frustum = frustum.clone(frustumResult);
  1693. result._frustumType = frustumType;
  1694. result._origin = Cartographic.Cartesian3.clone(origin, result._origin);
  1695. result._orientation = Transforms.Quaternion.clone(orientation, result._orientation);
  1696. result._vertexFormat = VertexFormat.VertexFormat.clone(vertexFormat, result._vertexFormat);
  1697. result._drawNearPlane = drawNearPlane;
  1698. return result;
  1699. };
  1700. function getAttributes(offset, normals, tangents, bitangents, st, normal, tangent, bitangent) {
  1701. var stOffset = offset / 3 * 2;
  1702. for (var i = 0; i < 4; ++i) {
  1703. if (when.defined(normals)) {
  1704. normals[offset] = normal.x;
  1705. normals[offset + 1] = normal.y;
  1706. normals[offset + 2] = normal.z;
  1707. }
  1708. if (when.defined(tangents)) {
  1709. tangents[offset] = tangent.x;
  1710. tangents[offset + 1] = tangent.y;
  1711. tangents[offset + 2] = tangent.z;
  1712. }
  1713. if (when.defined(bitangents)) {
  1714. bitangents[offset] = bitangent.x;
  1715. bitangents[offset + 1] = bitangent.y;
  1716. bitangents[offset + 2] = bitangent.z;
  1717. }
  1718. offset += 3;
  1719. }
  1720. st[stOffset] = 0.0;
  1721. st[stOffset + 1] = 0.0;
  1722. st[stOffset + 2] = 1.0;
  1723. st[stOffset + 3] = 0.0;
  1724. st[stOffset + 4] = 1.0;
  1725. st[stOffset + 5] = 1.0;
  1726. st[stOffset + 6] = 0.0;
  1727. st[stOffset + 7] = 1.0;
  1728. }
  1729. var scratchRotationMatrix = new BoundingSphere.Matrix3();
  1730. var scratchViewMatrix = new BoundingSphere.Matrix4();
  1731. var scratchInverseMatrix = new BoundingSphere.Matrix4();
  1732. var scratchXDirection = new Cartographic.Cartesian3();
  1733. var scratchYDirection = new Cartographic.Cartesian3();
  1734. var scratchZDirection = new Cartographic.Cartesian3();
  1735. var scratchNegativeX = new Cartographic.Cartesian3();
  1736. var scratchNegativeY = new Cartographic.Cartesian3();
  1737. var scratchNegativeZ = new Cartographic.Cartesian3();
  1738. var frustumSplits = new Array(3);
  1739. var frustumCornersNDC = new Array(4);
  1740. frustumCornersNDC[0] = new Cartesian4.Cartesian4(-1.0, -1.0, 1.0, 1.0);
  1741. frustumCornersNDC[1] = new Cartesian4.Cartesian4(1.0, -1.0, 1.0, 1.0);
  1742. frustumCornersNDC[2] = new Cartesian4.Cartesian4(1.0, 1.0, 1.0, 1.0);
  1743. frustumCornersNDC[3] = new Cartesian4.Cartesian4(-1.0, 1.0, 1.0, 1.0);
  1744. var scratchFrustumCorners = new Array(4);
  1745. for (var i = 0; i < 4; ++i) {
  1746. scratchFrustumCorners[i] = new Cartesian4.Cartesian4();
  1747. }
  1748. FrustumGeometry._computeNearFarPlanes = function(origin, orientation, frustumType, frustum, positions, xDirection, yDirection, zDirection) {
  1749. var rotationMatrix = BoundingSphere.Matrix3.fromQuaternion(orientation, scratchRotationMatrix);
  1750. var x = when.defaultValue(xDirection, scratchXDirection);
  1751. var y = when.defaultValue(yDirection, scratchYDirection);
  1752. var z = when.defaultValue(zDirection, scratchZDirection);
  1753. x = BoundingSphere.Matrix3.getColumn(rotationMatrix, 0, x);
  1754. y = BoundingSphere.Matrix3.getColumn(rotationMatrix, 1, y);
  1755. z = BoundingSphere.Matrix3.getColumn(rotationMatrix, 2, z);
  1756. Cartographic.Cartesian3.normalize(x, x);
  1757. Cartographic.Cartesian3.normalize(y, y);
  1758. Cartographic.Cartesian3.normalize(z, z);
  1759. Cartographic.Cartesian3.negate(x, x);
  1760. var view = BoundingSphere.Matrix4.computeView(origin, z, y, x, scratchViewMatrix);
  1761. var inverseView;
  1762. var inverseViewProjection;
  1763. if (frustumType === PERSPECTIVE) {
  1764. var projection = frustum.projectionMatrix;
  1765. var viewProjection = BoundingSphere.Matrix4.multiply(projection, view, scratchInverseMatrix);
  1766. inverseViewProjection = BoundingSphere.Matrix4.inverse(viewProjection, scratchInverseMatrix);
  1767. } else {
  1768. inverseView = BoundingSphere.Matrix4.inverseTransformation(view, scratchInverseMatrix);
  1769. }
  1770. if (when.defined(inverseViewProjection)) {
  1771. frustumSplits[0] = frustum.near;
  1772. frustumSplits[1] = frustum.far;
  1773. } else {
  1774. frustumSplits[0] = 0.0;
  1775. frustumSplits[1] = frustum.near;
  1776. frustumSplits[2] = frustum.far;
  1777. }
  1778. for (var i = 0; i < 2; ++i) {
  1779. for (var j = 0; j < 4; ++j) {
  1780. var corner = Cartesian4.Cartesian4.clone(frustumCornersNDC[j], scratchFrustumCorners[j]);
  1781. if (!when.defined(inverseViewProjection)) {
  1782. if (when.defined(frustum._offCenterFrustum)) {
  1783. frustum = frustum._offCenterFrustum;
  1784. }
  1785. var near = frustumSplits[i];
  1786. var far = frustumSplits[i + 1];
  1787. corner.x = (corner.x * (frustum.right - frustum.left) + frustum.left + frustum.right) * 0.5;
  1788. corner.y = (corner.y * (frustum.top - frustum.bottom) + frustum.bottom + frustum.top) * 0.5;
  1789. corner.z = (corner.z * (near - far) - near - far) * 0.5;
  1790. corner.w = 1.0;
  1791. BoundingSphere.Matrix4.multiplyByVector(inverseView, corner, corner);
  1792. } else {
  1793. corner = BoundingSphere.Matrix4.multiplyByVector(inverseViewProjection, corner, corner);
  1794. // Reverse perspective divide
  1795. var w = 1.0 / corner.w;
  1796. Cartographic.Cartesian3.multiplyByScalar(corner, w, corner);
  1797. Cartographic.Cartesian3.subtract(corner, origin, corner);
  1798. Cartographic.Cartesian3.normalize(corner, corner);
  1799. var fac = Cartographic.Cartesian3.dot(z, corner);
  1800. Cartographic.Cartesian3.multiplyByScalar(corner, frustumSplits[i] / fac, corner);
  1801. Cartographic.Cartesian3.add(corner, origin, corner);
  1802. }
  1803. positions[12 * i + j * 3] = corner.x;
  1804. positions[12 * i + j * 3 + 1] = corner.y;
  1805. positions[12 * i + j * 3 + 2] = corner.z;
  1806. }
  1807. }
  1808. };
  1809. /**
  1810. * Computes the geometric representation of a frustum, including its vertices, indices, and a bounding sphere.
  1811. *
  1812. * @param {FrustumGeometry} frustumGeometry A description of the frustum.
  1813. * @returns {Geometry|undefined} The computed vertices and indices.
  1814. */
  1815. FrustumGeometry.createGeometry = function(frustumGeometry) {
  1816. var frustumType = frustumGeometry._frustumType;
  1817. var frustum = frustumGeometry._frustum;
  1818. var origin = frustumGeometry._origin;
  1819. var orientation = frustumGeometry._orientation;
  1820. var drawNearPlane = frustumGeometry._drawNearPlane;
  1821. var vertexFormat = frustumGeometry._vertexFormat;
  1822. var numberOfPlanes = drawNearPlane ? 6 : 5;
  1823. var positions = new Float64Array(3 * 4 * 6);
  1824. FrustumGeometry._computeNearFarPlanes(origin, orientation, frustumType, frustum, positions);
  1825. // -x plane
  1826. var offset = 3 * 4 * 2;
  1827. positions[offset] = positions[3 * 4];
  1828. positions[offset + 1] = positions[3 * 4 + 1];
  1829. positions[offset + 2] = positions[3 * 4 + 2];
  1830. positions[offset + 3] = positions[0];
  1831. positions[offset + 4] = positions[1];
  1832. positions[offset + 5] = positions[2];
  1833. positions[offset + 6] = positions[3 * 3];
  1834. positions[offset + 7] = positions[3 * 3 + 1];
  1835. positions[offset + 8] = positions[3 * 3 + 2];
  1836. positions[offset + 9] = positions[3 * 7];
  1837. positions[offset + 10] = positions[3 * 7 + 1];
  1838. positions[offset + 11] = positions[3 * 7 + 2];
  1839. // -y plane
  1840. offset += 3 * 4;
  1841. positions[offset] = positions[3 * 5];
  1842. positions[offset + 1] = positions[3 * 5 + 1];
  1843. positions[offset + 2] = positions[3 * 5 + 2];
  1844. positions[offset + 3] = positions[3];
  1845. positions[offset + 4] = positions[3 + 1];
  1846. positions[offset + 5] = positions[3 + 2];
  1847. positions[offset + 6] = positions[0];
  1848. positions[offset + 7] = positions[1];
  1849. positions[offset + 8] = positions[2];
  1850. positions[offset + 9] = positions[3 * 4];
  1851. positions[offset + 10] = positions[3 * 4 + 1];
  1852. positions[offset + 11] = positions[3 * 4 + 2];
  1853. // +x plane
  1854. offset += 3 * 4;
  1855. positions[offset] = positions[3];
  1856. positions[offset + 1] = positions[3 + 1];
  1857. positions[offset + 2] = positions[3 + 2];
  1858. positions[offset + 3] = positions[3 * 5];
  1859. positions[offset + 4] = positions[3 * 5 + 1];
  1860. positions[offset + 5] = positions[3 * 5 + 2];
  1861. positions[offset + 6] = positions[3 * 6];
  1862. positions[offset + 7] = positions[3 * 6 + 1];
  1863. positions[offset + 8] = positions[3 * 6 + 2];
  1864. positions[offset + 9] = positions[3 * 2];
  1865. positions[offset + 10] = positions[3 * 2 + 1];
  1866. positions[offset + 11] = positions[3 * 2 + 2];
  1867. // +y plane
  1868. offset += 3 * 4;
  1869. positions[offset] = positions[3 * 2];
  1870. positions[offset + 1] = positions[3 * 2 + 1];
  1871. positions[offset + 2] = positions[3 * 2 + 2];
  1872. positions[offset + 3] = positions[3 * 6];
  1873. positions[offset + 4] = positions[3 * 6 + 1];
  1874. positions[offset + 5] = positions[3 * 6 + 2];
  1875. positions[offset + 6] = positions[3 * 7];
  1876. positions[offset + 7] = positions[3 * 7 + 1];
  1877. positions[offset + 8] = positions[3 * 7 + 2];
  1878. positions[offset + 9] = positions[3 * 3];
  1879. positions[offset + 10] = positions[3 * 3 + 1];
  1880. positions[offset + 11] = positions[3 * 3 + 2];
  1881. if (!drawNearPlane) {
  1882. positions = positions.subarray(3 * 4);
  1883. }
  1884. var attributes = new GeometryAttributes.GeometryAttributes({
  1885. position : new GeometryAttribute.GeometryAttribute({
  1886. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  1887. componentsPerAttribute : 3,
  1888. values : positions
  1889. })
  1890. });
  1891. if (when.defined(vertexFormat.normal) || when.defined(vertexFormat.tangent) || when.defined(vertexFormat.bitangent) || when.defined(vertexFormat.st)) {
  1892. var normals = when.defined(vertexFormat.normal) ? new Float32Array(3 * 4 * numberOfPlanes) : undefined;
  1893. var tangents = when.defined(vertexFormat.tangent) ? new Float32Array(3 * 4 * numberOfPlanes) : undefined;
  1894. var bitangents = when.defined(vertexFormat.bitangent) ? new Float32Array(3 * 4 * numberOfPlanes) : undefined;
  1895. var st = when.defined(vertexFormat.st) ? new Float32Array(2 * 4 * numberOfPlanes) : undefined;
  1896. var x = scratchXDirection;
  1897. var y = scratchYDirection;
  1898. var z = scratchZDirection;
  1899. var negativeX = Cartographic.Cartesian3.negate(x, scratchNegativeX);
  1900. var negativeY = Cartographic.Cartesian3.negate(y, scratchNegativeY);
  1901. var negativeZ = Cartographic.Cartesian3.negate(z, scratchNegativeZ);
  1902. offset = 0;
  1903. if (drawNearPlane) {
  1904. getAttributes(offset, normals, tangents, bitangents, st, negativeZ, x, y); // near
  1905. offset += 3 * 4;
  1906. }
  1907. getAttributes(offset, normals, tangents, bitangents, st, z, negativeX, y); // far
  1908. offset += 3 * 4;
  1909. getAttributes(offset, normals, tangents, bitangents, st, negativeX, negativeZ, y); // -x
  1910. offset += 3 * 4;
  1911. getAttributes(offset, normals, tangents, bitangents, st, negativeY, negativeZ, negativeX); // -y
  1912. offset += 3 * 4;
  1913. getAttributes(offset, normals, tangents, bitangents, st, x, z, y); // +x
  1914. offset += 3 * 4;
  1915. getAttributes(offset, normals, tangents, bitangents, st, y, z, negativeX); // +y
  1916. if (when.defined(normals)) {
  1917. attributes.normal = new GeometryAttribute.GeometryAttribute({
  1918. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1919. componentsPerAttribute : 3,
  1920. values : normals
  1921. });
  1922. }
  1923. if (when.defined(tangents)) {
  1924. attributes.tangent = new GeometryAttribute.GeometryAttribute({
  1925. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1926. componentsPerAttribute : 3,
  1927. values : tangents
  1928. });
  1929. }
  1930. if (when.defined(bitangents)) {
  1931. attributes.bitangent = new GeometryAttribute.GeometryAttribute({
  1932. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1933. componentsPerAttribute : 3,
  1934. values : bitangents
  1935. });
  1936. }
  1937. if (when.defined(st)) {
  1938. attributes.st = new GeometryAttribute.GeometryAttribute({
  1939. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1940. componentsPerAttribute : 2,
  1941. values : st
  1942. });
  1943. }
  1944. }
  1945. var indices = new Uint16Array(6 * numberOfPlanes);
  1946. for (var i = 0; i < numberOfPlanes; ++i) {
  1947. var indexOffset = i * 6;
  1948. var index = i * 4;
  1949. indices[indexOffset] = index;
  1950. indices[indexOffset + 1] = index + 1;
  1951. indices[indexOffset + 2] = index + 2;
  1952. indices[indexOffset + 3] = index;
  1953. indices[indexOffset + 4] = index + 2;
  1954. indices[indexOffset + 5] = index + 3;
  1955. }
  1956. return new GeometryAttribute.Geometry({
  1957. attributes : attributes,
  1958. indices : indices,
  1959. primitiveType : PrimitiveType.PrimitiveType.TRIANGLES,
  1960. boundingSphere : BoundingSphere.BoundingSphere.fromVertices(positions)
  1961. });
  1962. };
  1963. exports.FrustumGeometry = FrustumGeometry;
  1964. exports.OrthographicFrustum = OrthographicFrustum;
  1965. exports.PerspectiveFrustum = PerspectiveFrustum;
  1966. });