decodeI3S.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. /* global require */
  2. import createTaskProcessorWorker from "./createTaskProcessorWorker.js";
  3. import defined from "../Core/defined.js";
  4. import WebMercatorProjection from "../Core/WebMercatorProjection.js";
  5. import Ellipsoid from "../Core/Ellipsoid.js";
  6. import Cartographic from "../Core/Cartographic.js";
  7. import Cartesian3 from "../Core/Cartesian3.js";
  8. import Matrix3 from "../Core/Matrix3.js";
  9. import CesiumMath from "../Core/Math.js";
  10. let draco;
  11. function bilinearInterpolate(tx, ty, h00, h10, h01, h11) {
  12. const a = h00 * (1 - tx) + h10 * tx;
  13. const b = h01 * (1 - tx) + h11 * tx;
  14. return a * (1 - ty) + b * ty;
  15. }
  16. function sampleMap(u, v, width, data) {
  17. const address = u + v * width;
  18. return data[address];
  19. }
  20. function sampleGeoid(sampleX, sampleY, geoidData) {
  21. const extent = geoidData.nativeExtent;
  22. let x =
  23. ((sampleX - extent.west) / (extent.east - extent.west)) *
  24. (geoidData.width - 1);
  25. let y =
  26. ((sampleY - extent.south) / (extent.north - extent.south)) *
  27. (geoidData.height - 1);
  28. const xi = Math.floor(x);
  29. let yi = Math.floor(y);
  30. x -= xi;
  31. y -= yi;
  32. const xNext = xi < geoidData.width ? xi + 1 : xi;
  33. let yNext = yi < geoidData.height ? yi + 1 : yi;
  34. yi = geoidData.height - 1 - yi;
  35. yNext = geoidData.height - 1 - yNext;
  36. const h00 = sampleMap(xi, yi, geoidData.width, geoidData.buffer);
  37. const h10 = sampleMap(xNext, yi, geoidData.width, geoidData.buffer);
  38. const h01 = sampleMap(xi, yNext, geoidData.width, geoidData.buffer);
  39. const h11 = sampleMap(xNext, yNext, geoidData.width, geoidData.buffer);
  40. let finalHeight = bilinearInterpolate(x, y, h00, h10, h01, h11);
  41. finalHeight = finalHeight * geoidData.scale + geoidData.offset;
  42. return finalHeight;
  43. }
  44. function sampleGeoidFromList(lon, lat, geoidDataList) {
  45. for (let i = 0; i < geoidDataList.length; i++) {
  46. const localExtent = geoidDataList[i].nativeExtent;
  47. let localPt = new Cartesian3();
  48. if (geoidDataList[i].projectionType === "WebMercator") {
  49. const radii = geoidDataList[i].projection._ellipsoid._radii;
  50. const webMercatorProj = new WebMercatorProjection(
  51. new Ellipsoid(radii.x, radii.y, radii.z)
  52. );
  53. localPt = webMercatorProj.project(new Cartographic(lon, lat, 0));
  54. } else {
  55. localPt.x = lon;
  56. localPt.y = lat;
  57. }
  58. if (
  59. localPt.x > localExtent.west &&
  60. localPt.x < localExtent.east &&
  61. localPt.y > localExtent.south &&
  62. localPt.y < localExtent.north
  63. ) {
  64. return sampleGeoid(localPt.x, localPt.y, geoidDataList[i]);
  65. }
  66. }
  67. return 0;
  68. }
  69. function orthometricToEllipsoidal(
  70. vertexCount,
  71. position,
  72. scale_x,
  73. scale_y,
  74. center,
  75. geoidDataList,
  76. fast
  77. ) {
  78. if (fast) {
  79. // Geometry is already relative to the tile origin which has already been shifted to account for geoid height
  80. // Nothing to do here
  81. return;
  82. }
  83. // For more precision, sample the geoid height at each vertex and shift by the difference between that value and the height at the center of the tile
  84. const centerHeight = sampleGeoidFromList(
  85. center.longitude,
  86. center.latitude,
  87. geoidDataList
  88. );
  89. for (let i = 0; i < vertexCount; ++i) {
  90. const height = sampleGeoidFromList(
  91. center.longitude + CesiumMath.toRadians(scale_x * position[i * 3]),
  92. center.latitude + CesiumMath.toRadians(scale_y * position[i * 3 + 1]),
  93. geoidDataList
  94. );
  95. position[i * 3 + 2] += height - centerHeight;
  96. }
  97. }
  98. function transformToLocal(
  99. vertexCount,
  100. positions,
  101. normals,
  102. cartographicCenter,
  103. cartesianCenter,
  104. parentRotation,
  105. ellipsoidRadiiSquare,
  106. scale_x,
  107. scale_y
  108. ) {
  109. if (vertexCount === 0 || !defined(positions) || positions.length === 0) {
  110. return;
  111. }
  112. const ellipsoid = new Ellipsoid(
  113. Math.sqrt(ellipsoidRadiiSquare.x),
  114. Math.sqrt(ellipsoidRadiiSquare.y),
  115. Math.sqrt(ellipsoidRadiiSquare.z)
  116. );
  117. for (let i = 0; i < vertexCount; ++i) {
  118. const indexOffset = i * 3;
  119. const indexOffset1 = indexOffset + 1;
  120. const indexOffset2 = indexOffset + 2;
  121. const cartographic = new Cartographic();
  122. cartographic.longitude =
  123. cartographicCenter.longitude +
  124. CesiumMath.toRadians(scale_x * positions[indexOffset]);
  125. cartographic.latitude =
  126. cartographicCenter.latitude +
  127. CesiumMath.toRadians(scale_y * positions[indexOffset1]);
  128. cartographic.height = cartographicCenter.height + positions[indexOffset2];
  129. const position = {};
  130. ellipsoid.cartographicToCartesian(cartographic, position);
  131. position.x -= cartesianCenter.x;
  132. position.y -= cartesianCenter.y;
  133. position.z -= cartesianCenter.z;
  134. const rotatedPosition = {};
  135. Matrix3.multiplyByVector(parentRotation, position, rotatedPosition);
  136. positions[indexOffset] = rotatedPosition.x;
  137. positions[indexOffset1] = rotatedPosition.y;
  138. positions[indexOffset2] = rotatedPosition.z;
  139. if (defined(normals)) {
  140. const normal = new Cartesian3(
  141. normals[indexOffset],
  142. normals[indexOffset1],
  143. normals[indexOffset2]
  144. );
  145. const rotatedNormal = {};
  146. Matrix3.multiplyByVector(parentRotation, normal, rotatedNormal);
  147. // TODO: check if normals are Z-UP or Y-UP and flip y and z
  148. normals[indexOffset] = rotatedNormal.x;
  149. normals[indexOffset1] = rotatedNormal.y;
  150. normals[indexOffset2] = rotatedNormal.z;
  151. }
  152. }
  153. }
  154. function cropUVs(vertexCount, uv0s, uvRegions) {
  155. for (let vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
  156. const minU = uvRegions[vertexIndex * 4] / 65535.0;
  157. const minV = uvRegions[vertexIndex * 4 + 1] / 65535.0;
  158. const scaleU =
  159. (uvRegions[vertexIndex * 4 + 2] - uvRegions[vertexIndex * 4]) / 65535.0;
  160. const scaleV =
  161. (uvRegions[vertexIndex * 4 + 3] - uvRegions[vertexIndex * 4 + 1]) /
  162. 65535.0;
  163. uv0s[vertexIndex * 2] *= scaleU;
  164. uv0s[vertexIndex * 2] += minU;
  165. uv0s[vertexIndex * 2 + 1] *= scaleV;
  166. uv0s[vertexIndex * 2 + 1] += minV;
  167. }
  168. }
  169. function generateGltfBuffer(
  170. vertexCount,
  171. indices,
  172. positions,
  173. normals,
  174. uv0s,
  175. colors
  176. ) {
  177. if (vertexCount === 0 || !defined(positions) || positions.length === 0) {
  178. return {
  179. buffers: [],
  180. bufferViews: [],
  181. accessors: [],
  182. meshes: [],
  183. nodes: [],
  184. nodesInScene: [],
  185. };
  186. }
  187. const buffers = [];
  188. const bufferViews = [];
  189. const accessors = [];
  190. const meshes = [];
  191. const nodes = [];
  192. const nodesInScene = [];
  193. // If we provide indices, then the vertex count is the length
  194. // of that array, otherwise we assume non-indexed triangle
  195. if (defined(indices)) {
  196. vertexCount = indices.length;
  197. }
  198. // Allocate array
  199. const indexArray = new Uint32Array(vertexCount);
  200. if (defined(indices)) {
  201. // Set the indices
  202. for (let vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
  203. indexArray[vertexIndex] = indices[vertexIndex];
  204. }
  205. } else {
  206. // Generate indices
  207. for (
  208. let newVertexIndex = 0;
  209. newVertexIndex < vertexCount;
  210. ++newVertexIndex
  211. ) {
  212. indexArray[newVertexIndex] = newVertexIndex;
  213. }
  214. }
  215. // Push to the buffers, bufferViews and accessors
  216. const indicesBlob = new Blob([indexArray], { type: "application/binary" });
  217. const indicesURL = URL.createObjectURL(indicesBlob);
  218. const endIndex = vertexCount;
  219. // POSITIONS
  220. const meshPositions = positions.subarray(0, endIndex * 3);
  221. const positionsBlob = new Blob([meshPositions], {
  222. type: "application/binary",
  223. });
  224. const positionsURL = URL.createObjectURL(positionsBlob);
  225. let minX = Number.POSITIVE_INFINITY;
  226. let maxX = Number.NEGATIVE_INFINITY;
  227. let minY = Number.POSITIVE_INFINITY;
  228. let maxY = Number.NEGATIVE_INFINITY;
  229. let minZ = Number.POSITIVE_INFINITY;
  230. let maxZ = Number.NEGATIVE_INFINITY;
  231. for (let i = 0; i < meshPositions.length / 3; i++) {
  232. minX = Math.min(minX, meshPositions[i * 3 + 0]);
  233. maxX = Math.max(maxX, meshPositions[i * 3 + 0]);
  234. minY = Math.min(minY, meshPositions[i * 3 + 1]);
  235. maxY = Math.max(maxY, meshPositions[i * 3 + 1]);
  236. minZ = Math.min(minZ, meshPositions[i * 3 + 2]);
  237. maxZ = Math.max(maxZ, meshPositions[i * 3 + 2]);
  238. }
  239. // NORMALS
  240. const meshNormals = normals ? normals.subarray(0, endIndex * 3) : undefined;
  241. let normalsURL;
  242. if (defined(meshNormals)) {
  243. const normalsBlob = new Blob([meshNormals], {
  244. type: "application/binary",
  245. });
  246. normalsURL = URL.createObjectURL(normalsBlob);
  247. }
  248. // UV0s
  249. const meshUv0s = uv0s ? uv0s.subarray(0, endIndex * 2) : undefined;
  250. let uv0URL;
  251. if (defined(meshUv0s)) {
  252. const uv0Blob = new Blob([meshUv0s], { type: "application/binary" });
  253. uv0URL = URL.createObjectURL(uv0Blob);
  254. }
  255. // COLORS
  256. const meshColorsInBytes = defined(colors)
  257. ? colors.subarray(0, endIndex * 4)
  258. : undefined;
  259. let colorsURL;
  260. if (defined(meshColorsInBytes)) {
  261. const colorsBlob = new Blob([meshColorsInBytes], {
  262. type: "application/binary",
  263. });
  264. colorsURL = URL.createObjectURL(colorsBlob);
  265. }
  266. const posIndex = 0;
  267. let normalIndex = 0;
  268. let uv0Index = 0;
  269. let colorIndex = 0;
  270. let indicesIndex = 0;
  271. let currentIndex = posIndex;
  272. const attributes = {};
  273. // POSITIONS
  274. attributes.POSITION = posIndex;
  275. buffers.push({
  276. uri: positionsURL,
  277. byteLength: meshPositions.byteLength,
  278. });
  279. bufferViews.push({
  280. buffer: posIndex,
  281. byteOffset: 0,
  282. byteLength: meshPositions.byteLength,
  283. target: 34962,
  284. });
  285. accessors.push({
  286. bufferView: posIndex,
  287. byteOffset: 0,
  288. componentType: 5126,
  289. count: vertexCount,
  290. type: "VEC3",
  291. max: [minX, minY, minZ],
  292. min: [maxX, maxY, maxZ],
  293. });
  294. // NORMALS
  295. if (defined(normalsURL)) {
  296. ++currentIndex;
  297. normalIndex = currentIndex;
  298. attributes.NORMAL = normalIndex;
  299. buffers.push({
  300. uri: normalsURL,
  301. byteLength: meshNormals.byteLength,
  302. });
  303. bufferViews.push({
  304. buffer: normalIndex,
  305. byteOffset: 0,
  306. byteLength: meshNormals.byteLength,
  307. target: 34962,
  308. });
  309. accessors.push({
  310. bufferView: normalIndex,
  311. byteOffset: 0,
  312. componentType: 5126,
  313. count: vertexCount,
  314. type: "VEC3",
  315. });
  316. }
  317. // UV0
  318. if (defined(uv0URL)) {
  319. ++currentIndex;
  320. uv0Index = currentIndex;
  321. attributes.TEXCOORD_0 = uv0Index;
  322. buffers.push({
  323. uri: uv0URL,
  324. byteLength: meshUv0s.byteLength,
  325. });
  326. bufferViews.push({
  327. buffer: uv0Index,
  328. byteOffset: 0,
  329. byteLength: meshUv0s.byteLength,
  330. target: 34962,
  331. });
  332. accessors.push({
  333. bufferView: uv0Index,
  334. byteOffset: 0,
  335. componentType: 5126,
  336. count: vertexCount,
  337. type: "VEC2",
  338. });
  339. }
  340. // COLORS
  341. if (defined(colorsURL)) {
  342. ++currentIndex;
  343. colorIndex = currentIndex;
  344. attributes.COLOR_0 = colorIndex;
  345. buffers.push({
  346. uri: colorsURL,
  347. byteLength: meshColorsInBytes.byteLength,
  348. });
  349. bufferViews.push({
  350. buffer: colorIndex,
  351. byteOffset: 0,
  352. byteLength: meshColorsInBytes.byteLength,
  353. target: 34962,
  354. });
  355. accessors.push({
  356. bufferView: colorIndex,
  357. byteOffset: 0,
  358. componentType: 5121,
  359. normalized: true,
  360. count: vertexCount,
  361. type: "VEC4",
  362. });
  363. }
  364. // INDICES
  365. ++currentIndex;
  366. indicesIndex = currentIndex;
  367. buffers.push({
  368. uri: indicesURL,
  369. byteLength: indexArray.byteLength,
  370. });
  371. bufferViews.push({
  372. buffer: indicesIndex,
  373. byteOffset: 0,
  374. byteLength: indexArray.byteLength,
  375. target: 34963,
  376. });
  377. accessors.push({
  378. bufferView: indicesIndex,
  379. byteOffset: 0,
  380. componentType: 5125,
  381. count: vertexCount,
  382. type: "SCALAR",
  383. });
  384. // Create a new mesh for this page
  385. meshes.push({
  386. primitives: [
  387. {
  388. attributes: attributes,
  389. indices: indicesIndex,
  390. material: 0,
  391. },
  392. ],
  393. });
  394. nodesInScene.push(0);
  395. nodes.push({ mesh: 0 });
  396. return {
  397. buffers: buffers,
  398. bufferViews: bufferViews,
  399. accessors: accessors,
  400. meshes: meshes,
  401. nodes: nodes,
  402. nodesInScene: nodesInScene,
  403. };
  404. }
  405. function decode(data, schema, bufferInfo, featureData) {
  406. const magicNumber = new Uint8Array(data, 0, 5);
  407. if (
  408. magicNumber[0] === "D".charCodeAt() &&
  409. magicNumber[1] === "R".charCodeAt() &&
  410. magicNumber[2] === "A".charCodeAt() &&
  411. magicNumber[3] === "C".charCodeAt() &&
  412. magicNumber[4] === "O".charCodeAt()
  413. ) {
  414. return decodeDracoEncodedGeometry(data, bufferInfo);
  415. }
  416. return decodeBinaryGeometry(data, schema, bufferInfo, featureData);
  417. }
  418. function decodeDracoEncodedGeometry(data) {
  419. // Create the Draco decoder.
  420. const dracoDecoderModule = draco;
  421. const buffer = new dracoDecoderModule.DecoderBuffer();
  422. const byteArray = new Uint8Array(data);
  423. buffer.Init(byteArray, byteArray.length);
  424. // Create a buffer to hold the encoded data.
  425. const dracoDecoder = new dracoDecoderModule.Decoder();
  426. const geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  427. const metadataQuerier = new dracoDecoderModule.MetadataQuerier();
  428. // Decode the encoded geometry.
  429. // See: https://github.com/google/draco/blob/master/src/draco/javascript/emscripten/draco_web_decoder.idl
  430. let dracoGeometry;
  431. let status;
  432. if (geometryType === dracoDecoderModule.TRIANGULAR_MESH) {
  433. dracoGeometry = new dracoDecoderModule.Mesh();
  434. status = dracoDecoder.DecodeBufferToMesh(buffer, dracoGeometry);
  435. }
  436. const decodedGeometry = {
  437. vertexCount: [0],
  438. featureCount: 0,
  439. };
  440. // if all is OK
  441. if (defined(status) && status.ok() && dracoGeometry.ptr !== 0) {
  442. const faceCount = dracoGeometry.num_faces();
  443. const attributesCount = dracoGeometry.num_attributes();
  444. const vertexCount = dracoGeometry.num_points();
  445. decodedGeometry.indices = new Uint32Array(faceCount * 3);
  446. const faces = decodedGeometry.indices;
  447. decodedGeometry.vertexCount[0] = vertexCount;
  448. decodedGeometry.scale_x = 1;
  449. decodedGeometry.scale_y = 1;
  450. // Decode faces
  451. // @TODO: Replace that code with GetTrianglesUInt32Array for better efficiency
  452. const face = new dracoDecoderModule.DracoInt32Array(3);
  453. for (let faceIndex = 0; faceIndex < faceCount; ++faceIndex) {
  454. dracoDecoder.GetFaceFromMesh(dracoGeometry, faceIndex, face);
  455. faces[faceIndex * 3] = face.GetValue(0);
  456. faces[faceIndex * 3 + 1] = face.GetValue(1);
  457. faces[faceIndex * 3 + 2] = face.GetValue(2);
  458. }
  459. dracoDecoderModule.destroy(face);
  460. for (let attrIndex = 0; attrIndex < attributesCount; ++attrIndex) {
  461. const dracoAttribute = dracoDecoder.GetAttribute(
  462. dracoGeometry,
  463. attrIndex
  464. );
  465. const attributeData = decodeDracoAttribute(
  466. dracoDecoderModule,
  467. dracoDecoder,
  468. dracoGeometry,
  469. dracoAttribute,
  470. vertexCount
  471. );
  472. // initial mapping
  473. const dracoAttributeType = dracoAttribute.attribute_type();
  474. let attributei3sName = "unknown";
  475. if (dracoAttributeType === dracoDecoderModule.POSITION) {
  476. attributei3sName = "positions";
  477. } else if (dracoAttributeType === dracoDecoderModule.NORMAL) {
  478. attributei3sName = "normals";
  479. } else if (dracoAttributeType === dracoDecoderModule.COLOR) {
  480. attributei3sName = "colors";
  481. } else if (dracoAttributeType === dracoDecoderModule.TEX_COORD) {
  482. attributei3sName = "uv0s";
  483. }
  484. // get the metadata
  485. const metadata = dracoDecoder.GetAttributeMetadata(
  486. dracoGeometry,
  487. attrIndex
  488. );
  489. if (metadata.ptr !== 0) {
  490. const numEntries = metadataQuerier.NumEntries(metadata);
  491. for (let entry = 0; entry < numEntries; ++entry) {
  492. const entryName = metadataQuerier.GetEntryName(metadata, entry);
  493. if (entryName === "i3s-scale_x") {
  494. decodedGeometry.scale_x = metadataQuerier.GetDoubleEntry(
  495. metadata,
  496. "i3s-scale_x"
  497. );
  498. } else if (entryName === "i3s-scale_y") {
  499. decodedGeometry.scale_y = metadataQuerier.GetDoubleEntry(
  500. metadata,
  501. "i3s-scale_y"
  502. );
  503. } else if (entryName === "i3s-attribute-type") {
  504. attributei3sName = metadataQuerier.GetStringEntry(
  505. metadata,
  506. "i3s-attribute-type"
  507. );
  508. }
  509. }
  510. }
  511. if (defined(decodedGeometry[attributei3sName])) {
  512. console.log("Attribute already exists", attributei3sName);
  513. }
  514. decodedGeometry[attributei3sName] = attributeData;
  515. if (attributei3sName === "feature-index") {
  516. decodedGeometry.featureCount++;
  517. }
  518. }
  519. dracoDecoderModule.destroy(dracoGeometry);
  520. }
  521. dracoDecoderModule.destroy(metadataQuerier);
  522. dracoDecoderModule.destroy(dracoDecoder);
  523. return decodedGeometry;
  524. }
  525. function decodeDracoAttribute(
  526. dracoDecoderModule,
  527. dracoDecoder,
  528. dracoGeometry,
  529. dracoAttribute,
  530. vertexCount
  531. ) {
  532. const bufferSize = dracoAttribute.num_components() * vertexCount;
  533. let dracoAttributeData;
  534. const handlers = [
  535. function () {}, // DT_INVALID - 0
  536. function () {
  537. // DT_INT8 - 1
  538. dracoAttributeData = new dracoDecoderModule.DracoInt8Array(bufferSize);
  539. const success = dracoDecoder.GetAttributeInt8ForAllPoints(
  540. dracoGeometry,
  541. dracoAttribute,
  542. dracoAttributeData
  543. );
  544. if (!success) {
  545. console.error("Bad stream");
  546. }
  547. const attributeData = new Int8Array(bufferSize);
  548. for (let i = 0; i < bufferSize; ++i) {
  549. attributeData[i] = dracoAttributeData.GetValue(i);
  550. }
  551. return attributeData;
  552. },
  553. function () {
  554. // DT_UINT8 - 2
  555. dracoAttributeData = new dracoDecoderModule.DracoInt8Array(bufferSize);
  556. const success = dracoDecoder.GetAttributeUInt8ForAllPoints(
  557. dracoGeometry,
  558. dracoAttribute,
  559. dracoAttributeData
  560. );
  561. if (!success) {
  562. console.error("Bad stream");
  563. }
  564. const attributeData = new Uint8Array(bufferSize);
  565. for (let i = 0; i < bufferSize; ++i) {
  566. attributeData[i] = dracoAttributeData.GetValue(i);
  567. }
  568. return attributeData;
  569. },
  570. function () {
  571. // DT_INT16 - 3
  572. dracoAttributeData = new dracoDecoderModule.DracoInt16Array(bufferSize);
  573. const success = dracoDecoder.GetAttributeInt16ForAllPoints(
  574. dracoGeometry,
  575. dracoAttribute,
  576. dracoAttributeData
  577. );
  578. if (!success) {
  579. console.error("Bad stream");
  580. }
  581. const attributeData = new Int16Array(bufferSize);
  582. for (let i = 0; i < bufferSize; ++i) {
  583. attributeData[i] = dracoAttributeData.GetValue(i);
  584. }
  585. return attributeData;
  586. },
  587. function () {
  588. // DT_UINT16 - 4
  589. dracoAttributeData = new dracoDecoderModule.DracoInt16Array(bufferSize);
  590. const success = dracoDecoder.GetAttributeUInt16ForAllPoints(
  591. dracoGeometry,
  592. dracoAttribute,
  593. dracoAttributeData
  594. );
  595. if (!success) {
  596. console.error("Bad stream");
  597. }
  598. const attributeData = new Uint16Array(bufferSize);
  599. for (let i = 0; i < bufferSize; ++i) {
  600. attributeData[i] = dracoAttributeData.GetValue(i);
  601. }
  602. return attributeData;
  603. },
  604. function () {
  605. // DT_INT32 - 5
  606. dracoAttributeData = new dracoDecoderModule.DracoInt32Array(bufferSize);
  607. const success = dracoDecoder.GetAttributeInt32ForAllPoints(
  608. dracoGeometry,
  609. dracoAttribute,
  610. dracoAttributeData
  611. );
  612. if (!success) {
  613. console.error("Bad stream");
  614. }
  615. const attributeData = new Int32Array(bufferSize);
  616. for (let i = 0; i < bufferSize; ++i) {
  617. attributeData[i] = dracoAttributeData.GetValue(i);
  618. }
  619. return attributeData;
  620. },
  621. function () {
  622. // DT_UINT32 - 6
  623. dracoAttributeData = new dracoDecoderModule.DracoInt32Array(bufferSize);
  624. const success = dracoDecoder.GetAttributeUInt32ForAllPoints(
  625. dracoGeometry,
  626. dracoAttribute,
  627. dracoAttributeData
  628. );
  629. if (!success) {
  630. console.error("Bad stream");
  631. }
  632. const attributeData = new Uint32Array(bufferSize);
  633. for (let i = 0; i < bufferSize; ++i) {
  634. attributeData[i] = dracoAttributeData.GetValue(i);
  635. }
  636. return attributeData;
  637. },
  638. function () {
  639. // DT_INT64 - 7
  640. },
  641. function () {
  642. // DT_UINT64 - 8
  643. },
  644. function () {
  645. // DT_FLOAT32 - 9
  646. dracoAttributeData = new dracoDecoderModule.DracoFloat32Array(bufferSize);
  647. const success = dracoDecoder.GetAttributeFloatForAllPoints(
  648. dracoGeometry,
  649. dracoAttribute,
  650. dracoAttributeData
  651. );
  652. if (!success) {
  653. console.error("Bad stream");
  654. }
  655. const attributeData = new Float32Array(bufferSize);
  656. for (let i = 0; i < bufferSize; ++i) {
  657. attributeData[i] = dracoAttributeData.GetValue(i);
  658. }
  659. return attributeData;
  660. },
  661. function () {
  662. // DT_FLOAT64 - 10
  663. },
  664. function () {
  665. // DT_FLOAT32 - 11
  666. dracoAttributeData = new dracoDecoderModule.DracoUInt8Array(bufferSize);
  667. const success = dracoDecoder.GetAttributeUInt8ForAllPoints(
  668. dracoGeometry,
  669. dracoAttribute,
  670. dracoAttributeData
  671. );
  672. if (!success) {
  673. console.error("Bad stream");
  674. }
  675. const attributeData = new Uint8Array(bufferSize);
  676. for (let i = 0; i < bufferSize; ++i) {
  677. attributeData[i] = dracoAttributeData.GetValue(i);
  678. }
  679. return attributeData;
  680. },
  681. ];
  682. const attributeData = handlers[dracoAttribute.data_type()]();
  683. if (defined(dracoAttributeData)) {
  684. dracoDecoderModule.destroy(dracoAttributeData);
  685. }
  686. return attributeData;
  687. }
  688. const binaryAttributeDecoders = {
  689. position: function (decodedGeometry, data, offset) {
  690. const count = decodedGeometry.vertexCount * 3;
  691. decodedGeometry.positions = new Float32Array(data, offset, count);
  692. offset += count * 4;
  693. return offset;
  694. },
  695. normal: function (decodedGeometry, data, offset) {
  696. const count = decodedGeometry.vertexCount * 3;
  697. decodedGeometry.normals = new Float32Array(data, offset, count);
  698. offset += count * 4;
  699. return offset;
  700. },
  701. uv0: function (decodedGeometry, data, offset) {
  702. const count = decodedGeometry.vertexCount * 2;
  703. decodedGeometry.uv0s = new Float32Array(data, offset, count);
  704. offset += count * 4;
  705. return offset;
  706. },
  707. color: function (decodedGeometry, data, offset) {
  708. const count = decodedGeometry.vertexCount * 4;
  709. decodedGeometry.colors = new Uint8Array(data, offset, count);
  710. offset += count;
  711. return offset;
  712. },
  713. featureId: function (decodedGeometry, data, offset) {
  714. // We don't need to use this for anything so just increment the offset
  715. const count = decodedGeometry.featureCount;
  716. offset += count * 8;
  717. return offset;
  718. },
  719. id: function (decodedGeometry, data, offset) {
  720. // We don't need to use this for anything so just increment the offset
  721. const count = decodedGeometry.featureCount;
  722. offset += count * 8;
  723. return offset;
  724. },
  725. faceRange: function (decodedGeometry, data, offset) {
  726. const count = decodedGeometry.featureCount * 2;
  727. decodedGeometry.faceRange = new Uint32Array(data, offset, count);
  728. offset += count * 4;
  729. return offset;
  730. },
  731. uvRegion: function (decodedGeometry, data, offset) {
  732. const count = decodedGeometry.vertexCount * 4;
  733. decodedGeometry["uv-region"] = new Uint16Array(data, offset, count);
  734. offset += count * 2;
  735. return offset;
  736. },
  737. region: function (decodedGeometry, data, offset) {
  738. const count = decodedGeometry.vertexCount * 4;
  739. decodedGeometry["uv-region"] = new Uint16Array(data, offset, count);
  740. offset += count * 2;
  741. return offset;
  742. },
  743. };
  744. function decodeBinaryGeometry(data, schema, bufferInfo, featureData) {
  745. // From this spec:
  746. // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/defaultGeometrySchema.cmn.md
  747. const decodedGeometry = {
  748. vertexCount: 0,
  749. };
  750. const dataView = new DataView(data);
  751. try {
  752. let offset = 0;
  753. decodedGeometry.vertexCount = dataView.getUint32(offset, 1);
  754. offset += 4;
  755. decodedGeometry.featureCount = dataView.getUint32(offset, 1);
  756. offset += 4;
  757. if (defined(bufferInfo)) {
  758. for (
  759. let attrIndex = 0;
  760. attrIndex < bufferInfo.attributes.length;
  761. attrIndex++
  762. ) {
  763. if (
  764. defined(binaryAttributeDecoders[bufferInfo.attributes[attrIndex]])
  765. ) {
  766. offset = binaryAttributeDecoders[bufferInfo.attributes[attrIndex]](
  767. decodedGeometry,
  768. data,
  769. offset
  770. );
  771. } else {
  772. console.error(
  773. "Unknown decoder for",
  774. bufferInfo.attributes[attrIndex]
  775. );
  776. }
  777. }
  778. } else {
  779. let ordering = schema.ordering;
  780. let featureAttributeOrder = schema.featureAttributeOrder;
  781. if (
  782. defined(featureData) &&
  783. defined(featureData.geometryData) &&
  784. defined(featureData.geometryData[0]) &&
  785. defined(featureData.geometryData[0].params)
  786. ) {
  787. ordering = Object.keys(
  788. featureData.geometryData[0].params.vertexAttributes
  789. );
  790. featureAttributeOrder = Object.keys(
  791. featureData.geometryData[0].params.featureAttributes
  792. );
  793. }
  794. // Use default geometry schema
  795. for (let i = 0; i < ordering.length; i++) {
  796. const decoder = binaryAttributeDecoders[ordering[i]];
  797. if (!defined(decoder)) {
  798. console.log(ordering[i]);
  799. }
  800. offset = decoder(decodedGeometry, data, offset);
  801. }
  802. for (let j = 0; j < featureAttributeOrder.length; j++) {
  803. const curDecoder = binaryAttributeDecoders[featureAttributeOrder[j]];
  804. if (!defined(curDecoder)) {
  805. console.log(featureAttributeOrder[j]);
  806. }
  807. offset = curDecoder(decodedGeometry, data, offset);
  808. }
  809. }
  810. } catch (e) {
  811. console.error(e);
  812. }
  813. decodedGeometry.scale_x = 1;
  814. decodedGeometry.scale_y = 1;
  815. return decodedGeometry;
  816. }
  817. function decodeI3S(parameters) {
  818. // Decode the data into geometry
  819. const geometryData = decode(
  820. parameters.binaryData,
  821. parameters.schema,
  822. parameters.bufferInfo,
  823. parameters.featureData
  824. );
  825. // Adjust height from orthometric to ellipsoidal
  826. if (
  827. defined(parameters.geoidDataList) &&
  828. parameters.geoidDataList.length > 0
  829. ) {
  830. orthometricToEllipsoidal(
  831. geometryData.vertexCount,
  832. geometryData.positions,
  833. geometryData.scale_x,
  834. geometryData.scale_y,
  835. parameters.cartographicCenter,
  836. parameters.geoidDataList,
  837. false
  838. );
  839. }
  840. // Transform vertices to local
  841. transformToLocal(
  842. geometryData.vertexCount,
  843. geometryData.positions,
  844. geometryData.normals,
  845. parameters.cartographicCenter,
  846. parameters.cartesianCenter,
  847. parameters.parentRotation,
  848. parameters.ellipsoidRadiiSquare,
  849. geometryData.scale_x,
  850. geometryData.scale_y
  851. );
  852. // Adjust UVs if there is a UV region
  853. if (defined(geometryData.uv0s) && defined(geometryData["uv-region"])) {
  854. cropUVs(
  855. geometryData.vertexCount,
  856. geometryData.uv0s,
  857. geometryData["uv-region"]
  858. );
  859. }
  860. // Create the final buffer
  861. const meshData = generateGltfBuffer(
  862. geometryData.vertexCount,
  863. geometryData.indices,
  864. geometryData.positions,
  865. geometryData.normals,
  866. geometryData.uv0s,
  867. geometryData.colors
  868. );
  869. const customAttributes = {};
  870. if (defined(geometryData["feature-index"])) {
  871. customAttributes.positions = geometryData.positions;
  872. customAttributes.indices = geometryData.indices;
  873. customAttributes.featureIndex = geometryData["feature-index"];
  874. customAttributes.cartesianCenter = parameters.cartesianCenter;
  875. customAttributes.parentRotation = parameters.parentRotation;
  876. } else if (defined(geometryData["faceRange"])) {
  877. customAttributes.positions = geometryData.positions;
  878. customAttributes.indices = geometryData.indices;
  879. customAttributes.sourceURL = parameters.url;
  880. customAttributes.cartesianCenter = parameters.cartesianCenter;
  881. customAttributes.parentRotation = parameters.parentRotation;
  882. // Build the feature index array from the faceRange.
  883. customAttributes.featureIndex = new Array(geometryData.positions.length);
  884. for (
  885. let range = 0;
  886. range < geometryData["faceRange"].length - 1;
  887. range += 2
  888. ) {
  889. const curIndex = range / 2;
  890. const rangeStart = geometryData["faceRange"][range];
  891. const rangeEnd = geometryData["faceRange"][range + 1];
  892. for (let i = rangeStart; i <= rangeEnd; i++) {
  893. customAttributes.featureIndex[i * 3] = curIndex;
  894. customAttributes.featureIndex[i * 3 + 1] = curIndex;
  895. customAttributes.featureIndex[i * 3 + 2] = curIndex;
  896. }
  897. }
  898. }
  899. meshData._customAttributes = customAttributes;
  900. const results = {
  901. meshData: meshData,
  902. };
  903. return results;
  904. }
  905. function initWorker(dracoModule) {
  906. draco = dracoModule;
  907. self.onmessage = createTaskProcessorWorker(decodeI3S);
  908. self.postMessage(true);
  909. }
  910. function decodeI3SStart(event) {
  911. const data = event.data;
  912. // Expect the first message to be to load a web assembly module
  913. const wasmConfig = data.webAssemblyConfig;
  914. if (defined(wasmConfig)) {
  915. // Require and compile WebAssembly module, or use fallback if not supported
  916. return require([wasmConfig.modulePath], function (dracoModule) {
  917. if (defined(wasmConfig.wasmBinaryFile)) {
  918. if (!defined(dracoModule)) {
  919. dracoModule = self.DracoDecoderModule;
  920. }
  921. dracoModule(wasmConfig).then(function (compiledModule) {
  922. initWorker(compiledModule);
  923. });
  924. } else {
  925. initWorker(dracoModule());
  926. }
  927. });
  928. }
  929. }
  930. export default decodeI3SStart;