智慧水务管理系统 - 精河县供水工程综合管理平台

B3dmParser.js 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import Check from "../Core/Check.js";
  2. import deprecationWarning from "../Core/deprecationWarning.js";
  3. import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js";
  4. import RuntimeError from "../Core/RuntimeError.js";
  5. /**
  6. * Handles parsing of a Batched 3D Model.
  7. *
  8. * @namespace B3dmParser
  9. * @private
  10. */
  11. const B3dmParser = {};
  12. B3dmParser._deprecationWarning = deprecationWarning;
  13. const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  14. /**
  15. * Parses the contents of a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Batched3DModel|Batched 3D Model}.
  16. *
  17. * @private
  18. *
  19. * @param {ArrayBuffer} arrayBuffer The array buffer containing the b3dm.
  20. * @param {number} [byteOffset=0] The byte offset of the beginning of the b3dm in the array buffer.
  21. * @returns {object} Returns an object with the batch length, feature table (binary and json), batch table (binary and json) and glTF parts of the b3dm.
  22. */
  23. B3dmParser.parse = function (arrayBuffer, byteOffset) {
  24. const byteStart = byteOffset ?? 0;
  25. //>>includeStart('debug', pragmas.debug);
  26. Check.defined("arrayBuffer", arrayBuffer);
  27. //>>includeEnd('debug');
  28. byteOffset = byteStart;
  29. const uint8Array = new Uint8Array(arrayBuffer);
  30. const view = new DataView(arrayBuffer);
  31. byteOffset += sizeOfUint32; // Skip magic
  32. const version = view.getUint32(byteOffset, true);
  33. if (version !== 1) {
  34. throw new RuntimeError(
  35. `Only Batched 3D Model version 1 is supported. Version ${version} is not.`,
  36. );
  37. }
  38. byteOffset += sizeOfUint32;
  39. const byteLength = view.getUint32(byteOffset, true);
  40. byteOffset += sizeOfUint32;
  41. let featureTableJsonByteLength = view.getUint32(byteOffset, true);
  42. byteOffset += sizeOfUint32;
  43. let featureTableBinaryByteLength = view.getUint32(byteOffset, true);
  44. byteOffset += sizeOfUint32;
  45. let batchTableJsonByteLength = view.getUint32(byteOffset, true);
  46. byteOffset += sizeOfUint32;
  47. let batchTableBinaryByteLength = view.getUint32(byteOffset, true);
  48. byteOffset += sizeOfUint32;
  49. let batchLength;
  50. // Legacy header #1: [batchLength] [batchTableByteLength]
  51. // Legacy header #2: [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]
  52. // Current header: [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength]
  53. // If the header is in the first legacy format 'batchTableJsonByteLength' will be the start of the JSON string (a quotation mark) or the glTF magic.
  54. // Accordingly its first byte will be either 0x22 or 0x67, and so the minimum uint32 expected is 0x22000000 = 570425344 = 570MB. It is unlikely that the feature table JSON will exceed this length.
  55. // The check for the second legacy format is similar, except it checks 'batchTableBinaryByteLength' instead
  56. if (batchTableJsonByteLength >= 570425344) {
  57. // First legacy check
  58. byteOffset -= sizeOfUint32 * 2;
  59. batchLength = featureTableJsonByteLength;
  60. batchTableJsonByteLength = featureTableBinaryByteLength;
  61. batchTableBinaryByteLength = 0;
  62. featureTableJsonByteLength = 0;
  63. featureTableBinaryByteLength = 0;
  64. B3dmParser._deprecationWarning(
  65. "b3dm-legacy-header",
  66. "This b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Batched3DModel.",
  67. );
  68. } else if (batchTableBinaryByteLength >= 570425344) {
  69. // Second legacy check
  70. byteOffset -= sizeOfUint32;
  71. batchLength = batchTableJsonByteLength;
  72. batchTableJsonByteLength = featureTableJsonByteLength;
  73. batchTableBinaryByteLength = featureTableBinaryByteLength;
  74. featureTableJsonByteLength = 0;
  75. featureTableBinaryByteLength = 0;
  76. B3dmParser._deprecationWarning(
  77. "b3dm-legacy-header",
  78. "This b3dm header is using the legacy format [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Batched3DModel.",
  79. );
  80. }
  81. let featureTableJson;
  82. if (featureTableJsonByteLength === 0) {
  83. featureTableJson = {
  84. BATCH_LENGTH: batchLength ?? 0,
  85. };
  86. } else {
  87. featureTableJson = getJsonFromTypedArray(
  88. uint8Array,
  89. byteOffset,
  90. featureTableJsonByteLength,
  91. );
  92. byteOffset += featureTableJsonByteLength;
  93. }
  94. const featureTableBinary = new Uint8Array(
  95. arrayBuffer,
  96. byteOffset,
  97. featureTableBinaryByteLength,
  98. );
  99. byteOffset += featureTableBinaryByteLength;
  100. let batchTableJson;
  101. let batchTableBinary;
  102. if (batchTableJsonByteLength > 0) {
  103. // PERFORMANCE_IDEA: is it possible to allocate this on-demand? Perhaps keep the
  104. // arraybuffer/string compressed in memory and then decompress it when it is first accessed.
  105. //
  106. // We could also make another request for it, but that would make the property set/get
  107. // API async, and would double the number of numbers in some cases.
  108. batchTableJson = getJsonFromTypedArray(
  109. uint8Array,
  110. byteOffset,
  111. batchTableJsonByteLength,
  112. );
  113. byteOffset += batchTableJsonByteLength;
  114. if (batchTableBinaryByteLength > 0) {
  115. // Has a batch table binary
  116. batchTableBinary = new Uint8Array(
  117. arrayBuffer,
  118. byteOffset,
  119. batchTableBinaryByteLength,
  120. );
  121. // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed
  122. batchTableBinary = new Uint8Array(batchTableBinary);
  123. byteOffset += batchTableBinaryByteLength;
  124. }
  125. }
  126. const gltfByteLength = byteStart + byteLength - byteOffset;
  127. if (gltfByteLength === 0) {
  128. throw new RuntimeError("glTF byte length must be greater than 0.");
  129. }
  130. let gltfView;
  131. if (byteOffset % 4 === 0) {
  132. gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength);
  133. } else {
  134. // Create a copy of the glb so that it is 4-byte aligned
  135. B3dmParser._deprecationWarning(
  136. "b3dm-glb-unaligned",
  137. "The embedded glb is not aligned to a 4-byte boundary.",
  138. );
  139. gltfView = new Uint8Array(
  140. uint8Array.subarray(byteOffset, byteOffset + gltfByteLength),
  141. );
  142. }
  143. return {
  144. batchLength: batchLength,
  145. featureTableJson: featureTableJson,
  146. featureTableBinary: featureTableBinary,
  147. batchTableJson: batchTableJson,
  148. batchTableBinary: batchTableBinary,
  149. gltf: gltfView,
  150. };
  151. };
  152. export default B3dmParser;