FrustumGeometry-9ff1d87f.js 83 KB

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