| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296 | import AttributeCompression from "./AttributeCompression.js";import barycentricCoordinates from "./barycentricCoordinates.js";import BoundingSphere from "./BoundingSphere.js";import Cartesian2 from "./Cartesian2.js";import Cartesian3 from "./Cartesian3.js";import Cartesian4 from "./Cartesian4.js";import Cartographic from "./Cartographic.js";import ComponentDatatype from "./ComponentDatatype.js";import defaultValue from "./defaultValue.js";import defined from "./defined.js";import DeveloperError from "./DeveloperError.js";import EncodedCartesian3 from "./EncodedCartesian3.js";import GeographicProjection from "./GeographicProjection.js";import Geometry from "./Geometry.js";import GeometryAttribute from "./GeometryAttribute.js";import GeometryType from "./GeometryType.js";import IndexDatatype from "./IndexDatatype.js";import Intersect from "./Intersect.js";import IntersectionTests from "./IntersectionTests.js";import CesiumMath from "./Math.js";import Matrix3 from "./Matrix3.js";import Matrix4 from "./Matrix4.js";import Plane from "./Plane.js";import PrimitiveType from "./PrimitiveType.js";import Tipsify from "./Tipsify.js";/** * Content pipeline functions for geometries. * * @namespace GeometryPipeline * * @see Geometry */const GeometryPipeline = {};function addTriangle(lines, index, i0, i1, i2) {  lines[index++] = i0;  lines[index++] = i1;  lines[index++] = i1;  lines[index++] = i2;  lines[index++] = i2;  lines[index] = i0;}function trianglesToLines(triangles) {  const count = triangles.length;  const size = (count / 3) * 6;  const lines = IndexDatatype.createTypedArray(count, size);  let index = 0;  for (let i = 0; i < count; i += 3, index += 6) {    addTriangle(lines, index, triangles[i], triangles[i + 1], triangles[i + 2]);  }  return lines;}function triangleStripToLines(triangles) {  const count = triangles.length;  if (count >= 3) {    const size = (count - 2) * 6;    const lines = IndexDatatype.createTypedArray(count, size);    addTriangle(lines, 0, triangles[0], triangles[1], triangles[2]);    let index = 6;    for (let i = 3; i < count; ++i, index += 6) {      addTriangle(        lines,        index,        triangles[i - 1],        triangles[i],        triangles[i - 2]      );    }    return lines;  }  return new Uint16Array();}function triangleFanToLines(triangles) {  if (triangles.length > 0) {    const count = triangles.length - 1;    const size = (count - 1) * 6;    const lines = IndexDatatype.createTypedArray(count, size);    const base = triangles[0];    let index = 0;    for (let i = 1; i < count; ++i, index += 6) {      addTriangle(lines, index, base, triangles[i], triangles[i + 1]);    }    return lines;  }  return new Uint16Array();}/** * Converts a geometry's triangle indices to line indices.  If the geometry has an <code>indices</code> * and its <code>primitiveType</code> is <code>TRIANGLES</code>, <code>TRIANGLE_STRIP</code>, * <code>TRIANGLE_FAN</code>, it is converted to <code>LINES</code>; otherwise, the geometry is not changed. * <p> * This is commonly used to create a wireframe geometry for visual debugging. * </p> * * @param {Geometry} geometry The geometry to modify. * @returns {Geometry} The modified <code>geometry</code> argument, with its triangle indices converted to lines. * * @exception {DeveloperError} geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN. * * @example * geometry = Cesium.GeometryPipeline.toWireframe(geometry); */GeometryPipeline.toWireframe = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug');  const indices = geometry.indices;  if (defined(indices)) {    switch (geometry.primitiveType) {      case PrimitiveType.TRIANGLES:        geometry.indices = trianglesToLines(indices);        break;      case PrimitiveType.TRIANGLE_STRIP:        geometry.indices = triangleStripToLines(indices);        break;      case PrimitiveType.TRIANGLE_FAN:        geometry.indices = triangleFanToLines(indices);        break;      //>>includeStart('debug', pragmas.debug);      default:        throw new DeveloperError(          "geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN."        );      //>>includeEnd('debug');    }    geometry.primitiveType = PrimitiveType.LINES;  }  return geometry;};/** * Creates a new {@link Geometry} with <code>LINES</code> representing the provided * attribute (<code>attributeName</code>) for the provided geometry.  This is used to * visualize vector attributes like normals, tangents, and bitangents. * * @param {Geometry} geometry The <code>Geometry</code> instance with the attribute. * @param {String} [attributeName='normal'] The name of the attribute. * @param {Number} [length=10000.0] The length of each line segment in meters.  This can be negative to point the vector in the opposite direction. * @returns {Geometry} A new <code>Geometry</code> instance with line segments for the vector. * * @exception {DeveloperError} geometry.attributes must have an attribute with the same name as the attributeName parameter. * * @example * const geometry = Cesium.GeometryPipeline.createLineSegmentsForVectors(instance.geometry, 'bitangent', 100000.0); */GeometryPipeline.createLineSegmentsForVectors = function (  geometry,  attributeName,  length) {  attributeName = defaultValue(attributeName, "normal");  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  if (!defined(geometry.attributes.position)) {    throw new DeveloperError("geometry.attributes.position is required.");  }  if (!defined(geometry.attributes[attributeName])) {    throw new DeveloperError(      `geometry.attributes must have an attribute with the same name as the attributeName parameter, ${attributeName}.`    );  }  //>>includeEnd('debug');  length = defaultValue(length, 10000.0);  const positions = geometry.attributes.position.values;  const vectors = geometry.attributes[attributeName].values;  const positionsLength = positions.length;  const newPositions = new Float64Array(2 * positionsLength);  let j = 0;  for (let i = 0; i < positionsLength; i += 3) {    newPositions[j++] = positions[i];    newPositions[j++] = positions[i + 1];    newPositions[j++] = positions[i + 2];    newPositions[j++] = positions[i] + vectors[i] * length;    newPositions[j++] = positions[i + 1] + vectors[i + 1] * length;    newPositions[j++] = positions[i + 2] + vectors[i + 2] * length;  }  let newBoundingSphere;  const bs = geometry.boundingSphere;  if (defined(bs)) {    newBoundingSphere = new BoundingSphere(bs.center, bs.radius + length);  }  return new Geometry({    attributes: {      position: new GeometryAttribute({        componentDatatype: ComponentDatatype.DOUBLE,        componentsPerAttribute: 3,        values: newPositions,      }),    },    primitiveType: PrimitiveType.LINES,    boundingSphere: newBoundingSphere,  });};/** * Creates an object that maps attribute names to unique locations (indices) * for matching vertex attributes and shader programs. * * @param {Geometry} geometry The geometry, which is not modified, to create the object for. * @returns {Object} An object with attribute name / index pairs. * * @example * const attributeLocations = Cesium.GeometryPipeline.createAttributeLocations(geometry); * // Example output * // { * //   'position' : 0, * //   'normal' : 1 * // } */GeometryPipeline.createAttributeLocations = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug')  // There can be a WebGL performance hit when attribute 0 is disabled, so  // assign attribute locations to well-known attributes.  const semantics = [    "position",    "positionHigh",    "positionLow",    // From VertexFormat.position - after 2D projection and high-precision encoding    "position3DHigh",    "position3DLow",    "position2DHigh",    "position2DLow",    // From Primitive    "pickColor",    // From VertexFormat    "normal",    "st",    "tangent",    "bitangent",    // For shadow volumes    "extrudeDirection",    // From compressing texture coordinates and normals    "compressedAttributes",  ];  const attributes = geometry.attributes;  const indices = {};  let j = 0;  let i;  const len = semantics.length;  // Attribute locations for well-known attributes  for (i = 0; i < len; ++i) {    const semantic = semantics[i];    if (defined(attributes[semantic])) {      indices[semantic] = j++;    }  }  // Locations for custom attributes  for (const name in attributes) {    if (attributes.hasOwnProperty(name) && !defined(indices[name])) {      indices[name] = j++;    }  }  return indices;};/** * Reorders a geometry's attributes and <code>indices</code> to achieve better performance from the GPU's pre-vertex-shader cache. * * @param {Geometry} geometry The geometry to modify. * @returns {Geometry} The modified <code>geometry</code> argument, with its attributes and indices reordered for the GPU's pre-vertex-shader cache. * * @exception {DeveloperError} Each attribute array in geometry.attributes must have the same number of attributes. * * * @example * geometry = Cesium.GeometryPipeline.reorderForPreVertexCache(geometry); * * @see GeometryPipeline.reorderForPostVertexCache */GeometryPipeline.reorderForPreVertexCache = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug');  const numVertices = Geometry.computeNumberOfVertices(geometry);  const indices = geometry.indices;  if (defined(indices)) {    const indexCrossReferenceOldToNew = new Int32Array(numVertices);    for (let i = 0; i < numVertices; i++) {      indexCrossReferenceOldToNew[i] = -1;    }    // Construct cross reference and reorder indices    const indicesIn = indices;    const numIndices = indicesIn.length;    const indicesOut = IndexDatatype.createTypedArray(numVertices, numIndices);    let intoIndicesIn = 0;    let intoIndicesOut = 0;    let nextIndex = 0;    let tempIndex;    while (intoIndicesIn < numIndices) {      tempIndex = indexCrossReferenceOldToNew[indicesIn[intoIndicesIn]];      if (tempIndex !== -1) {        indicesOut[intoIndicesOut] = tempIndex;      } else {        tempIndex = indicesIn[intoIndicesIn];        indexCrossReferenceOldToNew[tempIndex] = nextIndex;        indicesOut[intoIndicesOut] = nextIndex;        ++nextIndex;      }      ++intoIndicesIn;      ++intoIndicesOut;    }    geometry.indices = indicesOut;    // Reorder attributes    const attributes = geometry.attributes;    for (const property in attributes) {      if (        attributes.hasOwnProperty(property) &&        defined(attributes[property]) &&        defined(attributes[property].values)      ) {        const attribute = attributes[property];        const elementsIn = attribute.values;        let intoElementsIn = 0;        const numComponents = attribute.componentsPerAttribute;        const elementsOut = ComponentDatatype.createTypedArray(          attribute.componentDatatype,          nextIndex * numComponents        );        while (intoElementsIn < numVertices) {          const temp = indexCrossReferenceOldToNew[intoElementsIn];          if (temp !== -1) {            for (let j = 0; j < numComponents; j++) {              elementsOut[numComponents * temp + j] =                elementsIn[numComponents * intoElementsIn + j];            }          }          ++intoElementsIn;        }        attribute.values = elementsOut;      }    }  }  return geometry;};/** * Reorders a geometry's <code>indices</code> to achieve better performance from the GPU's * post vertex-shader cache by using the Tipsify algorithm.  If the geometry <code>primitiveType</code> * is not <code>TRIANGLES</code> or the geometry does not have an <code>indices</code>, this function has no effect. * * @param {Geometry} geometry The geometry to modify. * @param {Number} [cacheCapacity=24] The number of vertices that can be held in the GPU's vertex cache. * @returns {Geometry} The modified <code>geometry</code> argument, with its indices reordered for the post-vertex-shader cache. * * @exception {DeveloperError} cacheCapacity must be greater than two. * * * @example * geometry = Cesium.GeometryPipeline.reorderForPostVertexCache(geometry); * * @see GeometryPipeline.reorderForPreVertexCache * @see {@link http://gfx.cs.princ0eton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf|Fast Triangle Reordering for Vertex Locality and Reduced Overdraw} * by Sander, Nehab, and Barczak */GeometryPipeline.reorderForPostVertexCache = function (  geometry,  cacheCapacity) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug');  const indices = geometry.indices;  if (geometry.primitiveType === PrimitiveType.TRIANGLES && defined(indices)) {    const numIndices = indices.length;    let maximumIndex = 0;    for (let j = 0; j < numIndices; j++) {      if (indices[j] > maximumIndex) {        maximumIndex = indices[j];      }    }    geometry.indices = Tipsify.tipsify({      indices: indices,      maximumIndex: maximumIndex,      cacheSize: cacheCapacity,    });  }  return geometry;};function copyAttributesDescriptions(attributes) {  const newAttributes = {};  for (const attribute in attributes) {    if (      attributes.hasOwnProperty(attribute) &&      defined(attributes[attribute]) &&      defined(attributes[attribute].values)    ) {      const attr = attributes[attribute];      newAttributes[attribute] = new GeometryAttribute({        componentDatatype: attr.componentDatatype,        componentsPerAttribute: attr.componentsPerAttribute,        normalize: attr.normalize,        values: [],      });    }  }  return newAttributes;}function copyVertex(destinationAttributes, sourceAttributes, index) {  for (const attribute in sourceAttributes) {    if (      sourceAttributes.hasOwnProperty(attribute) &&      defined(sourceAttributes[attribute]) &&      defined(sourceAttributes[attribute].values)    ) {      const attr = sourceAttributes[attribute];      for (let k = 0; k < attr.componentsPerAttribute; ++k) {        destinationAttributes[attribute].values.push(          attr.values[index * attr.componentsPerAttribute + k]        );      }    }  }}/** * Splits a geometry into multiple geometries, if necessary, to ensure that indices in the * <code>indices</code> fit into unsigned shorts.  This is used to meet the WebGL requirements * when unsigned int indices are not supported. * <p> * If the geometry does not have any <code>indices</code>, this function has no effect. * </p> * * @param {Geometry} geometry The geometry to be split into multiple geometries. * @returns {Geometry[]} An array of geometries, each with indices that fit into unsigned shorts. * * @exception {DeveloperError} geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS * @exception {DeveloperError} All geometry attribute lists must have the same number of attributes. * * @example * const geometries = Cesium.GeometryPipeline.fitToUnsignedShortIndices(geometry); */GeometryPipeline.fitToUnsignedShortIndices = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  if (    defined(geometry.indices) &&    geometry.primitiveType !== PrimitiveType.TRIANGLES &&    geometry.primitiveType !== PrimitiveType.LINES &&    geometry.primitiveType !== PrimitiveType.POINTS  ) {    throw new DeveloperError(      "geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS."    );  }  //>>includeEnd('debug');  const geometries = [];  // If there's an index list and more than 64K attributes, it is possible that  // some indices are outside the range of unsigned short [0, 64K - 1]  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  if (    defined(geometry.indices) &&    numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES  ) {    let oldToNewIndex = [];    let newIndices = [];    let currentIndex = 0;    let newAttributes = copyAttributesDescriptions(geometry.attributes);    const originalIndices = geometry.indices;    const numberOfIndices = originalIndices.length;    let indicesPerPrimitive;    if (geometry.primitiveType === PrimitiveType.TRIANGLES) {      indicesPerPrimitive = 3;    } else if (geometry.primitiveType === PrimitiveType.LINES) {      indicesPerPrimitive = 2;    } else if (geometry.primitiveType === PrimitiveType.POINTS) {      indicesPerPrimitive = 1;    }    for (let j = 0; j < numberOfIndices; j += indicesPerPrimitive) {      for (let k = 0; k < indicesPerPrimitive; ++k) {        const x = originalIndices[j + k];        let i = oldToNewIndex[x];        if (!defined(i)) {          i = currentIndex++;          oldToNewIndex[x] = i;          copyVertex(newAttributes, geometry.attributes, x);        }        newIndices.push(i);      }      if (        currentIndex + indicesPerPrimitive >=        CesiumMath.SIXTY_FOUR_KILOBYTES      ) {        geometries.push(          new Geometry({            attributes: newAttributes,            indices: newIndices,            primitiveType: geometry.primitiveType,            boundingSphere: geometry.boundingSphere,            boundingSphereCV: geometry.boundingSphereCV,          })        );        // Reset for next vertex-array        oldToNewIndex = [];        newIndices = [];        currentIndex = 0;        newAttributes = copyAttributesDescriptions(geometry.attributes);      }    }    if (newIndices.length !== 0) {      geometries.push(        new Geometry({          attributes: newAttributes,          indices: newIndices,          primitiveType: geometry.primitiveType,          boundingSphere: geometry.boundingSphere,          boundingSphereCV: geometry.boundingSphereCV,        })      );    }  } else {    // No need to split into multiple geometries    geometries.push(geometry);  }  return geometries;};const scratchProjectTo2DCartesian3 = new Cartesian3();const scratchProjectTo2DCartographic = new Cartographic();/** * Projects a geometry's 3D <code>position</code> attribute to 2D, replacing the <code>position</code> * attribute with separate <code>position3D</code> and <code>position2D</code> attributes. * <p> * If the geometry does not have a <code>position</code>, this function has no effect. * </p> * * @param {Geometry} geometry The geometry to modify. * @param {String} attributeName The name of the attribute. * @param {String} attributeName3D The name of the attribute in 3D. * @param {String} attributeName2D The name of the attribute in 2D. * @param {Object} [projection=new GeographicProjection()] The projection to use. * @returns {Geometry} The modified <code>geometry</code> argument with <code>position3D</code> and <code>position2D</code> attributes. * * @exception {DeveloperError} geometry must have attribute matching the attributeName argument. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE. * @exception {DeveloperError} Could not project a point to 2D. * * @example * geometry = Cesium.GeometryPipeline.projectTo2D(geometry, 'position', 'position3D', 'position2D'); */GeometryPipeline.projectTo2D = function (  geometry,  attributeName,  attributeName3D,  attributeName2D,  projection) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  if (!defined(attributeName)) {    throw new DeveloperError("attributeName is required.");  }  if (!defined(attributeName3D)) {    throw new DeveloperError("attributeName3D is required.");  }  if (!defined(attributeName2D)) {    throw new DeveloperError("attributeName2D is required.");  }  if (!defined(geometry.attributes[attributeName])) {    throw new DeveloperError(      `geometry must have attribute matching the attributeName argument: ${attributeName}.`    );  }  if (    geometry.attributes[attributeName].componentDatatype !==    ComponentDatatype.DOUBLE  ) {    throw new DeveloperError(      "The attribute componentDatatype must be ComponentDatatype.DOUBLE."    );  }  //>>includeEnd('debug');  const attribute = geometry.attributes[attributeName];  projection = defined(projection) ? projection : new GeographicProjection();  const ellipsoid = projection.ellipsoid;  // Project original values to 2D.  const values3D = attribute.values;  const projectedValues = new Float64Array(values3D.length);  let index = 0;  for (let i = 0; i < values3D.length; i += 3) {    const value = Cartesian3.fromArray(      values3D,      i,      scratchProjectTo2DCartesian3    );    const lonLat = ellipsoid.cartesianToCartographic(      value,      scratchProjectTo2DCartographic    );    //>>includeStart('debug', pragmas.debug);    if (!defined(lonLat)) {      throw new DeveloperError(        `Could not project point (${value.x}, ${value.y}, ${value.z}) to 2D.`      );    }    //>>includeEnd('debug');    const projectedLonLat = projection.project(      lonLat,      scratchProjectTo2DCartesian3    );    projectedValues[index++] = projectedLonLat.x;    projectedValues[index++] = projectedLonLat.y;    projectedValues[index++] = projectedLonLat.z;  }  // Rename original cartesians to WGS84 cartesians.  geometry.attributes[attributeName3D] = attribute;  // Replace original cartesians with 2D projected cartesians  geometry.attributes[attributeName2D] = new GeometryAttribute({    componentDatatype: ComponentDatatype.DOUBLE,    componentsPerAttribute: 3,    values: projectedValues,  });  delete geometry.attributes[attributeName];  return geometry;};const encodedResult = {  high: 0.0,  low: 0.0,};/** * Encodes floating-point geometry attribute values as two separate attributes to improve * rendering precision. * <p> * This is commonly used to create high-precision position vertex attributes. * </p> * * @param {Geometry} geometry The geometry to modify. * @param {String} attributeName The name of the attribute. * @param {String} attributeHighName The name of the attribute for the encoded high bits. * @param {String} attributeLowName The name of the attribute for the encoded low bits. * @returns {Geometry} The modified <code>geometry</code> argument, with its encoded attribute. * * @exception {DeveloperError} geometry must have attribute matching the attributeName argument. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE. * * @example * geometry = Cesium.GeometryPipeline.encodeAttribute(geometry, 'position3D', 'position3DHigh', 'position3DLow'); */GeometryPipeline.encodeAttribute = function (  geometry,  attributeName,  attributeHighName,  attributeLowName) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  if (!defined(attributeName)) {    throw new DeveloperError("attributeName is required.");  }  if (!defined(attributeHighName)) {    throw new DeveloperError("attributeHighName is required.");  }  if (!defined(attributeLowName)) {    throw new DeveloperError("attributeLowName is required.");  }  if (!defined(geometry.attributes[attributeName])) {    throw new DeveloperError(      `geometry must have attribute matching the attributeName argument: ${attributeName}.`    );  }  if (    geometry.attributes[attributeName].componentDatatype !==    ComponentDatatype.DOUBLE  ) {    throw new DeveloperError(      "The attribute componentDatatype must be ComponentDatatype.DOUBLE."    );  }  //>>includeEnd('debug');  const attribute = geometry.attributes[attributeName];  const values = attribute.values;  const length = values.length;  const highValues = new Float32Array(length);  const lowValues = new Float32Array(length);  for (let i = 0; i < length; ++i) {    EncodedCartesian3.encode(values[i], encodedResult);    highValues[i] = encodedResult.high;    lowValues[i] = encodedResult.low;  }  const componentsPerAttribute = attribute.componentsPerAttribute;  geometry.attributes[attributeHighName] = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: componentsPerAttribute,    values: highValues,  });  geometry.attributes[attributeLowName] = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: componentsPerAttribute,    values: lowValues,  });  delete geometry.attributes[attributeName];  return geometry;};let scratchCartesian3 = new Cartesian3();function transformPoint(matrix, attribute) {  if (defined(attribute)) {    const values = attribute.values;    const length = values.length;    for (let i = 0; i < length; i += 3) {      Cartesian3.unpack(values, i, scratchCartesian3);      Matrix4.multiplyByPoint(matrix, scratchCartesian3, scratchCartesian3);      Cartesian3.pack(scratchCartesian3, values, i);    }  }}function transformVector(matrix, attribute) {  if (defined(attribute)) {    const values = attribute.values;    const length = values.length;    for (let i = 0; i < length; i += 3) {      Cartesian3.unpack(values, i, scratchCartesian3);      Matrix3.multiplyByVector(matrix, scratchCartesian3, scratchCartesian3);      scratchCartesian3 = Cartesian3.normalize(        scratchCartesian3,        scratchCartesian3      );      Cartesian3.pack(scratchCartesian3, values, i);    }  }}const inverseTranspose = new Matrix4();const normalMatrix = new Matrix3();/** * Transforms a geometry instance to world coordinates.  This changes * the instance's <code>modelMatrix</code> to {@link Matrix4.IDENTITY} and transforms the * following attributes if they are present: <code>position</code>, <code>normal</code>, * <code>tangent</code>, and <code>bitangent</code>. * * @param {GeometryInstance} instance The geometry instance to modify. * @returns {GeometryInstance} The modified <code>instance</code> argument, with its attributes transforms to world coordinates. * * @example * Cesium.GeometryPipeline.transformToWorldCoordinates(instance); */GeometryPipeline.transformToWorldCoordinates = function (instance) {  //>>includeStart('debug', pragmas.debug);  if (!defined(instance)) {    throw new DeveloperError("instance is required.");  }  //>>includeEnd('debug');  const modelMatrix = instance.modelMatrix;  if (Matrix4.equals(modelMatrix, Matrix4.IDENTITY)) {    // Already in world coordinates    return instance;  }  const attributes = instance.geometry.attributes;  // Transform attributes in known vertex formats  transformPoint(modelMatrix, attributes.position);  transformPoint(modelMatrix, attributes.prevPosition);  transformPoint(modelMatrix, attributes.nextPosition);  if (    defined(attributes.normal) ||    defined(attributes.tangent) ||    defined(attributes.bitangent)  ) {    Matrix4.inverse(modelMatrix, inverseTranspose);    Matrix4.transpose(inverseTranspose, inverseTranspose);    Matrix4.getMatrix3(inverseTranspose, normalMatrix);    transformVector(normalMatrix, attributes.normal);    transformVector(normalMatrix, attributes.tangent);    transformVector(normalMatrix, attributes.bitangent);  }  const boundingSphere = instance.geometry.boundingSphere;  if (defined(boundingSphere)) {    instance.geometry.boundingSphere = BoundingSphere.transform(      boundingSphere,      modelMatrix,      boundingSphere    );  }  instance.modelMatrix = Matrix4.clone(Matrix4.IDENTITY);  return instance;};function findAttributesInAllGeometries(instances, propertyName) {  const length = instances.length;  const attributesInAllGeometries = {};  const attributes0 = instances[0][propertyName].attributes;  let name;  for (name in attributes0) {    if (      attributes0.hasOwnProperty(name) &&      defined(attributes0[name]) &&      defined(attributes0[name].values)    ) {      const attribute = attributes0[name];      let numberOfComponents = attribute.values.length;      let inAllGeometries = true;      // Does this same attribute exist in all geometries?      for (let i = 1; i < length; ++i) {        const otherAttribute = instances[i][propertyName].attributes[name];        if (          !defined(otherAttribute) ||          attribute.componentDatatype !== otherAttribute.componentDatatype ||          attribute.componentsPerAttribute !==            otherAttribute.componentsPerAttribute ||          attribute.normalize !== otherAttribute.normalize        ) {          inAllGeometries = false;          break;        }        numberOfComponents += otherAttribute.values.length;      }      if (inAllGeometries) {        attributesInAllGeometries[name] = new GeometryAttribute({          componentDatatype: attribute.componentDatatype,          componentsPerAttribute: attribute.componentsPerAttribute,          normalize: attribute.normalize,          values: ComponentDatatype.createTypedArray(            attribute.componentDatatype,            numberOfComponents          ),        });      }    }  }  return attributesInAllGeometries;}const tempScratch = new Cartesian3();function combineGeometries(instances, propertyName) {  const length = instances.length;  let name;  let i;  let j;  let k;  const m = instances[0].modelMatrix;  const haveIndices = defined(instances[0][propertyName].indices);  const primitiveType = instances[0][propertyName].primitiveType;  //>>includeStart('debug', pragmas.debug);  for (i = 1; i < length; ++i) {    if (!Matrix4.equals(instances[i].modelMatrix, m)) {      throw new DeveloperError("All instances must have the same modelMatrix.");    }    if (defined(instances[i][propertyName].indices) !== haveIndices) {      throw new DeveloperError(        "All instance geometries must have an indices or not have one."      );    }    if (instances[i][propertyName].primitiveType !== primitiveType) {      throw new DeveloperError(        "All instance geometries must have the same primitiveType."      );    }  }  //>>includeEnd('debug');  // Find subset of attributes in all geometries  const attributes = findAttributesInAllGeometries(instances, propertyName);  let values;  let sourceValues;  let sourceValuesLength;  // Combine attributes from each geometry into a single typed array  for (name in attributes) {    if (attributes.hasOwnProperty(name)) {      values = attributes[name].values;      k = 0;      for (i = 0; i < length; ++i) {        sourceValues = instances[i][propertyName].attributes[name].values;        sourceValuesLength = sourceValues.length;        for (j = 0; j < sourceValuesLength; ++j) {          values[k++] = sourceValues[j];        }      }    }  }  // Combine index lists  let indices;  if (haveIndices) {    let numberOfIndices = 0;    for (i = 0; i < length; ++i) {      numberOfIndices += instances[i][propertyName].indices.length;    }    const numberOfVertices = Geometry.computeNumberOfVertices(      new Geometry({        attributes: attributes,        primitiveType: PrimitiveType.POINTS,      })    );    const destIndices = IndexDatatype.createTypedArray(      numberOfVertices,      numberOfIndices    );    let destOffset = 0;    let offset = 0;    for (i = 0; i < length; ++i) {      const sourceIndices = instances[i][propertyName].indices;      const sourceIndicesLen = sourceIndices.length;      for (k = 0; k < sourceIndicesLen; ++k) {        destIndices[destOffset++] = offset + sourceIndices[k];      }      offset += Geometry.computeNumberOfVertices(instances[i][propertyName]);    }    indices = destIndices;  }  // Create bounding sphere that includes all instances  let center = new Cartesian3();  let radius = 0.0;  let bs;  for (i = 0; i < length; ++i) {    bs = instances[i][propertyName].boundingSphere;    if (!defined(bs)) {      // If any geometries have an undefined bounding sphere, then so does the combined geometry      center = undefined;      break;    }    Cartesian3.add(bs.center, center, center);  }  if (defined(center)) {    Cartesian3.divideByScalar(center, length, center);    for (i = 0; i < length; ++i) {      bs = instances[i][propertyName].boundingSphere;      const tempRadius =        Cartesian3.magnitude(          Cartesian3.subtract(bs.center, center, tempScratch)        ) + bs.radius;      if (tempRadius > radius) {        radius = tempRadius;      }    }  }  return new Geometry({    attributes: attributes,    indices: indices,    primitiveType: primitiveType,    boundingSphere: defined(center)      ? new BoundingSphere(center, radius)      : undefined,  });}/** * Combines geometry from several {@link GeometryInstance} objects into one geometry. * This concatenates the attributes, concatenates and adjusts the indices, and creates * a bounding sphere encompassing all instances. * <p> * If the instances do not have the same attributes, a subset of attributes common * to all instances is used, and the others are ignored. * </p> * <p> * This is used by {@link Primitive} to efficiently render a large amount of static data. * </p> * * @private * * @param {GeometryInstance[]} [instances] The array of {@link GeometryInstance} objects whose geometry will be combined. * @returns {Geometry} A single geometry created from the provided geometry instances. * * @exception {DeveloperError} All instances must have the same modelMatrix. * @exception {DeveloperError} All instance geometries must have an indices or not have one. * @exception {DeveloperError} All instance geometries must have the same primitiveType. * * * @example * for (let i = 0; i < instances.length; ++i) { *   Cesium.GeometryPipeline.transformToWorldCoordinates(instances[i]); * } * const geometries = Cesium.GeometryPipeline.combineInstances(instances); * * @see GeometryPipeline.transformToWorldCoordinates */GeometryPipeline.combineInstances = function (instances) {  //>>includeStart('debug', pragmas.debug);  if (!defined(instances) || instances.length < 1) {    throw new DeveloperError(      "instances is required and must have length greater than zero."    );  }  //>>includeEnd('debug');  const instanceGeometry = [];  const instanceSplitGeometry = [];  const length = instances.length;  for (let i = 0; i < length; ++i) {    const instance = instances[i];    if (defined(instance.geometry)) {      instanceGeometry.push(instance);    } else if (      defined(instance.westHemisphereGeometry) &&      defined(instance.eastHemisphereGeometry)    ) {      instanceSplitGeometry.push(instance);    }  }  const geometries = [];  if (instanceGeometry.length > 0) {    geometries.push(combineGeometries(instanceGeometry, "geometry"));  }  if (instanceSplitGeometry.length > 0) {    geometries.push(      combineGeometries(instanceSplitGeometry, "westHemisphereGeometry")    );    geometries.push(      combineGeometries(instanceSplitGeometry, "eastHemisphereGeometry")    );  }  return geometries;};const normal = new Cartesian3();const v0 = new Cartesian3();const v1 = new Cartesian3();const v2 = new Cartesian3();/** * Computes per-vertex normals for a geometry containing <code>TRIANGLES</code> by averaging the normals of * all triangles incident to the vertex.  The result is a new <code>normal</code> attribute added to the geometry. * This assumes a counter-clockwise winding order. * * @param {Geometry} geometry The geometry to modify. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>normal</code> attribute. * * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}. * * @example * Cesium.GeometryPipeline.computeNormal(geometry); */GeometryPipeline.computeNormal = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  if (    !defined(geometry.attributes.position) ||    !defined(geometry.attributes.position.values)  ) {    throw new DeveloperError(      "geometry.attributes.position.values is required."    );  }  if (!defined(geometry.indices)) {    throw new DeveloperError("geometry.indices is required.");  }  if (geometry.indices.length < 2 || geometry.indices.length % 3 !== 0) {    throw new DeveloperError(      "geometry.indices length must be greater than 0 and be a multiple of 3."    );  }  if (geometry.primitiveType !== PrimitiveType.TRIANGLES) {    throw new DeveloperError(      "geometry.primitiveType must be PrimitiveType.TRIANGLES."    );  }  //>>includeEnd('debug');  const indices = geometry.indices;  const attributes = geometry.attributes;  const vertices = attributes.position.values;  const numVertices = attributes.position.values.length / 3;  const numIndices = indices.length;  const normalsPerVertex = new Array(numVertices);  const normalsPerTriangle = new Array(numIndices / 3);  const normalIndices = new Array(numIndices);  let i;  for (i = 0; i < numVertices; i++) {    normalsPerVertex[i] = {      indexOffset: 0,      count: 0,      currentCount: 0,    };  }  let j = 0;  for (i = 0; i < numIndices; i += 3) {    const i0 = indices[i];    const i1 = indices[i + 1];    const i2 = indices[i + 2];    const i03 = i0 * 3;    const i13 = i1 * 3;    const i23 = i2 * 3;    v0.x = vertices[i03];    v0.y = vertices[i03 + 1];    v0.z = vertices[i03 + 2];    v1.x = vertices[i13];    v1.y = vertices[i13 + 1];    v1.z = vertices[i13 + 2];    v2.x = vertices[i23];    v2.y = vertices[i23 + 1];    v2.z = vertices[i23 + 2];    normalsPerVertex[i0].count++;    normalsPerVertex[i1].count++;    normalsPerVertex[i2].count++;    Cartesian3.subtract(v1, v0, v1);    Cartesian3.subtract(v2, v0, v2);    normalsPerTriangle[j] = Cartesian3.cross(v1, v2, new Cartesian3());    j++;  }  let indexOffset = 0;  for (i = 0; i < numVertices; i++) {    normalsPerVertex[i].indexOffset += indexOffset;    indexOffset += normalsPerVertex[i].count;  }  j = 0;  let vertexNormalData;  for (i = 0; i < numIndices; i += 3) {    vertexNormalData = normalsPerVertex[indices[i]];    let index = vertexNormalData.indexOffset + vertexNormalData.currentCount;    normalIndices[index] = j;    vertexNormalData.currentCount++;    vertexNormalData = normalsPerVertex[indices[i + 1]];    index = vertexNormalData.indexOffset + vertexNormalData.currentCount;    normalIndices[index] = j;    vertexNormalData.currentCount++;    vertexNormalData = normalsPerVertex[indices[i + 2]];    index = vertexNormalData.indexOffset + vertexNormalData.currentCount;    normalIndices[index] = j;    vertexNormalData.currentCount++;    j++;  }  const normalValues = new Float32Array(numVertices * 3);  for (i = 0; i < numVertices; i++) {    const i3 = i * 3;    vertexNormalData = normalsPerVertex[i];    Cartesian3.clone(Cartesian3.ZERO, normal);    if (vertexNormalData.count > 0) {      for (j = 0; j < vertexNormalData.count; j++) {        Cartesian3.add(          normal,          normalsPerTriangle[normalIndices[vertexNormalData.indexOffset + j]],          normal        );      }      // We can run into an issue where a vertex is used with 2 primitives that have opposite winding order.      if (        Cartesian3.equalsEpsilon(Cartesian3.ZERO, normal, CesiumMath.EPSILON10)      ) {        Cartesian3.clone(          normalsPerTriangle[normalIndices[vertexNormalData.indexOffset]],          normal        );      }    }    // We end up with a zero vector probably because of a degenerate triangle    if (      Cartesian3.equalsEpsilon(Cartesian3.ZERO, normal, CesiumMath.EPSILON10)    ) {      // Default to (0,0,1)      normal.z = 1.0;    }    Cartesian3.normalize(normal, normal);    normalValues[i3] = normal.x;    normalValues[i3 + 1] = normal.y;    normalValues[i3 + 2] = normal.z;  }  geometry.attributes.normal = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: 3,    values: normalValues,  });  return geometry;};const normalScratch = new Cartesian3();const normalScale = new Cartesian3();const tScratch = new Cartesian3();/** * Computes per-vertex tangents and bitangents for a geometry containing <code>TRIANGLES</code>. * The result is new <code>tangent</code> and <code>bitangent</code> attributes added to the geometry. * This assumes a counter-clockwise winding order. * <p> * Based on <a href="http://www.terathon.com/code/tangent.html">Computing Tangent Space Basis Vectors * for an Arbitrary Mesh</a> by Eric Lengyel. * </p> * * @param {Geometry} geometry The geometry to modify. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>tangent</code> and <code>bitangent</code> attributes. * * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}. * * @example * Cesium.GeometryPipeline.computeTangentAndBiTangent(geometry); */GeometryPipeline.computeTangentAndBitangent = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug');  const attributes = geometry.attributes;  const indices = geometry.indices;  //>>includeStart('debug', pragmas.debug);  if (!defined(attributes.position) || !defined(attributes.position.values)) {    throw new DeveloperError(      "geometry.attributes.position.values is required."    );  }  if (!defined(attributes.normal) || !defined(attributes.normal.values)) {    throw new DeveloperError("geometry.attributes.normal.values is required.");  }  if (!defined(attributes.st) || !defined(attributes.st.values)) {    throw new DeveloperError("geometry.attributes.st.values is required.");  }  if (!defined(indices)) {    throw new DeveloperError("geometry.indices is required.");  }  if (indices.length < 2 || indices.length % 3 !== 0) {    throw new DeveloperError(      "geometry.indices length must be greater than 0 and be a multiple of 3."    );  }  if (geometry.primitiveType !== PrimitiveType.TRIANGLES) {    throw new DeveloperError(      "geometry.primitiveType must be PrimitiveType.TRIANGLES."    );  }  //>>includeEnd('debug');  const vertices = geometry.attributes.position.values;  const normals = geometry.attributes.normal.values;  const st = geometry.attributes.st.values;  const numVertices = geometry.attributes.position.values.length / 3;  const numIndices = indices.length;  const tan1 = new Array(numVertices * 3);  let i;  for (i = 0; i < tan1.length; i++) {    tan1[i] = 0;  }  let i03;  let i13;  let i23;  for (i = 0; i < numIndices; i += 3) {    const i0 = indices[i];    const i1 = indices[i + 1];    const i2 = indices[i + 2];    i03 = i0 * 3;    i13 = i1 * 3;    i23 = i2 * 3;    const i02 = i0 * 2;    const i12 = i1 * 2;    const i22 = i2 * 2;    const ux = vertices[i03];    const uy = vertices[i03 + 1];    const uz = vertices[i03 + 2];    const wx = st[i02];    const wy = st[i02 + 1];    const t1 = st[i12 + 1] - wy;    const t2 = st[i22 + 1] - wy;    const r = 1.0 / ((st[i12] - wx) * t2 - (st[i22] - wx) * t1);    const sdirx = (t2 * (vertices[i13] - ux) - t1 * (vertices[i23] - ux)) * r;    const sdiry =      (t2 * (vertices[i13 + 1] - uy) - t1 * (vertices[i23 + 1] - uy)) * r;    const sdirz =      (t2 * (vertices[i13 + 2] - uz) - t1 * (vertices[i23 + 2] - uz)) * r;    tan1[i03] += sdirx;    tan1[i03 + 1] += sdiry;    tan1[i03 + 2] += sdirz;    tan1[i13] += sdirx;    tan1[i13 + 1] += sdiry;    tan1[i13 + 2] += sdirz;    tan1[i23] += sdirx;    tan1[i23 + 1] += sdiry;    tan1[i23 + 2] += sdirz;  }  const tangentValues = new Float32Array(numVertices * 3);  const bitangentValues = new Float32Array(numVertices * 3);  for (i = 0; i < numVertices; i++) {    i03 = i * 3;    i13 = i03 + 1;    i23 = i03 + 2;    const n = Cartesian3.fromArray(normals, i03, normalScratch);    const t = Cartesian3.fromArray(tan1, i03, tScratch);    const scalar = Cartesian3.dot(n, t);    Cartesian3.multiplyByScalar(n, scalar, normalScale);    Cartesian3.normalize(Cartesian3.subtract(t, normalScale, t), t);    tangentValues[i03] = t.x;    tangentValues[i13] = t.y;    tangentValues[i23] = t.z;    Cartesian3.normalize(Cartesian3.cross(n, t, t), t);    bitangentValues[i03] = t.x;    bitangentValues[i13] = t.y;    bitangentValues[i23] = t.z;  }  geometry.attributes.tangent = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: 3,    values: tangentValues,  });  geometry.attributes.bitangent = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: 3,    values: bitangentValues,  });  return geometry;};const scratchCartesian2 = new Cartesian2();const toEncode1 = new Cartesian3();const toEncode2 = new Cartesian3();const toEncode3 = new Cartesian3();let encodeResult2 = new Cartesian2();/** * Compresses and packs geometry normal attribute values to save memory. * * @param {Geometry} geometry The geometry to modify. * @returns {Geometry} The modified <code>geometry</code> argument, with its normals compressed and packed. * * @example * geometry = Cesium.GeometryPipeline.compressVertices(geometry); */GeometryPipeline.compressVertices = function (geometry) {  //>>includeStart('debug', pragmas.debug);  if (!defined(geometry)) {    throw new DeveloperError("geometry is required.");  }  //>>includeEnd('debug');  const extrudeAttribute = geometry.attributes.extrudeDirection;  let i;  let numVertices;  if (defined(extrudeAttribute)) {    //only shadow volumes use extrudeDirection, and shadow volumes use vertexFormat: POSITION_ONLY so we don't need to check other attributes    const extrudeDirections = extrudeAttribute.values;    numVertices = extrudeDirections.length / 3.0;    const compressedDirections = new Float32Array(numVertices * 2);    let i2 = 0;    for (i = 0; i < numVertices; ++i) {      Cartesian3.fromArray(extrudeDirections, i * 3.0, toEncode1);      if (Cartesian3.equals(toEncode1, Cartesian3.ZERO)) {        i2 += 2;        continue;      }      encodeResult2 = AttributeCompression.octEncodeInRange(        toEncode1,        65535,        encodeResult2      );      compressedDirections[i2++] = encodeResult2.x;      compressedDirections[i2++] = encodeResult2.y;    }    geometry.attributes.compressedAttributes = new GeometryAttribute({      componentDatatype: ComponentDatatype.FLOAT,      componentsPerAttribute: 2,      values: compressedDirections,    });    delete geometry.attributes.extrudeDirection;    return geometry;  }  const normalAttribute = geometry.attributes.normal;  const stAttribute = geometry.attributes.st;  const hasNormal = defined(normalAttribute);  const hasSt = defined(stAttribute);  if (!hasNormal && !hasSt) {    return geometry;  }  const tangentAttribute = geometry.attributes.tangent;  const bitangentAttribute = geometry.attributes.bitangent;  const hasTangent = defined(tangentAttribute);  const hasBitangent = defined(bitangentAttribute);  let normals;  let st;  let tangents;  let bitangents;  if (hasNormal) {    normals = normalAttribute.values;  }  if (hasSt) {    st = stAttribute.values;  }  if (hasTangent) {    tangents = tangentAttribute.values;  }  if (hasBitangent) {    bitangents = bitangentAttribute.values;  }  const length = hasNormal ? normals.length : st.length;  const numComponents = hasNormal ? 3.0 : 2.0;  numVertices = length / numComponents;  let compressedLength = numVertices;  let numCompressedComponents = hasSt && hasNormal ? 2.0 : 1.0;  numCompressedComponents += hasTangent || hasBitangent ? 1.0 : 0.0;  compressedLength *= numCompressedComponents;  const compressedAttributes = new Float32Array(compressedLength);  let normalIndex = 0;  for (i = 0; i < numVertices; ++i) {    if (hasSt) {      Cartesian2.fromArray(st, i * 2.0, scratchCartesian2);      compressedAttributes[        normalIndex++      ] = AttributeCompression.compressTextureCoordinates(scratchCartesian2);    }    const index = i * 3.0;    if (hasNormal && defined(tangents) && defined(bitangents)) {      Cartesian3.fromArray(normals, index, toEncode1);      Cartesian3.fromArray(tangents, index, toEncode2);      Cartesian3.fromArray(bitangents, index, toEncode3);      AttributeCompression.octPack(        toEncode1,        toEncode2,        toEncode3,        scratchCartesian2      );      compressedAttributes[normalIndex++] = scratchCartesian2.x;      compressedAttributes[normalIndex++] = scratchCartesian2.y;    } else {      if (hasNormal) {        Cartesian3.fromArray(normals, index, toEncode1);        compressedAttributes[          normalIndex++        ] = AttributeCompression.octEncodeFloat(toEncode1);      }      if (hasTangent) {        Cartesian3.fromArray(tangents, index, toEncode1);        compressedAttributes[          normalIndex++        ] = AttributeCompression.octEncodeFloat(toEncode1);      }      if (hasBitangent) {        Cartesian3.fromArray(bitangents, index, toEncode1);        compressedAttributes[          normalIndex++        ] = AttributeCompression.octEncodeFloat(toEncode1);      }    }  }  geometry.attributes.compressedAttributes = new GeometryAttribute({    componentDatatype: ComponentDatatype.FLOAT,    componentsPerAttribute: numCompressedComponents,    values: compressedAttributes,  });  if (hasNormal) {    delete geometry.attributes.normal;  }  if (hasSt) {    delete geometry.attributes.st;  }  if (hasBitangent) {    delete geometry.attributes.bitangent;  }  if (hasTangent) {    delete geometry.attributes.tangent;  }  return geometry;};function indexTriangles(geometry) {  if (defined(geometry.indices)) {    return geometry;  }  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 3) {    throw new DeveloperError("The number of vertices must be at least three.");  }  if (numberOfVertices % 3 !== 0) {    throw new DeveloperError(      "The number of vertices must be a multiple of three."    );  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    numberOfVertices  );  for (let i = 0; i < numberOfVertices; ++i) {    indices[i] = i;  }  geometry.indices = indices;  return geometry;}function indexTriangleFan(geometry) {  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 3) {    throw new DeveloperError("The number of vertices must be at least three.");  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    (numberOfVertices - 2) * 3  );  indices[0] = 1;  indices[1] = 0;  indices[2] = 2;  let indicesIndex = 3;  for (let i = 3; i < numberOfVertices; ++i) {    indices[indicesIndex++] = i - 1;    indices[indicesIndex++] = 0;    indices[indicesIndex++] = i;  }  geometry.indices = indices;  geometry.primitiveType = PrimitiveType.TRIANGLES;  return geometry;}function indexTriangleStrip(geometry) {  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 3) {    throw new DeveloperError("The number of vertices must be at least 3.");  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    (numberOfVertices - 2) * 3  );  indices[0] = 0;  indices[1] = 1;  indices[2] = 2;  if (numberOfVertices > 3) {    indices[3] = 0;    indices[4] = 2;    indices[5] = 3;  }  let indicesIndex = 6;  for (let i = 3; i < numberOfVertices - 1; i += 2) {    indices[indicesIndex++] = i;    indices[indicesIndex++] = i - 1;    indices[indicesIndex++] = i + 1;    if (i + 2 < numberOfVertices) {      indices[indicesIndex++] = i;      indices[indicesIndex++] = i + 1;      indices[indicesIndex++] = i + 2;    }  }  geometry.indices = indices;  geometry.primitiveType = PrimitiveType.TRIANGLES;  return geometry;}function indexLines(geometry) {  if (defined(geometry.indices)) {    return geometry;  }  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 2) {    throw new DeveloperError("The number of vertices must be at least two.");  }  if (numberOfVertices % 2 !== 0) {    throw new DeveloperError("The number of vertices must be a multiple of 2.");  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    numberOfVertices  );  for (let i = 0; i < numberOfVertices; ++i) {    indices[i] = i;  }  geometry.indices = indices;  return geometry;}function indexLineStrip(geometry) {  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 2) {    throw new DeveloperError("The number of vertices must be at least two.");  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    (numberOfVertices - 1) * 2  );  indices[0] = 0;  indices[1] = 1;  let indicesIndex = 2;  for (let i = 2; i < numberOfVertices; ++i) {    indices[indicesIndex++] = i - 1;    indices[indicesIndex++] = i;  }  geometry.indices = indices;  geometry.primitiveType = PrimitiveType.LINES;  return geometry;}function indexLineLoop(geometry) {  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  //>>includeStart('debug', pragmas.debug);  if (numberOfVertices < 2) {    throw new DeveloperError("The number of vertices must be at least two.");  }  //>>includeEnd('debug');  const indices = IndexDatatype.createTypedArray(    numberOfVertices,    numberOfVertices * 2  );  indices[0] = 0;  indices[1] = 1;  let indicesIndex = 2;  for (let i = 2; i < numberOfVertices; ++i) {    indices[indicesIndex++] = i - 1;    indices[indicesIndex++] = i;  }  indices[indicesIndex++] = numberOfVertices - 1;  indices[indicesIndex] = 0;  geometry.indices = indices;  geometry.primitiveType = PrimitiveType.LINES;  return geometry;}function indexPrimitive(geometry) {  switch (geometry.primitiveType) {    case PrimitiveType.TRIANGLE_FAN:      return indexTriangleFan(geometry);    case PrimitiveType.TRIANGLE_STRIP:      return indexTriangleStrip(geometry);    case PrimitiveType.TRIANGLES:      return indexTriangles(geometry);    case PrimitiveType.LINE_STRIP:      return indexLineStrip(geometry);    case PrimitiveType.LINE_LOOP:      return indexLineLoop(geometry);    case PrimitiveType.LINES:      return indexLines(geometry);  }  return geometry;}function offsetPointFromXZPlane(p, isBehind) {  if (Math.abs(p.y) < CesiumMath.EPSILON6) {    if (isBehind) {      p.y = -CesiumMath.EPSILON6;    } else {      p.y = CesiumMath.EPSILON6;    }  }}function offsetTriangleFromXZPlane(p0, p1, p2) {  if (p0.y !== 0.0 && p1.y !== 0.0 && p2.y !== 0.0) {    offsetPointFromXZPlane(p0, p0.y < 0.0);    offsetPointFromXZPlane(p1, p1.y < 0.0);    offsetPointFromXZPlane(p2, p2.y < 0.0);    return;  }  const p0y = Math.abs(p0.y);  const p1y = Math.abs(p1.y);  const p2y = Math.abs(p2.y);  let sign;  if (p0y > p1y) {    if (p0y > p2y) {      sign = CesiumMath.sign(p0.y);    } else {      sign = CesiumMath.sign(p2.y);    }  } else if (p1y > p2y) {    sign = CesiumMath.sign(p1.y);  } else {    sign = CesiumMath.sign(p2.y);  }  const isBehind = sign < 0.0;  offsetPointFromXZPlane(p0, isBehind);  offsetPointFromXZPlane(p1, isBehind);  offsetPointFromXZPlane(p2, isBehind);}const c3 = new Cartesian3();function getXZIntersectionOffsetPoints(p, p1, u1, v1) {  Cartesian3.add(    p,    Cartesian3.multiplyByScalar(      Cartesian3.subtract(p1, p, c3),      p.y / (p.y - p1.y),      c3    ),    u1  );  Cartesian3.clone(u1, v1);  offsetPointFromXZPlane(u1, true);  offsetPointFromXZPlane(v1, false);}const u1 = new Cartesian3();const u2 = new Cartesian3();const q1 = new Cartesian3();const q2 = new Cartesian3();const splitTriangleResult = {  positions: new Array(7),  indices: new Array(3 * 3),};function splitTriangle(p0, p1, p2) {  // In WGS84 coordinates, for a triangle approximately on the  // ellipsoid to cross the IDL, first it needs to be on the  // negative side of the plane x = 0.  if (p0.x >= 0.0 || p1.x >= 0.0 || p2.x >= 0.0) {    return undefined;  }  offsetTriangleFromXZPlane(p0, p1, p2);  const p0Behind = p0.y < 0.0;  const p1Behind = p1.y < 0.0;  const p2Behind = p2.y < 0.0;  let numBehind = 0;  numBehind += p0Behind ? 1 : 0;  numBehind += p1Behind ? 1 : 0;  numBehind += p2Behind ? 1 : 0;  const indices = splitTriangleResult.indices;  if (numBehind === 1) {    indices[1] = 3;    indices[2] = 4;    indices[5] = 6;    indices[7] = 6;    indices[8] = 5;    if (p0Behind) {      getXZIntersectionOffsetPoints(p0, p1, u1, q1);      getXZIntersectionOffsetPoints(p0, p2, u2, q2);      indices[0] = 0;      indices[3] = 1;      indices[4] = 2;      indices[6] = 1;    } else if (p1Behind) {      getXZIntersectionOffsetPoints(p1, p2, u1, q1);      getXZIntersectionOffsetPoints(p1, p0, u2, q2);      indices[0] = 1;      indices[3] = 2;      indices[4] = 0;      indices[6] = 2;    } else if (p2Behind) {      getXZIntersectionOffsetPoints(p2, p0, u1, q1);      getXZIntersectionOffsetPoints(p2, p1, u2, q2);      indices[0] = 2;      indices[3] = 0;      indices[4] = 1;      indices[6] = 0;    }  } else if (numBehind === 2) {    indices[2] = 4;    indices[4] = 4;    indices[5] = 3;    indices[7] = 5;    indices[8] = 6;    if (!p0Behind) {      getXZIntersectionOffsetPoints(p0, p1, u1, q1);      getXZIntersectionOffsetPoints(p0, p2, u2, q2);      indices[0] = 1;      indices[1] = 2;      indices[3] = 1;      indices[6] = 0;    } else if (!p1Behind) {      getXZIntersectionOffsetPoints(p1, p2, u1, q1);      getXZIntersectionOffsetPoints(p1, p0, u2, q2);      indices[0] = 2;      indices[1] = 0;      indices[3] = 2;      indices[6] = 1;    } else if (!p2Behind) {      getXZIntersectionOffsetPoints(p2, p0, u1, q1);      getXZIntersectionOffsetPoints(p2, p1, u2, q2);      indices[0] = 0;      indices[1] = 1;      indices[3] = 0;      indices[6] = 2;    }  }  const positions = splitTriangleResult.positions;  positions[0] = p0;  positions[1] = p1;  positions[2] = p2;  positions.length = 3;  if (numBehind === 1 || numBehind === 2) {    positions[3] = u1;    positions[4] = u2;    positions[5] = q1;    positions[6] = q2;    positions.length = 7;  }  return splitTriangleResult;}function updateGeometryAfterSplit(geometry, computeBoundingSphere) {  const attributes = geometry.attributes;  if (attributes.position.values.length === 0) {    return undefined;  }  for (const property in attributes) {    if (      attributes.hasOwnProperty(property) &&      defined(attributes[property]) &&      defined(attributes[property].values)    ) {      const attribute = attributes[property];      attribute.values = ComponentDatatype.createTypedArray(        attribute.componentDatatype,        attribute.values      );    }  }  const numberOfVertices = Geometry.computeNumberOfVertices(geometry);  geometry.indices = IndexDatatype.createTypedArray(    numberOfVertices,    geometry.indices  );  if (computeBoundingSphere) {    geometry.boundingSphere = BoundingSphere.fromVertices(      attributes.position.values    );  }  return geometry;}function copyGeometryForSplit(geometry) {  const attributes = geometry.attributes;  const copiedAttributes = {};  for (const property in attributes) {    if (      attributes.hasOwnProperty(property) &&      defined(attributes[property]) &&      defined(attributes[property].values)    ) {      const attribute = attributes[property];      copiedAttributes[property] = new GeometryAttribute({        componentDatatype: attribute.componentDatatype,        componentsPerAttribute: attribute.componentsPerAttribute,        normalize: attribute.normalize,        values: [],      });    }  }  return new Geometry({    attributes: copiedAttributes,    indices: [],    primitiveType: geometry.primitiveType,  });}function updateInstanceAfterSplit(instance, westGeometry, eastGeometry) {  const computeBoundingSphere = defined(instance.geometry.boundingSphere);  westGeometry = updateGeometryAfterSplit(westGeometry, computeBoundingSphere);  eastGeometry = updateGeometryAfterSplit(eastGeometry, computeBoundingSphere);  if (defined(eastGeometry) && !defined(westGeometry)) {    instance.geometry = eastGeometry;  } else if (!defined(eastGeometry) && defined(westGeometry)) {    instance.geometry = westGeometry;  } else {    instance.westHemisphereGeometry = westGeometry;    instance.eastHemisphereGeometry = eastGeometry;    instance.geometry = undefined;  }}function generateBarycentricInterpolateFunction(  CartesianType,  numberOfComponents) {  const v0Scratch = new CartesianType();  const v1Scratch = new CartesianType();  const v2Scratch = new CartesianType();  return function (    i0,    i1,    i2,    coords,    sourceValues,    currentValues,    insertedIndex,    normalize  ) {    const v0 = CartesianType.fromArray(      sourceValues,      i0 * numberOfComponents,      v0Scratch    );    const v1 = CartesianType.fromArray(      sourceValues,      i1 * numberOfComponents,      v1Scratch    );    const v2 = CartesianType.fromArray(      sourceValues,      i2 * numberOfComponents,      v2Scratch    );    CartesianType.multiplyByScalar(v0, coords.x, v0);    CartesianType.multiplyByScalar(v1, coords.y, v1);    CartesianType.multiplyByScalar(v2, coords.z, v2);    const value = CartesianType.add(v0, v1, v0);    CartesianType.add(value, v2, value);    if (normalize) {      CartesianType.normalize(value, value);    }    CartesianType.pack(      value,      currentValues,      insertedIndex * numberOfComponents    );  };}const interpolateAndPackCartesian4 = generateBarycentricInterpolateFunction(  Cartesian4,  4);const interpolateAndPackCartesian3 = generateBarycentricInterpolateFunction(  Cartesian3,  3);const interpolateAndPackCartesian2 = generateBarycentricInterpolateFunction(  Cartesian2,  2);const interpolateAndPackBoolean = function (  i0,  i1,  i2,  coords,  sourceValues,  currentValues,  insertedIndex) {  const v1 = sourceValues[i0] * coords.x;  const v2 = sourceValues[i1] * coords.y;  const v3 = sourceValues[i2] * coords.z;  currentValues[insertedIndex] = v1 + v2 + v3 > CesiumMath.EPSILON6 ? 1 : 0;};const p0Scratch = new Cartesian3();const p1Scratch = new Cartesian3();const p2Scratch = new Cartesian3();const barycentricScratch = new Cartesian3();function computeTriangleAttributes(  i0,  i1,  i2,  point,  positions,  normals,  tangents,  bitangents,  texCoords,  extrudeDirections,  applyOffset,  currentAttributes,  customAttributeNames,  customAttributesLength,  allAttributes,  insertedIndex) {  if (    !defined(normals) &&    !defined(tangents) &&    !defined(bitangents) &&    !defined(texCoords) &&    !defined(extrudeDirections) &&    customAttributesLength === 0  ) {    return;  }  const p0 = Cartesian3.fromArray(positions, i0 * 3, p0Scratch);  const p1 = Cartesian3.fromArray(positions, i1 * 3, p1Scratch);  const p2 = Cartesian3.fromArray(positions, i2 * 3, p2Scratch);  const coords = barycentricCoordinates(point, p0, p1, p2, barycentricScratch);  if (!defined(coords)) {    return;  }  if (defined(normals)) {    interpolateAndPackCartesian3(      i0,      i1,      i2,      coords,      normals,      currentAttributes.normal.values,      insertedIndex,      true    );  }  if (defined(extrudeDirections)) {    const d0 = Cartesian3.fromArray(extrudeDirections, i0 * 3, p0Scratch);    const d1 = Cartesian3.fromArray(extrudeDirections, i1 * 3, p1Scratch);    const d2 = Cartesian3.fromArray(extrudeDirections, i2 * 3, p2Scratch);    Cartesian3.multiplyByScalar(d0, coords.x, d0);    Cartesian3.multiplyByScalar(d1, coords.y, d1);    Cartesian3.multiplyByScalar(d2, coords.z, d2);    let direction;    if (      !Cartesian3.equals(d0, Cartesian3.ZERO) ||      !Cartesian3.equals(d1, Cartesian3.ZERO) ||      !Cartesian3.equals(d2, Cartesian3.ZERO)    ) {      direction = Cartesian3.add(d0, d1, d0);      Cartesian3.add(direction, d2, direction);      Cartesian3.normalize(direction, direction);    } else {      direction = p0Scratch;      direction.x = 0;      direction.y = 0;      direction.z = 0;    }    Cartesian3.pack(      direction,      currentAttributes.extrudeDirection.values,      insertedIndex * 3    );  }  if (defined(applyOffset)) {    interpolateAndPackBoolean(      i0,      i1,      i2,      coords,      applyOffset,      currentAttributes.applyOffset.values,      insertedIndex    );  }  if (defined(tangents)) {    interpolateAndPackCartesian3(      i0,      i1,      i2,      coords,      tangents,      currentAttributes.tangent.values,      insertedIndex,      true    );  }  if (defined(bitangents)) {    interpolateAndPackCartesian3(      i0,      i1,      i2,      coords,      bitangents,      currentAttributes.bitangent.values,      insertedIndex,      true    );  }  if (defined(texCoords)) {    interpolateAndPackCartesian2(      i0,      i1,      i2,      coords,      texCoords,      currentAttributes.st.values,      insertedIndex    );  }  if (customAttributesLength > 0) {    for (let i = 0; i < customAttributesLength; i++) {      const attributeName = customAttributeNames[i];      genericInterpolate(        i0,        i1,        i2,        coords,        insertedIndex,        allAttributes[attributeName],        currentAttributes[attributeName]      );    }  }}function genericInterpolate(  i0,  i1,  i2,  coords,  insertedIndex,  sourceAttribute,  currentAttribute) {  const componentsPerAttribute = sourceAttribute.componentsPerAttribute;  const sourceValues = sourceAttribute.values;  const currentValues = currentAttribute.values;  switch (componentsPerAttribute) {    case 4:      interpolateAndPackCartesian4(        i0,        i1,        i2,        coords,        sourceValues,        currentValues,        insertedIndex,        false      );      break;    case 3:      interpolateAndPackCartesian3(        i0,        i1,        i2,        coords,        sourceValues,        currentValues,        insertedIndex,        false      );      break;    case 2:      interpolateAndPackCartesian2(        i0,        i1,        i2,        coords,        sourceValues,        currentValues,        insertedIndex,        false      );      break;    default:      currentValues[insertedIndex] =        sourceValues[i0] * coords.x +        sourceValues[i1] * coords.y +        sourceValues[i2] * coords.z;  }}function insertSplitPoint(  currentAttributes,  currentIndices,  currentIndexMap,  indices,  currentIndex,  point) {  const insertIndex = currentAttributes.position.values.length / 3;  if (currentIndex !== -1) {    const prevIndex = indices[currentIndex];    const newIndex = currentIndexMap[prevIndex];    if (newIndex === -1) {      currentIndexMap[prevIndex] = insertIndex;      currentAttributes.position.values.push(point.x, point.y, point.z);      currentIndices.push(insertIndex);      return insertIndex;    }    currentIndices.push(newIndex);    return newIndex;  }  currentAttributes.position.values.push(point.x, point.y, point.z);  currentIndices.push(insertIndex);  return insertIndex;}const NAMED_ATTRIBUTES = {  position: true,  normal: true,  bitangent: true,  tangent: true,  st: true,  extrudeDirection: true,  applyOffset: true,};function splitLongitudeTriangles(instance) {  const geometry = instance.geometry;  const attributes = geometry.attributes;  const positions = attributes.position.values;  const normals = defined(attributes.normal)    ? attributes.normal.values    : undefined;  const bitangents = defined(attributes.bitangent)    ? attributes.bitangent.values    : undefined;  const tangents = defined(attributes.tangent)    ? attributes.tangent.values    : undefined;  const texCoords = defined(attributes.st) ? attributes.st.values : undefined;  const extrudeDirections = defined(attributes.extrudeDirection)    ? attributes.extrudeDirection.values    : undefined;  const applyOffset = defined(attributes.applyOffset)    ? attributes.applyOffset.values    : undefined;  const indices = geometry.indices;  const customAttributeNames = [];  for (const attributeName in attributes) {    if (      attributes.hasOwnProperty(attributeName) &&      !NAMED_ATTRIBUTES[attributeName] &&      defined(attributes[attributeName])    ) {      customAttributeNames.push(attributeName);    }  }  const customAttributesLength = customAttributeNames.length;  const eastGeometry = copyGeometryForSplit(geometry);  const westGeometry = copyGeometryForSplit(geometry);  let currentAttributes;  let currentIndices;  let currentIndexMap;  let insertedIndex;  let i;  const westGeometryIndexMap = [];  westGeometryIndexMap.length = positions.length / 3;  const eastGeometryIndexMap = [];  eastGeometryIndexMap.length = positions.length / 3;  for (i = 0; i < westGeometryIndexMap.length; ++i) {    westGeometryIndexMap[i] = -1;    eastGeometryIndexMap[i] = -1;  }  const len = indices.length;  for (i = 0; i < len; i += 3) {    const i0 = indices[i];    const i1 = indices[i + 1];    const i2 = indices[i + 2];    let p0 = Cartesian3.fromArray(positions, i0 * 3);    let p1 = Cartesian3.fromArray(positions, i1 * 3);    let p2 = Cartesian3.fromArray(positions, i2 * 3);    const result = splitTriangle(p0, p1, p2);    if (defined(result) && result.positions.length > 3) {      const resultPositions = result.positions;      const resultIndices = result.indices;      const resultLength = resultIndices.length;      for (let j = 0; j < resultLength; ++j) {        const resultIndex = resultIndices[j];        const point = resultPositions[resultIndex];        if (point.y < 0.0) {          currentAttributes = westGeometry.attributes;          currentIndices = westGeometry.indices;          currentIndexMap = westGeometryIndexMap;        } else {          currentAttributes = eastGeometry.attributes;          currentIndices = eastGeometry.indices;          currentIndexMap = eastGeometryIndexMap;        }        insertedIndex = insertSplitPoint(          currentAttributes,          currentIndices,          currentIndexMap,          indices,          resultIndex < 3 ? i + resultIndex : -1,          point        );        computeTriangleAttributes(          i0,          i1,          i2,          point,          positions,          normals,          tangents,          bitangents,          texCoords,          extrudeDirections,          applyOffset,          currentAttributes,          customAttributeNames,          customAttributesLength,          attributes,          insertedIndex        );      }    } else {      if (defined(result)) {        p0 = result.positions[0];        p1 = result.positions[1];        p2 = result.positions[2];      }      if (p0.y < 0.0) {        currentAttributes = westGeometry.attributes;        currentIndices = westGeometry.indices;        currentIndexMap = westGeometryIndexMap;      } else {        currentAttributes = eastGeometry.attributes;        currentIndices = eastGeometry.indices;        currentIndexMap = eastGeometryIndexMap;      }      insertedIndex = insertSplitPoint(        currentAttributes,        currentIndices,        currentIndexMap,        indices,        i,        p0      );      computeTriangleAttributes(        i0,        i1,        i2,        p0,        positions,        normals,        tangents,        bitangents,        texCoords,        extrudeDirections,        applyOffset,        currentAttributes,        customAttributeNames,        customAttributesLength,        attributes,        insertedIndex      );      insertedIndex = insertSplitPoint(        currentAttributes,        currentIndices,        currentIndexMap,        indices,        i + 1,        p1      );      computeTriangleAttributes(        i0,        i1,        i2,        p1,        positions,        normals,        tangents,        bitangents,        texCoords,        extrudeDirections,        applyOffset,        currentAttributes,        customAttributeNames,        customAttributesLength,        attributes,        insertedIndex      );      insertedIndex = insertSplitPoint(        currentAttributes,        currentIndices,        currentIndexMap,        indices,        i + 2,        p2      );      computeTriangleAttributes(        i0,        i1,        i2,        p2,        positions,        normals,        tangents,        bitangents,        texCoords,        extrudeDirections,        applyOffset,        currentAttributes,        customAttributeNames,        customAttributesLength,        attributes,        insertedIndex      );    }  }  updateInstanceAfterSplit(instance, westGeometry, eastGeometry);}const xzPlane = Plane.fromPointNormal(Cartesian3.ZERO, Cartesian3.UNIT_Y);const offsetScratch = new Cartesian3();const offsetPointScratch = new Cartesian3();function computeLineAttributes(  i0,  i1,  point,  positions,  insertIndex,  currentAttributes,  applyOffset) {  if (!defined(applyOffset)) {    return;  }  const p0 = Cartesian3.fromArray(positions, i0 * 3, p0Scratch);  if (Cartesian3.equalsEpsilon(p0, point, CesiumMath.EPSILON10)) {    currentAttributes.applyOffset.values[insertIndex] = applyOffset[i0];  } else {    currentAttributes.applyOffset.values[insertIndex] = applyOffset[i1];  }}function splitLongitudeLines(instance) {  const geometry = instance.geometry;  const attributes = geometry.attributes;  const positions = attributes.position.values;  const applyOffset = defined(attributes.applyOffset)    ? attributes.applyOffset.values    : undefined;  const indices = geometry.indices;  const eastGeometry = copyGeometryForSplit(geometry);  const westGeometry = copyGeometryForSplit(geometry);  let i;  const length = indices.length;  const westGeometryIndexMap = [];  westGeometryIndexMap.length = positions.length / 3;  const eastGeometryIndexMap = [];  eastGeometryIndexMap.length = positions.length / 3;  for (i = 0; i < westGeometryIndexMap.length; ++i) {    westGeometryIndexMap[i] = -1;    eastGeometryIndexMap[i] = -1;  }  for (i = 0; i < length; i += 2) {    const i0 = indices[i];    const i1 = indices[i + 1];    const p0 = Cartesian3.fromArray(positions, i0 * 3, p0Scratch);    const p1 = Cartesian3.fromArray(positions, i1 * 3, p1Scratch);    let insertIndex;    if (Math.abs(p0.y) < CesiumMath.EPSILON6) {      if (p0.y < 0.0) {        p0.y = -CesiumMath.EPSILON6;      } else {        p0.y = CesiumMath.EPSILON6;      }    }    if (Math.abs(p1.y) < CesiumMath.EPSILON6) {      if (p1.y < 0.0) {        p1.y = -CesiumMath.EPSILON6;      } else {        p1.y = CesiumMath.EPSILON6;      }    }    let p0Attributes = eastGeometry.attributes;    let p0Indices = eastGeometry.indices;    let p0IndexMap = eastGeometryIndexMap;    let p1Attributes = westGeometry.attributes;    let p1Indices = westGeometry.indices;    let p1IndexMap = westGeometryIndexMap;    const intersection = IntersectionTests.lineSegmentPlane(      p0,      p1,      xzPlane,      p2Scratch    );    if (defined(intersection)) {      // move point on the xz-plane slightly away from the plane      const offset = Cartesian3.multiplyByScalar(        Cartesian3.UNIT_Y,        5.0 * CesiumMath.EPSILON9,        offsetScratch      );      if (p0.y < 0.0) {        Cartesian3.negate(offset, offset);        p0Attributes = westGeometry.attributes;        p0Indices = westGeometry.indices;        p0IndexMap = westGeometryIndexMap;        p1Attributes = eastGeometry.attributes;        p1Indices = eastGeometry.indices;        p1IndexMap = eastGeometryIndexMap;      }      const offsetPoint = Cartesian3.add(        intersection,        offset,        offsetPointScratch      );      insertIndex = insertSplitPoint(        p0Attributes,        p0Indices,        p0IndexMap,        indices,        i,        p0      );      computeLineAttributes(        i0,        i1,        p0,        positions,        insertIndex,        p0Attributes,        applyOffset      );      insertIndex = insertSplitPoint(        p0Attributes,        p0Indices,        p0IndexMap,        indices,        -1,        offsetPoint      );      computeLineAttributes(        i0,        i1,        offsetPoint,        positions,        insertIndex,        p0Attributes,        applyOffset      );      Cartesian3.negate(offset, offset);      Cartesian3.add(intersection, offset, offsetPoint);      insertIndex = insertSplitPoint(        p1Attributes,        p1Indices,        p1IndexMap,        indices,        -1,        offsetPoint      );      computeLineAttributes(        i0,        i1,        offsetPoint,        positions,        insertIndex,        p1Attributes,        applyOffset      );      insertIndex = insertSplitPoint(        p1Attributes,        p1Indices,        p1IndexMap,        indices,        i + 1,        p1      );      computeLineAttributes(        i0,        i1,        p1,        positions,        insertIndex,        p1Attributes,        applyOffset      );    } else {      let currentAttributes;      let currentIndices;      let currentIndexMap;      if (p0.y < 0.0) {        currentAttributes = westGeometry.attributes;        currentIndices = westGeometry.indices;        currentIndexMap = westGeometryIndexMap;      } else {        currentAttributes = eastGeometry.attributes;        currentIndices = eastGeometry.indices;        currentIndexMap = eastGeometryIndexMap;      }      insertIndex = insertSplitPoint(        currentAttributes,        currentIndices,        currentIndexMap,        indices,        i,        p0      );      computeLineAttributes(        i0,        i1,        p0,        positions,        insertIndex,        currentAttributes,        applyOffset      );      insertIndex = insertSplitPoint(        currentAttributes,        currentIndices,        currentIndexMap,        indices,        i + 1,        p1      );      computeLineAttributes(        i0,        i1,        p1,        positions,        insertIndex,        currentAttributes,        applyOffset      );    }  }  updateInstanceAfterSplit(instance, westGeometry, eastGeometry);}const cartesian2Scratch0 = new Cartesian2();const cartesian2Scratch1 = new Cartesian2();const cartesian3Scratch0 = new Cartesian3();const cartesian3Scratch2 = new Cartesian3();const cartesian3Scratch3 = new Cartesian3();const cartesian3Scratch4 = new Cartesian3();const cartesian3Scratch5 = new Cartesian3();const cartesian3Scratch6 = new Cartesian3();const cartesian4Scratch0 = new Cartesian4();function updateAdjacencyAfterSplit(geometry) {  const attributes = geometry.attributes;  const positions = attributes.position.values;  const prevPositions = attributes.prevPosition.values;  const nextPositions = attributes.nextPosition.values;  const length = positions.length;  for (let j = 0; j < length; j += 3) {    const position = Cartesian3.unpack(positions, j, cartesian3Scratch0);    if (position.x > 0.0) {      continue;    }    const prevPosition = Cartesian3.unpack(      prevPositions,      j,      cartesian3Scratch2    );    if (      (position.y < 0.0 && prevPosition.y > 0.0) ||      (position.y > 0.0 && prevPosition.y < 0.0)    ) {      if (j - 3 > 0) {        prevPositions[j] = positions[j - 3];        prevPositions[j + 1] = positions[j - 2];        prevPositions[j + 2] = positions[j - 1];      } else {        Cartesian3.pack(position, prevPositions, j);      }    }    const nextPosition = Cartesian3.unpack(      nextPositions,      j,      cartesian3Scratch3    );    if (      (position.y < 0.0 && nextPosition.y > 0.0) ||      (position.y > 0.0 && nextPosition.y < 0.0)    ) {      if (j + 3 < length) {        nextPositions[j] = positions[j + 3];        nextPositions[j + 1] = positions[j + 4];        nextPositions[j + 2] = positions[j + 5];      } else {        Cartesian3.pack(position, nextPositions, j);      }    }  }}const offsetScalar = 5.0 * CesiumMath.EPSILON9;const coplanarOffset = CesiumMath.EPSILON6;function splitLongitudePolyline(instance) {  const geometry = instance.geometry;  const attributes = geometry.attributes;  const positions = attributes.position.values;  const prevPositions = attributes.prevPosition.values;  const nextPositions = attributes.nextPosition.values;  const expandAndWidths = attributes.expandAndWidth.values;  const texCoords = defined(attributes.st) ? attributes.st.values : undefined;  const colors = defined(attributes.color)    ? attributes.color.values    : undefined;  const eastGeometry = copyGeometryForSplit(geometry);  const westGeometry = copyGeometryForSplit(geometry);  let i;  let j;  let index;  let intersectionFound = false;  const length = positions.length / 3;  for (i = 0; i < length; i += 4) {    const i0 = i;    const i2 = i + 2;    const p0 = Cartesian3.fromArray(positions, i0 * 3, cartesian3Scratch0);    const p2 = Cartesian3.fromArray(positions, i2 * 3, cartesian3Scratch2);    // Offset points that are close to the 180 longitude and change the previous/next point    // to be the same offset point so it can be projected to 2D. There is special handling in the    // shader for when position == prevPosition || position == nextPosition.    if (Math.abs(p0.y) < coplanarOffset) {      p0.y = coplanarOffset * (p2.y < 0.0 ? -1.0 : 1.0);      positions[i * 3 + 1] = p0.y;      positions[(i + 1) * 3 + 1] = p0.y;      for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {        prevPositions[j] = positions[i * 3];        prevPositions[j + 1] = positions[i * 3 + 1];        prevPositions[j + 2] = positions[i * 3 + 2];      }    }    // Do the same but for when the line crosses 180 longitude in the opposite direction.    if (Math.abs(p2.y) < coplanarOffset) {      p2.y = coplanarOffset * (p0.y < 0.0 ? -1.0 : 1.0);      positions[(i + 2) * 3 + 1] = p2.y;      positions[(i + 3) * 3 + 1] = p2.y;      for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {        nextPositions[j] = positions[(i + 2) * 3];        nextPositions[j + 1] = positions[(i + 2) * 3 + 1];        nextPositions[j + 2] = positions[(i + 2) * 3 + 2];      }    }    let p0Attributes = eastGeometry.attributes;    let p0Indices = eastGeometry.indices;    let p2Attributes = westGeometry.attributes;    let p2Indices = westGeometry.indices;    const intersection = IntersectionTests.lineSegmentPlane(      p0,      p2,      xzPlane,      cartesian3Scratch4    );    if (defined(intersection)) {      intersectionFound = true;      // move point on the xz-plane slightly away from the plane      const offset = Cartesian3.multiplyByScalar(        Cartesian3.UNIT_Y,        offsetScalar,        cartesian3Scratch5      );      if (p0.y < 0.0) {        Cartesian3.negate(offset, offset);        p0Attributes = westGeometry.attributes;        p0Indices = westGeometry.indices;        p2Attributes = eastGeometry.attributes;        p2Indices = eastGeometry.indices;      }      const offsetPoint = Cartesian3.add(        intersection,        offset,        cartesian3Scratch6      );      p0Attributes.position.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);      p0Attributes.position.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p0Attributes.position.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p0Attributes.prevPosition.values.push(        prevPositions[i0 * 3],        prevPositions[i0 * 3 + 1],        prevPositions[i0 * 3 + 2]      );      p0Attributes.prevPosition.values.push(        prevPositions[i0 * 3 + 3],        prevPositions[i0 * 3 + 4],        prevPositions[i0 * 3 + 5]      );      p0Attributes.prevPosition.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);      p0Attributes.nextPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p0Attributes.nextPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p0Attributes.nextPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p0Attributes.nextPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      Cartesian3.negate(offset, offset);      Cartesian3.add(intersection, offset, offsetPoint);      p2Attributes.position.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.position.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.position.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);      p2Attributes.prevPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.prevPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.prevPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.prevPosition.values.push(        offsetPoint.x,        offsetPoint.y,        offsetPoint.z      );      p2Attributes.nextPosition.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);      p2Attributes.nextPosition.values.push(        nextPositions[i2 * 3],        nextPositions[i2 * 3 + 1],        nextPositions[i2 * 3 + 2]      );      p2Attributes.nextPosition.values.push(        nextPositions[i2 * 3 + 3],        nextPositions[i2 * 3 + 4],        nextPositions[i2 * 3 + 5]      );      const ew0 = Cartesian2.fromArray(        expandAndWidths,        i0 * 2,        cartesian2Scratch0      );      const width = Math.abs(ew0.y);      p0Attributes.expandAndWidth.values.push(-1, width, 1, width);      p0Attributes.expandAndWidth.values.push(-1, -width, 1, -width);      p2Attributes.expandAndWidth.values.push(-1, width, 1, width);      p2Attributes.expandAndWidth.values.push(-1, -width, 1, -width);      let t = Cartesian3.magnitudeSquared(        Cartesian3.subtract(intersection, p0, cartesian3Scratch3)      );      t /= Cartesian3.magnitudeSquared(        Cartesian3.subtract(p2, p0, cartesian3Scratch3)      );      if (defined(colors)) {        const c0 = Cartesian4.fromArray(colors, i0 * 4, cartesian4Scratch0);        const c2 = Cartesian4.fromArray(colors, i2 * 4, cartesian4Scratch0);        const r = CesiumMath.lerp(c0.x, c2.x, t);        const g = CesiumMath.lerp(c0.y, c2.y, t);        const b = CesiumMath.lerp(c0.z, c2.z, t);        const a = CesiumMath.lerp(c0.w, c2.w, t);        for (j = i0 * 4; j < i0 * 4 + 2 * 4; ++j) {          p0Attributes.color.values.push(colors[j]);        }        p0Attributes.color.values.push(r, g, b, a);        p0Attributes.color.values.push(r, g, b, a);        p2Attributes.color.values.push(r, g, b, a);        p2Attributes.color.values.push(r, g, b, a);        for (j = i2 * 4; j < i2 * 4 + 2 * 4; ++j) {          p2Attributes.color.values.push(colors[j]);        }      }      if (defined(texCoords)) {        const s0 = Cartesian2.fromArray(texCoords, i0 * 2, cartesian2Scratch0);        const s3 = Cartesian2.fromArray(          texCoords,          (i + 3) * 2,          cartesian2Scratch1        );        const sx = CesiumMath.lerp(s0.x, s3.x, t);        for (j = i0 * 2; j < i0 * 2 + 2 * 2; ++j) {          p0Attributes.st.values.push(texCoords[j]);        }        p0Attributes.st.values.push(sx, s0.y);        p0Attributes.st.values.push(sx, s3.y);        p2Attributes.st.values.push(sx, s0.y);        p2Attributes.st.values.push(sx, s3.y);        for (j = i2 * 2; j < i2 * 2 + 2 * 2; ++j) {          p2Attributes.st.values.push(texCoords[j]);        }      }      index = p0Attributes.position.values.length / 3 - 4;      p0Indices.push(index, index + 2, index + 1);      p0Indices.push(index + 1, index + 2, index + 3);      index = p2Attributes.position.values.length / 3 - 4;      p2Indices.push(index, index + 2, index + 1);      p2Indices.push(index + 1, index + 2, index + 3);    } else {      let currentAttributes;      let currentIndices;      if (p0.y < 0.0) {        currentAttributes = westGeometry.attributes;        currentIndices = westGeometry.indices;      } else {        currentAttributes = eastGeometry.attributes;        currentIndices = eastGeometry.indices;      }      currentAttributes.position.values.push(p0.x, p0.y, p0.z);      currentAttributes.position.values.push(p0.x, p0.y, p0.z);      currentAttributes.position.values.push(p2.x, p2.y, p2.z);      currentAttributes.position.values.push(p2.x, p2.y, p2.z);      for (j = i * 3; j < i * 3 + 4 * 3; ++j) {        currentAttributes.prevPosition.values.push(prevPositions[j]);        currentAttributes.nextPosition.values.push(nextPositions[j]);      }      for (j = i * 2; j < i * 2 + 4 * 2; ++j) {        currentAttributes.expandAndWidth.values.push(expandAndWidths[j]);        if (defined(texCoords)) {          currentAttributes.st.values.push(texCoords[j]);        }      }      if (defined(colors)) {        for (j = i * 4; j < i * 4 + 4 * 4; ++j) {          currentAttributes.color.values.push(colors[j]);        }      }      index = currentAttributes.position.values.length / 3 - 4;      currentIndices.push(index, index + 2, index + 1);      currentIndices.push(index + 1, index + 2, index + 3);    }  }  if (intersectionFound) {    updateAdjacencyAfterSplit(westGeometry);    updateAdjacencyAfterSplit(eastGeometry);  }  updateInstanceAfterSplit(instance, westGeometry, eastGeometry);}/** * Splits the instances's geometry, by introducing new vertices and indices,that * intersect the International Date Line and Prime Meridian so that no primitives cross longitude * -180/180 degrees.  This is not required for 3D drawing, but is required for * correcting drawing in 2D and Columbus view. * * @private * * @param {GeometryInstance} instance The instance to modify. * @returns {GeometryInstance} The modified <code>instance</code> argument, with it's geometry split at the International Date Line. * * @example * instance = Cesium.GeometryPipeline.splitLongitude(instance); */GeometryPipeline.splitLongitude = function (instance) {  //>>includeStart('debug', pragmas.debug);  if (!defined(instance)) {    throw new DeveloperError("instance is required.");  }  //>>includeEnd('debug');  const geometry = instance.geometry;  const boundingSphere = geometry.boundingSphere;  if (defined(boundingSphere)) {    const minX = boundingSphere.center.x - boundingSphere.radius;    if (      minX > 0 ||      BoundingSphere.intersectPlane(boundingSphere, Plane.ORIGIN_ZX_PLANE) !==        Intersect.INTERSECTING    ) {      return instance;    }  }  if (geometry.geometryType !== GeometryType.NONE) {    switch (geometry.geometryType) {      case GeometryType.POLYLINES:        splitLongitudePolyline(instance);        break;      case GeometryType.TRIANGLES:        splitLongitudeTriangles(instance);        break;      case GeometryType.LINES:        splitLongitudeLines(instance);        break;    }  } else {    indexPrimitive(geometry);    if (geometry.primitiveType === PrimitiveType.TRIANGLES) {      splitLongitudeTriangles(instance);    } else if (geometry.primitiveType === PrimitiveType.LINES) {      splitLongitudeLines(instance);    }  }  return instance;};export default GeometryPipeline;
 |