createVectorTileClampedPolylines.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. define(['./AttributeCompression-f9f6c717', './Matrix3-41c58dde', './combine-d9581036', './IndexDatatype-2643aa47', './Math-0a2ac845', './Matrix2-e1298525', './createTaskProcessorWorker', './ComponentDatatype-cf1fa08e', './defaultValue-fe22d8c0', './Check-6ede7e26', './WebGLConstants-0b1ce7ba', './RuntimeError-ef395448'], (function (AttributeCompression, Matrix3, combine, IndexDatatype, Math$1, Matrix2, createTaskProcessorWorker, ComponentDatatype, defaultValue, Check, WebGLConstants, RuntimeError) { 'use strict';
  2. const MAX_SHORT = 32767;
  3. const MITER_BREAK = Math.cos(Math$1.CesiumMath.toRadians(150.0));
  4. const scratchBVCartographic = new Matrix3.Cartographic();
  5. const scratchEncodedPosition = new Matrix3.Cartesian3();
  6. function decodePositions(
  7. uBuffer,
  8. vBuffer,
  9. heightBuffer,
  10. rectangle,
  11. minimumHeight,
  12. maximumHeight,
  13. ellipsoid
  14. ) {
  15. const positionsLength = uBuffer.length;
  16. const decodedPositions = new Float64Array(positionsLength * 3);
  17. for (let i = 0; i < positionsLength; ++i) {
  18. const u = uBuffer[i];
  19. const v = vBuffer[i];
  20. const h = heightBuffer[i];
  21. const lon = Math$1.CesiumMath.lerp(rectangle.west, rectangle.east, u / MAX_SHORT);
  22. const lat = Math$1.CesiumMath.lerp(
  23. rectangle.south,
  24. rectangle.north,
  25. v / MAX_SHORT
  26. );
  27. const alt = Math$1.CesiumMath.lerp(minimumHeight, maximumHeight, h / MAX_SHORT);
  28. const cartographic = Matrix3.Cartographic.fromRadians(
  29. lon,
  30. lat,
  31. alt,
  32. scratchBVCartographic
  33. );
  34. const decodedPosition = ellipsoid.cartographicToCartesian(
  35. cartographic,
  36. scratchEncodedPosition
  37. );
  38. Matrix3.Cartesian3.pack(decodedPosition, decodedPositions, i * 3);
  39. }
  40. return decodedPositions;
  41. }
  42. function getPositionOffsets(counts) {
  43. const countsLength = counts.length;
  44. const positionOffsets = new Uint32Array(countsLength + 1);
  45. let offset = 0;
  46. for (let i = 0; i < countsLength; ++i) {
  47. positionOffsets[i] = offset;
  48. offset += counts[i];
  49. }
  50. positionOffsets[countsLength] = offset;
  51. return positionOffsets;
  52. }
  53. const previousCompressedCartographicScratch = new Matrix3.Cartographic();
  54. const currentCompressedCartographicScratch = new Matrix3.Cartographic();
  55. function removeDuplicates(uBuffer, vBuffer, heightBuffer, counts) {
  56. const countsLength = counts.length;
  57. const positionsLength = uBuffer.length;
  58. const markRemoval = new Uint8Array(positionsLength);
  59. const previous = previousCompressedCartographicScratch;
  60. const current = currentCompressedCartographicScratch;
  61. let offset = 0;
  62. for (let i = 0; i < countsLength; i++) {
  63. const count = counts[i];
  64. let updatedCount = count;
  65. for (let j = 1; j < count; j++) {
  66. const index = offset + j;
  67. const previousIndex = index - 1;
  68. current.longitude = uBuffer[index];
  69. current.latitude = vBuffer[index];
  70. previous.longitude = uBuffer[previousIndex];
  71. previous.latitude = vBuffer[previousIndex];
  72. if (Matrix3.Cartographic.equals(current, previous)) {
  73. updatedCount--;
  74. markRemoval[previousIndex] = 1;
  75. }
  76. }
  77. counts[i] = updatedCount;
  78. offset += count;
  79. }
  80. let nextAvailableIndex = 0;
  81. for (let k = 0; k < positionsLength; k++) {
  82. if (markRemoval[k] !== 1) {
  83. uBuffer[nextAvailableIndex] = uBuffer[k];
  84. vBuffer[nextAvailableIndex] = vBuffer[k];
  85. heightBuffer[nextAvailableIndex] = heightBuffer[k];
  86. nextAvailableIndex++;
  87. }
  88. }
  89. }
  90. function VertexAttributesAndIndices(volumesCount) {
  91. const vertexCount = volumesCount * 8;
  92. const vec3Floats = vertexCount * 3;
  93. const vec4Floats = vertexCount * 4;
  94. this.startEllipsoidNormals = new Float32Array(vec3Floats);
  95. this.endEllipsoidNormals = new Float32Array(vec3Floats);
  96. this.startPositionAndHeights = new Float32Array(vec4Floats);
  97. this.startFaceNormalAndVertexCornerIds = new Float32Array(vec4Floats);
  98. this.endPositionAndHeights = new Float32Array(vec4Floats);
  99. this.endFaceNormalAndHalfWidths = new Float32Array(vec4Floats);
  100. this.vertexBatchIds = new Uint16Array(vertexCount);
  101. this.indices = IndexDatatype.IndexDatatype.createTypedArray(vertexCount, 36 * volumesCount);
  102. this.vec3Offset = 0;
  103. this.vec4Offset = 0;
  104. this.batchIdOffset = 0;
  105. this.indexOffset = 0;
  106. this.volumeStartIndex = 0;
  107. }
  108. const towardCurrScratch = new Matrix3.Cartesian3();
  109. const towardNextScratch = new Matrix3.Cartesian3();
  110. function computeMiteredNormal(
  111. previousPosition,
  112. position,
  113. nextPosition,
  114. ellipsoidSurfaceNormal,
  115. result
  116. ) {
  117. const towardNext = Matrix3.Cartesian3.subtract(
  118. nextPosition,
  119. position,
  120. towardNextScratch
  121. );
  122. let towardCurr = Matrix3.Cartesian3.subtract(
  123. position,
  124. previousPosition,
  125. towardCurrScratch
  126. );
  127. Matrix3.Cartesian3.normalize(towardNext, towardNext);
  128. Matrix3.Cartesian3.normalize(towardCurr, towardCurr);
  129. if (Matrix3.Cartesian3.dot(towardNext, towardCurr) < MITER_BREAK) {
  130. towardCurr = Matrix3.Cartesian3.multiplyByScalar(
  131. towardCurr,
  132. -1.0,
  133. towardCurrScratch
  134. );
  135. }
  136. Matrix3.Cartesian3.add(towardNext, towardCurr, result);
  137. if (Matrix3.Cartesian3.equals(result, Matrix3.Cartesian3.ZERO)) {
  138. result = Matrix3.Cartesian3.subtract(previousPosition, position);
  139. }
  140. // Make sure the normal is orthogonal to the ellipsoid surface normal
  141. Matrix3.Cartesian3.cross(result, ellipsoidSurfaceNormal, result);
  142. Matrix3.Cartesian3.cross(ellipsoidSurfaceNormal, result, result);
  143. Matrix3.Cartesian3.normalize(result, result);
  144. return result;
  145. }
  146. // Winding order is reversed so each segment's volume is inside-out
  147. // 3-----------7
  148. // /| left /|
  149. // / | 1 / |
  150. // 2-----------6 5 end
  151. // | / | /
  152. // start |/ right |/
  153. // 0-----------4
  154. //
  155. const REFERENCE_INDICES = [
  156. 0,
  157. 2,
  158. 6,
  159. 0,
  160. 6,
  161. 4, // right
  162. 0,
  163. 1,
  164. 3,
  165. 0,
  166. 3,
  167. 2, // start face
  168. 0,
  169. 4,
  170. 5,
  171. 0,
  172. 5,
  173. 1, // bottom
  174. 5,
  175. 3,
  176. 1,
  177. 5,
  178. 7,
  179. 3, // left
  180. 7,
  181. 5,
  182. 4,
  183. 7,
  184. 4,
  185. 6, // end face
  186. 7,
  187. 6,
  188. 2,
  189. 7,
  190. 2,
  191. 3, // top
  192. ];
  193. const REFERENCE_INDICES_LENGTH = REFERENCE_INDICES.length;
  194. const positionScratch = new Matrix3.Cartesian3();
  195. const scratchStartEllipsoidNormal = new Matrix3.Cartesian3();
  196. const scratchStartFaceNormal = new Matrix3.Cartesian3();
  197. const scratchEndEllipsoidNormal = new Matrix3.Cartesian3();
  198. const scratchEndFaceNormal = new Matrix3.Cartesian3();
  199. VertexAttributesAndIndices.prototype.addVolume = function (
  200. preStartRTC,
  201. startRTC,
  202. endRTC,
  203. postEndRTC,
  204. startHeight,
  205. endHeight,
  206. halfWidth,
  207. batchId,
  208. center,
  209. ellipsoid
  210. ) {
  211. let position = Matrix3.Cartesian3.add(startRTC, center, positionScratch);
  212. const startEllipsoidNormal = ellipsoid.geodeticSurfaceNormal(
  213. position,
  214. scratchStartEllipsoidNormal
  215. );
  216. position = Matrix3.Cartesian3.add(endRTC, center, positionScratch);
  217. const endEllipsoidNormal = ellipsoid.geodeticSurfaceNormal(
  218. position,
  219. scratchEndEllipsoidNormal
  220. );
  221. const startFaceNormal = computeMiteredNormal(
  222. preStartRTC,
  223. startRTC,
  224. endRTC,
  225. startEllipsoidNormal,
  226. scratchStartFaceNormal
  227. );
  228. const endFaceNormal = computeMiteredNormal(
  229. postEndRTC,
  230. endRTC,
  231. startRTC,
  232. endEllipsoidNormal,
  233. scratchEndFaceNormal
  234. );
  235. const startEllipsoidNormals = this.startEllipsoidNormals;
  236. const endEllipsoidNormals = this.endEllipsoidNormals;
  237. const startPositionAndHeights = this.startPositionAndHeights;
  238. const startFaceNormalAndVertexCornerIds = this
  239. .startFaceNormalAndVertexCornerIds;
  240. const endPositionAndHeights = this.endPositionAndHeights;
  241. const endFaceNormalAndHalfWidths = this.endFaceNormalAndHalfWidths;
  242. const vertexBatchIds = this.vertexBatchIds;
  243. let batchIdOffset = this.batchIdOffset;
  244. let vec3Offset = this.vec3Offset;
  245. let vec4Offset = this.vec4Offset;
  246. let i;
  247. for (i = 0; i < 8; i++) {
  248. Matrix3.Cartesian3.pack(startEllipsoidNormal, startEllipsoidNormals, vec3Offset);
  249. Matrix3.Cartesian3.pack(endEllipsoidNormal, endEllipsoidNormals, vec3Offset);
  250. Matrix3.Cartesian3.pack(startRTC, startPositionAndHeights, vec4Offset);
  251. startPositionAndHeights[vec4Offset + 3] = startHeight;
  252. Matrix3.Cartesian3.pack(endRTC, endPositionAndHeights, vec4Offset);
  253. endPositionAndHeights[vec4Offset + 3] = endHeight;
  254. Matrix3.Cartesian3.pack(
  255. startFaceNormal,
  256. startFaceNormalAndVertexCornerIds,
  257. vec4Offset
  258. );
  259. startFaceNormalAndVertexCornerIds[vec4Offset + 3] = i;
  260. Matrix3.Cartesian3.pack(endFaceNormal, endFaceNormalAndHalfWidths, vec4Offset);
  261. endFaceNormalAndHalfWidths[vec4Offset + 3] = halfWidth;
  262. vertexBatchIds[batchIdOffset++] = batchId;
  263. vec3Offset += 3;
  264. vec4Offset += 4;
  265. }
  266. this.batchIdOffset = batchIdOffset;
  267. this.vec3Offset = vec3Offset;
  268. this.vec4Offset = vec4Offset;
  269. const indices = this.indices;
  270. const volumeStartIndex = this.volumeStartIndex;
  271. const indexOffset = this.indexOffset;
  272. for (i = 0; i < REFERENCE_INDICES_LENGTH; i++) {
  273. indices[indexOffset + i] = REFERENCE_INDICES[i] + volumeStartIndex;
  274. }
  275. this.volumeStartIndex += 8;
  276. this.indexOffset += REFERENCE_INDICES_LENGTH;
  277. };
  278. const scratchRectangle = new Matrix2.Rectangle();
  279. const scratchEllipsoid = new Matrix3.Ellipsoid();
  280. const scratchCenter = new Matrix3.Cartesian3();
  281. const scratchPrev = new Matrix3.Cartesian3();
  282. const scratchP0 = new Matrix3.Cartesian3();
  283. const scratchP1 = new Matrix3.Cartesian3();
  284. const scratchNext = new Matrix3.Cartesian3();
  285. function createVectorTileClampedPolylines(parameters, transferableObjects) {
  286. const encodedPositions = new Uint16Array(parameters.positions);
  287. const widths = new Uint16Array(parameters.widths);
  288. const counts = new Uint32Array(parameters.counts);
  289. const batchIds = new Uint16Array(parameters.batchIds);
  290. // Unpack tile decoding parameters
  291. const rectangle = scratchRectangle;
  292. const ellipsoid = scratchEllipsoid;
  293. const center = scratchCenter;
  294. const packedBuffer = new Float64Array(parameters.packedBuffer);
  295. let offset = 0;
  296. const minimumHeight = packedBuffer[offset++];
  297. const maximumHeight = packedBuffer[offset++];
  298. Matrix2.Rectangle.unpack(packedBuffer, offset, rectangle);
  299. offset += Matrix2.Rectangle.packedLength;
  300. Matrix3.Ellipsoid.unpack(packedBuffer, offset, ellipsoid);
  301. offset += Matrix3.Ellipsoid.packedLength;
  302. Matrix3.Cartesian3.unpack(packedBuffer, offset, center);
  303. let i;
  304. // Unpack positions and generate volumes
  305. let positionsLength = encodedPositions.length / 3;
  306. const uBuffer = encodedPositions.subarray(0, positionsLength);
  307. const vBuffer = encodedPositions.subarray(
  308. positionsLength,
  309. 2 * positionsLength
  310. );
  311. const heightBuffer = encodedPositions.subarray(
  312. 2 * positionsLength,
  313. 3 * positionsLength
  314. );
  315. AttributeCompression.AttributeCompression.zigZagDeltaDecode(uBuffer, vBuffer, heightBuffer);
  316. removeDuplicates(uBuffer, vBuffer, heightBuffer, counts);
  317. // Figure out how many volumes and how many vertices there will be.
  318. const countsLength = counts.length;
  319. let volumesCount = 0;
  320. for (i = 0; i < countsLength; i++) {
  321. const polylinePositionCount = counts[i];
  322. volumesCount += polylinePositionCount - 1;
  323. }
  324. const attribsAndIndices = new VertexAttributesAndIndices(volumesCount);
  325. const positions = decodePositions(
  326. uBuffer,
  327. vBuffer,
  328. heightBuffer,
  329. rectangle,
  330. minimumHeight,
  331. maximumHeight,
  332. ellipsoid);
  333. positionsLength = uBuffer.length;
  334. const positionsRTC = new Float32Array(positionsLength * 3);
  335. for (i = 0; i < positionsLength; ++i) {
  336. positionsRTC[i * 3] = positions[i * 3] - center.x;
  337. positionsRTC[i * 3 + 1] = positions[i * 3 + 1] - center.y;
  338. positionsRTC[i * 3 + 2] = positions[i * 3 + 2] - center.z;
  339. }
  340. let currentPositionIndex = 0;
  341. let currentHeightIndex = 0;
  342. for (i = 0; i < countsLength; i++) {
  343. const polylineVolumeCount = counts[i] - 1;
  344. const halfWidth = widths[i] * 0.5;
  345. const batchId = batchIds[i];
  346. const volumeFirstPositionIndex = currentPositionIndex;
  347. for (let j = 0; j < polylineVolumeCount; j++) {
  348. const volumeStart = Matrix3.Cartesian3.unpack(
  349. positionsRTC,
  350. currentPositionIndex,
  351. scratchP0
  352. );
  353. const volumeEnd = Matrix3.Cartesian3.unpack(
  354. positionsRTC,
  355. currentPositionIndex + 3,
  356. scratchP1
  357. );
  358. let startHeight = heightBuffer[currentHeightIndex];
  359. let endHeight = heightBuffer[currentHeightIndex + 1];
  360. startHeight = Math$1.CesiumMath.lerp(
  361. minimumHeight,
  362. maximumHeight,
  363. startHeight / MAX_SHORT
  364. );
  365. endHeight = Math$1.CesiumMath.lerp(
  366. minimumHeight,
  367. maximumHeight,
  368. endHeight / MAX_SHORT
  369. );
  370. currentHeightIndex++;
  371. let preStart = scratchPrev;
  372. let postEnd = scratchNext;
  373. if (j === 0) {
  374. // Check if this volume is like a loop
  375. const finalPositionIndex =
  376. volumeFirstPositionIndex + polylineVolumeCount * 3;
  377. const finalPosition = Matrix3.Cartesian3.unpack(
  378. positionsRTC,
  379. finalPositionIndex,
  380. scratchPrev
  381. );
  382. if (Matrix3.Cartesian3.equals(finalPosition, volumeStart)) {
  383. Matrix3.Cartesian3.unpack(positionsRTC, finalPositionIndex - 3, preStart);
  384. } else {
  385. const offsetPastStart = Matrix3.Cartesian3.subtract(
  386. volumeStart,
  387. volumeEnd,
  388. scratchPrev
  389. );
  390. preStart = Matrix3.Cartesian3.add(offsetPastStart, volumeStart, scratchPrev);
  391. }
  392. } else {
  393. Matrix3.Cartesian3.unpack(positionsRTC, currentPositionIndex - 3, preStart);
  394. }
  395. if (j === polylineVolumeCount - 1) {
  396. // Check if this volume is like a loop
  397. const firstPosition = Matrix3.Cartesian3.unpack(
  398. positionsRTC,
  399. volumeFirstPositionIndex,
  400. scratchNext
  401. );
  402. if (Matrix3.Cartesian3.equals(firstPosition, volumeEnd)) {
  403. Matrix3.Cartesian3.unpack(
  404. positionsRTC,
  405. volumeFirstPositionIndex + 3,
  406. postEnd
  407. );
  408. } else {
  409. const offsetPastEnd = Matrix3.Cartesian3.subtract(
  410. volumeEnd,
  411. volumeStart,
  412. scratchNext
  413. );
  414. postEnd = Matrix3.Cartesian3.add(offsetPastEnd, volumeEnd, scratchNext);
  415. }
  416. } else {
  417. Matrix3.Cartesian3.unpack(positionsRTC, currentPositionIndex + 6, postEnd);
  418. }
  419. attribsAndIndices.addVolume(
  420. preStart,
  421. volumeStart,
  422. volumeEnd,
  423. postEnd,
  424. startHeight,
  425. endHeight,
  426. halfWidth,
  427. batchId,
  428. center,
  429. ellipsoid
  430. );
  431. currentPositionIndex += 3;
  432. }
  433. currentPositionIndex += 3;
  434. currentHeightIndex++;
  435. }
  436. const indices = attribsAndIndices.indices;
  437. transferableObjects.push(attribsAndIndices.startEllipsoidNormals.buffer);
  438. transferableObjects.push(attribsAndIndices.endEllipsoidNormals.buffer);
  439. transferableObjects.push(attribsAndIndices.startPositionAndHeights.buffer);
  440. transferableObjects.push(
  441. attribsAndIndices.startFaceNormalAndVertexCornerIds.buffer
  442. );
  443. transferableObjects.push(attribsAndIndices.endPositionAndHeights.buffer);
  444. transferableObjects.push(attribsAndIndices.endFaceNormalAndHalfWidths.buffer);
  445. transferableObjects.push(attribsAndIndices.vertexBatchIds.buffer);
  446. transferableObjects.push(indices.buffer);
  447. let results = {
  448. indexDatatype:
  449. indices.BYTES_PER_ELEMENT === 2
  450. ? IndexDatatype.IndexDatatype.UNSIGNED_SHORT
  451. : IndexDatatype.IndexDatatype.UNSIGNED_INT,
  452. startEllipsoidNormals: attribsAndIndices.startEllipsoidNormals.buffer,
  453. endEllipsoidNormals: attribsAndIndices.endEllipsoidNormals.buffer,
  454. startPositionAndHeights: attribsAndIndices.startPositionAndHeights.buffer,
  455. startFaceNormalAndVertexCornerIds:
  456. attribsAndIndices.startFaceNormalAndVertexCornerIds.buffer,
  457. endPositionAndHeights: attribsAndIndices.endPositionAndHeights.buffer,
  458. endFaceNormalAndHalfWidths:
  459. attribsAndIndices.endFaceNormalAndHalfWidths.buffer,
  460. vertexBatchIds: attribsAndIndices.vertexBatchIds.buffer,
  461. indices: indices.buffer,
  462. };
  463. if (parameters.keepDecodedPositions) {
  464. const positionOffsets = getPositionOffsets(counts);
  465. transferableObjects.push(positions.buffer, positionOffsets.buffer);
  466. results = combine.combine(results, {
  467. decodedPositions: positions.buffer,
  468. decodedPositionOffsets: positionOffsets.buffer,
  469. });
  470. }
  471. return results;
  472. }
  473. var createVectorTileClampedPolylines$1 = createTaskProcessorWorker(createVectorTileClampedPolylines);
  474. return createVectorTileClampedPolylines$1;
  475. }));