| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513 | /* This file is automatically rebuilt by the Cesium build process. */define(['exports', './Transforms-323408fe', './Matrix2-69c32d33', './RuntimeError-c581ca93', './ComponentDatatype-b1ea011a', './defaultValue-94c3e563', './GeometryAttribute-cb73bb3f', './GeometryAttributes-7df9bef6', './Plane-069b6800', './VertexFormat-e46f29d6'], (function (exports, Transforms, Matrix2, RuntimeError, ComponentDatatype, defaultValue, GeometryAttribute, GeometryAttributes, Plane, VertexFormat) { 'use strict';  /**   * The culling volume defined by planes.   *   * @alias CullingVolume   * @constructor   *   * @param {Cartesian4[]} [planes] An array of clipping planes.   */  function CullingVolume(planes) {    /**     * Each plane is represented by a Cartesian4 object, where the x, y, and z components     * define the unit vector normal to the plane, and the w component is the distance of the     * plane from the origin.     * @type {Cartesian4[]}     * @default []     */    this.planes = defaultValue.defaultValue(planes, []);  }  const faces = [new Matrix2.Cartesian3(), new Matrix2.Cartesian3(), new Matrix2.Cartesian3()];  Matrix2.Cartesian3.clone(Matrix2.Cartesian3.UNIT_X, faces[0]);  Matrix2.Cartesian3.clone(Matrix2.Cartesian3.UNIT_Y, faces[1]);  Matrix2.Cartesian3.clone(Matrix2.Cartesian3.UNIT_Z, faces[2]);  const scratchPlaneCenter = new Matrix2.Cartesian3();  const scratchPlaneNormal = new Matrix2.Cartesian3();  const scratchPlane = new Plane.Plane(new Matrix2.Cartesian3(1.0, 0.0, 0.0), 0.0);  /**   * Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.   * The planes are aligned to the x, y, and z axes in world coordinates.   *   * @param {BoundingSphere} boundingSphere The bounding sphere used to create the culling volume.   * @param {CullingVolume} [result] The object onto which to store the result.   * @returns {CullingVolume} The culling volume created from the bounding sphere.   */  CullingVolume.fromBoundingSphere = function (boundingSphere, result) {    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(boundingSphere)) {      throw new RuntimeError.DeveloperError("boundingSphere is required.");    }    //>>includeEnd('debug');    if (!defaultValue.defined(result)) {      result = new CullingVolume();    }    const length = faces.length;    const planes = result.planes;    planes.length = 2 * length;    const center = boundingSphere.center;    const radius = boundingSphere.radius;    let planeIndex = 0;    for (let i = 0; i < length; ++i) {      const faceNormal = faces[i];      let plane0 = planes[planeIndex];      let plane1 = planes[planeIndex + 1];      if (!defaultValue.defined(plane0)) {        plane0 = planes[planeIndex] = new Matrix2.Cartesian4();      }      if (!defaultValue.defined(plane1)) {        plane1 = planes[planeIndex + 1] = new Matrix2.Cartesian4();      }      Matrix2.Cartesian3.multiplyByScalar(faceNormal, -radius, scratchPlaneCenter);      Matrix2.Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);      plane0.x = faceNormal.x;      plane0.y = faceNormal.y;      plane0.z = faceNormal.z;      plane0.w = -Matrix2.Cartesian3.dot(faceNormal, scratchPlaneCenter);      Matrix2.Cartesian3.multiplyByScalar(faceNormal, radius, scratchPlaneCenter);      Matrix2.Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);      plane1.x = -faceNormal.x;      plane1.y = -faceNormal.y;      plane1.z = -faceNormal.z;      plane1.w = -Matrix2.Cartesian3.dot(        Matrix2.Cartesian3.negate(faceNormal, scratchPlaneNormal),        scratchPlaneCenter      );      planeIndex += 2;    }    return result;  };  /**   * Determines whether a bounding volume intersects the culling volume.   *   * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.   * @returns {Intersect}  Intersect.OUTSIDE, Intersect.INTERSECTING, or Intersect.INSIDE.   */  CullingVolume.prototype.computeVisibility = function (boundingVolume) {    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(boundingVolume)) {      throw new RuntimeError.DeveloperError("boundingVolume is required.");    }    //>>includeEnd('debug');    const planes = this.planes;    let intersecting = false;    for (let k = 0, len = planes.length; k < len; ++k) {      const result = boundingVolume.intersectPlane(        Plane.Plane.fromCartesian4(planes[k], scratchPlane)      );      if (result === Transforms.Intersect.OUTSIDE) {        return Transforms.Intersect.OUTSIDE;      } else if (result === Transforms.Intersect.INTERSECTING) {        intersecting = true;      }    }    return intersecting ? Transforms.Intersect.INTERSECTING : Transforms.Intersect.INSIDE;  };  /**   * Determines whether a bounding volume intersects the culling volume.   *   * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.   * @param {Number} parentPlaneMask A bit mask from the boundingVolume's parent's check against the same culling   *                                 volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then   *                                 the parent (and therefore this) volume is completely inside plane[planeIndex]   *                                 and that plane check can be skipped.   * @returns {Number} A plane mask as described above (which can be applied to this boundingVolume's children).   *   * @private   */  CullingVolume.prototype.computeVisibilityWithPlaneMask = function (    boundingVolume,    parentPlaneMask  ) {    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(boundingVolume)) {      throw new RuntimeError.DeveloperError("boundingVolume is required.");    }    if (!defaultValue.defined(parentPlaneMask)) {      throw new RuntimeError.DeveloperError("parentPlaneMask is required.");    }    //>>includeEnd('debug');    if (      parentPlaneMask === CullingVolume.MASK_OUTSIDE ||      parentPlaneMask === CullingVolume.MASK_INSIDE    ) {      // parent is completely outside or completely inside, so this child is as well.      return parentPlaneMask;    }    // Start with MASK_INSIDE (all zeros) so that after the loop, the return value can be compared with MASK_INSIDE.    // (Because if there are fewer than 31 planes, the upper bits wont be changed.)    let mask = CullingVolume.MASK_INSIDE;    const planes = this.planes;    for (let k = 0, len = planes.length; k < len; ++k) {      // For k greater than 31 (since 31 is the maximum number of INSIDE/INTERSECTING bits we can store), skip the optimization.      const flag = k < 31 ? 1 << k : 0;      if (k < 31 && (parentPlaneMask & flag) === 0) {        // boundingVolume is known to be INSIDE this plane.        continue;      }      const result = boundingVolume.intersectPlane(        Plane.Plane.fromCartesian4(planes[k], scratchPlane)      );      if (result === Transforms.Intersect.OUTSIDE) {        return CullingVolume.MASK_OUTSIDE;      } else if (result === Transforms.Intersect.INTERSECTING) {        mask |= flag;      }    }    return mask;  };  /**   * For plane masks (as used in {@link CullingVolume#computeVisibilityWithPlaneMask}), this special value   * represents the case where the object bounding volume is entirely outside the culling volume.   *   * @type {Number}   * @private   */  CullingVolume.MASK_OUTSIDE = 0xffffffff;  /**   * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value   * represents the case where the object bounding volume is entirely inside the culling volume.   *   * @type {Number}   * @private   */  CullingVolume.MASK_INSIDE = 0x00000000;  /**   * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value   * represents the case where the object bounding volume (may) intersect all planes of the culling volume.   *   * @type {Number}   * @private   */  CullingVolume.MASK_INDETERMINATE = 0x7fffffff;  /**   * The viewing frustum is defined by 6 planes.   * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components   * define the unit vector normal to the plane, and the w component is the distance of the   * plane from the origin/camera position.   *   * @alias OrthographicOffCenterFrustum   * @constructor   *   * @param {Object} [options] An object with the following properties:   * @param {Number} [options.left] The left clipping plane distance.   * @param {Number} [options.right] The right clipping plane distance.   * @param {Number} [options.top] The top clipping plane distance.   * @param {Number} [options.bottom] The bottom clipping plane distance.   * @param {Number} [options.near=1.0] The near clipping plane distance.   * @param {Number} [options.far=500000000.0] The far clipping plane distance.   *   * @example   * const maxRadii = ellipsoid.maximumRadius;   *   * const frustum = new Cesium.OrthographicOffCenterFrustum();   * frustum.right = maxRadii * Cesium.Math.PI;   * frustum.left = -c.frustum.right;   * frustum.top = c.frustum.right * (canvas.clientHeight / canvas.clientWidth);   * frustum.bottom = -c.frustum.top;   * frustum.near = 0.01 * maxRadii;   * frustum.far = 50.0 * maxRadii;   */  function OrthographicOffCenterFrustum(options) {    options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);    /**     * The left clipping plane.     * @type {Number}     * @default undefined     */    this.left = options.left;    this._left = undefined;    /**     * The right clipping plane.     * @type {Number}     * @default undefined     */    this.right = options.right;    this._right = undefined;    /**     * The top clipping plane.     * @type {Number}     * @default undefined     */    this.top = options.top;    this._top = undefined;    /**     * The bottom clipping plane.     * @type {Number}     * @default undefined     */    this.bottom = options.bottom;    this._bottom = undefined;    /**     * The distance of the near plane.     * @type {Number}     * @default 1.0     */    this.near = defaultValue.defaultValue(options.near, 1.0);    this._near = this.near;    /**     * The distance of the far plane.     * @type {Number}     * @default 500000000.0;     */    this.far = defaultValue.defaultValue(options.far, 500000000.0);    this._far = this.far;    this._cullingVolume = new CullingVolume();    this._orthographicMatrix = new Matrix2.Matrix4();  }  function update$3(frustum) {    //>>includeStart('debug', pragmas.debug);    if (      !defaultValue.defined(frustum.right) ||      !defaultValue.defined(frustum.left) ||      !defaultValue.defined(frustum.top) ||      !defaultValue.defined(frustum.bottom) ||      !defaultValue.defined(frustum.near) ||      !defaultValue.defined(frustum.far)    ) {      throw new RuntimeError.DeveloperError(        "right, left, top, bottom, near, or far parameters are not set."      );    }    //>>includeEnd('debug');    if (      frustum.top !== frustum._top ||      frustum.bottom !== frustum._bottom ||      frustum.left !== frustum._left ||      frustum.right !== frustum._right ||      frustum.near !== frustum._near ||      frustum.far !== frustum._far    ) {      //>>includeStart('debug', pragmas.debug);      if (frustum.left > frustum.right) {        throw new RuntimeError.DeveloperError("right must be greater than left.");      }      if (frustum.bottom > frustum.top) {        throw new RuntimeError.DeveloperError("top must be greater than bottom.");      }      if (frustum.near <= 0 || frustum.near > frustum.far) {        throw new RuntimeError.DeveloperError(          "near must be greater than zero and less than far."        );      }      //>>includeEnd('debug');      frustum._left = frustum.left;      frustum._right = frustum.right;      frustum._top = frustum.top;      frustum._bottom = frustum.bottom;      frustum._near = frustum.near;      frustum._far = frustum.far;      frustum._orthographicMatrix = Matrix2.Matrix4.computeOrthographicOffCenter(        frustum.left,        frustum.right,        frustum.bottom,        frustum.top,        frustum.near,        frustum.far,        frustum._orthographicMatrix      );    }  }  Object.defineProperties(OrthographicOffCenterFrustum.prototype, {    /**     * Gets the orthographic projection matrix computed from the view frustum.     * @memberof OrthographicOffCenterFrustum.prototype     * @type {Matrix4}     * @readonly     */    projectionMatrix: {      get: function () {        update$3(this);        return this._orthographicMatrix;      },    },  });  const getPlanesRight$1 = new Matrix2.Cartesian3();  const getPlanesNearCenter$1 = new Matrix2.Cartesian3();  const getPlanesPoint = new Matrix2.Cartesian3();  const negateScratch = new Matrix2.Cartesian3();  /**   * Creates a culling volume for this frustum.   *   * @param {Cartesian3} position The eye position.   * @param {Cartesian3} direction The view direction.   * @param {Cartesian3} up The up direction.   * @returns {CullingVolume} A culling volume at the given position and orientation.   *   * @example   * // Check if a bounding volume intersects the frustum.   * const cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);   * const intersect = cullingVolume.computeVisibility(boundingVolume);   */  OrthographicOffCenterFrustum.prototype.computeCullingVolume = function (    position,    direction,    up  ) {    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(position)) {      throw new RuntimeError.DeveloperError("position is required.");    }    if (!defaultValue.defined(direction)) {      throw new RuntimeError.DeveloperError("direction is required.");    }    if (!defaultValue.defined(up)) {      throw new RuntimeError.DeveloperError("up is required.");    }    //>>includeEnd('debug');    const planes = this._cullingVolume.planes;    const t = this.top;    const b = this.bottom;    const r = this.right;    const l = this.left;    const n = this.near;    const f = this.far;    const right = Matrix2.Cartesian3.cross(direction, up, getPlanesRight$1);    Matrix2.Cartesian3.normalize(right, right);    const nearCenter = getPlanesNearCenter$1;    Matrix2.Cartesian3.multiplyByScalar(direction, n, nearCenter);    Matrix2.Cartesian3.add(position, nearCenter, nearCenter);    const point = getPlanesPoint;    // Left plane    Matrix2.Cartesian3.multiplyByScalar(right, l, point);    Matrix2.Cartesian3.add(nearCenter, point, point);    let plane = planes[0];    if (!defaultValue.defined(plane)) {      plane = planes[0] = new Matrix2.Cartesian4();    }    plane.x = right.x;    plane.y = right.y;    plane.z = right.z;    plane.w = -Matrix2.Cartesian3.dot(right, point);    // Right plane    Matrix2.Cartesian3.multiplyByScalar(right, r, point);    Matrix2.Cartesian3.add(nearCenter, point, point);    plane = planes[1];    if (!defaultValue.defined(plane)) {      plane = planes[1] = new Matrix2.Cartesian4();    }    plane.x = -right.x;    plane.y = -right.y;    plane.z = -right.z;    plane.w = -Matrix2.Cartesian3.dot(Matrix2.Cartesian3.negate(right, negateScratch), point);    // Bottom plane    Matrix2.Cartesian3.multiplyByScalar(up, b, point);    Matrix2.Cartesian3.add(nearCenter, point, point);    plane = planes[2];    if (!defaultValue.defined(plane)) {      plane = planes[2] = new Matrix2.Cartesian4();    }    plane.x = up.x;    plane.y = up.y;    plane.z = up.z;    plane.w = -Matrix2.Cartesian3.dot(up, point);    // Top plane    Matrix2.Cartesian3.multiplyByScalar(up, t, point);    Matrix2.Cartesian3.add(nearCenter, point, point);    plane = planes[3];    if (!defaultValue.defined(plane)) {      plane = planes[3] = new Matrix2.Cartesian4();    }    plane.x = -up.x;    plane.y = -up.y;    plane.z = -up.z;    plane.w = -Matrix2.Cartesian3.dot(Matrix2.Cartesian3.negate(up, negateScratch), point);    // Near plane    plane = planes[4];    if (!defaultValue.defined(plane)) {      plane = planes[4] = new Matrix2.Cartesian4();    }    plane.x = direction.x;    plane.y = direction.y;    plane.z = direction.z;    plane.w = -Matrix2.Cartesian3.dot(direction, nearCenter);    // Far plane    Matrix2.Cartesian3.multiplyByScalar(direction, f, point);    Matrix2.Cartesian3.add(position, point, point);    plane = planes[5];    if (!defaultValue.defined(plane)) {      plane = planes[5] = new Matrix2.Cartesian4();    }    plane.x = -direction.x;    plane.y = -direction.y;    plane.z = -direction.z;    plane.w = -Matrix2.Cartesian3.dot(Matrix2.Cartesian3.negate(direction, negateScratch), point);    return this._cullingVolume;  };  /**   * Returns the pixel's width and height in meters.   *   * @param {Number} drawingBufferWidth The width of the drawing buffer.   * @param {Number} drawingBufferHeight The height of the drawing buffer.   * @param {Number} distance The distance to the near plane in meters.   * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.   * @param {Cartesian2} result The object onto which to store the result.   * @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.   *   * @exception {DeveloperError} drawingBufferWidth must be greater than zero.   * @exception {DeveloperError} drawingBufferHeight must be greater than zero.   * @exception {DeveloperError} pixelRatio must be greater than zero.   *   * @example   * // Example 1   * // Get the width and height of a pixel.   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 0.0, scene.pixelRatio, new Cesium.Cartesian2());   */  OrthographicOffCenterFrustum.prototype.getPixelDimensions = function (    drawingBufferWidth,    drawingBufferHeight,    distance,    pixelRatio,    result  ) {    update$3(this);    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(drawingBufferWidth) || !defaultValue.defined(drawingBufferHeight)) {      throw new RuntimeError.DeveloperError(        "Both drawingBufferWidth and drawingBufferHeight are required."      );    }    if (drawingBufferWidth <= 0) {      throw new RuntimeError.DeveloperError("drawingBufferWidth must be greater than zero.");    }    if (drawingBufferHeight <= 0) {      throw new RuntimeError.DeveloperError("drawingBufferHeight must be greater than zero.");    }    if (!defaultValue.defined(distance)) {      throw new RuntimeError.DeveloperError("distance is required.");    }    if (!defaultValue.defined(pixelRatio)) {      throw new RuntimeError.DeveloperError("pixelRatio is required.");    }    if (pixelRatio <= 0) {      throw new RuntimeError.DeveloperError("pixelRatio must be greater than zero.");    }    if (!defaultValue.defined(result)) {      throw new RuntimeError.DeveloperError("A result object is required.");    }    //>>includeEnd('debug');    const frustumWidth = this.right - this.left;    const frustumHeight = this.top - this.bottom;    const pixelWidth = (pixelRatio * frustumWidth) / drawingBufferWidth;    const pixelHeight = (pixelRatio * frustumHeight) / drawingBufferHeight;    result.x = pixelWidth;    result.y = pixelHeight;    return result;  };  /**   * Returns a duplicate of a OrthographicOffCenterFrustum instance.   *   * @param {OrthographicOffCenterFrustum} [result] The object onto which to store the result.   * @returns {OrthographicOffCenterFrustum} The modified result parameter or a new OrthographicOffCenterFrustum instance if one was not provided.   */  OrthographicOffCenterFrustum.prototype.clone = function (result) {    if (!defaultValue.defined(result)) {      result = new OrthographicOffCenterFrustum();    }    result.left = this.left;    result.right = this.right;    result.top = this.top;    result.bottom = this.bottom;    result.near = this.near;    result.far = this.far;    // force update of clone to compute matrices    result._left = undefined;    result._right = undefined;    result._top = undefined;    result._bottom = undefined;    result._near = undefined;    result._far = undefined;    return result;  };  /**   * Compares the provided OrthographicOffCenterFrustum componentwise and returns   * <code>true</code> if they are equal, <code>false</code> otherwise.   *   * @param {OrthographicOffCenterFrustum} [other] The right hand side OrthographicOffCenterFrustum.   * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.   */  OrthographicOffCenterFrustum.prototype.equals = function (other) {    return (      defaultValue.defined(other) &&      other instanceof OrthographicOffCenterFrustum &&      this.right === other.right &&      this.left === other.left &&      this.top === other.top &&      this.bottom === other.bottom &&      this.near === other.near &&      this.far === other.far    );  };  /**   * Compares the provided OrthographicOffCenterFrustum componentwise and returns   * <code>true</code> if they pass an absolute or relative tolerance test,   * <code>false</code> otherwise.   *   * @param {OrthographicOffCenterFrustum} other The right hand side OrthographicOffCenterFrustum.   * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.   * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.   * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.   */  OrthographicOffCenterFrustum.prototype.equalsEpsilon = function (    other,    relativeEpsilon,    absoluteEpsilon  ) {    return (      other === this ||      (defaultValue.defined(other) &&        other instanceof OrthographicOffCenterFrustum &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.right,          other.right,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.left,          other.left,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.top,          other.top,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.bottom,          other.bottom,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.near,          other.near,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.far,          other.far,          relativeEpsilon,          absoluteEpsilon        ))    );  };  /**   * The viewing frustum is defined by 6 planes.   * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components   * define the unit vector normal to the plane, and the w component is the distance of the   * plane from the origin/camera position.   *   * @alias OrthographicFrustum   * @constructor   *   * @param {Object} [options] An object with the following properties:   * @param {Number} [options.width] The width of the frustum in meters.   * @param {Number} [options.aspectRatio] The aspect ratio of the frustum's width to it's height.   * @param {Number} [options.near=1.0] The distance of the near plane.   * @param {Number} [options.far=500000000.0] The distance of the far plane.   *   * @example   * const maxRadii = ellipsoid.maximumRadius;   *   * const frustum = new Cesium.OrthographicFrustum();   * frustum.near = 0.01 * maxRadii;   * frustum.far = 50.0 * maxRadii;   */  function OrthographicFrustum(options) {    options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);    this._offCenterFrustum = new OrthographicOffCenterFrustum();    /**     * The horizontal width of the frustum in meters.     * @type {Number}     * @default undefined     */    this.width = options.width;    this._width = undefined;    /**     * The aspect ratio of the frustum's width to it's height.     * @type {Number}     * @default undefined     */    this.aspectRatio = options.aspectRatio;    this._aspectRatio = undefined;    /**     * The distance of the near plane.     * @type {Number}     * @default 1.0     */    this.near = defaultValue.defaultValue(options.near, 1.0);    this._near = this.near;    /**     * The distance of the far plane.     * @type {Number}     * @default 500000000.0;     */    this.far = defaultValue.defaultValue(options.far, 500000000.0);    this._far = this.far;  }  /**   * The number of elements used to pack the object into an array.   * @type {Number}   */  OrthographicFrustum.packedLength = 4;  /**   * Stores the provided instance into the provided array.   *   * @param {OrthographicFrustum} value The value to pack.   * @param {Number[]} array The array to pack into.   * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.   *   * @returns {Number[]} The array that was packed into   */  OrthographicFrustum.pack = function (value, array, startingIndex) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.typeOf.object("value", value);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    array[startingIndex++] = value.width;    array[startingIndex++] = value.aspectRatio;    array[startingIndex++] = value.near;    array[startingIndex] = value.far;    return array;  };  /**   * Retrieves an instance from a packed array.   *   * @param {Number[]} array The packed array.   * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.   * @param {OrthographicFrustum} [result] The object into which to store the result.   * @returns {OrthographicFrustum} The modified result parameter or a new OrthographicFrustum instance if one was not provided.   */  OrthographicFrustum.unpack = function (array, startingIndex, result) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    if (!defaultValue.defined(result)) {      result = new OrthographicFrustum();    }    result.width = array[startingIndex++];    result.aspectRatio = array[startingIndex++];    result.near = array[startingIndex++];    result.far = array[startingIndex];    return result;  };  function update$2(frustum) {    //>>includeStart('debug', pragmas.debug);    if (      !defaultValue.defined(frustum.width) ||      !defaultValue.defined(frustum.aspectRatio) ||      !defaultValue.defined(frustum.near) ||      !defaultValue.defined(frustum.far)    ) {      throw new RuntimeError.DeveloperError(        "width, aspectRatio, near, or far parameters are not set."      );    }    //>>includeEnd('debug');    const f = frustum._offCenterFrustum;    if (      frustum.width !== frustum._width ||      frustum.aspectRatio !== frustum._aspectRatio ||      frustum.near !== frustum._near ||      frustum.far !== frustum._far    ) {      //>>includeStart('debug', pragmas.debug);      if (frustum.aspectRatio < 0) {        throw new RuntimeError.DeveloperError("aspectRatio must be positive.");      }      if (frustum.near < 0 || frustum.near > frustum.far) {        throw new RuntimeError.DeveloperError(          "near must be greater than zero and less than far."        );      }      //>>includeEnd('debug');      frustum._aspectRatio = frustum.aspectRatio;      frustum._width = frustum.width;      frustum._near = frustum.near;      frustum._far = frustum.far;      const ratio = 1.0 / frustum.aspectRatio;      f.right = frustum.width * 0.5;      f.left = -f.right;      f.top = ratio * f.right;      f.bottom = -f.top;      f.near = frustum.near;      f.far = frustum.far;    }  }  Object.defineProperties(OrthographicFrustum.prototype, {    /**     * Gets the orthographic projection matrix computed from the view frustum.     * @memberof OrthographicFrustum.prototype     * @type {Matrix4}     * @readonly     */    projectionMatrix: {      get: function () {        update$2(this);        return this._offCenterFrustum.projectionMatrix;      },    },  });  /**   * Creates a culling volume for this frustum.   *   * @param {Cartesian3} position The eye position.   * @param {Cartesian3} direction The view direction.   * @param {Cartesian3} up The up direction.   * @returns {CullingVolume} A culling volume at the given position and orientation.   *   * @example   * // Check if a bounding volume intersects the frustum.   * const cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);   * const intersect = cullingVolume.computeVisibility(boundingVolume);   */  OrthographicFrustum.prototype.computeCullingVolume = function (    position,    direction,    up  ) {    update$2(this);    return this._offCenterFrustum.computeCullingVolume(position, direction, up);  };  /**   * Returns the pixel's width and height in meters.   *   * @param {Number} drawingBufferWidth The width of the drawing buffer.   * @param {Number} drawingBufferHeight The height of the drawing buffer.   * @param {Number} distance The distance to the near plane in meters.   * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.   * @param {Cartesian2} result The object onto which to store the result.   * @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.   *   * @exception {DeveloperError} drawingBufferWidth must be greater than zero.   * @exception {DeveloperError} drawingBufferHeight must be greater than zero.   * @exception {DeveloperError} pixelRatio must be greater than zero.   *   * @example   * // Example 1   * // Get the width and height of a pixel.   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 0.0, scene.pixelRatio, new Cesium.Cartesian2());   */  OrthographicFrustum.prototype.getPixelDimensions = function (    drawingBufferWidth,    drawingBufferHeight,    distance,    pixelRatio,    result  ) {    update$2(this);    return this._offCenterFrustum.getPixelDimensions(      drawingBufferWidth,      drawingBufferHeight,      distance,      pixelRatio,      result    );  };  /**   * Returns a duplicate of a OrthographicFrustum instance.   *   * @param {OrthographicFrustum} [result] The object onto which to store the result.   * @returns {OrthographicFrustum} The modified result parameter or a new OrthographicFrustum instance if one was not provided.   */  OrthographicFrustum.prototype.clone = function (result) {    if (!defaultValue.defined(result)) {      result = new OrthographicFrustum();    }    result.aspectRatio = this.aspectRatio;    result.width = this.width;    result.near = this.near;    result.far = this.far;    // force update of clone to compute matrices    result._aspectRatio = undefined;    result._width = undefined;    result._near = undefined;    result._far = undefined;    this._offCenterFrustum.clone(result._offCenterFrustum);    return result;  };  /**   * Compares the provided OrthographicFrustum componentwise and returns   * <code>true</code> if they are equal, <code>false</code> otherwise.   *   * @param {OrthographicFrustum} [other] The right hand side OrthographicFrustum.   * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.   */  OrthographicFrustum.prototype.equals = function (other) {    if (!defaultValue.defined(other) || !(other instanceof OrthographicFrustum)) {      return false;    }    update$2(this);    update$2(other);    return (      this.width === other.width &&      this.aspectRatio === other.aspectRatio &&      this._offCenterFrustum.equals(other._offCenterFrustum)    );  };  /**   * Compares the provided OrthographicFrustum componentwise and returns   * <code>true</code> if they pass an absolute or relative tolerance test,   * <code>false</code> otherwise.   *   * @param {OrthographicFrustum} other The right hand side OrthographicFrustum.   * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.   * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.   * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.   */  OrthographicFrustum.prototype.equalsEpsilon = function (    other,    relativeEpsilon,    absoluteEpsilon  ) {    if (!defaultValue.defined(other) || !(other instanceof OrthographicFrustum)) {      return false;    }    update$2(this);    update$2(other);    return (      ComponentDatatype.CesiumMath.equalsEpsilon(        this.width,        other.width,        relativeEpsilon,        absoluteEpsilon      ) &&      ComponentDatatype.CesiumMath.equalsEpsilon(        this.aspectRatio,        other.aspectRatio,        relativeEpsilon,        absoluteEpsilon      ) &&      this._offCenterFrustum.equalsEpsilon(        other._offCenterFrustum,        relativeEpsilon,        absoluteEpsilon      )    );  };  /**   * The viewing frustum is defined by 6 planes.   * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components   * define the unit vector normal to the plane, and the w component is the distance of the   * plane from the origin/camera position.   *   * @alias PerspectiveOffCenterFrustum   * @constructor   *   * @param {Object} [options] An object with the following properties:   * @param {Number} [options.left] The left clipping plane distance.   * @param {Number} [options.right] The right clipping plane distance.   * @param {Number} [options.top] The top clipping plane distance.   * @param {Number} [options.bottom] The bottom clipping plane distance.   * @param {Number} [options.near=1.0] The near clipping plane distance.   * @param {Number} [options.far=500000000.0] The far clipping plane distance.   *   * @example   * const frustum = new Cesium.PerspectiveOffCenterFrustum({   *     left : -1.0,   *     right : 1.0,   *     top : 1.0,   *     bottom : -1.0,   *     near : 1.0,   *     far : 100.0   * });   *   * @see PerspectiveFrustum   */  function PerspectiveOffCenterFrustum(options) {    options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);    /**     * Defines the left clipping plane.     * @type {Number}     * @default undefined     */    this.left = options.left;    this._left = undefined;    /**     * Defines the right clipping plane.     * @type {Number}     * @default undefined     */    this.right = options.right;    this._right = undefined;    /**     * Defines the top clipping plane.     * @type {Number}     * @default undefined     */    this.top = options.top;    this._top = undefined;    /**     * Defines the bottom clipping plane.     * @type {Number}     * @default undefined     */    this.bottom = options.bottom;    this._bottom = undefined;    /**     * The distance of the near plane.     * @type {Number}     * @default 1.0     */    this.near = defaultValue.defaultValue(options.near, 1.0);    this._near = this.near;    /**     * The distance of the far plane.     * @type {Number}     * @default 500000000.0     */    this.far = defaultValue.defaultValue(options.far, 500000000.0);    this._far = this.far;    this._cullingVolume = new CullingVolume();    this._perspectiveMatrix = new Matrix2.Matrix4();    this._infinitePerspective = new Matrix2.Matrix4();  }  function update$1(frustum) {    //>>includeStart('debug', pragmas.debug);    if (      !defaultValue.defined(frustum.right) ||      !defaultValue.defined(frustum.left) ||      !defaultValue.defined(frustum.top) ||      !defaultValue.defined(frustum.bottom) ||      !defaultValue.defined(frustum.near) ||      !defaultValue.defined(frustum.far)    ) {      throw new RuntimeError.DeveloperError(        "right, left, top, bottom, near, or far parameters are not set."      );    }    //>>includeEnd('debug');    const t = frustum.top;    const b = frustum.bottom;    const r = frustum.right;    const l = frustum.left;    const n = frustum.near;    const f = frustum.far;    if (      t !== frustum._top ||      b !== frustum._bottom ||      l !== frustum._left ||      r !== frustum._right ||      n !== frustum._near ||      f !== frustum._far    ) {      //>>includeStart('debug', pragmas.debug);      if (frustum.near <= 0 || frustum.near > frustum.far) {        throw new RuntimeError.DeveloperError(          "near must be greater than zero and less than far."        );      }      //>>includeEnd('debug');      frustum._left = l;      frustum._right = r;      frustum._top = t;      frustum._bottom = b;      frustum._near = n;      frustum._far = f;      frustum._perspectiveMatrix = Matrix2.Matrix4.computePerspectiveOffCenter(        l,        r,        b,        t,        n,        f,        frustum._perspectiveMatrix      );      frustum._infinitePerspective = Matrix2.Matrix4.computeInfinitePerspectiveOffCenter(        l,        r,        b,        t,        n,        frustum._infinitePerspective      );    }  }  Object.defineProperties(PerspectiveOffCenterFrustum.prototype, {    /**     * Gets the perspective projection matrix computed from the view frustum.     * @memberof PerspectiveOffCenterFrustum.prototype     * @type {Matrix4}     * @readonly     *     * @see PerspectiveOffCenterFrustum#infiniteProjectionMatrix     */    projectionMatrix: {      get: function () {        update$1(this);        return this._perspectiveMatrix;      },    },    /**     * Gets the perspective projection matrix computed from the view frustum with an infinite far plane.     * @memberof PerspectiveOffCenterFrustum.prototype     * @type {Matrix4}     * @readonly     *     * @see PerspectiveOffCenterFrustum#projectionMatrix     */    infiniteProjectionMatrix: {      get: function () {        update$1(this);        return this._infinitePerspective;      },    },  });  const getPlanesRight = new Matrix2.Cartesian3();  const getPlanesNearCenter = new Matrix2.Cartesian3();  const getPlanesFarCenter = new Matrix2.Cartesian3();  const getPlanesNormal = new Matrix2.Cartesian3();  /**   * Creates a culling volume for this frustum.   *   * @param {Cartesian3} position The eye position.   * @param {Cartesian3} direction The view direction.   * @param {Cartesian3} up The up direction.   * @returns {CullingVolume} A culling volume at the given position and orientation.   *   * @example   * // Check if a bounding volume intersects the frustum.   * const cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);   * const intersect = cullingVolume.computeVisibility(boundingVolume);   */  PerspectiveOffCenterFrustum.prototype.computeCullingVolume = function (    position,    direction,    up  ) {    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(position)) {      throw new RuntimeError.DeveloperError("position is required.");    }    if (!defaultValue.defined(direction)) {      throw new RuntimeError.DeveloperError("direction is required.");    }    if (!defaultValue.defined(up)) {      throw new RuntimeError.DeveloperError("up is required.");    }    //>>includeEnd('debug');    const planes = this._cullingVolume.planes;    const t = this.top;    const b = this.bottom;    const r = this.right;    const l = this.left;    const n = this.near;    const f = this.far;    const right = Matrix2.Cartesian3.cross(direction, up, getPlanesRight);    const nearCenter = getPlanesNearCenter;    Matrix2.Cartesian3.multiplyByScalar(direction, n, nearCenter);    Matrix2.Cartesian3.add(position, nearCenter, nearCenter);    const farCenter = getPlanesFarCenter;    Matrix2.Cartesian3.multiplyByScalar(direction, f, farCenter);    Matrix2.Cartesian3.add(position, farCenter, farCenter);    const normal = getPlanesNormal;    //Left plane computation    Matrix2.Cartesian3.multiplyByScalar(right, l, normal);    Matrix2.Cartesian3.add(nearCenter, normal, normal);    Matrix2.Cartesian3.subtract(normal, position, normal);    Matrix2.Cartesian3.normalize(normal, normal);    Matrix2.Cartesian3.cross(normal, up, normal);    Matrix2.Cartesian3.normalize(normal, normal);    let plane = planes[0];    if (!defaultValue.defined(plane)) {      plane = planes[0] = new Matrix2.Cartesian4();    }    plane.x = normal.x;    plane.y = normal.y;    plane.z = normal.z;    plane.w = -Matrix2.Cartesian3.dot(normal, position);    //Right plane computation    Matrix2.Cartesian3.multiplyByScalar(right, r, normal);    Matrix2.Cartesian3.add(nearCenter, normal, normal);    Matrix2.Cartesian3.subtract(normal, position, normal);    Matrix2.Cartesian3.cross(up, normal, normal);    Matrix2.Cartesian3.normalize(normal, normal);    plane = planes[1];    if (!defaultValue.defined(plane)) {      plane = planes[1] = new Matrix2.Cartesian4();    }    plane.x = normal.x;    plane.y = normal.y;    plane.z = normal.z;    plane.w = -Matrix2.Cartesian3.dot(normal, position);    //Bottom plane computation    Matrix2.Cartesian3.multiplyByScalar(up, b, normal);    Matrix2.Cartesian3.add(nearCenter, normal, normal);    Matrix2.Cartesian3.subtract(normal, position, normal);    Matrix2.Cartesian3.cross(right, normal, normal);    Matrix2.Cartesian3.normalize(normal, normal);    plane = planes[2];    if (!defaultValue.defined(plane)) {      plane = planes[2] = new Matrix2.Cartesian4();    }    plane.x = normal.x;    plane.y = normal.y;    plane.z = normal.z;    plane.w = -Matrix2.Cartesian3.dot(normal, position);    //Top plane computation    Matrix2.Cartesian3.multiplyByScalar(up, t, normal);    Matrix2.Cartesian3.add(nearCenter, normal, normal);    Matrix2.Cartesian3.subtract(normal, position, normal);    Matrix2.Cartesian3.cross(normal, right, normal);    Matrix2.Cartesian3.normalize(normal, normal);    plane = planes[3];    if (!defaultValue.defined(plane)) {      plane = planes[3] = new Matrix2.Cartesian4();    }    plane.x = normal.x;    plane.y = normal.y;    plane.z = normal.z;    plane.w = -Matrix2.Cartesian3.dot(normal, position);    //Near plane computation    plane = planes[4];    if (!defaultValue.defined(plane)) {      plane = planes[4] = new Matrix2.Cartesian4();    }    plane.x = direction.x;    plane.y = direction.y;    plane.z = direction.z;    plane.w = -Matrix2.Cartesian3.dot(direction, nearCenter);    //Far plane computation    Matrix2.Cartesian3.negate(direction, normal);    plane = planes[5];    if (!defaultValue.defined(plane)) {      plane = planes[5] = new Matrix2.Cartesian4();    }    plane.x = normal.x;    plane.y = normal.y;    plane.z = normal.z;    plane.w = -Matrix2.Cartesian3.dot(normal, farCenter);    return this._cullingVolume;  };  /**   * Returns the pixel's width and height in meters.   *   * @param {Number} drawingBufferWidth The width of the drawing buffer.   * @param {Number} drawingBufferHeight The height of the drawing buffer.   * @param {Number} distance The distance to the near plane in meters.   * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.   * @param {Cartesian2} result The object onto which to store the result.   * @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.   *   * @exception {DeveloperError} drawingBufferWidth must be greater than zero.   * @exception {DeveloperError} drawingBufferHeight must be greater than zero.   * @exception {DeveloperError} pixelRatio must be greater than zero.   *   * @example   * // Example 1   * // Get the width and height of a pixel.   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, scene.pixelRatio, new Cesium.Cartesian2());   *   * @example   * // Example 2   * // Get the width and height of a pixel if the near plane was set to 'distance'.   * // For example, get the size of a pixel of an image on a billboard.   * const position = camera.position;   * const direction = camera.direction;   * const toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3());      // vector from camera to a primitive   * const toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector   * const distance = Cesium.Cartesian3.magnitude(toCenterProj);   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, scene.pixelRatio, new Cesium.Cartesian2());   */  PerspectiveOffCenterFrustum.prototype.getPixelDimensions = function (    drawingBufferWidth,    drawingBufferHeight,    distance,    pixelRatio,    result  ) {    update$1(this);    //>>includeStart('debug', pragmas.debug);    if (!defaultValue.defined(drawingBufferWidth) || !defaultValue.defined(drawingBufferHeight)) {      throw new RuntimeError.DeveloperError(        "Both drawingBufferWidth and drawingBufferHeight are required."      );    }    if (drawingBufferWidth <= 0) {      throw new RuntimeError.DeveloperError("drawingBufferWidth must be greater than zero.");    }    if (drawingBufferHeight <= 0) {      throw new RuntimeError.DeveloperError("drawingBufferHeight must be greater than zero.");    }    if (!defaultValue.defined(distance)) {      throw new RuntimeError.DeveloperError("distance is required.");    }    if (!defaultValue.defined(pixelRatio)) {      throw new RuntimeError.DeveloperError("pixelRatio is required");    }    if (pixelRatio <= 0) {      throw new RuntimeError.DeveloperError("pixelRatio must be greater than zero.");    }    if (!defaultValue.defined(result)) {      throw new RuntimeError.DeveloperError("A result object is required.");    }    //>>includeEnd('debug');    const inverseNear = 1.0 / this.near;    let tanTheta = this.top * inverseNear;    const pixelHeight =      (2.0 * pixelRatio * distance * tanTheta) / drawingBufferHeight;    tanTheta = this.right * inverseNear;    const pixelWidth =      (2.0 * pixelRatio * distance * tanTheta) / drawingBufferWidth;    result.x = pixelWidth;    result.y = pixelHeight;    return result;  };  /**   * Returns a duplicate of a PerspectiveOffCenterFrustum instance.   *   * @param {PerspectiveOffCenterFrustum} [result] The object onto which to store the result.   * @returns {PerspectiveOffCenterFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.   */  PerspectiveOffCenterFrustum.prototype.clone = function (result) {    if (!defaultValue.defined(result)) {      result = new PerspectiveOffCenterFrustum();    }    result.right = this.right;    result.left = this.left;    result.top = this.top;    result.bottom = this.bottom;    result.near = this.near;    result.far = this.far;    // force update of clone to compute matrices    result._left = undefined;    result._right = undefined;    result._top = undefined;    result._bottom = undefined;    result._near = undefined;    result._far = undefined;    return result;  };  /**   * Compares the provided PerspectiveOffCenterFrustum componentwise and returns   * <code>true</code> if they are equal, <code>false</code> otherwise.   *   * @param {PerspectiveOffCenterFrustum} [other] The right hand side PerspectiveOffCenterFrustum.   * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.   */  PerspectiveOffCenterFrustum.prototype.equals = function (other) {    return (      defaultValue.defined(other) &&      other instanceof PerspectiveOffCenterFrustum &&      this.right === other.right &&      this.left === other.left &&      this.top === other.top &&      this.bottom === other.bottom &&      this.near === other.near &&      this.far === other.far    );  };  /**   * Compares the provided PerspectiveOffCenterFrustum componentwise and returns   * <code>true</code> if they pass an absolute or relative tolerance test,   * <code>false</code> otherwise.   *   * @param {PerspectiveOffCenterFrustum} other The right hand side PerspectiveOffCenterFrustum.   * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.   * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.   * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.   */  PerspectiveOffCenterFrustum.prototype.equalsEpsilon = function (    other,    relativeEpsilon,    absoluteEpsilon  ) {    return (      other === this ||      (defaultValue.defined(other) &&        other instanceof PerspectiveOffCenterFrustum &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.right,          other.right,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.left,          other.left,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.top,          other.top,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.bottom,          other.bottom,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.near,          other.near,          relativeEpsilon,          absoluteEpsilon        ) &&        ComponentDatatype.CesiumMath.equalsEpsilon(          this.far,          other.far,          relativeEpsilon,          absoluteEpsilon        ))    );  };  /**   * The viewing frustum is defined by 6 planes.   * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components   * define the unit vector normal to the plane, and the w component is the distance of the   * plane from the origin/camera position.   *   * @alias PerspectiveFrustum   * @constructor   *   * @param {Object} [options] An object with the following properties:   * @param {Number} [options.fov] The angle of the field of view (FOV), in radians.   * @param {Number} [options.aspectRatio] The aspect ratio of the frustum's width to it's height.   * @param {Number} [options.near=1.0] The distance of the near plane.   * @param {Number} [options.far=500000000.0] The distance of the far plane.   * @param {Number} [options.xOffset=0.0] The offset in the x direction.   * @param {Number} [options.yOffset=0.0] The offset in the y direction.   *   * @example   * const frustum = new Cesium.PerspectiveFrustum({   *     fov : Cesium.Math.PI_OVER_THREE,   *     aspectRatio : canvas.clientWidth / canvas.clientHeight   *     near : 1.0,   *     far : 1000.0   * });   *   * @see PerspectiveOffCenterFrustum   */  function PerspectiveFrustum(options) {    options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);    this._offCenterFrustum = new PerspectiveOffCenterFrustum();    /**     * The angle of the field of view (FOV), in radians.  This angle will be used     * as the horizontal FOV if the width is greater than the height, otherwise     * it will be the vertical FOV.     * @type {Number}     * @default undefined     */    this.fov = options.fov;    this._fov = undefined;    this._fovy = undefined;    this._sseDenominator = undefined;    /**     * The aspect ratio of the frustum's width to it's height.     * @type {Number}     * @default undefined     */    this.aspectRatio = options.aspectRatio;    this._aspectRatio = undefined;    /**     * The distance of the near plane.     * @type {Number}     * @default 1.0     */    this.near = defaultValue.defaultValue(options.near, 1.0);    this._near = this.near;    /**     * The distance of the far plane.     * @type {Number}     * @default 500000000.0     */    this.far = defaultValue.defaultValue(options.far, 500000000.0);    this._far = this.far;    /**     * Offsets the frustum in the x direction.     * @type {Number}     * @default 0.0     */    this.xOffset = defaultValue.defaultValue(options.xOffset, 0.0);    this._xOffset = this.xOffset;    /**     * Offsets the frustum in the y direction.     * @type {Number}     * @default 0.0     */    this.yOffset = defaultValue.defaultValue(options.yOffset, 0.0);    this._yOffset = this.yOffset;  }  /**   * The number of elements used to pack the object into an array.   * @type {Number}   */  PerspectiveFrustum.packedLength = 6;  /**   * Stores the provided instance into the provided array.   *   * @param {PerspectiveFrustum} value The value to pack.   * @param {Number[]} array The array to pack into.   * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.   *   * @returns {Number[]} The array that was packed into   */  PerspectiveFrustum.pack = function (value, array, startingIndex) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.typeOf.object("value", value);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    array[startingIndex++] = value.fov;    array[startingIndex++] = value.aspectRatio;    array[startingIndex++] = value.near;    array[startingIndex++] = value.far;    array[startingIndex++] = value.xOffset;    array[startingIndex] = value.yOffset;    return array;  };  /**   * Retrieves an instance from a packed array.   *   * @param {Number[]} array The packed array.   * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.   * @param {PerspectiveFrustum} [result] The object into which to store the result.   * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.   */  PerspectiveFrustum.unpack = function (array, startingIndex, result) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    if (!defaultValue.defined(result)) {      result = new PerspectiveFrustum();    }    result.fov = array[startingIndex++];    result.aspectRatio = array[startingIndex++];    result.near = array[startingIndex++];    result.far = array[startingIndex++];    result.xOffset = array[startingIndex++];    result.yOffset = array[startingIndex];    return result;  };  function update(frustum) {    //>>includeStart('debug', pragmas.debug);    if (      !defaultValue.defined(frustum.fov) ||      !defaultValue.defined(frustum.aspectRatio) ||      !defaultValue.defined(frustum.near) ||      !defaultValue.defined(frustum.far)    ) {      throw new RuntimeError.DeveloperError(        "fov, aspectRatio, near, or far parameters are not set."      );    }    //>>includeEnd('debug');    const f = frustum._offCenterFrustum;    if (      frustum.fov !== frustum._fov ||      frustum.aspectRatio !== frustum._aspectRatio ||      frustum.near !== frustum._near ||      frustum.far !== frustum._far ||      frustum.xOffset !== frustum._xOffset ||      frustum.yOffset !== frustum._yOffset    ) {      //>>includeStart('debug', pragmas.debug);      if (frustum.fov < 0 || frustum.fov >= Math.PI) {        throw new RuntimeError.DeveloperError("fov must be in the range [0, PI).");      }      if (frustum.aspectRatio < 0) {        throw new RuntimeError.DeveloperError("aspectRatio must be positive.");      }      if (frustum.near < 0 || frustum.near > frustum.far) {        throw new RuntimeError.DeveloperError(          "near must be greater than zero and less than far."        );      }      //>>includeEnd('debug');      frustum._aspectRatio = frustum.aspectRatio;      frustum._fov = frustum.fov;      frustum._fovy =        frustum.aspectRatio <= 1          ? frustum.fov          : Math.atan(Math.tan(frustum.fov * 0.5) / frustum.aspectRatio) * 2.0;      frustum._near = frustum.near;      frustum._far = frustum.far;      frustum._sseDenominator = 2.0 * Math.tan(0.5 * frustum._fovy);      frustum._xOffset = frustum.xOffset;      frustum._yOffset = frustum.yOffset;      f.top = frustum.near * Math.tan(0.5 * frustum._fovy);      f.bottom = -f.top;      f.right = frustum.aspectRatio * f.top;      f.left = -f.right;      f.near = frustum.near;      f.far = frustum.far;      f.right += frustum.xOffset;      f.left += frustum.xOffset;      f.top += frustum.yOffset;      f.bottom += frustum.yOffset;    }  }  Object.defineProperties(PerspectiveFrustum.prototype, {    /**     * Gets the perspective projection matrix computed from the view frustum.     * @memberof PerspectiveFrustum.prototype     * @type {Matrix4}     * @readonly     *     * @see PerspectiveFrustum#infiniteProjectionMatrix     */    projectionMatrix: {      get: function () {        update(this);        return this._offCenterFrustum.projectionMatrix;      },    },    /**     * The perspective projection matrix computed from the view frustum with an infinite far plane.     * @memberof PerspectiveFrustum.prototype     * @type {Matrix4}     * @readonly     *     * @see PerspectiveFrustum#projectionMatrix     */    infiniteProjectionMatrix: {      get: function () {        update(this);        return this._offCenterFrustum.infiniteProjectionMatrix;      },    },    /**     * Gets the angle of the vertical field of view, in radians.     * @memberof PerspectiveFrustum.prototype     * @type {Number}     * @readonly     * @default undefined     */    fovy: {      get: function () {        update(this);        return this._fovy;      },    },    /**     * @readonly     * @private     */    sseDenominator: {      get: function () {        update(this);        return this._sseDenominator;      },    },  });  /**   * Creates a culling volume for this frustum.   *   * @param {Cartesian3} position The eye position.   * @param {Cartesian3} direction The view direction.   * @param {Cartesian3} up The up direction.   * @returns {CullingVolume} A culling volume at the given position and orientation.   *   * @example   * // Check if a bounding volume intersects the frustum.   * const cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);   * const intersect = cullingVolume.computeVisibility(boundingVolume);   */  PerspectiveFrustum.prototype.computeCullingVolume = function (    position,    direction,    up  ) {    update(this);    return this._offCenterFrustum.computeCullingVolume(position, direction, up);  };  /**   * Returns the pixel's width and height in meters.   *   * @param {Number} drawingBufferWidth The width of the drawing buffer.   * @param {Number} drawingBufferHeight The height of the drawing buffer.   * @param {Number} distance The distance to the near plane in meters.   * @param {Number} pixelRatio The scaling factor from pixel space to coordinate space.   * @param {Cartesian2} result The object onto which to store the result.   * @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.   *   * @exception {DeveloperError} drawingBufferWidth must be greater than zero.   * @exception {DeveloperError} drawingBufferHeight must be greater than zero.   * @exception {DeveloperError} pixelRatio must be greater than zero.   *   * @example   * // Example 1   * // Get the width and height of a pixel.   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, scene.pixelRatio, new Cesium.Cartesian2());   *   * @example   * // Example 2   * // Get the width and height of a pixel if the near plane was set to 'distance'.   * // For example, get the size of a pixel of an image on a billboard.   * const position = camera.position;   * const direction = camera.direction;   * const toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3());      // vector from camera to a primitive   * const toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector   * const distance = Cesium.Cartesian3.magnitude(toCenterProj);   * const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, scene.pixelRatio, new Cesium.Cartesian2());   */  PerspectiveFrustum.prototype.getPixelDimensions = function (    drawingBufferWidth,    drawingBufferHeight,    distance,    pixelRatio,    result  ) {    update(this);    return this._offCenterFrustum.getPixelDimensions(      drawingBufferWidth,      drawingBufferHeight,      distance,      pixelRatio,      result    );  };  /**   * Returns a duplicate of a PerspectiveFrustum instance.   *   * @param {PerspectiveFrustum} [result] The object onto which to store the result.   * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.   */  PerspectiveFrustum.prototype.clone = function (result) {    if (!defaultValue.defined(result)) {      result = new PerspectiveFrustum();    }    result.aspectRatio = this.aspectRatio;    result.fov = this.fov;    result.near = this.near;    result.far = this.far;    // force update of clone to compute matrices    result._aspectRatio = undefined;    result._fov = undefined;    result._near = undefined;    result._far = undefined;    this._offCenterFrustum.clone(result._offCenterFrustum);    return result;  };  /**   * Compares the provided PerspectiveFrustum componentwise and returns   * <code>true</code> if they are equal, <code>false</code> otherwise.   *   * @param {PerspectiveFrustum} [other] The right hand side PerspectiveFrustum.   * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.   */  PerspectiveFrustum.prototype.equals = function (other) {    if (!defaultValue.defined(other) || !(other instanceof PerspectiveFrustum)) {      return false;    }    update(this);    update(other);    return (      this.fov === other.fov &&      this.aspectRatio === other.aspectRatio &&      this._offCenterFrustum.equals(other._offCenterFrustum)    );  };  /**   * Compares the provided PerspectiveFrustum componentwise and returns   * <code>true</code> if they pass an absolute or relative tolerance test,   * <code>false</code> otherwise.   *   * @param {PerspectiveFrustum} other The right hand side PerspectiveFrustum.   * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.   * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.   * @returns {Boolean} <code>true</code> if this and other are within the provided epsilon, <code>false</code> otherwise.   */  PerspectiveFrustum.prototype.equalsEpsilon = function (    other,    relativeEpsilon,    absoluteEpsilon  ) {    if (!defaultValue.defined(other) || !(other instanceof PerspectiveFrustum)) {      return false;    }    update(this);    update(other);    return (      ComponentDatatype.CesiumMath.equalsEpsilon(        this.fov,        other.fov,        relativeEpsilon,        absoluteEpsilon      ) &&      ComponentDatatype.CesiumMath.equalsEpsilon(        this.aspectRatio,        other.aspectRatio,        relativeEpsilon,        absoluteEpsilon      ) &&      this._offCenterFrustum.equalsEpsilon(        other._offCenterFrustum,        relativeEpsilon,        absoluteEpsilon      )    );  };  const PERSPECTIVE = 0;  const ORTHOGRAPHIC = 1;  /**   * Describes a frustum at the given the origin and orientation.   *   * @alias FrustumGeometry   * @constructor   *   * @param {Object} options Object with the following properties:   * @param {PerspectiveFrustum|OrthographicFrustum} options.frustum The frustum.   * @param {Cartesian3} options.origin The origin of the frustum.   * @param {Quaternion} options.orientation The orientation of the frustum.   * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.   */  function FrustumGeometry(options) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.typeOf.object("options", options);    RuntimeError.Check.typeOf.object("options.frustum", options.frustum);    RuntimeError.Check.typeOf.object("options.origin", options.origin);    RuntimeError.Check.typeOf.object("options.orientation", options.orientation);    //>>includeEnd('debug');    const frustum = options.frustum;    const orientation = options.orientation;    const origin = options.origin;    const vertexFormat = defaultValue.defaultValue(options.vertexFormat, VertexFormat.VertexFormat.DEFAULT);    // This is private because it is used by DebugCameraPrimitive to draw a multi-frustum by    // creating multiple FrustumGeometrys. This way the near plane of one frustum doesn't overlap    // the far plane of another.    const drawNearPlane = defaultValue.defaultValue(options._drawNearPlane, true);    let frustumType;    let frustumPackedLength;    if (frustum instanceof PerspectiveFrustum) {      frustumType = PERSPECTIVE;      frustumPackedLength = PerspectiveFrustum.packedLength;    } else if (frustum instanceof OrthographicFrustum) {      frustumType = ORTHOGRAPHIC;      frustumPackedLength = OrthographicFrustum.packedLength;    }    this._frustumType = frustumType;    this._frustum = frustum.clone();    this._origin = Matrix2.Cartesian3.clone(origin);    this._orientation = Transforms.Quaternion.clone(orientation);    this._drawNearPlane = drawNearPlane;    this._vertexFormat = vertexFormat;    this._workerName = "createFrustumGeometry";    /**     * The number of elements used to pack the object into an array.     * @type {Number}     */    this.packedLength =      2 +      frustumPackedLength +      Matrix2.Cartesian3.packedLength +      Transforms.Quaternion.packedLength +      VertexFormat.VertexFormat.packedLength;  }  /**   * Stores the provided instance into the provided array.   *   * @param {FrustumGeometry} value The value to pack.   * @param {Number[]} array The array to pack into.   * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.   *   * @returns {Number[]} The array that was packed into   */  FrustumGeometry.pack = function (value, array, startingIndex) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.typeOf.object("value", value);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    const frustumType = value._frustumType;    const frustum = value._frustum;    array[startingIndex++] = frustumType;    if (frustumType === PERSPECTIVE) {      PerspectiveFrustum.pack(frustum, array, startingIndex);      startingIndex += PerspectiveFrustum.packedLength;    } else {      OrthographicFrustum.pack(frustum, array, startingIndex);      startingIndex += OrthographicFrustum.packedLength;    }    Matrix2.Cartesian3.pack(value._origin, array, startingIndex);    startingIndex += Matrix2.Cartesian3.packedLength;    Transforms.Quaternion.pack(value._orientation, array, startingIndex);    startingIndex += Transforms.Quaternion.packedLength;    VertexFormat.VertexFormat.pack(value._vertexFormat, array, startingIndex);    startingIndex += VertexFormat.VertexFormat.packedLength;    array[startingIndex] = value._drawNearPlane ? 1.0 : 0.0;    return array;  };  const scratchPackPerspective = new PerspectiveFrustum();  const scratchPackOrthographic = new OrthographicFrustum();  const scratchPackQuaternion = new Transforms.Quaternion();  const scratchPackorigin = new Matrix2.Cartesian3();  const scratchVertexFormat = new VertexFormat.VertexFormat();  /**   * Retrieves an instance from a packed array.   *   * @param {Number[]} array The packed array.   * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.   * @param {FrustumGeometry} [result] The object into which to store the result.   */  FrustumGeometry.unpack = function (array, startingIndex, result) {    //>>includeStart('debug', pragmas.debug);    RuntimeError.Check.defined("array", array);    //>>includeEnd('debug');    startingIndex = defaultValue.defaultValue(startingIndex, 0);    const frustumType = array[startingIndex++];    let frustum;    if (frustumType === PERSPECTIVE) {      frustum = PerspectiveFrustum.unpack(        array,        startingIndex,        scratchPackPerspective      );      startingIndex += PerspectiveFrustum.packedLength;    } else {      frustum = OrthographicFrustum.unpack(        array,        startingIndex,        scratchPackOrthographic      );      startingIndex += OrthographicFrustum.packedLength;    }    const origin = Matrix2.Cartesian3.unpack(array, startingIndex, scratchPackorigin);    startingIndex += Matrix2.Cartesian3.packedLength;    const orientation = Transforms.Quaternion.unpack(      array,      startingIndex,      scratchPackQuaternion    );    startingIndex += Transforms.Quaternion.packedLength;    const vertexFormat = VertexFormat.VertexFormat.unpack(      array,      startingIndex,      scratchVertexFormat    );    startingIndex += VertexFormat.VertexFormat.packedLength;    const drawNearPlane = array[startingIndex] === 1.0;    if (!defaultValue.defined(result)) {      return new FrustumGeometry({        frustum: frustum,        origin: origin,        orientation: orientation,        vertexFormat: vertexFormat,        _drawNearPlane: drawNearPlane,      });    }    const frustumResult =      frustumType === result._frustumType ? result._frustum : undefined;    result._frustum = frustum.clone(frustumResult);    result._frustumType = frustumType;    result._origin = Matrix2.Cartesian3.clone(origin, result._origin);    result._orientation = Transforms.Quaternion.clone(orientation, result._orientation);    result._vertexFormat = VertexFormat.VertexFormat.clone(vertexFormat, result._vertexFormat);    result._drawNearPlane = drawNearPlane;    return result;  };  function getAttributes(    offset,    normals,    tangents,    bitangents,    st,    normal,    tangent,    bitangent  ) {    const stOffset = (offset / 3) * 2;    for (let i = 0; i < 4; ++i) {      if (defaultValue.defined(normals)) {        normals[offset] = normal.x;        normals[offset + 1] = normal.y;        normals[offset + 2] = normal.z;      }      if (defaultValue.defined(tangents)) {        tangents[offset] = tangent.x;        tangents[offset + 1] = tangent.y;        tangents[offset + 2] = tangent.z;      }      if (defaultValue.defined(bitangents)) {        bitangents[offset] = bitangent.x;        bitangents[offset + 1] = bitangent.y;        bitangents[offset + 2] = bitangent.z;      }      offset += 3;    }    st[stOffset] = 0.0;    st[stOffset + 1] = 0.0;    st[stOffset + 2] = 1.0;    st[stOffset + 3] = 0.0;    st[stOffset + 4] = 1.0;    st[stOffset + 5] = 1.0;    st[stOffset + 6] = 0.0;    st[stOffset + 7] = 1.0;  }  const scratchRotationMatrix = new Matrix2.Matrix3();  const scratchViewMatrix = new Matrix2.Matrix4();  const scratchInverseMatrix = new Matrix2.Matrix4();  const scratchXDirection = new Matrix2.Cartesian3();  const scratchYDirection = new Matrix2.Cartesian3();  const scratchZDirection = new Matrix2.Cartesian3();  const scratchNegativeX = new Matrix2.Cartesian3();  const scratchNegativeY = new Matrix2.Cartesian3();  const scratchNegativeZ = new Matrix2.Cartesian3();  const frustumSplits = new Array(3);  const frustumCornersNDC = new Array(4);  frustumCornersNDC[0] = new Matrix2.Cartesian4(-1.0, -1.0, 1.0, 1.0);  frustumCornersNDC[1] = new Matrix2.Cartesian4(1.0, -1.0, 1.0, 1.0);  frustumCornersNDC[2] = new Matrix2.Cartesian4(1.0, 1.0, 1.0, 1.0);  frustumCornersNDC[3] = new Matrix2.Cartesian4(-1.0, 1.0, 1.0, 1.0);  const scratchFrustumCorners = new Array(4);  for (let i = 0; i < 4; ++i) {    scratchFrustumCorners[i] = new Matrix2.Cartesian4();  }  FrustumGeometry._computeNearFarPlanes = function (    origin,    orientation,    frustumType,    frustum,    positions,    xDirection,    yDirection,    zDirection  ) {    const rotationMatrix = Matrix2.Matrix3.fromQuaternion(      orientation,      scratchRotationMatrix    );    let x = defaultValue.defaultValue(xDirection, scratchXDirection);    let y = defaultValue.defaultValue(yDirection, scratchYDirection);    let z = defaultValue.defaultValue(zDirection, scratchZDirection);    x = Matrix2.Matrix3.getColumn(rotationMatrix, 0, x);    y = Matrix2.Matrix3.getColumn(rotationMatrix, 1, y);    z = Matrix2.Matrix3.getColumn(rotationMatrix, 2, z);    Matrix2.Cartesian3.normalize(x, x);    Matrix2.Cartesian3.normalize(y, y);    Matrix2.Cartesian3.normalize(z, z);    Matrix2.Cartesian3.negate(x, x);    const view = Matrix2.Matrix4.computeView(origin, z, y, x, scratchViewMatrix);    let inverseView;    let inverseViewProjection;    if (frustumType === PERSPECTIVE) {      const projection = frustum.projectionMatrix;      const viewProjection = Matrix2.Matrix4.multiply(        projection,        view,        scratchInverseMatrix      );      inverseViewProjection = Matrix2.Matrix4.inverse(        viewProjection,        scratchInverseMatrix      );    } else {      inverseView = Matrix2.Matrix4.inverseTransformation(view, scratchInverseMatrix);    }    if (defaultValue.defined(inverseViewProjection)) {      frustumSplits[0] = frustum.near;      frustumSplits[1] = frustum.far;    } else {      frustumSplits[0] = 0.0;      frustumSplits[1] = frustum.near;      frustumSplits[2] = frustum.far;    }    for (let i = 0; i < 2; ++i) {      for (let j = 0; j < 4; ++j) {        let corner = Matrix2.Cartesian4.clone(          frustumCornersNDC[j],          scratchFrustumCorners[j]        );        if (!defaultValue.defined(inverseViewProjection)) {          if (defaultValue.defined(frustum._offCenterFrustum)) {            frustum = frustum._offCenterFrustum;          }          const near = frustumSplits[i];          const far = frustumSplits[i + 1];          corner.x =            (corner.x * (frustum.right - frustum.left) +              frustum.left +              frustum.right) *            0.5;          corner.y =            (corner.y * (frustum.top - frustum.bottom) +              frustum.bottom +              frustum.top) *            0.5;          corner.z = (corner.z * (near - far) - near - far) * 0.5;          corner.w = 1.0;          Matrix2.Matrix4.multiplyByVector(inverseView, corner, corner);        } else {          corner = Matrix2.Matrix4.multiplyByVector(            inverseViewProjection,            corner,            corner          );          // Reverse perspective divide          const w = 1.0 / corner.w;          Matrix2.Cartesian3.multiplyByScalar(corner, w, corner);          Matrix2.Cartesian3.subtract(corner, origin, corner);          Matrix2.Cartesian3.normalize(corner, corner);          const fac = Matrix2.Cartesian3.dot(z, corner);          Matrix2.Cartesian3.multiplyByScalar(corner, frustumSplits[i] / fac, corner);          Matrix2.Cartesian3.add(corner, origin, corner);        }        positions[12 * i + j * 3] = corner.x;        positions[12 * i + j * 3 + 1] = corner.y;        positions[12 * i + j * 3 + 2] = corner.z;      }    }  };  /**   * Computes the geometric representation of a frustum, including its vertices, indices, and a bounding sphere.   *   * @param {FrustumGeometry} frustumGeometry A description of the frustum.   * @returns {Geometry|undefined} The computed vertices and indices.   */  FrustumGeometry.createGeometry = function (frustumGeometry) {    const frustumType = frustumGeometry._frustumType;    const frustum = frustumGeometry._frustum;    const origin = frustumGeometry._origin;    const orientation = frustumGeometry._orientation;    const drawNearPlane = frustumGeometry._drawNearPlane;    const vertexFormat = frustumGeometry._vertexFormat;    const numberOfPlanes = drawNearPlane ? 6 : 5;    let positions = new Float64Array(3 * 4 * 6);    FrustumGeometry._computeNearFarPlanes(      origin,      orientation,      frustumType,      frustum,      positions    );    // -x plane    let offset = 3 * 4 * 2;    positions[offset] = positions[3 * 4];    positions[offset + 1] = positions[3 * 4 + 1];    positions[offset + 2] = positions[3 * 4 + 2];    positions[offset + 3] = positions[0];    positions[offset + 4] = positions[1];    positions[offset + 5] = positions[2];    positions[offset + 6] = positions[3 * 3];    positions[offset + 7] = positions[3 * 3 + 1];    positions[offset + 8] = positions[3 * 3 + 2];    positions[offset + 9] = positions[3 * 7];    positions[offset + 10] = positions[3 * 7 + 1];    positions[offset + 11] = positions[3 * 7 + 2];    // -y plane    offset += 3 * 4;    positions[offset] = positions[3 * 5];    positions[offset + 1] = positions[3 * 5 + 1];    positions[offset + 2] = positions[3 * 5 + 2];    positions[offset + 3] = positions[3];    positions[offset + 4] = positions[3 + 1];    positions[offset + 5] = positions[3 + 2];    positions[offset + 6] = positions[0];    positions[offset + 7] = positions[1];    positions[offset + 8] = positions[2];    positions[offset + 9] = positions[3 * 4];    positions[offset + 10] = positions[3 * 4 + 1];    positions[offset + 11] = positions[3 * 4 + 2];    // +x plane    offset += 3 * 4;    positions[offset] = positions[3];    positions[offset + 1] = positions[3 + 1];    positions[offset + 2] = positions[3 + 2];    positions[offset + 3] = positions[3 * 5];    positions[offset + 4] = positions[3 * 5 + 1];    positions[offset + 5] = positions[3 * 5 + 2];    positions[offset + 6] = positions[3 * 6];    positions[offset + 7] = positions[3 * 6 + 1];    positions[offset + 8] = positions[3 * 6 + 2];    positions[offset + 9] = positions[3 * 2];    positions[offset + 10] = positions[3 * 2 + 1];    positions[offset + 11] = positions[3 * 2 + 2];    // +y plane    offset += 3 * 4;    positions[offset] = positions[3 * 2];    positions[offset + 1] = positions[3 * 2 + 1];    positions[offset + 2] = positions[3 * 2 + 2];    positions[offset + 3] = positions[3 * 6];    positions[offset + 4] = positions[3 * 6 + 1];    positions[offset + 5] = positions[3 * 6 + 2];    positions[offset + 6] = positions[3 * 7];    positions[offset + 7] = positions[3 * 7 + 1];    positions[offset + 8] = positions[3 * 7 + 2];    positions[offset + 9] = positions[3 * 3];    positions[offset + 10] = positions[3 * 3 + 1];    positions[offset + 11] = positions[3 * 3 + 2];    if (!drawNearPlane) {      positions = positions.subarray(3 * 4);    }    const attributes = new GeometryAttributes.GeometryAttributes({      position: new GeometryAttribute.GeometryAttribute({        componentDatatype: ComponentDatatype.ComponentDatatype.DOUBLE,        componentsPerAttribute: 3,        values: positions,      }),    });    if (      defaultValue.defined(vertexFormat.normal) ||      defaultValue.defined(vertexFormat.tangent) ||      defaultValue.defined(vertexFormat.bitangent) ||      defaultValue.defined(vertexFormat.st)    ) {      const normals = defaultValue.defined(vertexFormat.normal)        ? new Float32Array(3 * 4 * numberOfPlanes)        : undefined;      const tangents = defaultValue.defined(vertexFormat.tangent)        ? new Float32Array(3 * 4 * numberOfPlanes)        : undefined;      const bitangents = defaultValue.defined(vertexFormat.bitangent)        ? new Float32Array(3 * 4 * numberOfPlanes)        : undefined;      const st = defaultValue.defined(vertexFormat.st)        ? new Float32Array(2 * 4 * numberOfPlanes)        : undefined;      const x = scratchXDirection;      const y = scratchYDirection;      const z = scratchZDirection;      const negativeX = Matrix2.Cartesian3.negate(x, scratchNegativeX);      const negativeY = Matrix2.Cartesian3.negate(y, scratchNegativeY);      const negativeZ = Matrix2.Cartesian3.negate(z, scratchNegativeZ);      offset = 0;      if (drawNearPlane) {        getAttributes(offset, normals, tangents, bitangents, st, negativeZ, x, y); // near        offset += 3 * 4;      }      getAttributes(offset, normals, tangents, bitangents, st, z, negativeX, y); // far      offset += 3 * 4;      getAttributes(        offset,        normals,        tangents,        bitangents,        st,        negativeX,        negativeZ,        y      ); // -x      offset += 3 * 4;      getAttributes(        offset,        normals,        tangents,        bitangents,        st,        negativeY,        negativeZ,        negativeX      ); // -y      offset += 3 * 4;      getAttributes(offset, normals, tangents, bitangents, st, x, z, y); // +x      offset += 3 * 4;      getAttributes(offset, normals, tangents, bitangents, st, y, z, negativeX); // +y      if (defaultValue.defined(normals)) {        attributes.normal = new GeometryAttribute.GeometryAttribute({          componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,          componentsPerAttribute: 3,          values: normals,        });      }      if (defaultValue.defined(tangents)) {        attributes.tangent = new GeometryAttribute.GeometryAttribute({          componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,          componentsPerAttribute: 3,          values: tangents,        });      }      if (defaultValue.defined(bitangents)) {        attributes.bitangent = new GeometryAttribute.GeometryAttribute({          componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,          componentsPerAttribute: 3,          values: bitangents,        });      }      if (defaultValue.defined(st)) {        attributes.st = new GeometryAttribute.GeometryAttribute({          componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,          componentsPerAttribute: 2,          values: st,        });      }    }    const indices = new Uint16Array(6 * numberOfPlanes);    for (let i = 0; i < numberOfPlanes; ++i) {      const indexOffset = i * 6;      const index = i * 4;      indices[indexOffset] = index;      indices[indexOffset + 1] = index + 1;      indices[indexOffset + 2] = index + 2;      indices[indexOffset + 3] = index;      indices[indexOffset + 4] = index + 2;      indices[indexOffset + 5] = index + 3;    }    return new GeometryAttribute.Geometry({      attributes: attributes,      indices: indices,      primitiveType: GeometryAttribute.PrimitiveType.TRIANGLES,      boundingSphere: Transforms.BoundingSphere.fromVertices(positions),    });  };  exports.FrustumGeometry = FrustumGeometry;  exports.OrthographicFrustum = OrthographicFrustum;  exports.PerspectiveFrustum = PerspectiveFrustum;}));
 |