FrustumGeometry-38605e69.js 83 KB

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