PolylineCollection.js 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import Cartesian2 from "../Core/Cartesian2.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Cartesian4 from "../Core/Cartesian4.js";
  5. import Cartographic from "../Core/Cartographic.js";
  6. import Color from "../Core/Color.js";
  7. import combine from "../Core/combine.js";
  8. import ComponentDatatype from "../Core/ComponentDatatype.js";
  9. import defaultValue from "../Core/defaultValue.js";
  10. import defined from "../Core/defined.js";
  11. import destroyObject from "../Core/destroyObject.js";
  12. import DeveloperError from "../Core/DeveloperError.js";
  13. import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
  14. import FeatureDetection from "../Core/FeatureDetection.js";
  15. import IndexDatatype from "../Core/IndexDatatype.js";
  16. import Intersect from "../Core/Intersect.js";
  17. import CesiumMath from "../Core/Math.js";
  18. import Matrix4 from "../Core/Matrix4.js";
  19. import Plane from "../Core/Plane.js";
  20. import RuntimeError from "../Core/RuntimeError.js";
  21. import Buffer from "../Renderer/Buffer.js";
  22. import BufferUsage from "../Renderer/BufferUsage.js";
  23. import ContextLimits from "../Renderer/ContextLimits.js";
  24. import DrawCommand from "../Renderer/DrawCommand.js";
  25. import Pass from "../Renderer/Pass.js";
  26. import RenderState from "../Renderer/RenderState.js";
  27. import ShaderProgram from "../Renderer/ShaderProgram.js";
  28. import ShaderSource from "../Renderer/ShaderSource.js";
  29. import Texture from "../Renderer/Texture.js";
  30. import VertexArray from "../Renderer/VertexArray.js";
  31. import PolylineCommon from "../Shaders/PolylineCommon.js";
  32. import PolylineFS from "../Shaders/PolylineFS.js";
  33. import PolylineVS from "../Shaders/PolylineVS.js";
  34. import BatchTable from "./BatchTable.js";
  35. import BlendingState from "./BlendingState.js";
  36. import Material from "./Material.js";
  37. import Polyline from "./Polyline.js";
  38. import SceneMode from "./SceneMode.js";
  39. var SHOW_INDEX = Polyline.SHOW_INDEX;
  40. var WIDTH_INDEX = Polyline.WIDTH_INDEX;
  41. var POSITION_INDEX = Polyline.POSITION_INDEX;
  42. var MATERIAL_INDEX = Polyline.MATERIAL_INDEX;
  43. //POSITION_SIZE_INDEX is needed for when the polyline's position array changes size.
  44. //When it does, we need to recreate the indicesBuffer.
  45. var POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX;
  46. var DISTANCE_DISPLAY_CONDITION = Polyline.DISTANCE_DISPLAY_CONDITION;
  47. var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES;
  48. var attributeLocations = {
  49. texCoordExpandAndBatchIndex: 0,
  50. position3DHigh: 1,
  51. position3DLow: 2,
  52. position2DHigh: 3,
  53. position2DLow: 4,
  54. prevPosition3DHigh: 5,
  55. prevPosition3DLow: 6,
  56. prevPosition2DHigh: 7,
  57. prevPosition2DLow: 8,
  58. nextPosition3DHigh: 9,
  59. nextPosition3DLow: 10,
  60. nextPosition2DHigh: 11,
  61. nextPosition2DLow: 12,
  62. };
  63. /**
  64. * A renderable collection of polylines.
  65. * <br /><br />
  66. * <div align="center">
  67. * <img src="Images/Polyline.png" width="400" height="300" /><br />
  68. * Example polylines
  69. * </div>
  70. * <br /><br />
  71. * Polylines are added and removed from the collection using {@link PolylineCollection#add}
  72. * and {@link PolylineCollection#remove}.
  73. *
  74. * @alias PolylineCollection
  75. * @constructor
  76. *
  77. * @param {Object} [options] Object with the following properties:
  78. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each polyline from model to world coordinates.
  79. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  80. *
  81. * @performance For best performance, prefer a few collections, each with many polylines, to
  82. * many collections with only a few polylines each. Organize collections so that polylines
  83. * with the same update frequency are in the same collection, i.e., polylines that do not
  84. * change should be in one collection; polylines that change every frame should be in another
  85. * collection; and so on.
  86. *
  87. * @see PolylineCollection#add
  88. * @see PolylineCollection#remove
  89. * @see Polyline
  90. * @see LabelCollection
  91. *
  92. * @example
  93. * // Create a polyline collection with two polylines
  94. * var polylines = new Cesium.PolylineCollection();
  95. * polylines.add({
  96. * positions : Cesium.Cartesian3.fromDegreesArray([
  97. * -75.10, 39.57,
  98. * -77.02, 38.53,
  99. * -80.50, 35.14,
  100. * -80.12, 25.46]),
  101. * width : 2
  102. * });
  103. *
  104. * polylines.add({
  105. * positions : Cesium.Cartesian3.fromDegreesArray([
  106. * -73.10, 37.57,
  107. * -75.02, 36.53,
  108. * -78.50, 33.14,
  109. * -78.12, 23.46]),
  110. * width : 4
  111. * });
  112. */
  113. function PolylineCollection(options) {
  114. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  115. /**
  116. * The 4x4 transformation matrix that transforms each polyline in this collection from model to world coordinates.
  117. * When this is the identity matrix, the polylines are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  118. * Local reference frames can be used by providing a different transformation matrix, like that returned
  119. * by {@link Transforms.eastNorthUpToFixedFrame}.
  120. *
  121. * @type {Matrix4}
  122. * @default {@link Matrix4.IDENTITY}
  123. */
  124. this.modelMatrix = Matrix4.clone(
  125. defaultValue(options.modelMatrix, Matrix4.IDENTITY)
  126. );
  127. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  128. /**
  129. * This property is for debugging only; it is not for production use nor is it optimized.
  130. * <p>
  131. * Draws the bounding sphere for each draw command in the primitive.
  132. * </p>
  133. *
  134. * @type {Boolean}
  135. *
  136. * @default false
  137. */
  138. this.debugShowBoundingVolume = defaultValue(
  139. options.debugShowBoundingVolume,
  140. false
  141. );
  142. this._opaqueRS = undefined;
  143. this._translucentRS = undefined;
  144. this._colorCommands = [];
  145. this._polylinesUpdated = false;
  146. this._polylinesRemoved = false;
  147. this._createVertexArray = false;
  148. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  149. this._polylines = [];
  150. this._polylineBuckets = {};
  151. // The buffer usage is determined based on the usage of the attribute over time.
  152. this._positionBufferUsage = {
  153. bufferUsage: BufferUsage.STATIC_DRAW,
  154. frameCount: 0,
  155. };
  156. this._mode = undefined;
  157. this._polylinesToUpdate = [];
  158. this._vertexArrays = [];
  159. this._positionBuffer = undefined;
  160. this._texCoordExpandAndBatchIndexBuffer = undefined;
  161. this._batchTable = undefined;
  162. this._createBatchTable = false;
  163. // Only used by Vector3DTilePoints
  164. this._useHighlightColor = false;
  165. this._highlightColor = Color.clone(Color.WHITE);
  166. var that = this;
  167. this._uniformMap = {
  168. u_highlightColor: function () {
  169. return that._highlightColor;
  170. },
  171. };
  172. }
  173. Object.defineProperties(PolylineCollection.prototype, {
  174. /**
  175. * Returns the number of polylines in this collection. This is commonly used with
  176. * {@link PolylineCollection#get} to iterate over all the polylines
  177. * in the collection.
  178. * @memberof PolylineCollection.prototype
  179. * @type {Number}
  180. */
  181. length: {
  182. get: function () {
  183. removePolylines(this);
  184. return this._polylines.length;
  185. },
  186. },
  187. });
  188. /**
  189. * Creates and adds a polyline with the specified initial properties to the collection.
  190. * The added polyline is returned so it can be modified or removed from the collection later.
  191. *
  192. * @param {Object}[options] A template describing the polyline's properties as shown in Example 1.
  193. * @returns {Polyline} The polyline that was added to the collection.
  194. *
  195. * @performance After calling <code>add</code>, {@link PolylineCollection#update} is called and
  196. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  197. * For best performance, add as many polylines as possible before calling <code>update</code>.
  198. *
  199. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  200. *
  201. *
  202. * @example
  203. * // Example 1: Add a polyline, specifying all the default values.
  204. * var p = polylines.add({
  205. * show : true,
  206. * positions : ellipsoid.cartographicArrayToCartesianArray([
  207. Cesium.Cartographic.fromDegrees(-75.10, 39.57),
  208. Cesium.Cartographic.fromDegrees(-77.02, 38.53)]),
  209. * width : 1
  210. * });
  211. *
  212. * @see PolylineCollection#remove
  213. * @see PolylineCollection#removeAll
  214. * @see PolylineCollection#update
  215. */
  216. PolylineCollection.prototype.add = function (options) {
  217. var p = new Polyline(options, this);
  218. p._index = this._polylines.length;
  219. this._polylines.push(p);
  220. this._createVertexArray = true;
  221. this._createBatchTable = true;
  222. return p;
  223. };
  224. /**
  225. * Removes a polyline from the collection.
  226. *
  227. * @param {Polyline} polyline The polyline to remove.
  228. * @returns {Boolean} <code>true</code> if the polyline was removed; <code>false</code> if the polyline was not found in the collection.
  229. *
  230. * @performance After calling <code>remove</code>, {@link PolylineCollection#update} is called and
  231. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  232. * For best performance, remove as many polylines as possible before calling <code>update</code>.
  233. * If you intend to temporarily hide a polyline, it is usually more efficient to call
  234. * {@link Polyline#show} instead of removing and re-adding the polyline.
  235. *
  236. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  237. *
  238. *
  239. * @example
  240. * var p = polylines.add(...);
  241. * polylines.remove(p); // Returns true
  242. *
  243. * @see PolylineCollection#add
  244. * @see PolylineCollection#removeAll
  245. * @see PolylineCollection#update
  246. * @see Polyline#show
  247. */
  248. PolylineCollection.prototype.remove = function (polyline) {
  249. if (this.contains(polyline)) {
  250. this._polylinesRemoved = true;
  251. this._createVertexArray = true;
  252. this._createBatchTable = true;
  253. if (defined(polyline._bucket)) {
  254. var bucket = polyline._bucket;
  255. bucket.shaderProgram =
  256. bucket.shaderProgram && bucket.shaderProgram.destroy();
  257. }
  258. polyline._destroy();
  259. return true;
  260. }
  261. return false;
  262. };
  263. /**
  264. * Removes all polylines from the collection.
  265. *
  266. * @performance <code>O(n)</code>. It is more efficient to remove all the polylines
  267. * from a collection and then add new ones than to create a new collection entirely.
  268. *
  269. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  270. *
  271. *
  272. * @example
  273. * polylines.add(...);
  274. * polylines.add(...);
  275. * polylines.removeAll();
  276. *
  277. * @see PolylineCollection#add
  278. * @see PolylineCollection#remove
  279. * @see PolylineCollection#update
  280. */
  281. PolylineCollection.prototype.removeAll = function () {
  282. releaseShaders(this);
  283. destroyPolylines(this);
  284. this._polylineBuckets = {};
  285. this._polylinesRemoved = false;
  286. this._polylines.length = 0;
  287. this._polylinesToUpdate.length = 0;
  288. this._createVertexArray = true;
  289. };
  290. /**
  291. * Determines if this collection contains the specified polyline.
  292. *
  293. * @param {Polyline} polyline The polyline to check for.
  294. * @returns {Boolean} true if this collection contains the polyline, false otherwise.
  295. *
  296. * @see PolylineCollection#get
  297. */
  298. PolylineCollection.prototype.contains = function (polyline) {
  299. return defined(polyline) && polyline._polylineCollection === this;
  300. };
  301. /**
  302. * Returns the polyline in the collection at the specified index. Indices are zero-based
  303. * and increase as polylines are added. Removing a polyline shifts all polylines after
  304. * it to the left, changing their indices. This function is commonly used with
  305. * {@link PolylineCollection#length} to iterate over all the polylines
  306. * in the collection.
  307. *
  308. * @param {Number} index The zero-based index of the polyline.
  309. * @returns {Polyline} The polyline at the specified index.
  310. *
  311. * @performance If polylines were removed from the collection and
  312. * {@link PolylineCollection#update} was not called, an implicit <code>O(n)</code>
  313. * operation is performed.
  314. *
  315. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  316. *
  317. * @example
  318. * // Toggle the show property of every polyline in the collection
  319. * var len = polylines.length;
  320. * for (var i = 0; i < len; ++i) {
  321. * var p = polylines.get(i);
  322. * p.show = !p.show;
  323. * }
  324. *
  325. * @see PolylineCollection#length
  326. */
  327. PolylineCollection.prototype.get = function (index) {
  328. //>>includeStart('debug', pragmas.debug);
  329. if (!defined(index)) {
  330. throw new DeveloperError("index is required.");
  331. }
  332. //>>includeEnd('debug');
  333. removePolylines(this);
  334. return this._polylines[index];
  335. };
  336. function createBatchTable(collection, context) {
  337. if (defined(collection._batchTable)) {
  338. collection._batchTable.destroy();
  339. }
  340. var attributes = [
  341. {
  342. functionName: "batchTable_getWidthAndShow",
  343. componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
  344. componentsPerAttribute: 2,
  345. },
  346. {
  347. functionName: "batchTable_getPickColor",
  348. componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
  349. componentsPerAttribute: 4,
  350. normalize: true,
  351. },
  352. {
  353. functionName: "batchTable_getCenterHigh",
  354. componentDatatype: ComponentDatatype.FLOAT,
  355. componentsPerAttribute: 3,
  356. },
  357. {
  358. functionName: "batchTable_getCenterLowAndRadius",
  359. componentDatatype: ComponentDatatype.FLOAT,
  360. componentsPerAttribute: 4,
  361. },
  362. {
  363. functionName: "batchTable_getDistanceDisplayCondition",
  364. componentDatatype: ComponentDatatype.FLOAT,
  365. componentsPerAttribute: 2,
  366. },
  367. ];
  368. collection._batchTable = new BatchTable(
  369. context,
  370. attributes,
  371. collection._polylines.length
  372. );
  373. }
  374. var scratchUpdatePolylineEncodedCartesian = new EncodedCartesian3();
  375. var scratchUpdatePolylineCartesian4 = new Cartesian4();
  376. var scratchNearFarCartesian2 = new Cartesian2();
  377. /**
  378. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  379. * get the draw commands needed to render this primitive.
  380. * <p>
  381. * Do not call this function directly. This is documented just to
  382. * list the exceptions that may be propagated when the scene is rendered:
  383. * </p>
  384. *
  385. * @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
  386. */
  387. PolylineCollection.prototype.update = function (frameState) {
  388. removePolylines(this);
  389. if (this._polylines.length === 0) {
  390. return;
  391. }
  392. updateMode(this, frameState);
  393. var context = frameState.context;
  394. var projection = frameState.mapProjection;
  395. var polyline;
  396. var properties = this._propertiesChanged;
  397. if (this._createBatchTable) {
  398. if (ContextLimits.maximumVertexTextureImageUnits === 0) {
  399. throw new RuntimeError(
  400. "Vertex texture fetch support is required to render polylines. The maximum number of vertex texture image units must be greater than zero."
  401. );
  402. }
  403. createBatchTable(this, context);
  404. this._createBatchTable = false;
  405. }
  406. if (this._createVertexArray || computeNewBuffersUsage(this)) {
  407. createVertexArrays(this, context, projection);
  408. } else if (this._polylinesUpdated) {
  409. // Polylines were modified, but no polylines were added or removed.
  410. var polylinesToUpdate = this._polylinesToUpdate;
  411. if (this._mode !== SceneMode.SCENE3D) {
  412. var updateLength = polylinesToUpdate.length;
  413. for (var i = 0; i < updateLength; ++i) {
  414. polyline = polylinesToUpdate[i];
  415. polyline.update();
  416. }
  417. }
  418. // if a polyline's positions size changes, we need to recreate the vertex arrays and vertex buffers because the indices will be different.
  419. // if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differently.
  420. if (properties[POSITION_SIZE_INDEX] || properties[MATERIAL_INDEX]) {
  421. createVertexArrays(this, context, projection);
  422. } else {
  423. var length = polylinesToUpdate.length;
  424. var polylineBuckets = this._polylineBuckets;
  425. for (var ii = 0; ii < length; ++ii) {
  426. polyline = polylinesToUpdate[ii];
  427. properties = polyline._propertiesChanged;
  428. var bucket = polyline._bucket;
  429. var index = 0;
  430. for (var x in polylineBuckets) {
  431. if (polylineBuckets.hasOwnProperty(x)) {
  432. if (polylineBuckets[x] === bucket) {
  433. if (properties[POSITION_INDEX]) {
  434. bucket.writeUpdate(
  435. index,
  436. polyline,
  437. this._positionBuffer,
  438. projection
  439. );
  440. }
  441. break;
  442. }
  443. index += polylineBuckets[x].lengthOfPositions;
  444. }
  445. }
  446. if (properties[SHOW_INDEX] || properties[WIDTH_INDEX]) {
  447. this._batchTable.setBatchedAttribute(
  448. polyline._index,
  449. 0,
  450. new Cartesian2(polyline._width, polyline._show)
  451. );
  452. }
  453. if (this._batchTable.attributes.length > 2) {
  454. if (properties[POSITION_INDEX] || properties[POSITION_SIZE_INDEX]) {
  455. var boundingSphere =
  456. frameState.mode === SceneMode.SCENE2D
  457. ? polyline._boundingVolume2D
  458. : polyline._boundingVolumeWC;
  459. var encodedCenter = EncodedCartesian3.fromCartesian(
  460. boundingSphere.center,
  461. scratchUpdatePolylineEncodedCartesian
  462. );
  463. var low = Cartesian4.fromElements(
  464. encodedCenter.low.x,
  465. encodedCenter.low.y,
  466. encodedCenter.low.z,
  467. boundingSphere.radius,
  468. scratchUpdatePolylineCartesian4
  469. );
  470. this._batchTable.setBatchedAttribute(
  471. polyline._index,
  472. 2,
  473. encodedCenter.high
  474. );
  475. this._batchTable.setBatchedAttribute(polyline._index, 3, low);
  476. }
  477. if (properties[DISTANCE_DISPLAY_CONDITION]) {
  478. var nearFarCartesian = scratchNearFarCartesian2;
  479. nearFarCartesian.x = 0.0;
  480. nearFarCartesian.y = Number.MAX_VALUE;
  481. var distanceDisplayCondition = polyline.distanceDisplayCondition;
  482. if (defined(distanceDisplayCondition)) {
  483. nearFarCartesian.x = distanceDisplayCondition.near;
  484. nearFarCartesian.y = distanceDisplayCondition.far;
  485. }
  486. this._batchTable.setBatchedAttribute(
  487. polyline._index,
  488. 4,
  489. nearFarCartesian
  490. );
  491. }
  492. }
  493. polyline._clean();
  494. }
  495. }
  496. polylinesToUpdate.length = 0;
  497. this._polylinesUpdated = false;
  498. }
  499. properties = this._propertiesChanged;
  500. for (var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  501. properties[k] = 0;
  502. }
  503. var modelMatrix = Matrix4.IDENTITY;
  504. if (frameState.mode === SceneMode.SCENE3D) {
  505. modelMatrix = this.modelMatrix;
  506. }
  507. var pass = frameState.passes;
  508. var useDepthTest = frameState.morphTime !== 0.0;
  509. if (
  510. !defined(this._opaqueRS) ||
  511. this._opaqueRS.depthTest.enabled !== useDepthTest
  512. ) {
  513. this._opaqueRS = RenderState.fromCache({
  514. depthMask: useDepthTest,
  515. depthTest: {
  516. enabled: useDepthTest,
  517. },
  518. });
  519. }
  520. if (
  521. !defined(this._translucentRS) ||
  522. this._translucentRS.depthTest.enabled !== useDepthTest
  523. ) {
  524. this._translucentRS = RenderState.fromCache({
  525. blending: BlendingState.ALPHA_BLEND,
  526. depthMask: !useDepthTest,
  527. depthTest: {
  528. enabled: useDepthTest,
  529. },
  530. });
  531. }
  532. this._batchTable.update(frameState);
  533. if (pass.render || pass.pick) {
  534. var colorList = this._colorCommands;
  535. createCommandLists(this, frameState, colorList, modelMatrix);
  536. }
  537. };
  538. var boundingSphereScratch = new BoundingSphere();
  539. var boundingSphereScratch2 = new BoundingSphere();
  540. function createCommandLists(
  541. polylineCollection,
  542. frameState,
  543. commands,
  544. modelMatrix
  545. ) {
  546. var context = frameState.context;
  547. var commandList = frameState.commandList;
  548. var commandsLength = commands.length;
  549. var commandIndex = 0;
  550. var cloneBoundingSphere = true;
  551. var vertexArrays = polylineCollection._vertexArrays;
  552. var debugShowBoundingVolume = polylineCollection.debugShowBoundingVolume;
  553. var batchTable = polylineCollection._batchTable;
  554. var uniformCallback = batchTable.getUniformMapCallback();
  555. var length = vertexArrays.length;
  556. for (var m = 0; m < length; ++m) {
  557. var va = vertexArrays[m];
  558. var buckets = va.buckets;
  559. var bucketLength = buckets.length;
  560. for (var n = 0; n < bucketLength; ++n) {
  561. var bucketLocator = buckets[n];
  562. var offset = bucketLocator.offset;
  563. var sp = bucketLocator.bucket.shaderProgram;
  564. var polylines = bucketLocator.bucket.polylines;
  565. var polylineLength = polylines.length;
  566. var currentId;
  567. var currentMaterial;
  568. var count = 0;
  569. var command;
  570. var uniformMap;
  571. for (var s = 0; s < polylineLength; ++s) {
  572. var polyline = polylines[s];
  573. var mId = createMaterialId(polyline._material);
  574. if (mId !== currentId) {
  575. if (defined(currentId) && count > 0) {
  576. var translucent = currentMaterial.isTranslucent();
  577. if (commandIndex >= commandsLength) {
  578. command = new DrawCommand({
  579. owner: polylineCollection,
  580. });
  581. commands.push(command);
  582. } else {
  583. command = commands[commandIndex];
  584. }
  585. ++commandIndex;
  586. uniformMap = combine(
  587. uniformCallback(currentMaterial._uniforms),
  588. polylineCollection._uniformMap
  589. );
  590. command.boundingVolume = BoundingSphere.clone(
  591. boundingSphereScratch,
  592. command.boundingVolume
  593. );
  594. command.modelMatrix = modelMatrix;
  595. command.shaderProgram = sp;
  596. command.vertexArray = va.va;
  597. command.renderState = translucent
  598. ? polylineCollection._translucentRS
  599. : polylineCollection._opaqueRS;
  600. command.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  601. command.debugShowBoundingVolume = debugShowBoundingVolume;
  602. command.pickId = "v_pickColor";
  603. command.uniformMap = uniformMap;
  604. command.count = count;
  605. command.offset = offset;
  606. offset += count;
  607. count = 0;
  608. cloneBoundingSphere = true;
  609. commandList.push(command);
  610. }
  611. currentMaterial = polyline._material;
  612. currentMaterial.update(context);
  613. currentId = mId;
  614. }
  615. var locators = polyline._locatorBuckets;
  616. var locatorLength = locators.length;
  617. for (var t = 0; t < locatorLength; ++t) {
  618. var locator = locators[t];
  619. if (locator.locator === bucketLocator) {
  620. count += locator.count;
  621. }
  622. }
  623. var boundingVolume;
  624. if (frameState.mode === SceneMode.SCENE3D) {
  625. boundingVolume = polyline._boundingVolumeWC;
  626. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  627. boundingVolume = polyline._boundingVolume2D;
  628. } else if (frameState.mode === SceneMode.SCENE2D) {
  629. if (defined(polyline._boundingVolume2D)) {
  630. boundingVolume = BoundingSphere.clone(
  631. polyline._boundingVolume2D,
  632. boundingSphereScratch2
  633. );
  634. boundingVolume.center.x = 0.0;
  635. }
  636. } else if (
  637. defined(polyline._boundingVolumeWC) &&
  638. defined(polyline._boundingVolume2D)
  639. ) {
  640. boundingVolume = BoundingSphere.union(
  641. polyline._boundingVolumeWC,
  642. polyline._boundingVolume2D,
  643. boundingSphereScratch2
  644. );
  645. }
  646. if (cloneBoundingSphere) {
  647. cloneBoundingSphere = false;
  648. BoundingSphere.clone(boundingVolume, boundingSphereScratch);
  649. } else {
  650. BoundingSphere.union(
  651. boundingVolume,
  652. boundingSphereScratch,
  653. boundingSphereScratch
  654. );
  655. }
  656. }
  657. if (defined(currentId) && count > 0) {
  658. if (commandIndex >= commandsLength) {
  659. command = new DrawCommand({
  660. owner: polylineCollection,
  661. });
  662. commands.push(command);
  663. } else {
  664. command = commands[commandIndex];
  665. }
  666. ++commandIndex;
  667. uniformMap = combine(
  668. uniformCallback(currentMaterial._uniforms),
  669. polylineCollection._uniformMap
  670. );
  671. command.boundingVolume = BoundingSphere.clone(
  672. boundingSphereScratch,
  673. command.boundingVolume
  674. );
  675. command.modelMatrix = modelMatrix;
  676. command.shaderProgram = sp;
  677. command.vertexArray = va.va;
  678. command.renderState = currentMaterial.isTranslucent()
  679. ? polylineCollection._translucentRS
  680. : polylineCollection._opaqueRS;
  681. command.pass = currentMaterial.isTranslucent()
  682. ? Pass.TRANSLUCENT
  683. : Pass.OPAQUE;
  684. command.debugShowBoundingVolume = debugShowBoundingVolume;
  685. command.pickId = "v_pickColor";
  686. command.uniformMap = uniformMap;
  687. command.count = count;
  688. command.offset = offset;
  689. cloneBoundingSphere = true;
  690. commandList.push(command);
  691. }
  692. currentId = undefined;
  693. }
  694. }
  695. commands.length = commandIndex;
  696. }
  697. /**
  698. * Returns true if this object was destroyed; otherwise, false.
  699. * <br /><br />
  700. * If this object was destroyed, it should not be used; calling any function other than
  701. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  702. *
  703. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  704. *
  705. * @see PolylineCollection#destroy
  706. */
  707. PolylineCollection.prototype.isDestroyed = function () {
  708. return false;
  709. };
  710. /**
  711. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  712. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  713. * <br /><br />
  714. * Once an object is destroyed, it should not be used; calling any function other than
  715. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  716. * assign the return value (<code>undefined</code>) to the object as done in the example.
  717. *
  718. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  719. *
  720. *
  721. * @example
  722. * polylines = polylines && polylines.destroy();
  723. *
  724. * @see PolylineCollection#isDestroyed
  725. */
  726. PolylineCollection.prototype.destroy = function () {
  727. destroyVertexArrays(this);
  728. releaseShaders(this);
  729. destroyPolylines(this);
  730. this._batchTable = this._batchTable && this._batchTable.destroy();
  731. return destroyObject(this);
  732. };
  733. function computeNewBuffersUsage(collection) {
  734. var usageChanged = false;
  735. var properties = collection._propertiesChanged;
  736. var bufferUsage = collection._positionBufferUsage;
  737. if (properties[POSITION_INDEX]) {
  738. if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) {
  739. usageChanged = true;
  740. bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW;
  741. bufferUsage.frameCount = 100;
  742. } else {
  743. bufferUsage.frameCount = 100;
  744. }
  745. } else if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) {
  746. if (bufferUsage.frameCount === 0) {
  747. usageChanged = true;
  748. bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW;
  749. } else {
  750. bufferUsage.frameCount--;
  751. }
  752. }
  753. return usageChanged;
  754. }
  755. var emptyVertexBuffer = [0.0, 0.0, 0.0];
  756. function createVertexArrays(collection, context, projection) {
  757. collection._createVertexArray = false;
  758. releaseShaders(collection);
  759. destroyVertexArrays(collection);
  760. sortPolylinesIntoBuckets(collection);
  761. //stores all of the individual indices arrays.
  762. var totalIndices = [[]];
  763. var indices = totalIndices[0];
  764. var batchTable = collection._batchTable;
  765. var useHighlightColor = collection._useHighlightColor;
  766. //used to determine the vertexBuffer offset if the indicesArray goes over 64k.
  767. //if it's the same polyline while it goes over 64k, the offset needs to backtrack componentsPerAttribute * componentDatatype bytes
  768. //so that the polyline looks contiguous.
  769. //if the polyline ends at the 64k mark, then the offset is just 64k * componentsPerAttribute * componentDatatype
  770. var vertexBufferOffset = [0];
  771. var offset = 0;
  772. var vertexArrayBuckets = [[]];
  773. var totalLength = 0;
  774. var polylineBuckets = collection._polylineBuckets;
  775. var x;
  776. var bucket;
  777. for (x in polylineBuckets) {
  778. if (polylineBuckets.hasOwnProperty(x)) {
  779. bucket = polylineBuckets[x];
  780. bucket.updateShader(context, batchTable, useHighlightColor);
  781. totalLength += bucket.lengthOfPositions;
  782. }
  783. }
  784. if (totalLength > 0) {
  785. var mode = collection._mode;
  786. var positionArray = new Float32Array(6 * totalLength * 3);
  787. var texCoordExpandAndBatchIndexArray = new Float32Array(totalLength * 4);
  788. var position3DArray;
  789. var positionIndex = 0;
  790. var colorIndex = 0;
  791. var texCoordExpandAndBatchIndexIndex = 0;
  792. for (x in polylineBuckets) {
  793. if (polylineBuckets.hasOwnProperty(x)) {
  794. bucket = polylineBuckets[x];
  795. bucket.write(
  796. positionArray,
  797. texCoordExpandAndBatchIndexArray,
  798. positionIndex,
  799. colorIndex,
  800. texCoordExpandAndBatchIndexIndex,
  801. batchTable,
  802. context,
  803. projection
  804. );
  805. if (mode === SceneMode.MORPHING) {
  806. if (!defined(position3DArray)) {
  807. position3DArray = new Float32Array(6 * totalLength * 3);
  808. }
  809. bucket.writeForMorph(position3DArray, positionIndex);
  810. }
  811. var bucketLength = bucket.lengthOfPositions;
  812. positionIndex += 6 * bucketLength * 3;
  813. colorIndex += bucketLength * 4;
  814. texCoordExpandAndBatchIndexIndex += bucketLength * 4;
  815. offset = bucket.updateIndices(
  816. totalIndices,
  817. vertexBufferOffset,
  818. vertexArrayBuckets,
  819. offset
  820. );
  821. }
  822. }
  823. var positionBufferUsage = collection._positionBufferUsage.bufferUsage;
  824. var texCoordExpandAndBatchIndexBufferUsage = BufferUsage.STATIC_DRAW;
  825. collection._positionBuffer = Buffer.createVertexBuffer({
  826. context: context,
  827. typedArray: positionArray,
  828. usage: positionBufferUsage,
  829. });
  830. var position3DBuffer;
  831. if (defined(position3DArray)) {
  832. position3DBuffer = Buffer.createVertexBuffer({
  833. context: context,
  834. typedArray: position3DArray,
  835. usage: positionBufferUsage,
  836. });
  837. }
  838. collection._texCoordExpandAndBatchIndexBuffer = Buffer.createVertexBuffer({
  839. context: context,
  840. typedArray: texCoordExpandAndBatchIndexArray,
  841. usage: texCoordExpandAndBatchIndexBufferUsage,
  842. });
  843. var positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT;
  844. var texCoordExpandAndBatchIndexSizeInBytes =
  845. 4 * Float32Array.BYTES_PER_ELEMENT;
  846. var vbo = 0;
  847. var numberOfIndicesArrays = totalIndices.length;
  848. for (var k = 0; k < numberOfIndicesArrays; ++k) {
  849. indices = totalIndices[k];
  850. if (indices.length > 0) {
  851. var indicesArray = new Uint16Array(indices);
  852. var indexBuffer = Buffer.createIndexBuffer({
  853. context: context,
  854. typedArray: indicesArray,
  855. usage: BufferUsage.STATIC_DRAW,
  856. indexDatatype: IndexDatatype.UNSIGNED_SHORT,
  857. });
  858. vbo += vertexBufferOffset[k];
  859. var positionHighOffset =
  860. 6 *
  861. (k * (positionSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) -
  862. vbo * positionSizeInBytes); //componentsPerAttribute(3) * componentDatatype(4)
  863. var positionLowOffset = positionSizeInBytes + positionHighOffset;
  864. var prevPositionHighOffset = positionSizeInBytes + positionLowOffset;
  865. var prevPositionLowOffset =
  866. positionSizeInBytes + prevPositionHighOffset;
  867. var nextPositionHighOffset =
  868. positionSizeInBytes + prevPositionLowOffset;
  869. var nextPositionLowOffset =
  870. positionSizeInBytes + nextPositionHighOffset;
  871. var vertexTexCoordExpandAndBatchIndexBufferOffset =
  872. k *
  873. (texCoordExpandAndBatchIndexSizeInBytes *
  874. CesiumMath.SIXTY_FOUR_KILOBYTES) -
  875. vbo * texCoordExpandAndBatchIndexSizeInBytes;
  876. var attributes = [
  877. {
  878. index: attributeLocations.position3DHigh,
  879. componentsPerAttribute: 3,
  880. componentDatatype: ComponentDatatype.FLOAT,
  881. offsetInBytes: positionHighOffset,
  882. strideInBytes: 6 * positionSizeInBytes,
  883. },
  884. {
  885. index: attributeLocations.position3DLow,
  886. componentsPerAttribute: 3,
  887. componentDatatype: ComponentDatatype.FLOAT,
  888. offsetInBytes: positionLowOffset,
  889. strideInBytes: 6 * positionSizeInBytes,
  890. },
  891. {
  892. index: attributeLocations.position2DHigh,
  893. componentsPerAttribute: 3,
  894. componentDatatype: ComponentDatatype.FLOAT,
  895. offsetInBytes: positionHighOffset,
  896. strideInBytes: 6 * positionSizeInBytes,
  897. },
  898. {
  899. index: attributeLocations.position2DLow,
  900. componentsPerAttribute: 3,
  901. componentDatatype: ComponentDatatype.FLOAT,
  902. offsetInBytes: positionLowOffset,
  903. strideInBytes: 6 * positionSizeInBytes,
  904. },
  905. {
  906. index: attributeLocations.prevPosition3DHigh,
  907. componentsPerAttribute: 3,
  908. componentDatatype: ComponentDatatype.FLOAT,
  909. offsetInBytes: prevPositionHighOffset,
  910. strideInBytes: 6 * positionSizeInBytes,
  911. },
  912. {
  913. index: attributeLocations.prevPosition3DLow,
  914. componentsPerAttribute: 3,
  915. componentDatatype: ComponentDatatype.FLOAT,
  916. offsetInBytes: prevPositionLowOffset,
  917. strideInBytes: 6 * positionSizeInBytes,
  918. },
  919. {
  920. index: attributeLocations.prevPosition2DHigh,
  921. componentsPerAttribute: 3,
  922. componentDatatype: ComponentDatatype.FLOAT,
  923. offsetInBytes: prevPositionHighOffset,
  924. strideInBytes: 6 * positionSizeInBytes,
  925. },
  926. {
  927. index: attributeLocations.prevPosition2DLow,
  928. componentsPerAttribute: 3,
  929. componentDatatype: ComponentDatatype.FLOAT,
  930. offsetInBytes: prevPositionLowOffset,
  931. strideInBytes: 6 * positionSizeInBytes,
  932. },
  933. {
  934. index: attributeLocations.nextPosition3DHigh,
  935. componentsPerAttribute: 3,
  936. componentDatatype: ComponentDatatype.FLOAT,
  937. offsetInBytes: nextPositionHighOffset,
  938. strideInBytes: 6 * positionSizeInBytes,
  939. },
  940. {
  941. index: attributeLocations.nextPosition3DLow,
  942. componentsPerAttribute: 3,
  943. componentDatatype: ComponentDatatype.FLOAT,
  944. offsetInBytes: nextPositionLowOffset,
  945. strideInBytes: 6 * positionSizeInBytes,
  946. },
  947. {
  948. index: attributeLocations.nextPosition2DHigh,
  949. componentsPerAttribute: 3,
  950. componentDatatype: ComponentDatatype.FLOAT,
  951. offsetInBytes: nextPositionHighOffset,
  952. strideInBytes: 6 * positionSizeInBytes,
  953. },
  954. {
  955. index: attributeLocations.nextPosition2DLow,
  956. componentsPerAttribute: 3,
  957. componentDatatype: ComponentDatatype.FLOAT,
  958. offsetInBytes: nextPositionLowOffset,
  959. strideInBytes: 6 * positionSizeInBytes,
  960. },
  961. {
  962. index: attributeLocations.texCoordExpandAndBatchIndex,
  963. componentsPerAttribute: 4,
  964. componentDatatype: ComponentDatatype.FLOAT,
  965. vertexBuffer: collection._texCoordExpandAndBatchIndexBuffer,
  966. offsetInBytes: vertexTexCoordExpandAndBatchIndexBufferOffset,
  967. },
  968. ];
  969. var buffer3D;
  970. var bufferProperty3D;
  971. var buffer2D;
  972. var bufferProperty2D;
  973. if (mode === SceneMode.SCENE3D) {
  974. buffer3D = collection._positionBuffer;
  975. bufferProperty3D = "vertexBuffer";
  976. buffer2D = emptyVertexBuffer;
  977. bufferProperty2D = "value";
  978. } else if (
  979. mode === SceneMode.SCENE2D ||
  980. mode === SceneMode.COLUMBUS_VIEW
  981. ) {
  982. buffer3D = emptyVertexBuffer;
  983. bufferProperty3D = "value";
  984. buffer2D = collection._positionBuffer;
  985. bufferProperty2D = "vertexBuffer";
  986. } else {
  987. buffer3D = position3DBuffer;
  988. bufferProperty3D = "vertexBuffer";
  989. buffer2D = collection._positionBuffer;
  990. bufferProperty2D = "vertexBuffer";
  991. }
  992. attributes[0][bufferProperty3D] = buffer3D;
  993. attributes[1][bufferProperty3D] = buffer3D;
  994. attributes[2][bufferProperty2D] = buffer2D;
  995. attributes[3][bufferProperty2D] = buffer2D;
  996. attributes[4][bufferProperty3D] = buffer3D;
  997. attributes[5][bufferProperty3D] = buffer3D;
  998. attributes[6][bufferProperty2D] = buffer2D;
  999. attributes[7][bufferProperty2D] = buffer2D;
  1000. attributes[8][bufferProperty3D] = buffer3D;
  1001. attributes[9][bufferProperty3D] = buffer3D;
  1002. attributes[10][bufferProperty2D] = buffer2D;
  1003. attributes[11][bufferProperty2D] = buffer2D;
  1004. var va = new VertexArray({
  1005. context: context,
  1006. attributes: attributes,
  1007. indexBuffer: indexBuffer,
  1008. });
  1009. collection._vertexArrays.push({
  1010. va: va,
  1011. buckets: vertexArrayBuckets[k],
  1012. });
  1013. }
  1014. }
  1015. }
  1016. }
  1017. function replacer(key, value) {
  1018. if (value instanceof Texture) {
  1019. return value.id;
  1020. }
  1021. return value;
  1022. }
  1023. var scratchUniformArray = [];
  1024. function createMaterialId(material) {
  1025. var uniforms = Material._uniformList[material.type];
  1026. var length = uniforms.length;
  1027. scratchUniformArray.length = 2.0 * length;
  1028. var index = 0;
  1029. for (var i = 0; i < length; ++i) {
  1030. var uniform = uniforms[i];
  1031. scratchUniformArray[index] = uniform;
  1032. scratchUniformArray[index + 1] = material._uniforms[uniform]();
  1033. index += 2;
  1034. }
  1035. return material.type + ":" + JSON.stringify(scratchUniformArray, replacer);
  1036. }
  1037. function sortPolylinesIntoBuckets(collection) {
  1038. var mode = collection._mode;
  1039. var modelMatrix = collection._modelMatrix;
  1040. var polylineBuckets = (collection._polylineBuckets = {});
  1041. var polylines = collection._polylines;
  1042. var length = polylines.length;
  1043. for (var i = 0; i < length; ++i) {
  1044. var p = polylines[i];
  1045. if (p._actualPositions.length > 1) {
  1046. p.update();
  1047. var material = p.material;
  1048. var value = polylineBuckets[material.type];
  1049. if (!defined(value)) {
  1050. value = polylineBuckets[material.type] = new PolylineBucket(
  1051. material,
  1052. mode,
  1053. modelMatrix
  1054. );
  1055. }
  1056. value.addPolyline(p);
  1057. }
  1058. }
  1059. }
  1060. function updateMode(collection, frameState) {
  1061. var mode = frameState.mode;
  1062. if (
  1063. collection._mode !== mode ||
  1064. !Matrix4.equals(collection._modelMatrix, collection.modelMatrix)
  1065. ) {
  1066. collection._mode = mode;
  1067. collection._modelMatrix = Matrix4.clone(collection.modelMatrix);
  1068. collection._createVertexArray = true;
  1069. }
  1070. }
  1071. function removePolylines(collection) {
  1072. if (collection._polylinesRemoved) {
  1073. collection._polylinesRemoved = false;
  1074. var definedPolylines = [];
  1075. var definedPolylinesToUpdate = [];
  1076. var polyIndex = 0;
  1077. var polyline;
  1078. var length = collection._polylines.length;
  1079. for (var i = 0; i < length; ++i) {
  1080. polyline = collection._polylines[i];
  1081. if (!polyline.isDestroyed) {
  1082. polyline._index = polyIndex++;
  1083. definedPolylinesToUpdate.push(polyline);
  1084. definedPolylines.push(polyline);
  1085. }
  1086. }
  1087. collection._polylines = definedPolylines;
  1088. collection._polylinesToUpdate = definedPolylinesToUpdate;
  1089. }
  1090. }
  1091. function releaseShaders(collection) {
  1092. var polylines = collection._polylines;
  1093. var length = polylines.length;
  1094. for (var i = 0; i < length; ++i) {
  1095. if (!polylines[i].isDestroyed) {
  1096. var bucket = polylines[i]._bucket;
  1097. if (defined(bucket)) {
  1098. bucket.shaderProgram =
  1099. bucket.shaderProgram && bucket.shaderProgram.destroy();
  1100. }
  1101. }
  1102. }
  1103. }
  1104. function destroyVertexArrays(collection) {
  1105. var length = collection._vertexArrays.length;
  1106. for (var t = 0; t < length; ++t) {
  1107. collection._vertexArrays[t].va.destroy();
  1108. }
  1109. collection._vertexArrays.length = 0;
  1110. }
  1111. PolylineCollection.prototype._updatePolyline = function (
  1112. polyline,
  1113. propertyChanged
  1114. ) {
  1115. this._polylinesUpdated = true;
  1116. if (!polyline._dirty) {
  1117. this._polylinesToUpdate.push(polyline);
  1118. }
  1119. ++this._propertiesChanged[propertyChanged];
  1120. };
  1121. function destroyPolylines(collection) {
  1122. var polylines = collection._polylines;
  1123. var length = polylines.length;
  1124. for (var i = 0; i < length; ++i) {
  1125. if (!polylines[i].isDestroyed) {
  1126. polylines[i]._destroy();
  1127. }
  1128. }
  1129. }
  1130. function VertexArrayBucketLocator(count, offset, bucket) {
  1131. this.count = count;
  1132. this.offset = offset;
  1133. this.bucket = bucket;
  1134. }
  1135. function PolylineBucket(material, mode, modelMatrix) {
  1136. this.polylines = [];
  1137. this.lengthOfPositions = 0;
  1138. this.material = material;
  1139. this.shaderProgram = undefined;
  1140. this.mode = mode;
  1141. this.modelMatrix = modelMatrix;
  1142. }
  1143. PolylineBucket.prototype.addPolyline = function (p) {
  1144. var polylines = this.polylines;
  1145. polylines.push(p);
  1146. p._actualLength = this.getPolylinePositionsLength(p);
  1147. this.lengthOfPositions += p._actualLength;
  1148. p._bucket = this;
  1149. };
  1150. PolylineBucket.prototype.updateShader = function (
  1151. context,
  1152. batchTable,
  1153. useHighlightColor
  1154. ) {
  1155. if (defined(this.shaderProgram)) {
  1156. return;
  1157. }
  1158. var defines = ["DISTANCE_DISPLAY_CONDITION"];
  1159. if (useHighlightColor) {
  1160. defines.push("VECTOR_TILE");
  1161. }
  1162. // Check for use of v_polylineAngle in material shader
  1163. if (
  1164. this.material.shaderSource.search(/varying\s+float\s+v_polylineAngle;/g) !==
  1165. -1
  1166. ) {
  1167. defines.push("POLYLINE_DASH");
  1168. }
  1169. if (!FeatureDetection.isInternetExplorer()) {
  1170. defines.push("CLIP_POLYLINE");
  1171. }
  1172. var fs = new ShaderSource({
  1173. defines: defines,
  1174. sources: [
  1175. "varying vec4 v_pickColor;\n",
  1176. this.material.shaderSource,
  1177. PolylineFS,
  1178. ],
  1179. });
  1180. var vsSource = batchTable.getVertexShaderCallback()(PolylineVS);
  1181. var vs = new ShaderSource({
  1182. defines: defines,
  1183. sources: [PolylineCommon, vsSource],
  1184. });
  1185. this.shaderProgram = ShaderProgram.fromCache({
  1186. context: context,
  1187. vertexShaderSource: vs,
  1188. fragmentShaderSource: fs,
  1189. attributeLocations: attributeLocations,
  1190. });
  1191. };
  1192. function intersectsIDL(polyline) {
  1193. return (
  1194. Cartesian3.dot(Cartesian3.UNIT_X, polyline._boundingVolume.center) < 0 ||
  1195. polyline._boundingVolume.intersectPlane(Plane.ORIGIN_ZX_PLANE) ===
  1196. Intersect.INTERSECTING
  1197. );
  1198. }
  1199. PolylineBucket.prototype.getPolylinePositionsLength = function (polyline) {
  1200. var length;
  1201. if (this.mode === SceneMode.SCENE3D || !intersectsIDL(polyline)) {
  1202. length = polyline._actualPositions.length;
  1203. return length * 4.0 - 4.0;
  1204. }
  1205. var count = 0;
  1206. var segmentLengths = polyline._segments.lengths;
  1207. length = segmentLengths.length;
  1208. for (var i = 0; i < length; ++i) {
  1209. count += segmentLengths[i] * 4.0 - 4.0;
  1210. }
  1211. return count;
  1212. };
  1213. var scratchWritePosition = new Cartesian3();
  1214. var scratchWritePrevPosition = new Cartesian3();
  1215. var scratchWriteNextPosition = new Cartesian3();
  1216. var scratchWriteVector = new Cartesian3();
  1217. var scratchPickColorCartesian = new Cartesian4();
  1218. var scratchWidthShowCartesian = new Cartesian2();
  1219. PolylineBucket.prototype.write = function (
  1220. positionArray,
  1221. texCoordExpandAndBatchIndexArray,
  1222. positionIndex,
  1223. colorIndex,
  1224. texCoordExpandAndBatchIndexIndex,
  1225. batchTable,
  1226. context,
  1227. projection
  1228. ) {
  1229. var mode = this.mode;
  1230. var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
  1231. var polylines = this.polylines;
  1232. var length = polylines.length;
  1233. for (var i = 0; i < length; ++i) {
  1234. var polyline = polylines[i];
  1235. var width = polyline.width;
  1236. var show = polyline.show && width > 0.0;
  1237. var polylineBatchIndex = polyline._index;
  1238. var segments = this.getSegments(polyline, projection);
  1239. var positions = segments.positions;
  1240. var lengths = segments.lengths;
  1241. var positionsLength = positions.length;
  1242. var pickColor = polyline.getPickId(context).color;
  1243. var segmentIndex = 0;
  1244. var count = 0;
  1245. var position;
  1246. for (var j = 0; j < positionsLength; ++j) {
  1247. if (j === 0) {
  1248. if (polyline._loop) {
  1249. position = positions[positionsLength - 2];
  1250. } else {
  1251. position = scratchWriteVector;
  1252. Cartesian3.subtract(positions[0], positions[1], position);
  1253. Cartesian3.add(positions[0], position, position);
  1254. }
  1255. } else {
  1256. position = positions[j - 1];
  1257. }
  1258. Cartesian3.clone(position, scratchWritePrevPosition);
  1259. Cartesian3.clone(positions[j], scratchWritePosition);
  1260. if (j === positionsLength - 1) {
  1261. if (polyline._loop) {
  1262. position = positions[1];
  1263. } else {
  1264. position = scratchWriteVector;
  1265. Cartesian3.subtract(
  1266. positions[positionsLength - 1],
  1267. positions[positionsLength - 2],
  1268. position
  1269. );
  1270. Cartesian3.add(positions[positionsLength - 1], position, position);
  1271. }
  1272. } else {
  1273. position = positions[j + 1];
  1274. }
  1275. Cartesian3.clone(position, scratchWriteNextPosition);
  1276. var segmentLength = lengths[segmentIndex];
  1277. if (j === count + segmentLength) {
  1278. count += segmentLength;
  1279. ++segmentIndex;
  1280. }
  1281. var segmentStart = j - count === 0;
  1282. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  1283. if (mode === SceneMode.SCENE2D) {
  1284. scratchWritePrevPosition.z = 0.0;
  1285. scratchWritePosition.z = 0.0;
  1286. scratchWriteNextPosition.z = 0.0;
  1287. }
  1288. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  1289. if (
  1290. (segmentStart || segmentEnd) &&
  1291. maxLon - Math.abs(scratchWritePosition.x) < 1.0
  1292. ) {
  1293. if (
  1294. (scratchWritePosition.x < 0.0 &&
  1295. scratchWritePrevPosition.x > 0.0) ||
  1296. (scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)
  1297. ) {
  1298. Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
  1299. }
  1300. if (
  1301. (scratchWritePosition.x < 0.0 &&
  1302. scratchWriteNextPosition.x > 0.0) ||
  1303. (scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)
  1304. ) {
  1305. Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
  1306. }
  1307. }
  1308. }
  1309. var startK = segmentStart ? 2 : 0;
  1310. var endK = segmentEnd ? 2 : 4;
  1311. for (var k = startK; k < endK; ++k) {
  1312. EncodedCartesian3.writeElements(
  1313. scratchWritePosition,
  1314. positionArray,
  1315. positionIndex
  1316. );
  1317. EncodedCartesian3.writeElements(
  1318. scratchWritePrevPosition,
  1319. positionArray,
  1320. positionIndex + 6
  1321. );
  1322. EncodedCartesian3.writeElements(
  1323. scratchWriteNextPosition,
  1324. positionArray,
  1325. positionIndex + 12
  1326. );
  1327. var direction = k - 2 < 0 ? -1.0 : 1.0;
  1328. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex] =
  1329. j / (positionsLength - 1); // s tex coord
  1330. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 1] =
  1331. 2 * (k % 2) - 1; // expand direction
  1332. texCoordExpandAndBatchIndexArray[
  1333. texCoordExpandAndBatchIndexIndex + 2
  1334. ] = direction;
  1335. texCoordExpandAndBatchIndexArray[
  1336. texCoordExpandAndBatchIndexIndex + 3
  1337. ] = polylineBatchIndex;
  1338. positionIndex += 6 * 3;
  1339. texCoordExpandAndBatchIndexIndex += 4;
  1340. }
  1341. }
  1342. var colorCartesian = scratchPickColorCartesian;
  1343. colorCartesian.x = Color.floatToByte(pickColor.red);
  1344. colorCartesian.y = Color.floatToByte(pickColor.green);
  1345. colorCartesian.z = Color.floatToByte(pickColor.blue);
  1346. colorCartesian.w = Color.floatToByte(pickColor.alpha);
  1347. var widthShowCartesian = scratchWidthShowCartesian;
  1348. widthShowCartesian.x = width;
  1349. widthShowCartesian.y = show ? 1.0 : 0.0;
  1350. var boundingSphere =
  1351. mode === SceneMode.SCENE2D
  1352. ? polyline._boundingVolume2D
  1353. : polyline._boundingVolumeWC;
  1354. var encodedCenter = EncodedCartesian3.fromCartesian(
  1355. boundingSphere.center,
  1356. scratchUpdatePolylineEncodedCartesian
  1357. );
  1358. var high = encodedCenter.high;
  1359. var low = Cartesian4.fromElements(
  1360. encodedCenter.low.x,
  1361. encodedCenter.low.y,
  1362. encodedCenter.low.z,
  1363. boundingSphere.radius,
  1364. scratchUpdatePolylineCartesian4
  1365. );
  1366. var nearFarCartesian = scratchNearFarCartesian2;
  1367. nearFarCartesian.x = 0.0;
  1368. nearFarCartesian.y = Number.MAX_VALUE;
  1369. var distanceDisplayCondition = polyline.distanceDisplayCondition;
  1370. if (defined(distanceDisplayCondition)) {
  1371. nearFarCartesian.x = distanceDisplayCondition.near;
  1372. nearFarCartesian.y = distanceDisplayCondition.far;
  1373. }
  1374. batchTable.setBatchedAttribute(polylineBatchIndex, 0, widthShowCartesian);
  1375. batchTable.setBatchedAttribute(polylineBatchIndex, 1, colorCartesian);
  1376. if (batchTable.attributes.length > 2) {
  1377. batchTable.setBatchedAttribute(polylineBatchIndex, 2, high);
  1378. batchTable.setBatchedAttribute(polylineBatchIndex, 3, low);
  1379. batchTable.setBatchedAttribute(polylineBatchIndex, 4, nearFarCartesian);
  1380. }
  1381. }
  1382. };
  1383. var morphPositionScratch = new Cartesian3();
  1384. var morphPrevPositionScratch = new Cartesian3();
  1385. var morphNextPositionScratch = new Cartesian3();
  1386. var morphVectorScratch = new Cartesian3();
  1387. PolylineBucket.prototype.writeForMorph = function (
  1388. positionArray,
  1389. positionIndex
  1390. ) {
  1391. var modelMatrix = this.modelMatrix;
  1392. var polylines = this.polylines;
  1393. var length = polylines.length;
  1394. for (var i = 0; i < length; ++i) {
  1395. var polyline = polylines[i];
  1396. var positions = polyline._segments.positions;
  1397. var lengths = polyline._segments.lengths;
  1398. var positionsLength = positions.length;
  1399. var segmentIndex = 0;
  1400. var count = 0;
  1401. for (var j = 0; j < positionsLength; ++j) {
  1402. var prevPosition;
  1403. if (j === 0) {
  1404. if (polyline._loop) {
  1405. prevPosition = positions[positionsLength - 2];
  1406. } else {
  1407. prevPosition = morphVectorScratch;
  1408. Cartesian3.subtract(positions[0], positions[1], prevPosition);
  1409. Cartesian3.add(positions[0], prevPosition, prevPosition);
  1410. }
  1411. } else {
  1412. prevPosition = positions[j - 1];
  1413. }
  1414. prevPosition = Matrix4.multiplyByPoint(
  1415. modelMatrix,
  1416. prevPosition,
  1417. morphPrevPositionScratch
  1418. );
  1419. var position = Matrix4.multiplyByPoint(
  1420. modelMatrix,
  1421. positions[j],
  1422. morphPositionScratch
  1423. );
  1424. var nextPosition;
  1425. if (j === positionsLength - 1) {
  1426. if (polyline._loop) {
  1427. nextPosition = positions[1];
  1428. } else {
  1429. nextPosition = morphVectorScratch;
  1430. Cartesian3.subtract(
  1431. positions[positionsLength - 1],
  1432. positions[positionsLength - 2],
  1433. nextPosition
  1434. );
  1435. Cartesian3.add(
  1436. positions[positionsLength - 1],
  1437. nextPosition,
  1438. nextPosition
  1439. );
  1440. }
  1441. } else {
  1442. nextPosition = positions[j + 1];
  1443. }
  1444. nextPosition = Matrix4.multiplyByPoint(
  1445. modelMatrix,
  1446. nextPosition,
  1447. morphNextPositionScratch
  1448. );
  1449. var segmentLength = lengths[segmentIndex];
  1450. if (j === count + segmentLength) {
  1451. count += segmentLength;
  1452. ++segmentIndex;
  1453. }
  1454. var segmentStart = j - count === 0;
  1455. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  1456. var startK = segmentStart ? 2 : 0;
  1457. var endK = segmentEnd ? 2 : 4;
  1458. for (var k = startK; k < endK; ++k) {
  1459. EncodedCartesian3.writeElements(position, positionArray, positionIndex);
  1460. EncodedCartesian3.writeElements(
  1461. prevPosition,
  1462. positionArray,
  1463. positionIndex + 6
  1464. );
  1465. EncodedCartesian3.writeElements(
  1466. nextPosition,
  1467. positionArray,
  1468. positionIndex + 12
  1469. );
  1470. positionIndex += 6 * 3;
  1471. }
  1472. }
  1473. }
  1474. };
  1475. var scratchSegmentLengths = new Array(1);
  1476. PolylineBucket.prototype.updateIndices = function (
  1477. totalIndices,
  1478. vertexBufferOffset,
  1479. vertexArrayBuckets,
  1480. offset
  1481. ) {
  1482. var vaCount = vertexArrayBuckets.length - 1;
  1483. var bucketLocator = new VertexArrayBucketLocator(0, offset, this);
  1484. vertexArrayBuckets[vaCount].push(bucketLocator);
  1485. var count = 0;
  1486. var indices = totalIndices[totalIndices.length - 1];
  1487. var indicesCount = 0;
  1488. if (indices.length > 0) {
  1489. indicesCount = indices[indices.length - 1] + 1;
  1490. }
  1491. var polylines = this.polylines;
  1492. var length = polylines.length;
  1493. for (var i = 0; i < length; ++i) {
  1494. var polyline = polylines[i];
  1495. polyline._locatorBuckets = [];
  1496. var segments;
  1497. if (this.mode === SceneMode.SCENE3D) {
  1498. segments = scratchSegmentLengths;
  1499. var positionsLength = polyline._actualPositions.length;
  1500. if (positionsLength > 0) {
  1501. segments[0] = positionsLength;
  1502. } else {
  1503. continue;
  1504. }
  1505. } else {
  1506. segments = polyline._segments.lengths;
  1507. }
  1508. var numberOfSegments = segments.length;
  1509. if (numberOfSegments > 0) {
  1510. var segmentIndexCount = 0;
  1511. for (var j = 0; j < numberOfSegments; ++j) {
  1512. var segmentLength = segments[j] - 1.0;
  1513. for (var k = 0; k < segmentLength; ++k) {
  1514. if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) {
  1515. polyline._locatorBuckets.push({
  1516. locator: bucketLocator,
  1517. count: segmentIndexCount,
  1518. });
  1519. segmentIndexCount = 0;
  1520. vertexBufferOffset.push(4);
  1521. indices = [];
  1522. totalIndices.push(indices);
  1523. indicesCount = 0;
  1524. bucketLocator.count = count;
  1525. count = 0;
  1526. offset = 0;
  1527. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  1528. vertexArrayBuckets[++vaCount] = [bucketLocator];
  1529. }
  1530. indices.push(indicesCount, indicesCount + 2, indicesCount + 1);
  1531. indices.push(indicesCount + 1, indicesCount + 2, indicesCount + 3);
  1532. segmentIndexCount += 6;
  1533. count += 6;
  1534. offset += 6;
  1535. indicesCount += 4;
  1536. }
  1537. }
  1538. polyline._locatorBuckets.push({
  1539. locator: bucketLocator,
  1540. count: segmentIndexCount,
  1541. });
  1542. if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) {
  1543. vertexBufferOffset.push(0);
  1544. indices = [];
  1545. totalIndices.push(indices);
  1546. indicesCount = 0;
  1547. bucketLocator.count = count;
  1548. offset = 0;
  1549. count = 0;
  1550. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  1551. vertexArrayBuckets[++vaCount] = [bucketLocator];
  1552. }
  1553. }
  1554. polyline._clean();
  1555. }
  1556. bucketLocator.count = count;
  1557. return offset;
  1558. };
  1559. PolylineBucket.prototype.getPolylineStartIndex = function (polyline) {
  1560. var polylines = this.polylines;
  1561. var positionIndex = 0;
  1562. var length = polylines.length;
  1563. for (var i = 0; i < length; ++i) {
  1564. var p = polylines[i];
  1565. if (p === polyline) {
  1566. break;
  1567. }
  1568. positionIndex += p._actualLength;
  1569. }
  1570. return positionIndex;
  1571. };
  1572. var scratchSegments = {
  1573. positions: undefined,
  1574. lengths: undefined,
  1575. };
  1576. var scratchLengths = new Array(1);
  1577. var pscratch = new Cartesian3();
  1578. var scratchCartographic = new Cartographic();
  1579. PolylineBucket.prototype.getSegments = function (polyline, projection) {
  1580. var positions = polyline._actualPositions;
  1581. if (this.mode === SceneMode.SCENE3D) {
  1582. scratchLengths[0] = positions.length;
  1583. scratchSegments.positions = positions;
  1584. scratchSegments.lengths = scratchLengths;
  1585. return scratchSegments;
  1586. }
  1587. if (intersectsIDL(polyline)) {
  1588. positions = polyline._segments.positions;
  1589. }
  1590. var ellipsoid = projection.ellipsoid;
  1591. var newPositions = [];
  1592. var modelMatrix = this.modelMatrix;
  1593. var length = positions.length;
  1594. var position;
  1595. var p = pscratch;
  1596. for (var n = 0; n < length; ++n) {
  1597. position = positions[n];
  1598. p = Matrix4.multiplyByPoint(modelMatrix, position, p);
  1599. newPositions.push(
  1600. projection.project(
  1601. ellipsoid.cartesianToCartographic(p, scratchCartographic)
  1602. )
  1603. );
  1604. }
  1605. if (newPositions.length > 0) {
  1606. polyline._boundingVolume2D = BoundingSphere.fromPoints(
  1607. newPositions,
  1608. polyline._boundingVolume2D
  1609. );
  1610. var center2D = polyline._boundingVolume2D.center;
  1611. polyline._boundingVolume2D.center = new Cartesian3(
  1612. center2D.z,
  1613. center2D.x,
  1614. center2D.y
  1615. );
  1616. }
  1617. scratchSegments.positions = newPositions;
  1618. scratchSegments.lengths = polyline._segments.lengths;
  1619. return scratchSegments;
  1620. };
  1621. var scratchPositionsArray;
  1622. PolylineBucket.prototype.writeUpdate = function (
  1623. index,
  1624. polyline,
  1625. positionBuffer,
  1626. projection
  1627. ) {
  1628. var mode = this.mode;
  1629. var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
  1630. var positionsLength = polyline._actualLength;
  1631. if (positionsLength) {
  1632. index += this.getPolylineStartIndex(polyline);
  1633. var positionArray = scratchPositionsArray;
  1634. var positionsArrayLength = 6 * positionsLength * 3;
  1635. if (
  1636. !defined(positionArray) ||
  1637. positionArray.length < positionsArrayLength
  1638. ) {
  1639. positionArray = scratchPositionsArray = new Float32Array(
  1640. positionsArrayLength
  1641. );
  1642. } else if (positionArray.length > positionsArrayLength) {
  1643. positionArray = new Float32Array(
  1644. positionArray.buffer,
  1645. 0,
  1646. positionsArrayLength
  1647. );
  1648. }
  1649. var segments = this.getSegments(polyline, projection);
  1650. var positions = segments.positions;
  1651. var lengths = segments.lengths;
  1652. var positionIndex = 0;
  1653. var segmentIndex = 0;
  1654. var count = 0;
  1655. var position;
  1656. positionsLength = positions.length;
  1657. for (var i = 0; i < positionsLength; ++i) {
  1658. if (i === 0) {
  1659. if (polyline._loop) {
  1660. position = positions[positionsLength - 2];
  1661. } else {
  1662. position = scratchWriteVector;
  1663. Cartesian3.subtract(positions[0], positions[1], position);
  1664. Cartesian3.add(positions[0], position, position);
  1665. }
  1666. } else {
  1667. position = positions[i - 1];
  1668. }
  1669. Cartesian3.clone(position, scratchWritePrevPosition);
  1670. Cartesian3.clone(positions[i], scratchWritePosition);
  1671. if (i === positionsLength - 1) {
  1672. if (polyline._loop) {
  1673. position = positions[1];
  1674. } else {
  1675. position = scratchWriteVector;
  1676. Cartesian3.subtract(
  1677. positions[positionsLength - 1],
  1678. positions[positionsLength - 2],
  1679. position
  1680. );
  1681. Cartesian3.add(positions[positionsLength - 1], position, position);
  1682. }
  1683. } else {
  1684. position = positions[i + 1];
  1685. }
  1686. Cartesian3.clone(position, scratchWriteNextPosition);
  1687. var segmentLength = lengths[segmentIndex];
  1688. if (i === count + segmentLength) {
  1689. count += segmentLength;
  1690. ++segmentIndex;
  1691. }
  1692. var segmentStart = i - count === 0;
  1693. var segmentEnd = i === count + lengths[segmentIndex] - 1;
  1694. if (mode === SceneMode.SCENE2D) {
  1695. scratchWritePrevPosition.z = 0.0;
  1696. scratchWritePosition.z = 0.0;
  1697. scratchWriteNextPosition.z = 0.0;
  1698. }
  1699. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  1700. if (
  1701. (segmentStart || segmentEnd) &&
  1702. maxLon - Math.abs(scratchWritePosition.x) < 1.0
  1703. ) {
  1704. if (
  1705. (scratchWritePosition.x < 0.0 &&
  1706. scratchWritePrevPosition.x > 0.0) ||
  1707. (scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)
  1708. ) {
  1709. Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
  1710. }
  1711. if (
  1712. (scratchWritePosition.x < 0.0 &&
  1713. scratchWriteNextPosition.x > 0.0) ||
  1714. (scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)
  1715. ) {
  1716. Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
  1717. }
  1718. }
  1719. }
  1720. var startJ = segmentStart ? 2 : 0;
  1721. var endJ = segmentEnd ? 2 : 4;
  1722. for (var j = startJ; j < endJ; ++j) {
  1723. EncodedCartesian3.writeElements(
  1724. scratchWritePosition,
  1725. positionArray,
  1726. positionIndex
  1727. );
  1728. EncodedCartesian3.writeElements(
  1729. scratchWritePrevPosition,
  1730. positionArray,
  1731. positionIndex + 6
  1732. );
  1733. EncodedCartesian3.writeElements(
  1734. scratchWriteNextPosition,
  1735. positionArray,
  1736. positionIndex + 12
  1737. );
  1738. positionIndex += 6 * 3;
  1739. }
  1740. }
  1741. positionBuffer.copyFromArrayView(
  1742. positionArray,
  1743. 6 * 3 * Float32Array.BYTES_PER_ELEMENT * index
  1744. );
  1745. }
  1746. };
  1747. export default PolylineCollection;