智慧水务管理系统 - 精河县供水工程综合管理平台

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