decodeI3S.js 31 KB

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