GeometryPipeline-901e57f7.js 125 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012
  1. /**
  2. * Cesium - https://github.com/CesiumGS/cesium
  3. *
  4. * Copyright 2011-2020 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/CesiumGS/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['exports', './when-8d13db60', './Check-70bec281', './Math-61ede240', './Cartographic-fe4be337', './Cartesian4-5af5bb24', './Cartesian2-85064f09', './BoundingSphere-8f8a682c', './ComponentDatatype-5862616f', './GeometryAttribute-ed9d707f', './PrimitiveType-97893bc7', './AttributeCompression-84a90a13', './EncodedCartesian3-a569cba8', './IndexDatatype-9435b55f', './IntersectionTests-ca40c01c', './Plane-b1361c67'], function (exports, when, Check, _Math, Cartographic, Cartesian4, Cartesian2, BoundingSphere, ComponentDatatype, GeometryAttribute, PrimitiveType, AttributeCompression, EncodedCartesian3, IndexDatatype, IntersectionTests, Plane) { 'use strict';
  24. var scratchCartesian1 = new Cartographic.Cartesian3();
  25. var scratchCartesian2 = new Cartographic.Cartesian3();
  26. var scratchCartesian3 = new Cartographic.Cartesian3();
  27. /**
  28. * Computes the barycentric coordinates for a point with respect to a triangle.
  29. *
  30. * @exports barycentricCoordinates
  31. *
  32. * @param {Cartesian2|Cartesian3} point The point to test.
  33. * @param {Cartesian2|Cartesian3} p0 The first point of the triangle, corresponding to the barycentric x-axis.
  34. * @param {Cartesian2|Cartesian3} p1 The second point of the triangle, corresponding to the barycentric y-axis.
  35. * @param {Cartesian2|Cartesian3} p2 The third point of the triangle, corresponding to the barycentric z-axis.
  36. * @param {Cartesian3} [result] The object onto which to store the result.
  37. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  38. *
  39. * @example
  40. * // Returns Cartesian3.UNIT_X
  41. * var p = new Cesium.Cartesian3(-1.0, 0.0, 0.0);
  42. * var b = Cesium.barycentricCoordinates(p,
  43. * new Cesium.Cartesian3(-1.0, 0.0, 0.0),
  44. * new Cesium.Cartesian3( 1.0, 0.0, 0.0),
  45. * new Cesium.Cartesian3( 0.0, 1.0, 1.0));
  46. */
  47. function barycentricCoordinates(point, p0, p1, p2, result) {
  48. //>>includeStart('debug', pragmas.debug);
  49. Check.Check.defined('point', point);
  50. Check.Check.defined('p0', p0);
  51. Check.Check.defined('p1', p1);
  52. Check.Check.defined('p2', p2);
  53. //>>includeEnd('debug');
  54. if (!when.defined(result)) {
  55. result = new Cartographic.Cartesian3();
  56. }
  57. // Implementation based on http://www.blackpawn.com/texts/pointinpoly/default.html.
  58. var v0;
  59. var v1;
  60. var v2;
  61. var dot00;
  62. var dot01;
  63. var dot02;
  64. var dot11;
  65. var dot12;
  66. if(!when.defined(p0.z)) {
  67. if (Cartesian2.Cartesian2.equalsEpsilon(point, p0, _Math.CesiumMath.EPSILON14)) {
  68. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_X, result);
  69. }
  70. if (Cartesian2.Cartesian2.equalsEpsilon(point, p1, _Math.CesiumMath.EPSILON14)) {
  71. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Y, result);
  72. }
  73. if (Cartesian2.Cartesian2.equalsEpsilon(point, p2, _Math.CesiumMath.EPSILON14)) {
  74. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Z, result);
  75. }
  76. v0 = Cartesian2.Cartesian2.subtract(p1, p0, scratchCartesian1);
  77. v1 = Cartesian2.Cartesian2.subtract(p2, p0, scratchCartesian2);
  78. v2 = Cartesian2.Cartesian2.subtract(point, p0, scratchCartesian3);
  79. dot00 = Cartesian2.Cartesian2.dot(v0, v0);
  80. dot01 = Cartesian2.Cartesian2.dot(v0, v1);
  81. dot02 = Cartesian2.Cartesian2.dot(v0, v2);
  82. dot11 = Cartesian2.Cartesian2.dot(v1, v1);
  83. dot12 = Cartesian2.Cartesian2.dot(v1, v2);
  84. } else {
  85. if (Cartographic.Cartesian3.equalsEpsilon(point, p0, _Math.CesiumMath.EPSILON14)) {
  86. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_X, result);
  87. }
  88. if (Cartographic.Cartesian3.equalsEpsilon(point, p1, _Math.CesiumMath.EPSILON14)) {
  89. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Y, result);
  90. }
  91. if (Cartographic.Cartesian3.equalsEpsilon(point, p2, _Math.CesiumMath.EPSILON14)) {
  92. return Cartographic.Cartesian3.clone(Cartographic.Cartesian3.UNIT_Z, result);
  93. }
  94. v0 = Cartographic.Cartesian3.subtract(p1, p0, scratchCartesian1);
  95. v1 = Cartographic.Cartesian3.subtract(p2, p0, scratchCartesian2);
  96. v2 = Cartographic.Cartesian3.subtract(point, p0, scratchCartesian3);
  97. dot00 = Cartographic.Cartesian3.dot(v0, v0);
  98. dot01 = Cartographic.Cartesian3.dot(v0, v1);
  99. dot02 = Cartographic.Cartesian3.dot(v0, v2);
  100. dot11 = Cartographic.Cartesian3.dot(v1, v1);
  101. dot12 = Cartographic.Cartesian3.dot(v1, v2);
  102. }
  103. result.y = (dot11 * dot02 - dot01 * dot12);
  104. result.z = (dot00 * dot12 - dot01 * dot02);
  105. var q = dot00 * dot11 - dot01 * dot01;
  106. // This is done to avoid dividing by infinity causing a NaN
  107. if (result.y !== 0) {
  108. result.y /= q;
  109. }
  110. if (result.z !== 0) {
  111. result.z /= q;
  112. }
  113. result.x = 1.0 - result.y - result.z;
  114. return result;
  115. }
  116. /**
  117. * Encapsulates an algorithm to optimize triangles for the post
  118. * vertex-shader cache. This is based on the 2007 SIGGRAPH paper
  119. * 'Fast Triangle Reordering for Vertex Locality and Reduced Overdraw.'
  120. * The runtime is linear but several passes are made.
  121. *
  122. * @exports Tipsify
  123. *
  124. * @see <a href='http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf'>
  125. * Fast Triangle Reordering for Vertex Locality and Reduced Overdraw</a>
  126. * by Sander, Nehab, and Barczak
  127. *
  128. * @private
  129. */
  130. var Tipsify = {};
  131. /**
  132. * Calculates the average cache miss ratio (ACMR) for a given set of indices.
  133. *
  134. * @param {Object} options Object with the following properties:
  135. * @param {Number[]} options.indices Lists triads of numbers corresponding to the indices of the vertices
  136. * in the vertex buffer that define the geometry's triangles.
  137. * @param {Number} [options.maximumIndex] The maximum value of the elements in <code>args.indices</code>.
  138. * If not supplied, this value will be computed.
  139. * @param {Number} [options.cacheSize=24] The number of vertices that can be stored in the cache at any one time.
  140. * @returns {Number} The average cache miss ratio (ACMR).
  141. *
  142. * @exception {DeveloperError} indices length must be a multiple of three.
  143. * @exception {DeveloperError} cacheSize must be greater than two.
  144. *
  145. * @example
  146. * var indices = [0, 1, 2, 3, 4, 5];
  147. * var maxIndex = 5;
  148. * var cacheSize = 3;
  149. * var acmr = Cesium.Tipsify.calculateACMR({indices : indices, maxIndex : maxIndex, cacheSize : cacheSize});
  150. */
  151. Tipsify.calculateACMR = function(options) {
  152. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  153. var indices = options.indices;
  154. var maximumIndex = options.maximumIndex;
  155. var cacheSize = when.defaultValue(options.cacheSize, 24);
  156. //>>includeStart('debug', pragmas.debug);
  157. if (!when.defined(indices)) {
  158. throw new Check.DeveloperError('indices is required.');
  159. }
  160. //>>includeEnd('debug');
  161. var numIndices = indices.length;
  162. //>>includeStart('debug', pragmas.debug);
  163. if (numIndices < 3 || numIndices % 3 !== 0) {
  164. throw new Check.DeveloperError('indices length must be a multiple of three.');
  165. }
  166. if (maximumIndex <= 0) {
  167. throw new Check.DeveloperError('maximumIndex must be greater than zero.');
  168. }
  169. if (cacheSize < 3) {
  170. throw new Check.DeveloperError('cacheSize must be greater than two.');
  171. }
  172. //>>includeEnd('debug');
  173. // Compute the maximumIndex if not given
  174. if (!when.defined(maximumIndex)) {
  175. maximumIndex = 0;
  176. var currentIndex = 0;
  177. var intoIndices = indices[currentIndex];
  178. while (currentIndex < numIndices) {
  179. if (intoIndices > maximumIndex) {
  180. maximumIndex = intoIndices;
  181. }
  182. ++currentIndex;
  183. intoIndices = indices[currentIndex];
  184. }
  185. }
  186. // Vertex time stamps
  187. var vertexTimeStamps = [];
  188. for ( var i = 0; i < maximumIndex + 1; i++) {
  189. vertexTimeStamps[i] = 0;
  190. }
  191. // Cache processing
  192. var s = cacheSize + 1;
  193. for ( var j = 0; j < numIndices; ++j) {
  194. if ((s - vertexTimeStamps[indices[j]]) > cacheSize) {
  195. vertexTimeStamps[indices[j]] = s;
  196. ++s;
  197. }
  198. }
  199. return (s - cacheSize + 1) / (numIndices / 3);
  200. };
  201. /**
  202. * Optimizes triangles for the post-vertex shader cache.
  203. *
  204. * @param {Object} options Object with the following properties:
  205. * @param {Number[]} options.indices Lists triads of numbers corresponding to the indices of the vertices
  206. * in the vertex buffer that define the geometry's triangles.
  207. * @param {Number} [options.maximumIndex] The maximum value of the elements in <code>args.indices</code>.
  208. * If not supplied, this value will be computed.
  209. * @param {Number} [options.cacheSize=24] The number of vertices that can be stored in the cache at any one time.
  210. * @returns {Number[]} A list of the input indices in an optimized order.
  211. *
  212. * @exception {DeveloperError} indices length must be a multiple of three.
  213. * @exception {DeveloperError} cacheSize must be greater than two.
  214. *
  215. * @example
  216. * var indices = [0, 1, 2, 3, 4, 5];
  217. * var maxIndex = 5;
  218. * var cacheSize = 3;
  219. * var reorderedIndices = Cesium.Tipsify.tipsify({indices : indices, maxIndex : maxIndex, cacheSize : cacheSize});
  220. */
  221. Tipsify.tipsify = function(options) {
  222. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  223. var indices = options.indices;
  224. var maximumIndex = options.maximumIndex;
  225. var cacheSize = when.defaultValue(options.cacheSize, 24);
  226. var cursor;
  227. function skipDeadEnd(vertices, deadEnd, indices, maximumIndexPlusOne) {
  228. while (deadEnd.length >= 1) {
  229. // while the stack is not empty
  230. var d = deadEnd[deadEnd.length - 1]; // top of the stack
  231. deadEnd.splice(deadEnd.length - 1, 1); // pop the stack
  232. if (vertices[d].numLiveTriangles > 0) {
  233. return d;
  234. }
  235. }
  236. while (cursor < maximumIndexPlusOne) {
  237. if (vertices[cursor].numLiveTriangles > 0) {
  238. ++cursor;
  239. return cursor - 1;
  240. }
  241. ++cursor;
  242. }
  243. return -1;
  244. }
  245. function getNextVertex(indices, cacheSize, oneRing, vertices, s, deadEnd, maximumIndexPlusOne) {
  246. var n = -1;
  247. var p;
  248. var m = -1;
  249. var itOneRing = 0;
  250. while (itOneRing < oneRing.length) {
  251. var index = oneRing[itOneRing];
  252. if (vertices[index].numLiveTriangles) {
  253. p = 0;
  254. if ((s - vertices[index].timeStamp + (2 * vertices[index].numLiveTriangles)) <= cacheSize) {
  255. p = s - vertices[index].timeStamp;
  256. }
  257. if ((p > m) || (m === -1)) {
  258. m = p;
  259. n = index;
  260. }
  261. }
  262. ++itOneRing;
  263. }
  264. if (n === -1) {
  265. return skipDeadEnd(vertices, deadEnd, indices, maximumIndexPlusOne);
  266. }
  267. return n;
  268. }
  269. //>>includeStart('debug', pragmas.debug);
  270. if (!when.defined(indices)) {
  271. throw new Check.DeveloperError('indices is required.');
  272. }
  273. //>>includeEnd('debug');
  274. var numIndices = indices.length;
  275. //>>includeStart('debug', pragmas.debug);
  276. if (numIndices < 3 || numIndices % 3 !== 0) {
  277. throw new Check.DeveloperError('indices length must be a multiple of three.');
  278. }
  279. if (maximumIndex <= 0) {
  280. throw new Check.DeveloperError('maximumIndex must be greater than zero.');
  281. }
  282. if (cacheSize < 3) {
  283. throw new Check.DeveloperError('cacheSize must be greater than two.');
  284. }
  285. //>>includeEnd('debug');
  286. // Determine maximum index
  287. var maximumIndexPlusOne = 0;
  288. var currentIndex = 0;
  289. var intoIndices = indices[currentIndex];
  290. var endIndex = numIndices;
  291. if (when.defined(maximumIndex)) {
  292. maximumIndexPlusOne = maximumIndex + 1;
  293. } else {
  294. while (currentIndex < endIndex) {
  295. if (intoIndices > maximumIndexPlusOne) {
  296. maximumIndexPlusOne = intoIndices;
  297. }
  298. ++currentIndex;
  299. intoIndices = indices[currentIndex];
  300. }
  301. if (maximumIndexPlusOne === -1) {
  302. return 0;
  303. }
  304. ++maximumIndexPlusOne;
  305. }
  306. // Vertices
  307. var vertices = [];
  308. var i;
  309. for (i = 0; i < maximumIndexPlusOne; i++) {
  310. vertices[i] = {
  311. numLiveTriangles : 0,
  312. timeStamp : 0,
  313. vertexTriangles : []
  314. };
  315. }
  316. currentIndex = 0;
  317. var triangle = 0;
  318. while (currentIndex < endIndex) {
  319. vertices[indices[currentIndex]].vertexTriangles.push(triangle);
  320. ++(vertices[indices[currentIndex]]).numLiveTriangles;
  321. vertices[indices[currentIndex + 1]].vertexTriangles.push(triangle);
  322. ++(vertices[indices[currentIndex + 1]]).numLiveTriangles;
  323. vertices[indices[currentIndex + 2]].vertexTriangles.push(triangle);
  324. ++(vertices[indices[currentIndex + 2]]).numLiveTriangles;
  325. ++triangle;
  326. currentIndex += 3;
  327. }
  328. // Starting index
  329. var f = 0;
  330. // Time Stamp
  331. var s = cacheSize + 1;
  332. cursor = 1;
  333. // Process
  334. var oneRing = [];
  335. var deadEnd = []; //Stack
  336. var vertex;
  337. var intoVertices;
  338. var currentOutputIndex = 0;
  339. var outputIndices = [];
  340. var numTriangles = numIndices / 3;
  341. var triangleEmitted = [];
  342. for (i = 0; i < numTriangles; i++) {
  343. triangleEmitted[i] = false;
  344. }
  345. var index;
  346. var limit;
  347. while (f !== -1) {
  348. oneRing = [];
  349. intoVertices = vertices[f];
  350. limit = intoVertices.vertexTriangles.length;
  351. for ( var k = 0; k < limit; ++k) {
  352. triangle = intoVertices.vertexTriangles[k];
  353. if (!triangleEmitted[triangle]) {
  354. triangleEmitted[triangle] = true;
  355. currentIndex = triangle + triangle + triangle;
  356. for ( var j = 0; j < 3; ++j) {
  357. // Set this index as a possible next index
  358. index = indices[currentIndex];
  359. oneRing.push(index);
  360. deadEnd.push(index);
  361. // Output index
  362. outputIndices[currentOutputIndex] = index;
  363. ++currentOutputIndex;
  364. // Cache processing
  365. vertex = vertices[index];
  366. --vertex.numLiveTriangles;
  367. if ((s - vertex.timeStamp) > cacheSize) {
  368. vertex.timeStamp = s;
  369. ++s;
  370. }
  371. ++currentIndex;
  372. }
  373. }
  374. }
  375. f = getNextVertex(indices, cacheSize, oneRing, vertices, s, deadEnd, maximumIndexPlusOne);
  376. }
  377. return outputIndices;
  378. };
  379. /**
  380. * Content pipeline functions for geometries.
  381. *
  382. * @exports GeometryPipeline
  383. *
  384. * @see Geometry
  385. */
  386. var GeometryPipeline = {};
  387. function addTriangle(lines, index, i0, i1, i2) {
  388. lines[index++] = i0;
  389. lines[index++] = i1;
  390. lines[index++] = i1;
  391. lines[index++] = i2;
  392. lines[index++] = i2;
  393. lines[index] = i0;
  394. }
  395. function trianglesToLines(triangles) {
  396. var count = triangles.length;
  397. var size = (count / 3) * 6;
  398. var lines = IndexDatatype.IndexDatatype.createTypedArray(count, size);
  399. var index = 0;
  400. for ( var i = 0; i < count; i += 3, index += 6) {
  401. addTriangle(lines, index, triangles[i], triangles[i + 1], triangles[i + 2]);
  402. }
  403. return lines;
  404. }
  405. function triangleStripToLines(triangles) {
  406. var count = triangles.length;
  407. if (count >= 3) {
  408. var size = (count - 2) * 6;
  409. var lines = IndexDatatype.IndexDatatype.createTypedArray(count, size);
  410. addTriangle(lines, 0, triangles[0], triangles[1], triangles[2]);
  411. var index = 6;
  412. for ( var i = 3; i < count; ++i, index += 6) {
  413. addTriangle(lines, index, triangles[i - 1], triangles[i], triangles[i - 2]);
  414. }
  415. return lines;
  416. }
  417. return new Uint16Array();
  418. }
  419. function triangleFanToLines(triangles) {
  420. if (triangles.length > 0) {
  421. var count = triangles.length - 1;
  422. var size = (count - 1) * 6;
  423. var lines = IndexDatatype.IndexDatatype.createTypedArray(count, size);
  424. var base = triangles[0];
  425. var index = 0;
  426. for ( var i = 1; i < count; ++i, index += 6) {
  427. addTriangle(lines, index, base, triangles[i], triangles[i + 1]);
  428. }
  429. return lines;
  430. }
  431. return new Uint16Array();
  432. }
  433. /**
  434. * Converts a geometry's triangle indices to line indices. If the geometry has an <code>indices</code>
  435. * and its <code>primitiveType</code> is <code>TRIANGLES</code>, <code>TRIANGLE_STRIP</code>,
  436. * <code>TRIANGLE_FAN</code>, it is converted to <code>LINES</code>; otherwise, the geometry is not changed.
  437. * <p>
  438. * This is commonly used to create a wireframe geometry for visual debugging.
  439. * </p>
  440. *
  441. * @param {Geometry} geometry The geometry to modify.
  442. * @returns {Geometry} The modified <code>geometry</code> argument, with its triangle indices converted to lines.
  443. *
  444. * @exception {DeveloperError} geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.
  445. *
  446. * @example
  447. * geometry = Cesium.GeometryPipeline.toWireframe(geometry);
  448. */
  449. GeometryPipeline.toWireframe = function(geometry) {
  450. //>>includeStart('debug', pragmas.debug);
  451. if (!when.defined(geometry)) {
  452. throw new Check.DeveloperError('geometry is required.');
  453. }
  454. //>>includeEnd('debug');
  455. var indices = geometry.indices;
  456. if (when.defined(indices)) {
  457. switch (geometry.primitiveType) {
  458. case PrimitiveType.PrimitiveType.TRIANGLES:
  459. geometry.indices = trianglesToLines(indices);
  460. break;
  461. case PrimitiveType.PrimitiveType.TRIANGLE_STRIP:
  462. geometry.indices = triangleStripToLines(indices);
  463. break;
  464. case PrimitiveType.PrimitiveType.TRIANGLE_FAN:
  465. geometry.indices = triangleFanToLines(indices);
  466. break;
  467. //>>includeStart('debug', pragmas.debug);
  468. default:
  469. throw new Check.DeveloperError('geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.');
  470. //>>includeEnd('debug');
  471. }
  472. geometry.primitiveType = PrimitiveType.PrimitiveType.LINES;
  473. }
  474. return geometry;
  475. };
  476. /**
  477. * Creates a new {@link Geometry} with <code>LINES</code> representing the provided
  478. * attribute (<code>attributeName</code>) for the provided geometry. This is used to
  479. * visualize vector attributes like normals, tangents, and bitangents.
  480. *
  481. * @param {Geometry} geometry The <code>Geometry</code> instance with the attribute.
  482. * @param {String} [attributeName='normal'] The name of the attribute.
  483. * @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.
  484. * @returns {Geometry} A new <code>Geometry</code> instance with line segments for the vector.
  485. *
  486. * @exception {DeveloperError} geometry.attributes must have an attribute with the same name as the attributeName parameter.
  487. *
  488. * @example
  489. * var geometry = Cesium.GeometryPipeline.createLineSegmentsForVectors(instance.geometry, 'bitangent', 100000.0);
  490. */
  491. GeometryPipeline.createLineSegmentsForVectors = function(geometry, attributeName, length) {
  492. attributeName = when.defaultValue(attributeName, 'normal');
  493. //>>includeStart('debug', pragmas.debug);
  494. if (!when.defined(geometry)) {
  495. throw new Check.DeveloperError('geometry is required.');
  496. }
  497. if (!when.defined(geometry.attributes.position)) {
  498. throw new Check.DeveloperError('geometry.attributes.position is required.');
  499. }
  500. if (!when.defined(geometry.attributes[attributeName])) {
  501. throw new Check.DeveloperError('geometry.attributes must have an attribute with the same name as the attributeName parameter, ' + attributeName + '.');
  502. }
  503. //>>includeEnd('debug');
  504. length = when.defaultValue(length, 10000.0);
  505. var positions = geometry.attributes.position.values;
  506. var vectors = geometry.attributes[attributeName].values;
  507. var positionsLength = positions.length;
  508. var newPositions = new Float64Array(2 * positionsLength);
  509. var j = 0;
  510. for (var i = 0; i < positionsLength; i += 3) {
  511. newPositions[j++] = positions[i];
  512. newPositions[j++] = positions[i + 1];
  513. newPositions[j++] = positions[i + 2];
  514. newPositions[j++] = positions[i] + (vectors[i] * length);
  515. newPositions[j++] = positions[i + 1] + (vectors[i + 1] * length);
  516. newPositions[j++] = positions[i + 2] + (vectors[i + 2] * length);
  517. }
  518. var newBoundingSphere;
  519. var bs = geometry.boundingSphere;
  520. if (when.defined(bs)) {
  521. newBoundingSphere = new BoundingSphere.BoundingSphere(bs.center, bs.radius + length);
  522. }
  523. return new GeometryAttribute.Geometry({
  524. attributes : {
  525. position : new GeometryAttribute.GeometryAttribute({
  526. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  527. componentsPerAttribute : 3,
  528. values : newPositions
  529. })
  530. },
  531. primitiveType : PrimitiveType.PrimitiveType.LINES,
  532. boundingSphere : newBoundingSphere
  533. });
  534. };
  535. /**
  536. * Creates an object that maps attribute names to unique locations (indices)
  537. * for matching vertex attributes and shader programs.
  538. *
  539. * @param {Geometry} geometry The geometry, which is not modified, to create the object for.
  540. * @returns {Object} An object with attribute name / index pairs.
  541. *
  542. * @example
  543. * var attributeLocations = Cesium.GeometryPipeline.createAttributeLocations(geometry);
  544. * // Example output
  545. * // {
  546. * // 'position' : 0,
  547. * // 'normal' : 1
  548. * // }
  549. */
  550. GeometryPipeline.createAttributeLocations = function(geometry) {
  551. //>>includeStart('debug', pragmas.debug);
  552. if (!when.defined(geometry)) {
  553. throw new Check.DeveloperError('geometry is required.');
  554. }
  555. //>>includeEnd('debug')
  556. // There can be a WebGL performance hit when attribute 0 is disabled, so
  557. // assign attribute locations to well-known attributes.
  558. var semantics = [
  559. 'position',
  560. 'positionHigh',
  561. 'positionLow',
  562. // From VertexFormat.position - after 2D projection and high-precision encoding
  563. 'position3DHigh',
  564. 'position3DLow',
  565. 'position2DHigh',
  566. 'position2DLow',
  567. // From Primitive
  568. 'pickColor',
  569. // From VertexFormat
  570. 'normal',
  571. 'st',
  572. 'tangent',
  573. 'bitangent',
  574. // For shadow volumes
  575. 'extrudeDirection',
  576. // From compressing texture coordinates and normals
  577. 'compressedAttributes'
  578. ];
  579. var attributes = geometry.attributes;
  580. var indices = {};
  581. var j = 0;
  582. var i;
  583. var len = semantics.length;
  584. // Attribute locations for well-known attributes
  585. for (i = 0; i < len; ++i) {
  586. var semantic = semantics[i];
  587. if (when.defined(attributes[semantic])) {
  588. indices[semantic] = j++;
  589. }
  590. }
  591. // Locations for custom attributes
  592. for (var name in attributes) {
  593. if (attributes.hasOwnProperty(name) && (!when.defined(indices[name]))) {
  594. indices[name] = j++;
  595. }
  596. }
  597. return indices;
  598. };
  599. /**
  600. * Reorders a geometry's attributes and <code>indices</code> to achieve better performance from the GPU's pre-vertex-shader cache.
  601. *
  602. * @param {Geometry} geometry The geometry to modify.
  603. * @returns {Geometry} The modified <code>geometry</code> argument, with its attributes and indices reordered for the GPU's pre-vertex-shader cache.
  604. *
  605. * @exception {DeveloperError} Each attribute array in geometry.attributes must have the same number of attributes.
  606. *
  607. *
  608. * @example
  609. * geometry = Cesium.GeometryPipeline.reorderForPreVertexCache(geometry);
  610. *
  611. * @see GeometryPipeline.reorderForPostVertexCache
  612. */
  613. GeometryPipeline.reorderForPreVertexCache = function(geometry) {
  614. //>>includeStart('debug', pragmas.debug);
  615. if (!when.defined(geometry)) {
  616. throw new Check.DeveloperError('geometry is required.');
  617. }
  618. //>>includeEnd('debug');
  619. var numVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  620. var indices = geometry.indices;
  621. if (when.defined(indices)) {
  622. var indexCrossReferenceOldToNew = new Int32Array(numVertices);
  623. for ( var i = 0; i < numVertices; i++) {
  624. indexCrossReferenceOldToNew[i] = -1;
  625. }
  626. // Construct cross reference and reorder indices
  627. var indicesIn = indices;
  628. var numIndices = indicesIn.length;
  629. var indicesOut = IndexDatatype.IndexDatatype.createTypedArray(numVertices, numIndices);
  630. var intoIndicesIn = 0;
  631. var intoIndicesOut = 0;
  632. var nextIndex = 0;
  633. var tempIndex;
  634. while (intoIndicesIn < numIndices) {
  635. tempIndex = indexCrossReferenceOldToNew[indicesIn[intoIndicesIn]];
  636. if (tempIndex !== -1) {
  637. indicesOut[intoIndicesOut] = tempIndex;
  638. } else {
  639. tempIndex = indicesIn[intoIndicesIn];
  640. indexCrossReferenceOldToNew[tempIndex] = nextIndex;
  641. indicesOut[intoIndicesOut] = nextIndex;
  642. ++nextIndex;
  643. }
  644. ++intoIndicesIn;
  645. ++intoIndicesOut;
  646. }
  647. geometry.indices = indicesOut;
  648. // Reorder attributes
  649. var attributes = geometry.attributes;
  650. for ( var property in attributes) {
  651. if (attributes.hasOwnProperty(property) &&
  652. when.defined(attributes[property]) &&
  653. when.defined(attributes[property].values)) {
  654. var attribute = attributes[property];
  655. var elementsIn = attribute.values;
  656. var intoElementsIn = 0;
  657. var numComponents = attribute.componentsPerAttribute;
  658. var elementsOut = ComponentDatatype.ComponentDatatype.createTypedArray(attribute.componentDatatype, nextIndex * numComponents);
  659. while (intoElementsIn < numVertices) {
  660. var temp = indexCrossReferenceOldToNew[intoElementsIn];
  661. if (temp !== -1) {
  662. for (var j = 0; j < numComponents; j++) {
  663. elementsOut[numComponents * temp + j] = elementsIn[numComponents * intoElementsIn + j];
  664. }
  665. }
  666. ++intoElementsIn;
  667. }
  668. attribute.values = elementsOut;
  669. }
  670. }
  671. }
  672. return geometry;
  673. };
  674. /**
  675. * Reorders a geometry's <code>indices</code> to achieve better performance from the GPU's
  676. * post vertex-shader cache by using the Tipsify algorithm. If the geometry <code>primitiveType</code>
  677. * is not <code>TRIANGLES</code> or the geometry does not have an <code>indices</code>, this function has no effect.
  678. *
  679. * @param {Geometry} geometry The geometry to modify.
  680. * @param {Number} [cacheCapacity=24] The number of vertices that can be held in the GPU's vertex cache.
  681. * @returns {Geometry} The modified <code>geometry</code> argument, with its indices reordered for the post-vertex-shader cache.
  682. *
  683. * @exception {DeveloperError} cacheCapacity must be greater than two.
  684. *
  685. *
  686. * @example
  687. * geometry = Cesium.GeometryPipeline.reorderForPostVertexCache(geometry);
  688. *
  689. * @see GeometryPipeline.reorderForPreVertexCache
  690. * @see {@link http://gfx.cs.princ0eton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf|Fast Triangle Reordering for Vertex Locality and Reduced Overdraw}
  691. * by Sander, Nehab, and Barczak
  692. */
  693. GeometryPipeline.reorderForPostVertexCache = function(geometry, cacheCapacity) {
  694. //>>includeStart('debug', pragmas.debug);
  695. if (!when.defined(geometry)) {
  696. throw new Check.DeveloperError('geometry is required.');
  697. }
  698. //>>includeEnd('debug');
  699. var indices = geometry.indices;
  700. if ((geometry.primitiveType === PrimitiveType.PrimitiveType.TRIANGLES) && (when.defined(indices))) {
  701. var numIndices = indices.length;
  702. var maximumIndex = 0;
  703. for ( var j = 0; j < numIndices; j++) {
  704. if (indices[j] > maximumIndex) {
  705. maximumIndex = indices[j];
  706. }
  707. }
  708. geometry.indices = Tipsify.tipsify({
  709. indices : indices,
  710. maximumIndex : maximumIndex,
  711. cacheSize : cacheCapacity
  712. });
  713. }
  714. return geometry;
  715. };
  716. function copyAttributesDescriptions(attributes) {
  717. var newAttributes = {};
  718. for ( var attribute in attributes) {
  719. if (attributes.hasOwnProperty(attribute) &&
  720. when.defined(attributes[attribute]) &&
  721. when.defined(attributes[attribute].values)) {
  722. var attr = attributes[attribute];
  723. newAttributes[attribute] = new GeometryAttribute.GeometryAttribute({
  724. componentDatatype : attr.componentDatatype,
  725. componentsPerAttribute : attr.componentsPerAttribute,
  726. normalize : attr.normalize,
  727. values : []
  728. });
  729. }
  730. }
  731. return newAttributes;
  732. }
  733. function copyVertex(destinationAttributes, sourceAttributes, index) {
  734. for ( var attribute in sourceAttributes) {
  735. if (sourceAttributes.hasOwnProperty(attribute) &&
  736. when.defined(sourceAttributes[attribute]) &&
  737. when.defined(sourceAttributes[attribute].values)) {
  738. var attr = sourceAttributes[attribute];
  739. for ( var k = 0; k < attr.componentsPerAttribute; ++k) {
  740. destinationAttributes[attribute].values.push(attr.values[(index * attr.componentsPerAttribute) + k]);
  741. }
  742. }
  743. }
  744. }
  745. /**
  746. * Splits a geometry into multiple geometries, if necessary, to ensure that indices in the
  747. * <code>indices</code> fit into unsigned shorts. This is used to meet the WebGL requirements
  748. * when unsigned int indices are not supported.
  749. * <p>
  750. * If the geometry does not have any <code>indices</code>, this function has no effect.
  751. * </p>
  752. *
  753. * @param {Geometry} geometry The geometry to be split into multiple geometries.
  754. * @returns {Geometry[]} An array of geometries, each with indices that fit into unsigned shorts.
  755. *
  756. * @exception {DeveloperError} geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS
  757. * @exception {DeveloperError} All geometry attribute lists must have the same number of attributes.
  758. *
  759. * @example
  760. * var geometries = Cesium.GeometryPipeline.fitToUnsignedShortIndices(geometry);
  761. */
  762. GeometryPipeline.fitToUnsignedShortIndices = function(geometry) {
  763. //>>includeStart('debug', pragmas.debug);
  764. if (!when.defined(geometry)) {
  765. throw new Check.DeveloperError('geometry is required.');
  766. }
  767. if ((when.defined(geometry.indices)) &&
  768. ((geometry.primitiveType !== PrimitiveType.PrimitiveType.TRIANGLES) &&
  769. (geometry.primitiveType !== PrimitiveType.PrimitiveType.LINES) &&
  770. (geometry.primitiveType !== PrimitiveType.PrimitiveType.POINTS))) {
  771. throw new Check.DeveloperError('geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS.');
  772. }
  773. //>>includeEnd('debug');
  774. var geometries = [];
  775. // If there's an index list and more than 64K attributes, it is possible that
  776. // some indices are outside the range of unsigned short [0, 64K - 1]
  777. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  778. if (when.defined(geometry.indices) && (numberOfVertices >= _Math.CesiumMath.SIXTY_FOUR_KILOBYTES)) {
  779. var oldToNewIndex = [];
  780. var newIndices = [];
  781. var currentIndex = 0;
  782. var newAttributes = copyAttributesDescriptions(geometry.attributes);
  783. var originalIndices = geometry.indices;
  784. var numberOfIndices = originalIndices.length;
  785. var indicesPerPrimitive;
  786. if (geometry.primitiveType === PrimitiveType.PrimitiveType.TRIANGLES) {
  787. indicesPerPrimitive = 3;
  788. } else if (geometry.primitiveType === PrimitiveType.PrimitiveType.LINES) {
  789. indicesPerPrimitive = 2;
  790. } else if (geometry.primitiveType === PrimitiveType.PrimitiveType.POINTS) {
  791. indicesPerPrimitive = 1;
  792. }
  793. for ( var j = 0; j < numberOfIndices; j += indicesPerPrimitive) {
  794. for (var k = 0; k < indicesPerPrimitive; ++k) {
  795. var x = originalIndices[j + k];
  796. var i = oldToNewIndex[x];
  797. if (!when.defined(i)) {
  798. i = currentIndex++;
  799. oldToNewIndex[x] = i;
  800. copyVertex(newAttributes, geometry.attributes, x);
  801. }
  802. newIndices.push(i);
  803. }
  804. if (currentIndex + indicesPerPrimitive >= _Math.CesiumMath.SIXTY_FOUR_KILOBYTES) {
  805. geometries.push(new GeometryAttribute.Geometry({
  806. attributes : newAttributes,
  807. indices : newIndices,
  808. primitiveType : geometry.primitiveType,
  809. boundingSphere : geometry.boundingSphere,
  810. boundingSphereCV : geometry.boundingSphereCV
  811. }));
  812. // Reset for next vertex-array
  813. oldToNewIndex = [];
  814. newIndices = [];
  815. currentIndex = 0;
  816. newAttributes = copyAttributesDescriptions(geometry.attributes);
  817. }
  818. }
  819. if (newIndices.length !== 0) {
  820. geometries.push(new GeometryAttribute.Geometry({
  821. attributes : newAttributes,
  822. indices : newIndices,
  823. primitiveType : geometry.primitiveType,
  824. boundingSphere : geometry.boundingSphere,
  825. boundingSphereCV : geometry.boundingSphereCV
  826. }));
  827. }
  828. } else {
  829. // No need to split into multiple geometries
  830. geometries.push(geometry);
  831. }
  832. return geometries;
  833. };
  834. var scratchProjectTo2DCartesian3 = new Cartographic.Cartesian3();
  835. var scratchProjectTo2DCartographic = new Cartographic.Cartographic();
  836. /**
  837. * Projects a geometry's 3D <code>position</code> attribute to 2D, replacing the <code>position</code>
  838. * attribute with separate <code>position3D</code> and <code>position2D</code> attributes.
  839. * <p>
  840. * If the geometry does not have a <code>position</code>, this function has no effect.
  841. * </p>
  842. *
  843. * @param {Geometry} geometry The geometry to modify.
  844. * @param {String} attributeName The name of the attribute.
  845. * @param {String} attributeName3D The name of the attribute in 3D.
  846. * @param {String} attributeName2D The name of the attribute in 2D.
  847. * @param {Object} [projection=new GeographicProjection()] The projection to use.
  848. * @returns {Geometry} The modified <code>geometry</code> argument with <code>position3D</code> and <code>position2D</code> attributes.
  849. *
  850. * @exception {DeveloperError} geometry must have attribute matching the attributeName argument.
  851. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE.
  852. * @exception {DeveloperError} Could not project a point to 2D.
  853. *
  854. * @example
  855. * geometry = Cesium.GeometryPipeline.projectTo2D(geometry, 'position', 'position3D', 'position2D');
  856. */
  857. GeometryPipeline.projectTo2D = function(geometry, attributeName, attributeName3D, attributeName2D, projection) {
  858. //>>includeStart('debug', pragmas.debug);
  859. if (!when.defined(geometry)) {
  860. throw new Check.DeveloperError('geometry is required.');
  861. }
  862. if (!when.defined(attributeName)) {
  863. throw new Check.DeveloperError('attributeName is required.');
  864. }
  865. if (!when.defined(attributeName3D)) {
  866. throw new Check.DeveloperError('attributeName3D is required.');
  867. }
  868. if (!when.defined(attributeName2D)) {
  869. throw new Check.DeveloperError('attributeName2D is required.');
  870. }
  871. if (!when.defined(geometry.attributes[attributeName])) {
  872. throw new Check.DeveloperError('geometry must have attribute matching the attributeName argument: ' + attributeName + '.');
  873. }
  874. if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype.ComponentDatatype.DOUBLE) {
  875. throw new Check.DeveloperError('The attribute componentDatatype must be ComponentDatatype.DOUBLE.');
  876. }
  877. //>>includeEnd('debug');
  878. var attribute = geometry.attributes[attributeName];
  879. projection = (when.defined(projection)) ? projection : new BoundingSphere.GeographicProjection();
  880. var ellipsoid = projection.ellipsoid;
  881. // Project original values to 2D.
  882. var values3D = attribute.values;
  883. var projectedValues = new Float64Array(values3D.length);
  884. var index = 0;
  885. for ( var i = 0; i < values3D.length; i += 3) {
  886. var value = Cartographic.Cartesian3.fromArray(values3D, i, scratchProjectTo2DCartesian3);
  887. var lonLat = ellipsoid.cartesianToCartographic(value, scratchProjectTo2DCartographic);
  888. //>>includeStart('debug', pragmas.debug);
  889. if (!when.defined(lonLat)) {
  890. throw new Check.DeveloperError('Could not project point (' + value.x + ', ' + value.y + ', ' + value.z + ') to 2D.');
  891. }
  892. //>>includeEnd('debug');
  893. var projectedLonLat = projection.project(lonLat, scratchProjectTo2DCartesian3);
  894. projectedValues[index++] = projectedLonLat.x;
  895. projectedValues[index++] = projectedLonLat.y;
  896. projectedValues[index++] = projectedLonLat.z;
  897. }
  898. // Rename original cartesians to WGS84 cartesians.
  899. geometry.attributes[attributeName3D] = attribute;
  900. // Replace original cartesians with 2D projected cartesians
  901. geometry.attributes[attributeName2D] = new GeometryAttribute.GeometryAttribute({
  902. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  903. componentsPerAttribute : 3,
  904. values : projectedValues
  905. });
  906. delete geometry.attributes[attributeName];
  907. return geometry;
  908. };
  909. var encodedResult = {
  910. high : 0.0,
  911. low : 0.0
  912. };
  913. /**
  914. * Encodes floating-point geometry attribute values as two separate attributes to improve
  915. * rendering precision.
  916. * <p>
  917. * This is commonly used to create high-precision position vertex attributes.
  918. * </p>
  919. *
  920. * @param {Geometry} geometry The geometry to modify.
  921. * @param {String} attributeName The name of the attribute.
  922. * @param {String} attributeHighName The name of the attribute for the encoded high bits.
  923. * @param {String} attributeLowName The name of the attribute for the encoded low bits.
  924. * @returns {Geometry} The modified <code>geometry</code> argument, with its encoded attribute.
  925. *
  926. * @exception {DeveloperError} geometry must have attribute matching the attributeName argument.
  927. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE.
  928. *
  929. * @example
  930. * geometry = Cesium.GeometryPipeline.encodeAttribute(geometry, 'position3D', 'position3DHigh', 'position3DLow');
  931. */
  932. GeometryPipeline.encodeAttribute = function(geometry, attributeName, attributeHighName, attributeLowName) {
  933. //>>includeStart('debug', pragmas.debug);
  934. if (!when.defined(geometry)) {
  935. throw new Check.DeveloperError('geometry is required.');
  936. }
  937. if (!when.defined(attributeName)) {
  938. throw new Check.DeveloperError('attributeName is required.');
  939. }
  940. if (!when.defined(attributeHighName)) {
  941. throw new Check.DeveloperError('attributeHighName is required.');
  942. }
  943. if (!when.defined(attributeLowName)) {
  944. throw new Check.DeveloperError('attributeLowName is required.');
  945. }
  946. if (!when.defined(geometry.attributes[attributeName])) {
  947. throw new Check.DeveloperError('geometry must have attribute matching the attributeName argument: ' + attributeName + '.');
  948. }
  949. if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype.ComponentDatatype.DOUBLE) {
  950. throw new Check.DeveloperError('The attribute componentDatatype must be ComponentDatatype.DOUBLE.');
  951. }
  952. //>>includeEnd('debug');
  953. var attribute = geometry.attributes[attributeName];
  954. var values = attribute.values;
  955. var length = values.length;
  956. var highValues = new Float32Array(length);
  957. var lowValues = new Float32Array(length);
  958. for (var i = 0; i < length; ++i) {
  959. EncodedCartesian3.EncodedCartesian3.encode(values[i], encodedResult);
  960. highValues[i] = encodedResult.high;
  961. lowValues[i] = encodedResult.low;
  962. }
  963. var componentsPerAttribute = attribute.componentsPerAttribute;
  964. geometry.attributes[attributeHighName] = new GeometryAttribute.GeometryAttribute({
  965. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  966. componentsPerAttribute : componentsPerAttribute,
  967. values : highValues
  968. });
  969. geometry.attributes[attributeLowName] = new GeometryAttribute.GeometryAttribute({
  970. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  971. componentsPerAttribute : componentsPerAttribute,
  972. values : lowValues
  973. });
  974. delete geometry.attributes[attributeName];
  975. return geometry;
  976. };
  977. var scratchCartesian3$1 = new Cartographic.Cartesian3();
  978. function transformPoint(matrix, attribute) {
  979. if (when.defined(attribute)) {
  980. var values = attribute.values;
  981. var length = values.length;
  982. for (var i = 0; i < length; i += 3) {
  983. Cartographic.Cartesian3.unpack(values, i, scratchCartesian3$1);
  984. BoundingSphere.Matrix4.multiplyByPoint(matrix, scratchCartesian3$1, scratchCartesian3$1);
  985. Cartographic.Cartesian3.pack(scratchCartesian3$1, values, i);
  986. }
  987. }
  988. }
  989. function transformVector(matrix, attribute) {
  990. if (when.defined(attribute)) {
  991. var values = attribute.values;
  992. var length = values.length;
  993. for (var i = 0; i < length; i += 3) {
  994. Cartographic.Cartesian3.unpack(values, i, scratchCartesian3$1);
  995. BoundingSphere.Matrix3.multiplyByVector(matrix, scratchCartesian3$1, scratchCartesian3$1);
  996. scratchCartesian3$1 = Cartographic.Cartesian3.normalize(scratchCartesian3$1, scratchCartesian3$1);
  997. Cartographic.Cartesian3.pack(scratchCartesian3$1, values, i);
  998. }
  999. }
  1000. }
  1001. var inverseTranspose = new BoundingSphere.Matrix4();
  1002. var normalMatrix = new BoundingSphere.Matrix3();
  1003. /**
  1004. * Transforms a geometry instance to world coordinates. This changes
  1005. * the instance's <code>modelMatrix</code> to {@link Matrix4.IDENTITY} and transforms the
  1006. * following attributes if they are present: <code>position</code>, <code>normal</code>,
  1007. * <code>tangent</code>, and <code>bitangent</code>.
  1008. *
  1009. * @param {GeometryInstance} instance The geometry instance to modify.
  1010. * @returns {GeometryInstance} The modified <code>instance</code> argument, with its attributes transforms to world coordinates.
  1011. *
  1012. * @example
  1013. * Cesium.GeometryPipeline.transformToWorldCoordinates(instance);
  1014. */
  1015. GeometryPipeline.transformToWorldCoordinates = function(instance) {
  1016. //>>includeStart('debug', pragmas.debug);
  1017. if (!when.defined(instance)) {
  1018. throw new Check.DeveloperError('instance is required.');
  1019. }
  1020. //>>includeEnd('debug');
  1021. var modelMatrix = instance.modelMatrix;
  1022. if (BoundingSphere.Matrix4.equals(modelMatrix, BoundingSphere.Matrix4.IDENTITY)) {
  1023. // Already in world coordinates
  1024. return instance;
  1025. }
  1026. var attributes = instance.geometry.attributes;
  1027. // Transform attributes in known vertex formats
  1028. transformPoint(modelMatrix, attributes.position);
  1029. transformPoint(modelMatrix, attributes.prevPosition);
  1030. transformPoint(modelMatrix, attributes.nextPosition);
  1031. if ((when.defined(attributes.normal)) ||
  1032. (when.defined(attributes.tangent)) ||
  1033. (when.defined(attributes.bitangent))) {
  1034. BoundingSphere.Matrix4.inverse(modelMatrix, inverseTranspose);
  1035. BoundingSphere.Matrix4.transpose(inverseTranspose, inverseTranspose);
  1036. BoundingSphere.Matrix4.getRotation(inverseTranspose, normalMatrix);
  1037. transformVector(normalMatrix, attributes.normal);
  1038. transformVector(normalMatrix, attributes.tangent);
  1039. transformVector(normalMatrix, attributes.bitangent);
  1040. }
  1041. var boundingSphere = instance.geometry.boundingSphere;
  1042. if (when.defined(boundingSphere)) {
  1043. instance.geometry.boundingSphere = BoundingSphere.BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere);
  1044. }
  1045. instance.modelMatrix = BoundingSphere.Matrix4.clone(BoundingSphere.Matrix4.IDENTITY);
  1046. return instance;
  1047. };
  1048. function findAttributesInAllGeometries(instances, propertyName) {
  1049. var length = instances.length;
  1050. var attributesInAllGeometries = {};
  1051. var attributes0 = instances[0][propertyName].attributes;
  1052. var name;
  1053. for (name in attributes0) {
  1054. if (attributes0.hasOwnProperty(name) &&
  1055. when.defined(attributes0[name]) &&
  1056. when.defined(attributes0[name].values)) {
  1057. var attribute = attributes0[name];
  1058. var numberOfComponents = attribute.values.length;
  1059. var inAllGeometries = true;
  1060. // Does this same attribute exist in all geometries?
  1061. for (var i = 1; i < length; ++i) {
  1062. var otherAttribute = instances[i][propertyName].attributes[name];
  1063. if ((!when.defined(otherAttribute)) ||
  1064. (attribute.componentDatatype !== otherAttribute.componentDatatype) ||
  1065. (attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute) ||
  1066. (attribute.normalize !== otherAttribute.normalize)) {
  1067. inAllGeometries = false;
  1068. break;
  1069. }
  1070. numberOfComponents += otherAttribute.values.length;
  1071. }
  1072. if (inAllGeometries) {
  1073. attributesInAllGeometries[name] = new GeometryAttribute.GeometryAttribute({
  1074. componentDatatype : attribute.componentDatatype,
  1075. componentsPerAttribute : attribute.componentsPerAttribute,
  1076. normalize : attribute.normalize,
  1077. values : ComponentDatatype.ComponentDatatype.createTypedArray(attribute.componentDatatype, numberOfComponents)
  1078. });
  1079. }
  1080. }
  1081. }
  1082. return attributesInAllGeometries;
  1083. }
  1084. var tempScratch = new Cartographic.Cartesian3();
  1085. function combineGeometries(instances, propertyName) {
  1086. var length = instances.length;
  1087. var name;
  1088. var i;
  1089. var j;
  1090. var k;
  1091. var m = instances[0].modelMatrix;
  1092. var haveIndices = (when.defined(instances[0][propertyName].indices));
  1093. var primitiveType = instances[0][propertyName].primitiveType;
  1094. //>>includeStart('debug', pragmas.debug);
  1095. for (i = 1; i < length; ++i) {
  1096. if (!BoundingSphere.Matrix4.equals(instances[i].modelMatrix, m)) {
  1097. throw new Check.DeveloperError('All instances must have the same modelMatrix.');
  1098. }
  1099. if ((when.defined(instances[i][propertyName].indices)) !== haveIndices) {
  1100. throw new Check.DeveloperError('All instance geometries must have an indices or not have one.');
  1101. }
  1102. if (instances[i][propertyName].primitiveType !== primitiveType) {
  1103. throw new Check.DeveloperError('All instance geometries must have the same primitiveType.');
  1104. }
  1105. }
  1106. //>>includeEnd('debug');
  1107. // Find subset of attributes in all geometries
  1108. var attributes = findAttributesInAllGeometries(instances, propertyName);
  1109. var values;
  1110. var sourceValues;
  1111. var sourceValuesLength;
  1112. // Combine attributes from each geometry into a single typed array
  1113. for (name in attributes) {
  1114. if (attributes.hasOwnProperty(name)) {
  1115. values = attributes[name].values;
  1116. k = 0;
  1117. for (i = 0; i < length; ++i) {
  1118. sourceValues = instances[i][propertyName].attributes[name].values;
  1119. sourceValuesLength = sourceValues.length;
  1120. for (j = 0; j < sourceValuesLength; ++j) {
  1121. values[k++] = sourceValues[j];
  1122. }
  1123. }
  1124. }
  1125. }
  1126. // Combine index lists
  1127. var indices;
  1128. if (haveIndices) {
  1129. var numberOfIndices = 0;
  1130. for (i = 0; i < length; ++i) {
  1131. numberOfIndices += instances[i][propertyName].indices.length;
  1132. }
  1133. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(new GeometryAttribute.Geometry({
  1134. attributes : attributes,
  1135. primitiveType : PrimitiveType.PrimitiveType.POINTS
  1136. }));
  1137. var destIndices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices);
  1138. var destOffset = 0;
  1139. var offset = 0;
  1140. for (i = 0; i < length; ++i) {
  1141. var sourceIndices = instances[i][propertyName].indices;
  1142. var sourceIndicesLen = sourceIndices.length;
  1143. for (k = 0; k < sourceIndicesLen; ++k) {
  1144. destIndices[destOffset++] = offset + sourceIndices[k];
  1145. }
  1146. offset += GeometryAttribute.Geometry.computeNumberOfVertices(instances[i][propertyName]);
  1147. }
  1148. indices = destIndices;
  1149. }
  1150. // Create bounding sphere that includes all instances
  1151. var center = new Cartographic.Cartesian3();
  1152. var radius = 0.0;
  1153. var bs;
  1154. for (i = 0; i < length; ++i) {
  1155. bs = instances[i][propertyName].boundingSphere;
  1156. if (!when.defined(bs)) {
  1157. // If any geometries have an undefined bounding sphere, then so does the combined geometry
  1158. center = undefined;
  1159. break;
  1160. }
  1161. Cartographic.Cartesian3.add(bs.center, center, center);
  1162. }
  1163. if (when.defined(center)) {
  1164. Cartographic.Cartesian3.divideByScalar(center, length, center);
  1165. for (i = 0; i < length; ++i) {
  1166. bs = instances[i][propertyName].boundingSphere;
  1167. var tempRadius = Cartographic.Cartesian3.magnitude(Cartographic.Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius;
  1168. if (tempRadius > radius) {
  1169. radius = tempRadius;
  1170. }
  1171. }
  1172. }
  1173. return new GeometryAttribute.Geometry({
  1174. attributes : attributes,
  1175. indices : indices,
  1176. primitiveType : primitiveType,
  1177. boundingSphere : (when.defined(center)) ? new BoundingSphere.BoundingSphere(center, radius) : undefined
  1178. });
  1179. }
  1180. /**
  1181. * Combines geometry from several {@link GeometryInstance} objects into one geometry.
  1182. * This concatenates the attributes, concatenates and adjusts the indices, and creates
  1183. * a bounding sphere encompassing all instances.
  1184. * <p>
  1185. * If the instances do not have the same attributes, a subset of attributes common
  1186. * to all instances is used, and the others are ignored.
  1187. * </p>
  1188. * <p>
  1189. * This is used by {@link Primitive} to efficiently render a large amount of static data.
  1190. * </p>
  1191. *
  1192. * @private
  1193. *
  1194. * @param {GeometryInstance[]} [instances] The array of {@link GeometryInstance} objects whose geometry will be combined.
  1195. * @returns {Geometry} A single geometry created from the provided geometry instances.
  1196. *
  1197. * @exception {DeveloperError} All instances must have the same modelMatrix.
  1198. * @exception {DeveloperError} All instance geometries must have an indices or not have one.
  1199. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  1200. *
  1201. *
  1202. * @example
  1203. * for (var i = 0; i < instances.length; ++i) {
  1204. * Cesium.GeometryPipeline.transformToWorldCoordinates(instances[i]);
  1205. * }
  1206. * var geometries = Cesium.GeometryPipeline.combineInstances(instances);
  1207. *
  1208. * @see GeometryPipeline.transformToWorldCoordinates
  1209. */
  1210. GeometryPipeline.combineInstances = function(instances) {
  1211. //>>includeStart('debug', pragmas.debug);
  1212. if ((!when.defined(instances)) || (instances.length < 1)) {
  1213. throw new Check.DeveloperError('instances is required and must have length greater than zero.');
  1214. }
  1215. //>>includeEnd('debug');
  1216. var instanceGeometry = [];
  1217. var instanceSplitGeometry = [];
  1218. var length = instances.length;
  1219. for (var i = 0; i < length; ++i) {
  1220. var instance = instances[i];
  1221. if (when.defined(instance.geometry)) {
  1222. instanceGeometry.push(instance);
  1223. } else if (when.defined(instance.westHemisphereGeometry) && when.defined(instance.eastHemisphereGeometry)) {
  1224. instanceSplitGeometry.push(instance);
  1225. }
  1226. }
  1227. var geometries = [];
  1228. if (instanceGeometry.length > 0) {
  1229. geometries.push(combineGeometries(instanceGeometry, 'geometry'));
  1230. }
  1231. if (instanceSplitGeometry.length > 0) {
  1232. geometries.push(combineGeometries(instanceSplitGeometry, 'westHemisphereGeometry'));
  1233. geometries.push(combineGeometries(instanceSplitGeometry, 'eastHemisphereGeometry'));
  1234. }
  1235. return geometries;
  1236. };
  1237. var normal = new Cartographic.Cartesian3();
  1238. var v0 = new Cartographic.Cartesian3();
  1239. var v1 = new Cartographic.Cartesian3();
  1240. var v2 = new Cartographic.Cartesian3();
  1241. /**
  1242. * Computes per-vertex normals for a geometry containing <code>TRIANGLES</code> by averaging the normals of
  1243. * all triangles incident to the vertex. The result is a new <code>normal</code> attribute added to the geometry.
  1244. * This assumes a counter-clockwise winding order.
  1245. *
  1246. * @param {Geometry} geometry The geometry to modify.
  1247. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>normal</code> attribute.
  1248. *
  1249. * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3.
  1250. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}.
  1251. *
  1252. * @example
  1253. * Cesium.GeometryPipeline.computeNormal(geometry);
  1254. */
  1255. GeometryPipeline.computeNormal = function(geometry) {
  1256. //>>includeStart('debug', pragmas.debug);
  1257. if (!when.defined(geometry)) {
  1258. throw new Check.DeveloperError('geometry is required.');
  1259. }
  1260. if (!when.defined(geometry.attributes.position) || !when.defined(geometry.attributes.position.values)) {
  1261. throw new Check.DeveloperError('geometry.attributes.position.values is required.');
  1262. }
  1263. if (!when.defined(geometry.indices)) {
  1264. throw new Check.DeveloperError('geometry.indices is required.');
  1265. }
  1266. if (geometry.indices.length < 2 || geometry.indices.length % 3 !== 0) {
  1267. throw new Check.DeveloperError('geometry.indices length must be greater than 0 and be a multiple of 3.');
  1268. }
  1269. if (geometry.primitiveType !== PrimitiveType.PrimitiveType.TRIANGLES) {
  1270. throw new Check.DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLES.');
  1271. }
  1272. //>>includeEnd('debug');
  1273. var indices = geometry.indices;
  1274. var attributes = geometry.attributes;
  1275. var vertices = attributes.position.values;
  1276. var numVertices = attributes.position.values.length / 3;
  1277. var numIndices = indices.length;
  1278. var normalsPerVertex = new Array(numVertices);
  1279. var normalsPerTriangle = new Array(numIndices / 3);
  1280. var normalIndices = new Array(numIndices);
  1281. var i;
  1282. for ( i = 0; i < numVertices; i++) {
  1283. normalsPerVertex[i] = {
  1284. indexOffset : 0,
  1285. count : 0,
  1286. currentCount : 0
  1287. };
  1288. }
  1289. var j = 0;
  1290. for (i = 0; i < numIndices; i += 3) {
  1291. var i0 = indices[i];
  1292. var i1 = indices[i + 1];
  1293. var i2 = indices[i + 2];
  1294. var i03 = i0 * 3;
  1295. var i13 = i1 * 3;
  1296. var i23 = i2 * 3;
  1297. v0.x = vertices[i03];
  1298. v0.y = vertices[i03 + 1];
  1299. v0.z = vertices[i03 + 2];
  1300. v1.x = vertices[i13];
  1301. v1.y = vertices[i13 + 1];
  1302. v1.z = vertices[i13 + 2];
  1303. v2.x = vertices[i23];
  1304. v2.y = vertices[i23 + 1];
  1305. v2.z = vertices[i23 + 2];
  1306. normalsPerVertex[i0].count++;
  1307. normalsPerVertex[i1].count++;
  1308. normalsPerVertex[i2].count++;
  1309. Cartographic.Cartesian3.subtract(v1, v0, v1);
  1310. Cartographic.Cartesian3.subtract(v2, v0, v2);
  1311. normalsPerTriangle[j] = Cartographic.Cartesian3.cross(v1, v2, new Cartographic.Cartesian3());
  1312. j++;
  1313. }
  1314. var indexOffset = 0;
  1315. for (i = 0; i < numVertices; i++) {
  1316. normalsPerVertex[i].indexOffset += indexOffset;
  1317. indexOffset += normalsPerVertex[i].count;
  1318. }
  1319. j = 0;
  1320. var vertexNormalData;
  1321. for (i = 0; i < numIndices; i += 3) {
  1322. vertexNormalData = normalsPerVertex[indices[i]];
  1323. var index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  1324. normalIndices[index] = j;
  1325. vertexNormalData.currentCount++;
  1326. vertexNormalData = normalsPerVertex[indices[i + 1]];
  1327. index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  1328. normalIndices[index] = j;
  1329. vertexNormalData.currentCount++;
  1330. vertexNormalData = normalsPerVertex[indices[i + 2]];
  1331. index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  1332. normalIndices[index] = j;
  1333. vertexNormalData.currentCount++;
  1334. j++;
  1335. }
  1336. var normalValues = new Float32Array(numVertices * 3);
  1337. for (i = 0; i < numVertices; i++) {
  1338. var i3 = i * 3;
  1339. vertexNormalData = normalsPerVertex[i];
  1340. Cartographic.Cartesian3.clone(Cartographic.Cartesian3.ZERO, normal);
  1341. if (vertexNormalData.count > 0) {
  1342. for (j = 0; j < vertexNormalData.count; j++) {
  1343. Cartographic.Cartesian3.add(normal, normalsPerTriangle[normalIndices[vertexNormalData.indexOffset + j]], normal);
  1344. }
  1345. // We can run into an issue where a vertex is used with 2 primitives that have opposite winding order.
  1346. if (Cartographic.Cartesian3.equalsEpsilon(Cartographic.Cartesian3.ZERO, normal, _Math.CesiumMath.EPSILON10)) {
  1347. Cartographic.Cartesian3.clone(normalsPerTriangle[normalIndices[vertexNormalData.indexOffset]], normal);
  1348. }
  1349. }
  1350. // We end up with a zero vector probably because of a degenerate triangle
  1351. if (Cartographic.Cartesian3.equalsEpsilon(Cartographic.Cartesian3.ZERO, normal, _Math.CesiumMath.EPSILON10)) {
  1352. // Default to (0,0,1)
  1353. normal.z = 1.0;
  1354. }
  1355. Cartographic.Cartesian3.normalize(normal, normal);
  1356. normalValues[i3] = normal.x;
  1357. normalValues[i3 + 1] = normal.y;
  1358. normalValues[i3 + 2] = normal.z;
  1359. }
  1360. geometry.attributes.normal = new GeometryAttribute.GeometryAttribute({
  1361. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1362. componentsPerAttribute : 3,
  1363. values : normalValues
  1364. });
  1365. return geometry;
  1366. };
  1367. var normalScratch = new Cartographic.Cartesian3();
  1368. var normalScale = new Cartographic.Cartesian3();
  1369. var tScratch = new Cartographic.Cartesian3();
  1370. /**
  1371. * Computes per-vertex tangents and bitangents for a geometry containing <code>TRIANGLES</code>.
  1372. * The result is new <code>tangent</code> and <code>bitangent</code> attributes added to the geometry.
  1373. * This assumes a counter-clockwise winding order.
  1374. * <p>
  1375. * Based on <a href="http://www.terathon.com/code/tangent.html">Computing Tangent Space Basis Vectors
  1376. * for an Arbitrary Mesh</a> by Eric Lengyel.
  1377. * </p>
  1378. *
  1379. * @param {Geometry} geometry The geometry to modify.
  1380. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>tangent</code> and <code>bitangent</code> attributes.
  1381. *
  1382. * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3.
  1383. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}.
  1384. *
  1385. * @example
  1386. * Cesium.GeometryPipeline.computeTangentAndBiTangent(geometry);
  1387. */
  1388. GeometryPipeline.computeTangentAndBitangent = function(geometry) {
  1389. //>>includeStart('debug', pragmas.debug);
  1390. if (!when.defined(geometry)) {
  1391. throw new Check.DeveloperError('geometry is required.');
  1392. }
  1393. //>>includeEnd('debug');
  1394. var attributes = geometry.attributes;
  1395. var indices = geometry.indices;
  1396. //>>includeStart('debug', pragmas.debug);
  1397. if (!when.defined(attributes.position) || !when.defined(attributes.position.values)) {
  1398. throw new Check.DeveloperError('geometry.attributes.position.values is required.');
  1399. }
  1400. if (!when.defined(attributes.normal) || !when.defined(attributes.normal.values)) {
  1401. throw new Check.DeveloperError('geometry.attributes.normal.values is required.');
  1402. }
  1403. if (!when.defined(attributes.st) || !when.defined(attributes.st.values)) {
  1404. throw new Check.DeveloperError('geometry.attributes.st.values is required.');
  1405. }
  1406. if (!when.defined(indices)) {
  1407. throw new Check.DeveloperError('geometry.indices is required.');
  1408. }
  1409. if (indices.length < 2 || indices.length % 3 !== 0) {
  1410. throw new Check.DeveloperError('geometry.indices length must be greater than 0 and be a multiple of 3.');
  1411. }
  1412. if (geometry.primitiveType !== PrimitiveType.PrimitiveType.TRIANGLES) {
  1413. throw new Check.DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLES.');
  1414. }
  1415. //>>includeEnd('debug');
  1416. var vertices = geometry.attributes.position.values;
  1417. var normals = geometry.attributes.normal.values;
  1418. var st = geometry.attributes.st.values;
  1419. var numVertices = geometry.attributes.position.values.length / 3;
  1420. var numIndices = indices.length;
  1421. var tan1 = new Array(numVertices * 3);
  1422. var i;
  1423. for ( i = 0; i < tan1.length; i++) {
  1424. tan1[i] = 0;
  1425. }
  1426. var i03;
  1427. var i13;
  1428. var i23;
  1429. for (i = 0; i < numIndices; i += 3) {
  1430. var i0 = indices[i];
  1431. var i1 = indices[i + 1];
  1432. var i2 = indices[i + 2];
  1433. i03 = i0 * 3;
  1434. i13 = i1 * 3;
  1435. i23 = i2 * 3;
  1436. var i02 = i0 * 2;
  1437. var i12 = i1 * 2;
  1438. var i22 = i2 * 2;
  1439. var ux = vertices[i03];
  1440. var uy = vertices[i03 + 1];
  1441. var uz = vertices[i03 + 2];
  1442. var wx = st[i02];
  1443. var wy = st[i02 + 1];
  1444. var t1 = st[i12 + 1] - wy;
  1445. var t2 = st[i22 + 1] - wy;
  1446. var r = 1.0 / ((st[i12] - wx) * t2 - (st[i22] - wx) * t1);
  1447. var sdirx = (t2 * (vertices[i13] - ux) - t1 * (vertices[i23] - ux)) * r;
  1448. var sdiry = (t2 * (vertices[i13 + 1] - uy) - t1 * (vertices[i23 + 1] - uy)) * r;
  1449. var sdirz = (t2 * (vertices[i13 + 2] - uz) - t1 * (vertices[i23 + 2] - uz)) * r;
  1450. tan1[i03] += sdirx;
  1451. tan1[i03 + 1] += sdiry;
  1452. tan1[i03 + 2] += sdirz;
  1453. tan1[i13] += sdirx;
  1454. tan1[i13 + 1] += sdiry;
  1455. tan1[i13 + 2] += sdirz;
  1456. tan1[i23] += sdirx;
  1457. tan1[i23 + 1] += sdiry;
  1458. tan1[i23 + 2] += sdirz;
  1459. }
  1460. var tangentValues = new Float32Array(numVertices * 3);
  1461. var bitangentValues = new Float32Array(numVertices * 3);
  1462. for (i = 0; i < numVertices; i++) {
  1463. i03 = i * 3;
  1464. i13 = i03 + 1;
  1465. i23 = i03 + 2;
  1466. var n = Cartographic.Cartesian3.fromArray(normals, i03, normalScratch);
  1467. var t = Cartographic.Cartesian3.fromArray(tan1, i03, tScratch);
  1468. var scalar = Cartographic.Cartesian3.dot(n, t);
  1469. Cartographic.Cartesian3.multiplyByScalar(n, scalar, normalScale);
  1470. Cartographic.Cartesian3.normalize(Cartographic.Cartesian3.subtract(t, normalScale, t), t);
  1471. tangentValues[i03] = t.x;
  1472. tangentValues[i13] = t.y;
  1473. tangentValues[i23] = t.z;
  1474. Cartographic.Cartesian3.normalize(Cartographic.Cartesian3.cross(n, t, t), t);
  1475. bitangentValues[i03] = t.x;
  1476. bitangentValues[i13] = t.y;
  1477. bitangentValues[i23] = t.z;
  1478. }
  1479. geometry.attributes.tangent = new GeometryAttribute.GeometryAttribute({
  1480. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1481. componentsPerAttribute : 3,
  1482. values : tangentValues
  1483. });
  1484. geometry.attributes.bitangent = new GeometryAttribute.GeometryAttribute({
  1485. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1486. componentsPerAttribute : 3,
  1487. values : bitangentValues
  1488. });
  1489. return geometry;
  1490. };
  1491. var scratchCartesian2$1 = new Cartesian2.Cartesian2();
  1492. var toEncode1 = new Cartographic.Cartesian3();
  1493. var toEncode2 = new Cartographic.Cartesian3();
  1494. var toEncode3 = new Cartographic.Cartesian3();
  1495. var encodeResult2 = new Cartesian2.Cartesian2();
  1496. /**
  1497. * Compresses and packs geometry normal attribute values to save memory.
  1498. *
  1499. * @param {Geometry} geometry The geometry to modify.
  1500. * @returns {Geometry} The modified <code>geometry</code> argument, with its normals compressed and packed.
  1501. *
  1502. * @example
  1503. * geometry = Cesium.GeometryPipeline.compressVertices(geometry);
  1504. */
  1505. GeometryPipeline.compressVertices = function(geometry) {
  1506. //>>includeStart('debug', pragmas.debug);
  1507. if (!when.defined(geometry)) {
  1508. throw new Check.DeveloperError('geometry is required.');
  1509. }
  1510. //>>includeEnd('debug');
  1511. var extrudeAttribute = geometry.attributes.extrudeDirection;
  1512. var i;
  1513. var numVertices;
  1514. if (when.defined(extrudeAttribute)) {
  1515. //only shadow volumes use extrudeDirection, and shadow volumes use vertexFormat: POSITION_ONLY so we don't need to check other attributes
  1516. var extrudeDirections = extrudeAttribute.values;
  1517. numVertices = extrudeDirections.length / 3.0;
  1518. var compressedDirections = new Float32Array(numVertices * 2);
  1519. var i2 = 0;
  1520. for (i = 0; i < numVertices; ++i) {
  1521. Cartographic.Cartesian3.fromArray(extrudeDirections, i * 3.0, toEncode1);
  1522. if (Cartographic.Cartesian3.equals(toEncode1, Cartographic.Cartesian3.ZERO)) {
  1523. i2 += 2;
  1524. continue;
  1525. }
  1526. encodeResult2 = AttributeCompression.AttributeCompression.octEncodeInRange(toEncode1, 65535, encodeResult2);
  1527. compressedDirections[i2++] = encodeResult2.x;
  1528. compressedDirections[i2++] = encodeResult2.y;
  1529. }
  1530. geometry.attributes.compressedAttributes = new GeometryAttribute.GeometryAttribute({
  1531. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1532. componentsPerAttribute : 2,
  1533. values : compressedDirections
  1534. });
  1535. delete geometry.attributes.extrudeDirection;
  1536. return geometry;
  1537. }
  1538. var normalAttribute = geometry.attributes.normal;
  1539. var stAttribute = geometry.attributes.st;
  1540. var hasNormal = when.defined(normalAttribute);
  1541. var hasSt = when.defined(stAttribute);
  1542. if (!hasNormal && !hasSt) {
  1543. return geometry;
  1544. }
  1545. var tangentAttribute = geometry.attributes.tangent;
  1546. var bitangentAttribute = geometry.attributes.bitangent;
  1547. var hasTangent = when.defined(tangentAttribute);
  1548. var hasBitangent = when.defined(bitangentAttribute);
  1549. var normals;
  1550. var st;
  1551. var tangents;
  1552. var bitangents;
  1553. if (hasNormal) {
  1554. normals = normalAttribute.values;
  1555. }
  1556. if (hasSt) {
  1557. st = stAttribute.values;
  1558. }
  1559. if (hasTangent) {
  1560. tangents = tangentAttribute.values;
  1561. }
  1562. if (hasBitangent) {
  1563. bitangents = bitangentAttribute.values;
  1564. }
  1565. var length = hasNormal ? normals.length : st.length;
  1566. var numComponents = hasNormal ? 3.0 : 2.0;
  1567. numVertices = length / numComponents;
  1568. var compressedLength = numVertices;
  1569. var numCompressedComponents = hasSt && hasNormal ? 2.0 : 1.0;
  1570. numCompressedComponents += hasTangent || hasBitangent ? 1.0 : 0.0;
  1571. compressedLength *= numCompressedComponents;
  1572. var compressedAttributes = new Float32Array(compressedLength);
  1573. var normalIndex = 0;
  1574. for (i = 0; i < numVertices; ++i) {
  1575. if (hasSt) {
  1576. Cartesian2.Cartesian2.fromArray(st, i * 2.0, scratchCartesian2$1);
  1577. compressedAttributes[normalIndex++] = AttributeCompression.AttributeCompression.compressTextureCoordinates(scratchCartesian2$1);
  1578. }
  1579. var index = i * 3.0;
  1580. if (hasNormal && when.defined(tangents) && when.defined(bitangents)) {
  1581. Cartographic.Cartesian3.fromArray(normals, index, toEncode1);
  1582. Cartographic.Cartesian3.fromArray(tangents, index, toEncode2);
  1583. Cartographic.Cartesian3.fromArray(bitangents, index, toEncode3);
  1584. AttributeCompression.AttributeCompression.octPack(toEncode1, toEncode2, toEncode3, scratchCartesian2$1);
  1585. compressedAttributes[normalIndex++] = scratchCartesian2$1.x;
  1586. compressedAttributes[normalIndex++] = scratchCartesian2$1.y;
  1587. } else {
  1588. if (hasNormal) {
  1589. Cartographic.Cartesian3.fromArray(normals, index, toEncode1);
  1590. compressedAttributes[normalIndex++] = AttributeCompression.AttributeCompression.octEncodeFloat(toEncode1);
  1591. }
  1592. if (hasTangent) {
  1593. Cartographic.Cartesian3.fromArray(tangents, index, toEncode1);
  1594. compressedAttributes[normalIndex++] = AttributeCompression.AttributeCompression.octEncodeFloat(toEncode1);
  1595. }
  1596. if (hasBitangent) {
  1597. Cartographic.Cartesian3.fromArray(bitangents, index, toEncode1);
  1598. compressedAttributes[normalIndex++] = AttributeCompression.AttributeCompression.octEncodeFloat(toEncode1);
  1599. }
  1600. }
  1601. }
  1602. geometry.attributes.compressedAttributes = new GeometryAttribute.GeometryAttribute({
  1603. componentDatatype : ComponentDatatype.ComponentDatatype.FLOAT,
  1604. componentsPerAttribute : numCompressedComponents,
  1605. values : compressedAttributes
  1606. });
  1607. if (hasNormal) {
  1608. delete geometry.attributes.normal;
  1609. }
  1610. if (hasSt) {
  1611. delete geometry.attributes.st;
  1612. }
  1613. if (hasBitangent) {
  1614. delete geometry.attributes.bitangent;
  1615. }
  1616. if (hasTangent) {
  1617. delete geometry.attributes.tangent;
  1618. }
  1619. return geometry;
  1620. };
  1621. function indexTriangles(geometry) {
  1622. if (when.defined(geometry.indices)) {
  1623. return geometry;
  1624. }
  1625. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1626. //>>includeStart('debug', pragmas.debug);
  1627. if (numberOfVertices < 3) {
  1628. throw new Check.DeveloperError('The number of vertices must be at least three.');
  1629. }
  1630. if (numberOfVertices % 3 !== 0) {
  1631. throw new Check.DeveloperError('The number of vertices must be a multiple of three.');
  1632. }
  1633. //>>includeEnd('debug');
  1634. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices);
  1635. for (var i = 0; i < numberOfVertices; ++i) {
  1636. indices[i] = i;
  1637. }
  1638. geometry.indices = indices;
  1639. return geometry;
  1640. }
  1641. function indexTriangleFan(geometry) {
  1642. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1643. //>>includeStart('debug', pragmas.debug);
  1644. if (numberOfVertices < 3) {
  1645. throw new Check.DeveloperError('The number of vertices must be at least three.');
  1646. }
  1647. //>>includeEnd('debug');
  1648. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 2) * 3);
  1649. indices[0] = 1;
  1650. indices[1] = 0;
  1651. indices[2] = 2;
  1652. var indicesIndex = 3;
  1653. for (var i = 3; i < numberOfVertices; ++i) {
  1654. indices[indicesIndex++] = i - 1;
  1655. indices[indicesIndex++] = 0;
  1656. indices[indicesIndex++] = i;
  1657. }
  1658. geometry.indices = indices;
  1659. geometry.primitiveType = PrimitiveType.PrimitiveType.TRIANGLES;
  1660. return geometry;
  1661. }
  1662. function indexTriangleStrip(geometry) {
  1663. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1664. //>>includeStart('debug', pragmas.debug);
  1665. if (numberOfVertices < 3) {
  1666. throw new Check.DeveloperError('The number of vertices must be at least 3.');
  1667. }
  1668. //>>includeEnd('debug');
  1669. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 2) * 3);
  1670. indices[0] = 0;
  1671. indices[1] = 1;
  1672. indices[2] = 2;
  1673. if (numberOfVertices > 3) {
  1674. indices[3] = 0;
  1675. indices[4] = 2;
  1676. indices[5] = 3;
  1677. }
  1678. var indicesIndex = 6;
  1679. for (var i = 3; i < numberOfVertices - 1; i += 2) {
  1680. indices[indicesIndex++] = i;
  1681. indices[indicesIndex++] = i - 1;
  1682. indices[indicesIndex++] = i + 1;
  1683. if (i + 2 < numberOfVertices) {
  1684. indices[indicesIndex++] = i;
  1685. indices[indicesIndex++] = i + 1;
  1686. indices[indicesIndex++] = i + 2;
  1687. }
  1688. }
  1689. geometry.indices = indices;
  1690. geometry.primitiveType = PrimitiveType.PrimitiveType.TRIANGLES;
  1691. return geometry;
  1692. }
  1693. function indexLines(geometry) {
  1694. if (when.defined(geometry.indices)) {
  1695. return geometry;
  1696. }
  1697. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1698. //>>includeStart('debug', pragmas.debug);
  1699. if (numberOfVertices < 2) {
  1700. throw new Check.DeveloperError('The number of vertices must be at least two.');
  1701. }
  1702. if (numberOfVertices % 2 !== 0) {
  1703. throw new Check.DeveloperError('The number of vertices must be a multiple of 2.');
  1704. }
  1705. //>>includeEnd('debug');
  1706. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices);
  1707. for (var i = 0; i < numberOfVertices; ++i) {
  1708. indices[i] = i;
  1709. }
  1710. geometry.indices = indices;
  1711. return geometry;
  1712. }
  1713. function indexLineStrip(geometry) {
  1714. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1715. //>>includeStart('debug', pragmas.debug);
  1716. if (numberOfVertices < 2) {
  1717. throw new Check.DeveloperError('The number of vertices must be at least two.');
  1718. }
  1719. //>>includeEnd('debug');
  1720. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 1) * 2);
  1721. indices[0] = 0;
  1722. indices[1] = 1;
  1723. var indicesIndex = 2;
  1724. for (var i = 2; i < numberOfVertices; ++i) {
  1725. indices[indicesIndex++] = i - 1;
  1726. indices[indicesIndex++] = i;
  1727. }
  1728. geometry.indices = indices;
  1729. geometry.primitiveType = PrimitiveType.PrimitiveType.LINES;
  1730. return geometry;
  1731. }
  1732. function indexLineLoop(geometry) {
  1733. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1734. //>>includeStart('debug', pragmas.debug);
  1735. if (numberOfVertices < 2) {
  1736. throw new Check.DeveloperError('The number of vertices must be at least two.');
  1737. }
  1738. //>>includeEnd('debug');
  1739. var indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices * 2);
  1740. indices[0] = 0;
  1741. indices[1] = 1;
  1742. var indicesIndex = 2;
  1743. for (var i = 2; i < numberOfVertices; ++i) {
  1744. indices[indicesIndex++] = i - 1;
  1745. indices[indicesIndex++] = i;
  1746. }
  1747. indices[indicesIndex++] = numberOfVertices - 1;
  1748. indices[indicesIndex] = 0;
  1749. geometry.indices = indices;
  1750. geometry.primitiveType = PrimitiveType.PrimitiveType.LINES;
  1751. return geometry;
  1752. }
  1753. function indexPrimitive(geometry) {
  1754. switch (geometry.primitiveType) {
  1755. case PrimitiveType.PrimitiveType.TRIANGLE_FAN:
  1756. return indexTriangleFan(geometry);
  1757. case PrimitiveType.PrimitiveType.TRIANGLE_STRIP:
  1758. return indexTriangleStrip(geometry);
  1759. case PrimitiveType.PrimitiveType.TRIANGLES:
  1760. return indexTriangles(geometry);
  1761. case PrimitiveType.PrimitiveType.LINE_STRIP:
  1762. return indexLineStrip(geometry);
  1763. case PrimitiveType.PrimitiveType.LINE_LOOP:
  1764. return indexLineLoop(geometry);
  1765. case PrimitiveType.PrimitiveType.LINES:
  1766. return indexLines(geometry);
  1767. }
  1768. return geometry;
  1769. }
  1770. function offsetPointFromXZPlane(p, isBehind) {
  1771. if (Math.abs(p.y) < _Math.CesiumMath.EPSILON6){
  1772. if (isBehind) {
  1773. p.y = -_Math.CesiumMath.EPSILON6;
  1774. } else {
  1775. p.y = _Math.CesiumMath.EPSILON6;
  1776. }
  1777. }
  1778. }
  1779. function offsetTriangleFromXZPlane(p0, p1, p2) {
  1780. if (p0.y !== 0.0 && p1.y !== 0.0 && p2.y !== 0.0) {
  1781. offsetPointFromXZPlane(p0, p0.y < 0.0);
  1782. offsetPointFromXZPlane(p1, p1.y < 0.0);
  1783. offsetPointFromXZPlane(p2, p2.y < 0.0);
  1784. return;
  1785. }
  1786. var p0y = Math.abs(p0.y);
  1787. var p1y = Math.abs(p1.y);
  1788. var p2y = Math.abs(p2.y);
  1789. var sign;
  1790. if (p0y > p1y) {
  1791. if (p0y > p2y) {
  1792. sign = _Math.CesiumMath.sign(p0.y);
  1793. } else {
  1794. sign = _Math.CesiumMath.sign(p2.y);
  1795. }
  1796. } else if (p1y > p2y) {
  1797. sign = _Math.CesiumMath.sign(p1.y);
  1798. } else {
  1799. sign = _Math.CesiumMath.sign(p2.y);
  1800. }
  1801. var isBehind = sign < 0.0;
  1802. offsetPointFromXZPlane(p0, isBehind);
  1803. offsetPointFromXZPlane(p1, isBehind);
  1804. offsetPointFromXZPlane(p2, isBehind);
  1805. }
  1806. var c3 = new Cartographic.Cartesian3();
  1807. function getXZIntersectionOffsetPoints(p, p1, u1, v1) {
  1808. Cartographic.Cartesian3.add(p, Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.subtract(p1, p, c3), p.y/(p.y-p1.y), c3), u1);
  1809. Cartographic.Cartesian3.clone(u1, v1);
  1810. offsetPointFromXZPlane(u1, true);
  1811. offsetPointFromXZPlane(v1, false);
  1812. }
  1813. var u1 = new Cartographic.Cartesian3();
  1814. var u2 = new Cartographic.Cartesian3();
  1815. var q1 = new Cartographic.Cartesian3();
  1816. var q2 = new Cartographic.Cartesian3();
  1817. var splitTriangleResult = {
  1818. positions : new Array(7),
  1819. indices : new Array(3 * 3)
  1820. };
  1821. function splitTriangle(p0, p1, p2) {
  1822. // In WGS84 coordinates, for a triangle approximately on the
  1823. // ellipsoid to cross the IDL, first it needs to be on the
  1824. // negative side of the plane x = 0.
  1825. if ((p0.x >= 0.0) || (p1.x >= 0.0) || (p2.x >= 0.0)) {
  1826. return undefined;
  1827. }
  1828. offsetTriangleFromXZPlane(p0, p1, p2);
  1829. var p0Behind = p0.y < 0.0;
  1830. var p1Behind = p1.y < 0.0;
  1831. var p2Behind = p2.y < 0.0;
  1832. var numBehind = 0;
  1833. numBehind += p0Behind ? 1 : 0;
  1834. numBehind += p1Behind ? 1 : 0;
  1835. numBehind += p2Behind ? 1 : 0;
  1836. var indices = splitTriangleResult.indices;
  1837. if (numBehind === 1) {
  1838. indices[1] = 3;
  1839. indices[2] = 4;
  1840. indices[5] = 6;
  1841. indices[7] = 6;
  1842. indices[8] = 5;
  1843. if (p0Behind) {
  1844. getXZIntersectionOffsetPoints(p0, p1, u1, q1);
  1845. getXZIntersectionOffsetPoints(p0, p2, u2, q2);
  1846. indices[0] = 0;
  1847. indices[3] = 1;
  1848. indices[4] = 2;
  1849. indices[6] = 1;
  1850. } else if (p1Behind) {
  1851. getXZIntersectionOffsetPoints(p1, p2, u1, q1);
  1852. getXZIntersectionOffsetPoints(p1, p0, u2, q2);
  1853. indices[0] = 1;
  1854. indices[3] = 2;
  1855. indices[4] = 0;
  1856. indices[6] = 2;
  1857. } else if (p2Behind) {
  1858. getXZIntersectionOffsetPoints(p2, p0, u1, q1);
  1859. getXZIntersectionOffsetPoints(p2, p1, u2, q2);
  1860. indices[0] = 2;
  1861. indices[3] = 0;
  1862. indices[4] = 1;
  1863. indices[6] = 0;
  1864. }
  1865. } else if (numBehind === 2) {
  1866. indices[2] = 4;
  1867. indices[4] = 4;
  1868. indices[5] = 3;
  1869. indices[7] = 5;
  1870. indices[8] = 6;
  1871. if (!p0Behind) {
  1872. getXZIntersectionOffsetPoints(p0, p1, u1, q1);
  1873. getXZIntersectionOffsetPoints(p0, p2, u2, q2);
  1874. indices[0] = 1;
  1875. indices[1] = 2;
  1876. indices[3] = 1;
  1877. indices[6] = 0;
  1878. } else if (!p1Behind) {
  1879. getXZIntersectionOffsetPoints(p1, p2, u1, q1);
  1880. getXZIntersectionOffsetPoints(p1, p0, u2, q2);
  1881. indices[0] = 2;
  1882. indices[1] = 0;
  1883. indices[3] = 2;
  1884. indices[6] = 1;
  1885. } else if (!p2Behind) {
  1886. getXZIntersectionOffsetPoints(p2, p0, u1, q1);
  1887. getXZIntersectionOffsetPoints(p2, p1, u2, q2);
  1888. indices[0] = 0;
  1889. indices[1] = 1;
  1890. indices[3] = 0;
  1891. indices[6] = 2;
  1892. }
  1893. }
  1894. var positions = splitTriangleResult.positions;
  1895. positions[0] = p0;
  1896. positions[1] = p1;
  1897. positions[2] = p2;
  1898. positions.length = 3;
  1899. if (numBehind === 1 || numBehind === 2) {
  1900. positions[3] = u1;
  1901. positions[4] = u2;
  1902. positions[5] = q1;
  1903. positions[6] = q2;
  1904. positions.length = 7;
  1905. }
  1906. return splitTriangleResult;
  1907. }
  1908. function updateGeometryAfterSplit(geometry, computeBoundingSphere) {
  1909. var attributes = geometry.attributes;
  1910. if (attributes.position.values.length === 0) {
  1911. return undefined;
  1912. }
  1913. for (var property in attributes) {
  1914. if (attributes.hasOwnProperty(property) &&
  1915. when.defined(attributes[property]) &&
  1916. when.defined(attributes[property].values)) {
  1917. var attribute = attributes[property];
  1918. attribute.values = ComponentDatatype.ComponentDatatype.createTypedArray(attribute.componentDatatype, attribute.values);
  1919. }
  1920. }
  1921. var numberOfVertices = GeometryAttribute.Geometry.computeNumberOfVertices(geometry);
  1922. geometry.indices = IndexDatatype.IndexDatatype.createTypedArray(numberOfVertices, geometry.indices);
  1923. if (computeBoundingSphere) {
  1924. geometry.boundingSphere = BoundingSphere.BoundingSphere.fromVertices(attributes.position.values);
  1925. }
  1926. return geometry;
  1927. }
  1928. function copyGeometryForSplit(geometry) {
  1929. var attributes = geometry.attributes;
  1930. var copiedAttributes = {};
  1931. for (var property in attributes) {
  1932. if (attributes.hasOwnProperty(property) &&
  1933. when.defined(attributes[property]) &&
  1934. when.defined(attributes[property].values)) {
  1935. var attribute = attributes[property];
  1936. copiedAttributes[property] = new GeometryAttribute.GeometryAttribute({
  1937. componentDatatype : attribute.componentDatatype,
  1938. componentsPerAttribute : attribute.componentsPerAttribute,
  1939. normalize : attribute.normalize,
  1940. values : []
  1941. });
  1942. }
  1943. }
  1944. return new GeometryAttribute.Geometry({
  1945. attributes : copiedAttributes,
  1946. indices : [],
  1947. primitiveType : geometry.primitiveType
  1948. });
  1949. }
  1950. function updateInstanceAfterSplit(instance, westGeometry, eastGeometry) {
  1951. var computeBoundingSphere = when.defined(instance.geometry.boundingSphere);
  1952. westGeometry = updateGeometryAfterSplit(westGeometry, computeBoundingSphere);
  1953. eastGeometry = updateGeometryAfterSplit(eastGeometry, computeBoundingSphere);
  1954. if (when.defined(eastGeometry) && !when.defined(westGeometry)) {
  1955. instance.geometry = eastGeometry;
  1956. } else if (!when.defined(eastGeometry) && when.defined(westGeometry)) {
  1957. instance.geometry = westGeometry;
  1958. } else {
  1959. instance.westHemisphereGeometry = westGeometry;
  1960. instance.eastHemisphereGeometry = eastGeometry;
  1961. instance.geometry = undefined;
  1962. }
  1963. }
  1964. function generateBarycentricInterpolateFunction(CartesianType, numberOfComponents) {
  1965. var v0Scratch = new CartesianType();
  1966. var v1Scratch = new CartesianType();
  1967. var v2Scratch = new CartesianType();
  1968. return function(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, normalize) {
  1969. var v0 = CartesianType.fromArray(sourceValues, i0 * numberOfComponents, v0Scratch);
  1970. var v1 = CartesianType.fromArray(sourceValues, i1 * numberOfComponents, v1Scratch);
  1971. var v2 = CartesianType.fromArray(sourceValues, i2 * numberOfComponents, v2Scratch);
  1972. CartesianType.multiplyByScalar(v0, coords.x, v0);
  1973. CartesianType.multiplyByScalar(v1, coords.y, v1);
  1974. CartesianType.multiplyByScalar(v2, coords.z, v2);
  1975. var value = CartesianType.add(v0, v1, v0);
  1976. CartesianType.add(value, v2, value);
  1977. if (normalize) {
  1978. CartesianType.normalize(value, value);
  1979. }
  1980. CartesianType.pack(value, currentValues, insertedIndex * numberOfComponents);
  1981. };
  1982. }
  1983. var interpolateAndPackCartesian4 = generateBarycentricInterpolateFunction(Cartesian4.Cartesian4, 4);
  1984. var interpolateAndPackCartesian3 = generateBarycentricInterpolateFunction(Cartographic.Cartesian3, 3);
  1985. var interpolateAndPackCartesian2 = generateBarycentricInterpolateFunction(Cartesian2.Cartesian2, 2);
  1986. var interpolateAndPackBoolean = function(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex) {
  1987. var v1 = sourceValues[i0] * coords.x;
  1988. var v2 = sourceValues[i1] * coords.y;
  1989. var v3 = sourceValues[i2] * coords.z;
  1990. currentValues[insertedIndex] = (v1 + v2 + v3) > _Math.CesiumMath.EPSILON6 ? 1 : 0;
  1991. };
  1992. var p0Scratch = new Cartographic.Cartesian3();
  1993. var p1Scratch = new Cartographic.Cartesian3();
  1994. var p2Scratch = new Cartographic.Cartesian3();
  1995. var barycentricScratch = new Cartographic.Cartesian3();
  1996. function computeTriangleAttributes(i0, i1, i2, point, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, allAttributes, insertedIndex) {
  1997. if (!when.defined(normals) && !when.defined(tangents) && !when.defined(bitangents) && !when.defined(texCoords) && !when.defined(extrudeDirections) && customAttributesLength === 0) {
  1998. return;
  1999. }
  2000. var p0 = Cartographic.Cartesian3.fromArray(positions, i0 * 3, p0Scratch);
  2001. var p1 = Cartographic.Cartesian3.fromArray(positions, i1 * 3, p1Scratch);
  2002. var p2 = Cartographic.Cartesian3.fromArray(positions, i2 * 3, p2Scratch);
  2003. var coords = barycentricCoordinates(point, p0, p1, p2, barycentricScratch);
  2004. if (when.defined(normals)) {
  2005. interpolateAndPackCartesian3(i0, i1, i2, coords, normals, currentAttributes.normal.values, insertedIndex, true);
  2006. }
  2007. if (when.defined(extrudeDirections)) {
  2008. var d0 = Cartographic.Cartesian3.fromArray(extrudeDirections, i0 * 3, p0Scratch);
  2009. var d1 = Cartographic.Cartesian3.fromArray(extrudeDirections, i1 * 3, p1Scratch);
  2010. var d2 = Cartographic.Cartesian3.fromArray(extrudeDirections, i2 * 3, p2Scratch);
  2011. Cartographic.Cartesian3.multiplyByScalar(d0, coords.x, d0);
  2012. Cartographic.Cartesian3.multiplyByScalar(d1, coords.y, d1);
  2013. Cartographic.Cartesian3.multiplyByScalar(d2, coords.z, d2);
  2014. var direction;
  2015. if (!Cartographic.Cartesian3.equals(d0, Cartographic.Cartesian3.ZERO) || !Cartographic.Cartesian3.equals(d1, Cartographic.Cartesian3.ZERO) || !Cartographic.Cartesian3.equals(d2, Cartographic.Cartesian3.ZERO)) {
  2016. direction = Cartographic.Cartesian3.add(d0, d1, d0);
  2017. Cartographic.Cartesian3.add(direction, d2, direction);
  2018. Cartographic.Cartesian3.normalize(direction, direction);
  2019. } else {
  2020. direction = p0Scratch;
  2021. direction.x = 0;
  2022. direction.y = 0;
  2023. direction.z = 0;
  2024. }
  2025. Cartographic.Cartesian3.pack(direction, currentAttributes.extrudeDirection.values, insertedIndex * 3);
  2026. }
  2027. if (when.defined(applyOffset)) {
  2028. interpolateAndPackBoolean(i0, i1, i2, coords, applyOffset, currentAttributes.applyOffset.values, insertedIndex);
  2029. }
  2030. if (when.defined(tangents)) {
  2031. interpolateAndPackCartesian3(i0, i1, i2, coords, tangents, currentAttributes.tangent.values, insertedIndex, true);
  2032. }
  2033. if (when.defined(bitangents)) {
  2034. interpolateAndPackCartesian3(i0, i1, i2, coords, bitangents, currentAttributes.bitangent.values, insertedIndex, true);
  2035. }
  2036. if (when.defined(texCoords)) {
  2037. interpolateAndPackCartesian2(i0, i1, i2, coords, texCoords, currentAttributes.st.values, insertedIndex);
  2038. }
  2039. if (customAttributesLength > 0) {
  2040. for (var i = 0; i < customAttributesLength; i++) {
  2041. var attributeName = customAttributeNames[i];
  2042. genericInterpolate(i0, i1, i2, coords, insertedIndex, allAttributes[attributeName], currentAttributes[attributeName]);
  2043. }
  2044. }
  2045. }
  2046. function genericInterpolate(i0, i1, i2, coords, insertedIndex, sourceAttribute, currentAttribute) {
  2047. var componentsPerAttribute = sourceAttribute.componentsPerAttribute;
  2048. var sourceValues = sourceAttribute.values;
  2049. var currentValues = currentAttribute.values;
  2050. switch(componentsPerAttribute) {
  2051. case 4:
  2052. interpolateAndPackCartesian4(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false);
  2053. break;
  2054. case 3:
  2055. interpolateAndPackCartesian3(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false);
  2056. break;
  2057. case 2:
  2058. interpolateAndPackCartesian2(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false);
  2059. break;
  2060. default:
  2061. currentValues[insertedIndex] = sourceValues[i0] * coords.x + sourceValues[i1] * coords.y + sourceValues[i2] * coords.z;
  2062. }
  2063. }
  2064. function insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, currentIndex, point) {
  2065. var insertIndex = currentAttributes.position.values.length / 3;
  2066. if (currentIndex !== -1) {
  2067. var prevIndex = indices[currentIndex];
  2068. var newIndex = currentIndexMap[prevIndex];
  2069. if (newIndex === -1) {
  2070. currentIndexMap[prevIndex] = insertIndex;
  2071. currentAttributes.position.values.push(point.x, point.y, point.z);
  2072. currentIndices.push(insertIndex);
  2073. return insertIndex;
  2074. }
  2075. currentIndices.push(newIndex);
  2076. return newIndex;
  2077. }
  2078. currentAttributes.position.values.push(point.x, point.y, point.z);
  2079. currentIndices.push(insertIndex);
  2080. return insertIndex;
  2081. }
  2082. var NAMED_ATTRIBUTES = {
  2083. position : true,
  2084. normal : true,
  2085. bitangent : true,
  2086. tangent : true,
  2087. st : true,
  2088. extrudeDirection : true,
  2089. applyOffset: true
  2090. };
  2091. function splitLongitudeTriangles(instance) {
  2092. var geometry = instance.geometry;
  2093. var attributes = geometry.attributes;
  2094. var positions = attributes.position.values;
  2095. var normals = (when.defined(attributes.normal)) ? attributes.normal.values : undefined;
  2096. var bitangents = (when.defined(attributes.bitangent)) ? attributes.bitangent.values : undefined;
  2097. var tangents = (when.defined(attributes.tangent)) ? attributes.tangent.values : undefined;
  2098. var texCoords = (when.defined(attributes.st)) ? attributes.st.values : undefined;
  2099. var extrudeDirections = (when.defined(attributes.extrudeDirection)) ? attributes.extrudeDirection.values : undefined;
  2100. var applyOffset = when.defined(attributes.applyOffset) ? attributes.applyOffset.values : undefined;
  2101. var indices = geometry.indices;
  2102. var customAttributeNames = [];
  2103. for (var attributeName in attributes) {
  2104. if (attributes.hasOwnProperty(attributeName) && !NAMED_ATTRIBUTES[attributeName] && when.defined(attributes[attributeName])) {
  2105. customAttributeNames.push(attributeName);
  2106. }
  2107. }
  2108. var customAttributesLength = customAttributeNames.length;
  2109. var eastGeometry = copyGeometryForSplit(geometry);
  2110. var westGeometry = copyGeometryForSplit(geometry);
  2111. var currentAttributes;
  2112. var currentIndices;
  2113. var currentIndexMap;
  2114. var insertedIndex;
  2115. var i;
  2116. var westGeometryIndexMap = [];
  2117. westGeometryIndexMap.length = positions.length / 3;
  2118. var eastGeometryIndexMap = [];
  2119. eastGeometryIndexMap.length = positions.length / 3;
  2120. for (i = 0; i < westGeometryIndexMap.length; ++i) {
  2121. westGeometryIndexMap[i] = -1;
  2122. eastGeometryIndexMap[i] = -1;
  2123. }
  2124. var len = indices.length;
  2125. for (i = 0; i < len; i += 3) {
  2126. var i0 = indices[i];
  2127. var i1 = indices[i + 1];
  2128. var i2 = indices[i + 2];
  2129. var p0 = Cartographic.Cartesian3.fromArray(positions, i0 * 3);
  2130. var p1 = Cartographic.Cartesian3.fromArray(positions, i1 * 3);
  2131. var p2 = Cartographic.Cartesian3.fromArray(positions, i2 * 3);
  2132. var result = splitTriangle(p0, p1, p2);
  2133. if (when.defined(result) && result.positions.length > 3) {
  2134. var resultPositions = result.positions;
  2135. var resultIndices = result.indices;
  2136. var resultLength = resultIndices.length;
  2137. for (var j = 0; j < resultLength; ++j) {
  2138. var resultIndex = resultIndices[j];
  2139. var point = resultPositions[resultIndex];
  2140. if (point.y < 0.0) {
  2141. currentAttributes = westGeometry.attributes;
  2142. currentIndices = westGeometry.indices;
  2143. currentIndexMap = westGeometryIndexMap;
  2144. } else {
  2145. currentAttributes = eastGeometry.attributes;
  2146. currentIndices = eastGeometry.indices;
  2147. currentIndexMap = eastGeometryIndexMap;
  2148. }
  2149. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, resultIndex < 3 ? i + resultIndex : -1, point);
  2150. computeTriangleAttributes(i0, i1, i2, point, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex);
  2151. }
  2152. } else {
  2153. if (when.defined(result)) {
  2154. p0 = result.positions[0];
  2155. p1 = result.positions[1];
  2156. p2 = result.positions[2];
  2157. }
  2158. if (p0.y < 0.0) {
  2159. currentAttributes = westGeometry.attributes;
  2160. currentIndices = westGeometry.indices;
  2161. currentIndexMap = westGeometryIndexMap;
  2162. } else {
  2163. currentAttributes = eastGeometry.attributes;
  2164. currentIndices = eastGeometry.indices;
  2165. currentIndexMap = eastGeometryIndexMap;
  2166. }
  2167. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i, p0);
  2168. computeTriangleAttributes(i0, i1, i2, p0, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex);
  2169. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1);
  2170. computeTriangleAttributes(i0, i1, i2, p1, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex);
  2171. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 2, p2);
  2172. computeTriangleAttributes(i0, i1, i2, p2, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex);
  2173. }
  2174. }
  2175. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  2176. }
  2177. var xzPlane = Plane.Plane.fromPointNormal(Cartographic.Cartesian3.ZERO, Cartographic.Cartesian3.UNIT_Y);
  2178. var offsetScratch = new Cartographic.Cartesian3();
  2179. var offsetPointScratch = new Cartographic.Cartesian3();
  2180. function computeLineAttributes(i0, i1, point, positions, insertIndex, currentAttributes, applyOffset) {
  2181. if (!when.defined(applyOffset)) {
  2182. return;
  2183. }
  2184. var p0 = Cartographic.Cartesian3.fromArray(positions, i0 * 3, p0Scratch);
  2185. if (Cartographic.Cartesian3.equalsEpsilon(p0, point, _Math.CesiumMath.EPSILON10)) {
  2186. currentAttributes.applyOffset.values[insertIndex] = applyOffset[i0];
  2187. } else {
  2188. currentAttributes.applyOffset.values[insertIndex] = applyOffset[i1];
  2189. }
  2190. }
  2191. function splitLongitudeLines(instance) {
  2192. var geometry = instance.geometry;
  2193. var attributes = geometry.attributes;
  2194. var positions = attributes.position.values;
  2195. var applyOffset = when.defined(attributes.applyOffset) ? attributes.applyOffset.values : undefined;
  2196. var indices = geometry.indices;
  2197. var eastGeometry = copyGeometryForSplit(geometry);
  2198. var westGeometry = copyGeometryForSplit(geometry);
  2199. var i;
  2200. var length = indices.length;
  2201. var westGeometryIndexMap = [];
  2202. westGeometryIndexMap.length = positions.length / 3;
  2203. var eastGeometryIndexMap = [];
  2204. eastGeometryIndexMap.length = positions.length / 3;
  2205. for (i = 0; i < westGeometryIndexMap.length; ++i) {
  2206. westGeometryIndexMap[i] = -1;
  2207. eastGeometryIndexMap[i] = -1;
  2208. }
  2209. for (i = 0; i < length; i += 2) {
  2210. var i0 = indices[i];
  2211. var i1 = indices[i + 1];
  2212. var p0 = Cartographic.Cartesian3.fromArray(positions, i0 * 3, p0Scratch);
  2213. var p1 = Cartographic.Cartesian3.fromArray(positions, i1 * 3, p1Scratch);
  2214. var insertIndex;
  2215. if (Math.abs(p0.y) < _Math.CesiumMath.EPSILON6){
  2216. if (p0.y < 0.0) {
  2217. p0.y = -_Math.CesiumMath.EPSILON6;
  2218. } else {
  2219. p0.y = _Math.CesiumMath.EPSILON6;
  2220. }
  2221. }
  2222. if (Math.abs(p1.y) < _Math.CesiumMath.EPSILON6){
  2223. if (p1.y < 0.0) {
  2224. p1.y = -_Math.CesiumMath.EPSILON6;
  2225. } else {
  2226. p1.y = _Math.CesiumMath.EPSILON6;
  2227. }
  2228. }
  2229. var p0Attributes = eastGeometry.attributes;
  2230. var p0Indices = eastGeometry.indices;
  2231. var p0IndexMap = eastGeometryIndexMap;
  2232. var p1Attributes = westGeometry.attributes;
  2233. var p1Indices = westGeometry.indices;
  2234. var p1IndexMap = westGeometryIndexMap;
  2235. var intersection = IntersectionTests.IntersectionTests.lineSegmentPlane(p0, p1, xzPlane, p2Scratch);
  2236. if (when.defined(intersection)) {
  2237. // move point on the xz-plane slightly away from the plane
  2238. var offset = Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.UNIT_Y, 5.0 * _Math.CesiumMath.EPSILON9, offsetScratch);
  2239. if (p0.y < 0.0) {
  2240. Cartographic.Cartesian3.negate(offset, offset);
  2241. p0Attributes = westGeometry.attributes;
  2242. p0Indices = westGeometry.indices;
  2243. p0IndexMap = westGeometryIndexMap;
  2244. p1Attributes = eastGeometry.attributes;
  2245. p1Indices = eastGeometry.indices;
  2246. p1IndexMap = eastGeometryIndexMap;
  2247. }
  2248. var offsetPoint = Cartographic.Cartesian3.add(intersection, offset, offsetPointScratch);
  2249. insertIndex = insertSplitPoint(p0Attributes, p0Indices, p0IndexMap, indices, i, p0);
  2250. computeLineAttributes(i0, i1, p0, positions, insertIndex, p0Attributes, applyOffset);
  2251. insertIndex = insertSplitPoint(p0Attributes, p0Indices, p0IndexMap, indices, -1, offsetPoint);
  2252. computeLineAttributes(i0, i1, offsetPoint, positions, insertIndex, p0Attributes, applyOffset);
  2253. Cartographic.Cartesian3.negate(offset, offset);
  2254. Cartographic.Cartesian3.add(intersection, offset, offsetPoint);
  2255. insertIndex = insertSplitPoint(p1Attributes, p1Indices, p1IndexMap, indices, -1, offsetPoint);
  2256. computeLineAttributes(i0, i1, offsetPoint, positions, insertIndex, p1Attributes, applyOffset);
  2257. insertIndex = insertSplitPoint(p1Attributes, p1Indices, p1IndexMap, indices, i + 1, p1);
  2258. computeLineAttributes(i0, i1, p1, positions, insertIndex, p1Attributes, applyOffset);
  2259. } else {
  2260. var currentAttributes;
  2261. var currentIndices;
  2262. var currentIndexMap;
  2263. if (p0.y < 0.0) {
  2264. currentAttributes = westGeometry.attributes;
  2265. currentIndices = westGeometry.indices;
  2266. currentIndexMap = westGeometryIndexMap;
  2267. } else {
  2268. currentAttributes = eastGeometry.attributes;
  2269. currentIndices = eastGeometry.indices;
  2270. currentIndexMap = eastGeometryIndexMap;
  2271. }
  2272. insertIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i, p0);
  2273. computeLineAttributes(i0, i1, p0, positions, insertIndex, currentAttributes, applyOffset);
  2274. insertIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1);
  2275. computeLineAttributes(i0, i1, p1, positions, insertIndex, currentAttributes, applyOffset);
  2276. }
  2277. }
  2278. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  2279. }
  2280. var cartesian2Scratch0 = new Cartesian2.Cartesian2();
  2281. var cartesian2Scratch1 = new Cartesian2.Cartesian2();
  2282. var cartesian3Scratch0 = new Cartographic.Cartesian3();
  2283. var cartesian3Scratch2 = new Cartographic.Cartesian3();
  2284. var cartesian3Scratch3 = new Cartographic.Cartesian3();
  2285. var cartesian3Scratch4 = new Cartographic.Cartesian3();
  2286. var cartesian3Scratch5 = new Cartographic.Cartesian3();
  2287. var cartesian3Scratch6 = new Cartographic.Cartesian3();
  2288. var cartesian3Scratch7 = new Cartographic.Cartesian3();
  2289. var cartesian4Scratch0 = new Cartesian4.Cartesian4();
  2290. function updateAdjacencyAfterSplit(geometry) {
  2291. var attributes = geometry.attributes;
  2292. var positions = attributes.position.values;
  2293. var prevPositions = attributes.prevPosition.values;
  2294. var nextPositions = attributes.nextPosition.values;
  2295. var length = positions.length;
  2296. for (var j = 0; j < length; j += 3) {
  2297. var position = Cartographic.Cartesian3.unpack(positions, j, cartesian3Scratch0);
  2298. if (position.x > 0.0) {
  2299. continue;
  2300. }
  2301. var prevPosition = Cartographic.Cartesian3.unpack(prevPositions, j, cartesian3Scratch2);
  2302. if ((position.y < 0.0 && prevPosition.y > 0.0) || (position.y > 0.0 && prevPosition.y < 0.0)) {
  2303. if (j - 3 > 0) {
  2304. prevPositions[j] = positions[j - 3];
  2305. prevPositions[j + 1] = positions[j - 2];
  2306. prevPositions[j + 2] = positions[j - 1];
  2307. } else {
  2308. Cartographic.Cartesian3.pack(position, prevPositions, j);
  2309. }
  2310. }
  2311. var nextPosition = Cartographic.Cartesian3.unpack(nextPositions, j, cartesian3Scratch3);
  2312. if ((position.y < 0.0 && nextPosition.y > 0.0) || (position.y > 0.0 && nextPosition.y < 0.0)) {
  2313. if (j + 3 < length) {
  2314. nextPositions[j] = positions[j + 3];
  2315. nextPositions[j + 1] = positions[j + 4];
  2316. nextPositions[j + 2] = positions[j + 5];
  2317. } else {
  2318. Cartographic.Cartesian3.pack(position, nextPositions, j);
  2319. }
  2320. }
  2321. }
  2322. }
  2323. var offsetScalar = 5.0 * _Math.CesiumMath.EPSILON9;
  2324. var coplanarOffset = _Math.CesiumMath.EPSILON6;
  2325. function splitLongitudePolyline(instance) {
  2326. var geometry = instance.geometry;
  2327. var attributes = geometry.attributes;
  2328. var positions = attributes.position.values;
  2329. var prevPositions = attributes.prevPosition.values;
  2330. var nextPositions = attributes.nextPosition.values;
  2331. var expandAndWidths = attributes.expandAndWidth.values;
  2332. var texCoords = (when.defined(attributes.st)) ? attributes.st.values : undefined;
  2333. var colors = (when.defined(attributes.color)) ? attributes.color.values : undefined;
  2334. var dist = (when.defined(attributes.dist)) ? attributes.dist.values : undefined;
  2335. var eastGeometry = copyGeometryForSplit(geometry);
  2336. var westGeometry = copyGeometryForSplit(geometry);
  2337. var i;
  2338. var j;
  2339. var index;
  2340. var intersectionFound = false;
  2341. var length = positions.length / 3;
  2342. for (i = 0; i < length; i += 4) {
  2343. var i0 = i;
  2344. var i2 = i + 2;
  2345. var p0 = Cartographic.Cartesian3.fromArray(positions, i0 * 3, cartesian3Scratch0);
  2346. var p2 = Cartographic.Cartesian3.fromArray(positions, i2 * 3, cartesian3Scratch2);
  2347. // Offset points that are close to the 180 longitude and change the previous/next point
  2348. // to be the same offset point so it can be projected to 2D. There is special handling in the
  2349. // shader for when position == prevPosition || position == nextPosition.
  2350. if (Math.abs(p0.y) < coplanarOffset) {
  2351. p0.y = coplanarOffset * (p2.y < 0.0 ? -1.0 : 1.0);
  2352. positions[i * 3 + 1] = p0.y;
  2353. positions[(i + 1) * 3 + 1] = p0.y;
  2354. for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {
  2355. prevPositions[j] = positions[i * 3];
  2356. prevPositions[j + 1] = positions[i * 3 + 1];
  2357. prevPositions[j + 2] = positions[i * 3 + 2];
  2358. }
  2359. }
  2360. // Do the same but for when the line crosses 180 longitude in the opposite direction.
  2361. if (Math.abs(p2.y) < coplanarOffset) {
  2362. p2.y = coplanarOffset * (p0.y < 0.0 ? -1.0 : 1.0);
  2363. positions[(i + 2) * 3 + 1] = p2.y;
  2364. positions[(i + 3) * 3 + 1] = p2.y;
  2365. for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {
  2366. nextPositions[j] = positions[(i + 2) * 3];
  2367. nextPositions[j + 1] = positions[(i + 2) * 3 + 1];
  2368. nextPositions[j + 2] = positions[(i + 2) * 3 + 2];
  2369. }
  2370. }
  2371. var p0Attributes = eastGeometry.attributes;
  2372. var p0Indices = eastGeometry.indices;
  2373. var p2Attributes = westGeometry.attributes;
  2374. var p2Indices = westGeometry.indices;
  2375. var intersection = IntersectionTests.IntersectionTests.lineSegmentPlane(p0, p2, xzPlane, cartesian3Scratch4);
  2376. if (when.defined(intersection)) {
  2377. intersectionFound = true;
  2378. // move point on the xz-plane slightly away from the plane
  2379. var offset = Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.UNIT_Y, offsetScalar, cartesian3Scratch5);
  2380. if (p0.y < 0.0) {
  2381. Cartographic.Cartesian3.negate(offset, offset);
  2382. p0Attributes = westGeometry.attributes;
  2383. p0Indices = westGeometry.indices;
  2384. p2Attributes = eastGeometry.attributes;
  2385. p2Indices = eastGeometry.indices;
  2386. }
  2387. var offsetPoint = Cartographic.Cartesian3.add(intersection, offset, cartesian3Scratch6);
  2388. p0Attributes.position.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);
  2389. p0Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2390. p0Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2391. p0Attributes.prevPosition.values.push(prevPositions[i0 * 3], prevPositions[i0 * 3 + 1], prevPositions[i0 * 3 + 2]);
  2392. p0Attributes.prevPosition.values.push(prevPositions[i0 * 3 + 3], prevPositions[i0 * 3 + 4], prevPositions[i0 * 3 + 5]);
  2393. p0Attributes.prevPosition.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);
  2394. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2395. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2396. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2397. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2398. Cartographic.Cartesian3.negate(offset, offset);
  2399. Cartographic.Cartesian3.add(intersection, offset, offsetPoint);
  2400. p2Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2401. p2Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2402. p2Attributes.position.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);
  2403. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2404. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2405. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2406. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  2407. p2Attributes.nextPosition.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);
  2408. p2Attributes.nextPosition.values.push(nextPositions[i2 * 3], nextPositions[i2 * 3 + 1], nextPositions[i2 * 3 + 2]);
  2409. p2Attributes.nextPosition.values.push(nextPositions[i2 * 3 + 3], nextPositions[i2 * 3 + 4], nextPositions[i2 * 3 + 5]);
  2410. var ew0 = Cartesian2.Cartesian2.fromArray(expandAndWidths, i0 * 2, cartesian2Scratch0);
  2411. var width = Math.abs(ew0.y);
  2412. p0Attributes.expandAndWidth.values.push(-1, width, 1, width);
  2413. p0Attributes.expandAndWidth.values.push(-1, -width, 1, -width);
  2414. p2Attributes.expandAndWidth.values.push(-1, width, 1, width);
  2415. p2Attributes.expandAndWidth.values.push(-1, -width, 1, -width);
  2416. var t = Cartographic.Cartesian3.magnitudeSquared(Cartographic.Cartesian3.subtract(intersection, p0, cartesian3Scratch3));
  2417. t /= Cartographic.Cartesian3.magnitudeSquared(Cartographic.Cartesian3.subtract(p2, p0, cartesian3Scratch3));
  2418. if (when.defined(colors)) {
  2419. var c0 = Cartesian4.Cartesian4.fromArray(colors, i0 * 4, cartesian4Scratch0);
  2420. var c2 = Cartesian4.Cartesian4.fromArray(colors, i2 * 4, cartesian4Scratch0);
  2421. var r = _Math.CesiumMath.lerp(c0.x, c2.x, t);
  2422. var g = _Math.CesiumMath.lerp(c0.y, c2.y, t);
  2423. var b = _Math.CesiumMath.lerp(c0.z, c2.z, t);
  2424. var a = _Math.CesiumMath.lerp(c0.w, c2.w, t);
  2425. for (j = i0 * 4; j < i0 * 4 + 2 * 4; ++j) {
  2426. p0Attributes.color.values.push(colors[j]);
  2427. }
  2428. p0Attributes.color.values.push(r, g, b, a);
  2429. p0Attributes.color.values.push(r, g, b, a);
  2430. p2Attributes.color.values.push(r, g, b, a);
  2431. p2Attributes.color.values.push(r, g, b, a);
  2432. for (j = i2 * 4; j < i2 * 4 + 2 * 4; ++j) {
  2433. p2Attributes.color.values.push(colors[j]);
  2434. }
  2435. }
  2436. if (when.defined(texCoords)) {
  2437. var s0 = Cartesian2.Cartesian2.fromArray(texCoords, i0 * 2, cartesian2Scratch0);
  2438. var s3 = Cartesian2.Cartesian2.fromArray(texCoords, (i + 3) * 2, cartesian2Scratch1);
  2439. var sx = _Math.CesiumMath.lerp(s0.x, s3.x, t);
  2440. for (j = i0 * 2; j < i0 * 2 + 2 * 2; ++j) {
  2441. p0Attributes.st.values.push(texCoords[j]);
  2442. }
  2443. p0Attributes.st.values.push(sx, s0.y);
  2444. p0Attributes.st.values.push(sx, s3.y);
  2445. p2Attributes.st.values.push(sx, s0.y);
  2446. p2Attributes.st.values.push(sx, s3.y);
  2447. for (j = i2 * 2; j < i2 * 2 + 2 * 2; ++j) {
  2448. p2Attributes.st.values.push(texCoords[j]);
  2449. }
  2450. }
  2451. if (when.defined(dist)) {
  2452. var d0 = Cartographic.Cartesian3.fromArray(dist, i0 * 3, cartesian3Scratch7);
  2453. var d1 = Cartographic.Cartesian3.fromArray(dist, i2 * 3, cartesian3Scratch7);
  2454. var disFrom = _Math.CesiumMath.lerp(d0.x, d1.x, t);
  2455. for (j = i0 * 3; j < i0 * 3 + 2 * 3; ++j) {
  2456. p0Attributes.dist.values.push(dist[j]);
  2457. }
  2458. p0Attributes.dist.values.push(disFrom, d0.y, d0.z);
  2459. p0Attributes.dist.values.push(disFrom, d0.y, d0.z);
  2460. p2Attributes.dist.values.push(disFrom, d1.y, d1.z);
  2461. p2Attributes.dist.values.push(disFrom, d1.y, d1.z);
  2462. for (j = i2 * 3; j < i2 * 3 + 2 * 3; ++j) {
  2463. p2Attributes.dist.values.push(dist[j]);
  2464. }
  2465. }
  2466. index = p0Attributes.position.values.length / 3 - 4;
  2467. p0Indices.push(index, index + 2, index + 1);
  2468. p0Indices.push(index + 1, index + 2, index + 3);
  2469. index = p2Attributes.position.values.length / 3 - 4;
  2470. p2Indices.push(index, index + 2, index + 1);
  2471. p2Indices.push(index + 1, index + 2, index + 3);
  2472. } else {
  2473. var currentAttributes;
  2474. var currentIndices;
  2475. if (p0.y < 0.0) {
  2476. currentAttributes = westGeometry.attributes;
  2477. currentIndices = westGeometry.indices;
  2478. } else {
  2479. currentAttributes = eastGeometry.attributes;
  2480. currentIndices = eastGeometry.indices;
  2481. }
  2482. currentAttributes.position.values.push(p0.x, p0.y, p0.z);
  2483. currentAttributes.position.values.push(p0.x, p0.y, p0.z);
  2484. currentAttributes.position.values.push(p2.x, p2.y, p2.z);
  2485. currentAttributes.position.values.push(p2.x, p2.y, p2.z);
  2486. for (j = i * 3; j < i * 3 + 4 * 3; ++j) {
  2487. currentAttributes.prevPosition.values.push(prevPositions[j]);
  2488. currentAttributes.nextPosition.values.push(nextPositions[j]);
  2489. }
  2490. for (j = i * 2; j < i * 2 + 4 * 2; ++j) {
  2491. currentAttributes.expandAndWidth.values.push(expandAndWidths[j]);
  2492. if (when.defined(texCoords)) {
  2493. currentAttributes.st.values.push(texCoords[j]);
  2494. }
  2495. }
  2496. if (when.defined(colors)) {
  2497. for (j = i * 4; j < i * 4 + 4 * 4; ++j) {
  2498. currentAttributes.color.values.push(colors[j]);
  2499. }
  2500. }
  2501. if (when.defined(dist)) {
  2502. for (j = i * 3; j < i * 3 + 4 * 3; ++j) {
  2503. currentAttributes.dist.values.push(dist[j]);
  2504. }
  2505. }
  2506. index = currentAttributes.position.values.length / 3 - 4;
  2507. currentIndices.push(index, index + 2, index + 1);
  2508. currentIndices.push(index + 1, index + 2, index + 3);
  2509. }
  2510. }
  2511. if (intersectionFound) {
  2512. updateAdjacencyAfterSplit(westGeometry);
  2513. updateAdjacencyAfterSplit(eastGeometry);
  2514. }
  2515. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  2516. }
  2517. /**
  2518. * Splits the instances's geometry, by introducing new vertices and indices,that
  2519. * intersect the International Date Line and Prime Meridian so that no primitives cross longitude
  2520. * -180/180 degrees. This is not required for 3D drawing, but is required for
  2521. * correcting drawing in 2D and Columbus view.
  2522. *
  2523. * @private
  2524. *
  2525. * @param {GeometryInstance} instance The instance to modify.
  2526. * @returns {GeometryInstance} The modified <code>instance</code> argument, with it's geometry split at the International Date Line.
  2527. *
  2528. * @example
  2529. * instance = Cesium.GeometryPipeline.splitLongitude(instance);
  2530. */
  2531. GeometryPipeline.splitLongitude = function(instance) {
  2532. //>>includeStart('debug', pragmas.debug);
  2533. if (!when.defined(instance)) {
  2534. throw new Check.DeveloperError('instance is required.');
  2535. }
  2536. //>>includeEnd('debug');
  2537. var geometry = instance.geometry;
  2538. var boundingSphere = geometry.boundingSphere;
  2539. if (when.defined(boundingSphere)) {
  2540. var minX = boundingSphere.center.x - boundingSphere.radius;
  2541. if (minX > 0 || BoundingSphere.BoundingSphere.intersectPlane(boundingSphere, Plane.Plane.ORIGIN_ZX_PLANE) !== BoundingSphere.Intersect.INTERSECTING) {
  2542. return instance;
  2543. }
  2544. }
  2545. if (geometry.geometryType !== GeometryAttribute.GeometryType.NONE) {
  2546. switch (geometry.geometryType) {
  2547. case GeometryAttribute.GeometryType.POLYLINES:
  2548. splitLongitudePolyline(instance);
  2549. break;
  2550. case GeometryAttribute.GeometryType.TRIANGLES:
  2551. splitLongitudeTriangles(instance);
  2552. break;
  2553. case GeometryAttribute.GeometryType.LINES:
  2554. splitLongitudeLines(instance);
  2555. break;
  2556. }
  2557. } else {
  2558. indexPrimitive(geometry);
  2559. if (geometry.primitiveType === PrimitiveType.PrimitiveType.TRIANGLES) {
  2560. splitLongitudeTriangles(instance);
  2561. } else if (geometry.primitiveType === PrimitiveType.PrimitiveType.LINES) {
  2562. splitLongitudeLines(instance);
  2563. }
  2564. }
  2565. return instance;
  2566. };
  2567. exports.GeometryPipeline = GeometryPipeline;
  2568. });