createVerticesFromGoogleEarthEnterpriseBuffer.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. import AxisAlignedBoundingBox from "../Core/AxisAlignedBoundingBox.js";
  2. import BoundingSphere from "../Core/BoundingSphere.js";
  3. import Cartesian2 from "../Core/Cartesian2.js";
  4. import Cartesian3 from "../Core/Cartesian3.js";
  5. import Cartographic from "../Core/Cartographic.js";
  6. import defaultValue from "../Core/defaultValue.js";
  7. import defined from "../Core/defined.js";
  8. import Ellipsoid from "../Core/Ellipsoid.js";
  9. import EllipsoidalOccluder from "../Core/EllipsoidalOccluder.js";
  10. import CesiumMath from "../Core/Math.js";
  11. import Matrix4 from "../Core/Matrix4.js";
  12. import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";
  13. import Rectangle from "../Core/Rectangle.js";
  14. import RuntimeError from "../Core/RuntimeError.js";
  15. import TerrainEncoding from "../Core/TerrainEncoding.js";
  16. import Transforms from "../Core/Transforms.js";
  17. import WebMercatorProjection from "../Core/WebMercatorProjection.js";
  18. import createTaskProcessorWorker from "./createTaskProcessorWorker.js";
  19. const sizeOfUint16 = Uint16Array.BYTES_PER_ELEMENT;
  20. const sizeOfInt32 = Int32Array.BYTES_PER_ELEMENT;
  21. const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  22. const sizeOfFloat = Float32Array.BYTES_PER_ELEMENT;
  23. const sizeOfDouble = Float64Array.BYTES_PER_ELEMENT;
  24. function indexOfEpsilon(arr, elem, elemType) {
  25. elemType = defaultValue(elemType, CesiumMath);
  26. const count = arr.length;
  27. for (let i = 0; i < count; ++i) {
  28. if (elemType.equalsEpsilon(arr[i], elem, CesiumMath.EPSILON12)) {
  29. return i;
  30. }
  31. }
  32. return -1;
  33. }
  34. function createVerticesFromGoogleEarthEnterpriseBuffer(
  35. parameters,
  36. transferableObjects
  37. ) {
  38. parameters.ellipsoid = Ellipsoid.clone(parameters.ellipsoid);
  39. parameters.rectangle = Rectangle.clone(parameters.rectangle);
  40. const statistics = processBuffer(
  41. parameters.buffer,
  42. parameters.relativeToCenter,
  43. parameters.ellipsoid,
  44. parameters.rectangle,
  45. parameters.nativeRectangle,
  46. parameters.exaggeration,
  47. parameters.exaggerationRelativeHeight,
  48. parameters.skirtHeight,
  49. parameters.includeWebMercatorT,
  50. parameters.negativeAltitudeExponentBias,
  51. parameters.negativeElevationThreshold
  52. );
  53. const vertices = statistics.vertices;
  54. transferableObjects.push(vertices.buffer);
  55. const indices = statistics.indices;
  56. transferableObjects.push(indices.buffer);
  57. return {
  58. vertices: vertices.buffer,
  59. indices: indices.buffer,
  60. numberOfAttributes: statistics.encoding.stride,
  61. minimumHeight: statistics.minimumHeight,
  62. maximumHeight: statistics.maximumHeight,
  63. boundingSphere3D: statistics.boundingSphere3D,
  64. orientedBoundingBox: statistics.orientedBoundingBox,
  65. occludeePointInScaledSpace: statistics.occludeePointInScaledSpace,
  66. encoding: statistics.encoding,
  67. vertexCountWithoutSkirts: statistics.vertexCountWithoutSkirts,
  68. indexCountWithoutSkirts: statistics.indexCountWithoutSkirts,
  69. westIndicesSouthToNorth: statistics.westIndicesSouthToNorth,
  70. southIndicesEastToWest: statistics.southIndicesEastToWest,
  71. eastIndicesNorthToSouth: statistics.eastIndicesNorthToSouth,
  72. northIndicesWestToEast: statistics.northIndicesWestToEast,
  73. };
  74. }
  75. const scratchCartographic = new Cartographic();
  76. const scratchCartesian = new Cartesian3();
  77. const minimumScratch = new Cartesian3();
  78. const maximumScratch = new Cartesian3();
  79. const matrix4Scratch = new Matrix4();
  80. function processBuffer(
  81. buffer,
  82. relativeToCenter,
  83. ellipsoid,
  84. rectangle,
  85. nativeRectangle,
  86. exaggeration,
  87. exaggerationRelativeHeight,
  88. skirtHeight,
  89. includeWebMercatorT,
  90. negativeAltitudeExponentBias,
  91. negativeElevationThreshold
  92. ) {
  93. let geographicWest;
  94. let geographicSouth;
  95. let geographicEast;
  96. let geographicNorth;
  97. let rectangleWidth, rectangleHeight;
  98. if (!defined(rectangle)) {
  99. geographicWest = CesiumMath.toRadians(nativeRectangle.west);
  100. geographicSouth = CesiumMath.toRadians(nativeRectangle.south);
  101. geographicEast = CesiumMath.toRadians(nativeRectangle.east);
  102. geographicNorth = CesiumMath.toRadians(nativeRectangle.north);
  103. rectangleWidth = CesiumMath.toRadians(rectangle.width);
  104. rectangleHeight = CesiumMath.toRadians(rectangle.height);
  105. } else {
  106. geographicWest = rectangle.west;
  107. geographicSouth = rectangle.south;
  108. geographicEast = rectangle.east;
  109. geographicNorth = rectangle.north;
  110. rectangleWidth = rectangle.width;
  111. rectangleHeight = rectangle.height;
  112. }
  113. // Keep track of quad borders so we can remove duplicates around the borders
  114. const quadBorderLatitudes = [geographicSouth, geographicNorth];
  115. const quadBorderLongitudes = [geographicWest, geographicEast];
  116. const fromENU = Transforms.eastNorthUpToFixedFrame(
  117. relativeToCenter,
  118. ellipsoid
  119. );
  120. const toENU = Matrix4.inverseTransformation(fromENU, matrix4Scratch);
  121. let southMercatorY;
  122. let oneOverMercatorHeight;
  123. if (includeWebMercatorT) {
  124. southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  125. geographicSouth
  126. );
  127. oneOverMercatorHeight =
  128. 1.0 /
  129. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(geographicNorth) -
  130. southMercatorY);
  131. }
  132. const hasExaggeration = exaggeration !== 1.0;
  133. const includeGeodeticSurfaceNormals = hasExaggeration;
  134. const dv = new DataView(buffer);
  135. let minHeight = Number.POSITIVE_INFINITY;
  136. let maxHeight = Number.NEGATIVE_INFINITY;
  137. const minimum = minimumScratch;
  138. minimum.x = Number.POSITIVE_INFINITY;
  139. minimum.y = Number.POSITIVE_INFINITY;
  140. minimum.z = Number.POSITIVE_INFINITY;
  141. const maximum = maximumScratch;
  142. maximum.x = Number.NEGATIVE_INFINITY;
  143. maximum.y = Number.NEGATIVE_INFINITY;
  144. maximum.z = Number.NEGATIVE_INFINITY;
  145. // Compute sizes
  146. let offset = 0;
  147. let size = 0;
  148. let indicesSize = 0;
  149. let quadSize;
  150. let quad;
  151. for (quad = 0; quad < 4; ++quad) {
  152. let o = offset;
  153. quadSize = dv.getUint32(o, true);
  154. o += sizeOfUint32;
  155. const x = CesiumMath.toRadians(dv.getFloat64(o, true) * 180.0);
  156. o += sizeOfDouble;
  157. if (indexOfEpsilon(quadBorderLongitudes, x) === -1) {
  158. quadBorderLongitudes.push(x);
  159. }
  160. const y = CesiumMath.toRadians(dv.getFloat64(o, true) * 180.0);
  161. o += sizeOfDouble;
  162. if (indexOfEpsilon(quadBorderLatitudes, y) === -1) {
  163. quadBorderLatitudes.push(y);
  164. }
  165. o += 2 * sizeOfDouble; // stepX + stepY
  166. let c = dv.getInt32(o, true); // Read point count
  167. o += sizeOfInt32;
  168. size += c;
  169. c = dv.getInt32(o, true); // Read index count
  170. indicesSize += c * 3;
  171. offset += quadSize + sizeOfUint32; // Jump to next quad
  172. }
  173. // Quad Border points to remove duplicates
  174. const quadBorderPoints = [];
  175. const quadBorderIndices = [];
  176. // Create arrays
  177. const positions = new Array(size);
  178. const uvs = new Array(size);
  179. const heights = new Array(size);
  180. const webMercatorTs = includeWebMercatorT ? new Array(size) : [];
  181. const geodeticSurfaceNormals = includeGeodeticSurfaceNormals
  182. ? new Array(size)
  183. : [];
  184. const indices = new Array(indicesSize);
  185. // Points are laid out in rows starting at SW, so storing border points as we
  186. // come across them all points will be adjacent.
  187. const westBorder = [];
  188. const southBorder = [];
  189. const eastBorder = [];
  190. const northBorder = [];
  191. // Each tile is split into 4 parts
  192. let pointOffset = 0;
  193. let indicesOffset = 0;
  194. offset = 0;
  195. for (quad = 0; quad < 4; ++quad) {
  196. quadSize = dv.getUint32(offset, true);
  197. offset += sizeOfUint32;
  198. const startQuad = offset;
  199. const originX = CesiumMath.toRadians(dv.getFloat64(offset, true) * 180.0);
  200. offset += sizeOfDouble;
  201. const originY = CesiumMath.toRadians(dv.getFloat64(offset, true) * 180.0);
  202. offset += sizeOfDouble;
  203. const stepX = CesiumMath.toRadians(dv.getFloat64(offset, true) * 180.0);
  204. const halfStepX = stepX * 0.5;
  205. offset += sizeOfDouble;
  206. const stepY = CesiumMath.toRadians(dv.getFloat64(offset, true) * 180.0);
  207. const halfStepY = stepY * 0.5;
  208. offset += sizeOfDouble;
  209. const numPoints = dv.getInt32(offset, true);
  210. offset += sizeOfInt32;
  211. const numFaces = dv.getInt32(offset, true);
  212. offset += sizeOfInt32;
  213. //const level = dv.getInt32(offset, true);
  214. offset += sizeOfInt32;
  215. // Keep track of quad indices to overall tile indices
  216. const indicesMapping = new Array(numPoints);
  217. for (let i = 0; i < numPoints; ++i) {
  218. const longitude = originX + dv.getUint8(offset++) * stepX;
  219. scratchCartographic.longitude = longitude;
  220. const latitude = originY + dv.getUint8(offset++) * stepY;
  221. scratchCartographic.latitude = latitude;
  222. let height = dv.getFloat32(offset, true);
  223. offset += sizeOfFloat;
  224. // In order to support old clients, negative altitude values are stored as
  225. // height/-2^32. Old clients see the value as really close to 0 but new clients multiply
  226. // by -2^32 to get the real negative altitude value.
  227. if (height !== 0 && height < negativeElevationThreshold) {
  228. height *= -Math.pow(2, negativeAltitudeExponentBias);
  229. }
  230. // Height is stored in units of (1/EarthRadius) or (1/6371010.0)
  231. height *= 6371010.0;
  232. scratchCartographic.height = height;
  233. // Is it along a quad border - if so check if already exists and use that index
  234. if (
  235. indexOfEpsilon(quadBorderLongitudes, longitude) !== -1 ||
  236. indexOfEpsilon(quadBorderLatitudes, latitude) !== -1
  237. ) {
  238. const index = indexOfEpsilon(
  239. quadBorderPoints,
  240. scratchCartographic,
  241. Cartographic
  242. );
  243. if (index === -1) {
  244. quadBorderPoints.push(Cartographic.clone(scratchCartographic));
  245. quadBorderIndices.push(pointOffset);
  246. } else {
  247. indicesMapping[i] = quadBorderIndices[index];
  248. continue;
  249. }
  250. }
  251. indicesMapping[i] = pointOffset;
  252. if (Math.abs(longitude - geographicWest) < halfStepX) {
  253. westBorder.push({
  254. index: pointOffset,
  255. cartographic: Cartographic.clone(scratchCartographic),
  256. });
  257. } else if (Math.abs(longitude - geographicEast) < halfStepX) {
  258. eastBorder.push({
  259. index: pointOffset,
  260. cartographic: Cartographic.clone(scratchCartographic),
  261. });
  262. } else if (Math.abs(latitude - geographicSouth) < halfStepY) {
  263. southBorder.push({
  264. index: pointOffset,
  265. cartographic: Cartographic.clone(scratchCartographic),
  266. });
  267. } else if (Math.abs(latitude - geographicNorth) < halfStepY) {
  268. northBorder.push({
  269. index: pointOffset,
  270. cartographic: Cartographic.clone(scratchCartographic),
  271. });
  272. }
  273. minHeight = Math.min(height, minHeight);
  274. maxHeight = Math.max(height, maxHeight);
  275. heights[pointOffset] = height;
  276. const pos = ellipsoid.cartographicToCartesian(scratchCartographic);
  277. positions[pointOffset] = pos;
  278. if (includeWebMercatorT) {
  279. webMercatorTs[pointOffset] =
  280. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(latitude) -
  281. southMercatorY) *
  282. oneOverMercatorHeight;
  283. }
  284. if (includeGeodeticSurfaceNormals) {
  285. const normal = ellipsoid.geodeticSurfaceNormal(pos);
  286. geodeticSurfaceNormals[pointOffset] = normal;
  287. }
  288. Matrix4.multiplyByPoint(toENU, pos, scratchCartesian);
  289. Cartesian3.minimumByComponent(scratchCartesian, minimum, minimum);
  290. Cartesian3.maximumByComponent(scratchCartesian, maximum, maximum);
  291. let u = (longitude - geographicWest) / (geographicEast - geographicWest);
  292. u = CesiumMath.clamp(u, 0.0, 1.0);
  293. let v =
  294. (latitude - geographicSouth) / (geographicNorth - geographicSouth);
  295. v = CesiumMath.clamp(v, 0.0, 1.0);
  296. uvs[pointOffset] = new Cartesian2(u, v);
  297. ++pointOffset;
  298. }
  299. const facesElementCount = numFaces * 3;
  300. for (let j = 0; j < facesElementCount; ++j, ++indicesOffset) {
  301. indices[indicesOffset] = indicesMapping[dv.getUint16(offset, true)];
  302. offset += sizeOfUint16;
  303. }
  304. if (quadSize !== offset - startQuad) {
  305. throw new RuntimeError("Invalid terrain tile.");
  306. }
  307. }
  308. positions.length = pointOffset;
  309. uvs.length = pointOffset;
  310. heights.length = pointOffset;
  311. if (includeWebMercatorT) {
  312. webMercatorTs.length = pointOffset;
  313. }
  314. if (includeGeodeticSurfaceNormals) {
  315. geodeticSurfaceNormals.length = pointOffset;
  316. }
  317. const vertexCountWithoutSkirts = pointOffset;
  318. const indexCountWithoutSkirts = indicesOffset;
  319. // Add skirt points
  320. const skirtOptions = {
  321. hMin: minHeight,
  322. lastBorderPoint: undefined,
  323. skirtHeight: skirtHeight,
  324. toENU: toENU,
  325. ellipsoid: ellipsoid,
  326. minimum: minimum,
  327. maximum: maximum,
  328. };
  329. // Sort counter clockwise from NW corner
  330. // Corner points are in the east/west arrays
  331. westBorder.sort(function (a, b) {
  332. return b.cartographic.latitude - a.cartographic.latitude;
  333. });
  334. southBorder.sort(function (a, b) {
  335. return a.cartographic.longitude - b.cartographic.longitude;
  336. });
  337. eastBorder.sort(function (a, b) {
  338. return a.cartographic.latitude - b.cartographic.latitude;
  339. });
  340. northBorder.sort(function (a, b) {
  341. return b.cartographic.longitude - a.cartographic.longitude;
  342. });
  343. const percentage = 0.00001;
  344. addSkirt(
  345. positions,
  346. heights,
  347. uvs,
  348. webMercatorTs,
  349. geodeticSurfaceNormals,
  350. indices,
  351. skirtOptions,
  352. westBorder,
  353. -percentage * rectangleWidth,
  354. true,
  355. -percentage * rectangleHeight
  356. );
  357. addSkirt(
  358. positions,
  359. heights,
  360. uvs,
  361. webMercatorTs,
  362. geodeticSurfaceNormals,
  363. indices,
  364. skirtOptions,
  365. southBorder,
  366. -percentage * rectangleHeight,
  367. false
  368. );
  369. addSkirt(
  370. positions,
  371. heights,
  372. uvs,
  373. webMercatorTs,
  374. geodeticSurfaceNormals,
  375. indices,
  376. skirtOptions,
  377. eastBorder,
  378. percentage * rectangleWidth,
  379. true,
  380. percentage * rectangleHeight
  381. );
  382. addSkirt(
  383. positions,
  384. heights,
  385. uvs,
  386. webMercatorTs,
  387. geodeticSurfaceNormals,
  388. indices,
  389. skirtOptions,
  390. northBorder,
  391. percentage * rectangleHeight,
  392. false
  393. );
  394. // Since the corner between the north and west sides is in the west array, generate the last
  395. // two triangles between the last north vertex and the first west vertex
  396. if (westBorder.length > 0 && northBorder.length > 0) {
  397. const firstBorderIndex = westBorder[0].index;
  398. const firstSkirtIndex = vertexCountWithoutSkirts;
  399. const lastBorderIndex = northBorder[northBorder.length - 1].index;
  400. const lastSkirtIndex = positions.length - 1;
  401. indices.push(
  402. lastBorderIndex,
  403. lastSkirtIndex,
  404. firstSkirtIndex,
  405. firstSkirtIndex,
  406. firstBorderIndex,
  407. lastBorderIndex
  408. );
  409. }
  410. size = positions.length; // Get new size with skirt vertices
  411. const boundingSphere3D = BoundingSphere.fromPoints(positions);
  412. let orientedBoundingBox;
  413. if (defined(rectangle)) {
  414. orientedBoundingBox = OrientedBoundingBox.fromRectangle(
  415. rectangle,
  416. minHeight,
  417. maxHeight,
  418. ellipsoid
  419. );
  420. }
  421. const occluder = new EllipsoidalOccluder(ellipsoid);
  422. const occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(
  423. relativeToCenter,
  424. positions,
  425. minHeight
  426. );
  427. const aaBox = new AxisAlignedBoundingBox(minimum, maximum, relativeToCenter);
  428. const encoding = new TerrainEncoding(
  429. relativeToCenter,
  430. aaBox,
  431. skirtOptions.hMin,
  432. maxHeight,
  433. fromENU,
  434. false,
  435. includeWebMercatorT,
  436. includeGeodeticSurfaceNormals,
  437. exaggeration,
  438. exaggerationRelativeHeight
  439. );
  440. const vertices = new Float32Array(size * encoding.stride);
  441. let bufferIndex = 0;
  442. for (let k = 0; k < size; ++k) {
  443. bufferIndex = encoding.encode(
  444. vertices,
  445. bufferIndex,
  446. positions[k],
  447. uvs[k],
  448. heights[k],
  449. undefined,
  450. webMercatorTs[k],
  451. geodeticSurfaceNormals[k]
  452. );
  453. }
  454. const westIndicesSouthToNorth = westBorder
  455. .map(function (vertex) {
  456. return vertex.index;
  457. })
  458. .reverse();
  459. const southIndicesEastToWest = southBorder
  460. .map(function (vertex) {
  461. return vertex.index;
  462. })
  463. .reverse();
  464. const eastIndicesNorthToSouth = eastBorder
  465. .map(function (vertex) {
  466. return vertex.index;
  467. })
  468. .reverse();
  469. const northIndicesWestToEast = northBorder
  470. .map(function (vertex) {
  471. return vertex.index;
  472. })
  473. .reverse();
  474. southIndicesEastToWest.unshift(
  475. eastIndicesNorthToSouth[eastIndicesNorthToSouth.length - 1]
  476. );
  477. southIndicesEastToWest.push(westIndicesSouthToNorth[0]);
  478. northIndicesWestToEast.unshift(
  479. westIndicesSouthToNorth[westIndicesSouthToNorth.length - 1]
  480. );
  481. northIndicesWestToEast.push(eastIndicesNorthToSouth[0]);
  482. return {
  483. vertices: vertices,
  484. indices: new Uint16Array(indices),
  485. maximumHeight: maxHeight,
  486. minimumHeight: minHeight,
  487. encoding: encoding,
  488. boundingSphere3D: boundingSphere3D,
  489. orientedBoundingBox: orientedBoundingBox,
  490. occludeePointInScaledSpace: occludeePointInScaledSpace,
  491. vertexCountWithoutSkirts: vertexCountWithoutSkirts,
  492. indexCountWithoutSkirts: indexCountWithoutSkirts,
  493. westIndicesSouthToNorth: westIndicesSouthToNorth,
  494. southIndicesEastToWest: southIndicesEastToWest,
  495. eastIndicesNorthToSouth: eastIndicesNorthToSouth,
  496. northIndicesWestToEast: northIndicesWestToEast,
  497. };
  498. }
  499. function addSkirt(
  500. positions,
  501. heights,
  502. uvs,
  503. webMercatorTs,
  504. geodeticSurfaceNormals,
  505. indices,
  506. skirtOptions,
  507. borderPoints,
  508. fudgeFactor,
  509. eastOrWest,
  510. cornerFudge
  511. ) {
  512. const count = borderPoints.length;
  513. for (let j = 0; j < count; ++j) {
  514. const borderPoint = borderPoints[j];
  515. const borderCartographic = borderPoint.cartographic;
  516. const borderIndex = borderPoint.index;
  517. const currentIndex = positions.length;
  518. const longitude = borderCartographic.longitude;
  519. let latitude = borderCartographic.latitude;
  520. latitude = CesiumMath.clamp(
  521. latitude,
  522. -CesiumMath.PI_OVER_TWO,
  523. CesiumMath.PI_OVER_TWO
  524. ); // Don't go over the poles
  525. const height = borderCartographic.height - skirtOptions.skirtHeight;
  526. skirtOptions.hMin = Math.min(skirtOptions.hMin, height);
  527. Cartographic.fromRadians(longitude, latitude, height, scratchCartographic);
  528. // Adjust sides to angle out
  529. if (eastOrWest) {
  530. scratchCartographic.longitude += fudgeFactor;
  531. }
  532. // Adjust top or bottom to angle out
  533. // Since corners are in the east/west arrays angle the first and last points as well
  534. if (!eastOrWest) {
  535. scratchCartographic.latitude += fudgeFactor;
  536. } else if (j === count - 1) {
  537. scratchCartographic.latitude += cornerFudge;
  538. } else if (j === 0) {
  539. scratchCartographic.latitude -= cornerFudge;
  540. }
  541. const pos = skirtOptions.ellipsoid.cartographicToCartesian(
  542. scratchCartographic
  543. );
  544. positions.push(pos);
  545. heights.push(height);
  546. uvs.push(Cartesian2.clone(uvs[borderIndex])); // Copy UVs from border point
  547. if (webMercatorTs.length > 0) {
  548. webMercatorTs.push(webMercatorTs[borderIndex]);
  549. }
  550. if (geodeticSurfaceNormals.length > 0) {
  551. geodeticSurfaceNormals.push(geodeticSurfaceNormals[borderIndex]);
  552. }
  553. Matrix4.multiplyByPoint(skirtOptions.toENU, pos, scratchCartesian);
  554. const minimum = skirtOptions.minimum;
  555. const maximum = skirtOptions.maximum;
  556. Cartesian3.minimumByComponent(scratchCartesian, minimum, minimum);
  557. Cartesian3.maximumByComponent(scratchCartesian, maximum, maximum);
  558. const lastBorderPoint = skirtOptions.lastBorderPoint;
  559. if (defined(lastBorderPoint)) {
  560. const lastBorderIndex = lastBorderPoint.index;
  561. indices.push(
  562. lastBorderIndex,
  563. currentIndex - 1,
  564. currentIndex,
  565. currentIndex,
  566. borderIndex,
  567. lastBorderIndex
  568. );
  569. }
  570. skirtOptions.lastBorderPoint = borderPoint;
  571. }
  572. }
  573. export default createTaskProcessorWorker(
  574. createVerticesFromGoogleEarthEnterpriseBuffer
  575. );