createVerticesFromGoogleEarthEnterpriseBuffer.js 18 KB

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