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

Composite3DTileContent.js 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import Cartesian3 from "../Core/Cartesian3.js";
  2. import defined from "../Core/defined.js";
  3. import destroyObject from "../Core/destroyObject.js";
  4. import getMagic from "../Core/getMagic.js";
  5. import RuntimeError from "../Core/RuntimeError.js";
  6. /**
  7. * Represents the contents of a
  8. * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Composite|Composite}
  9. * tile in a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification|3D Tiles} tileset.
  10. * <p>
  11. * Implements the {@link Cesium3DTileContent} interface.
  12. * </p>
  13. *
  14. * @implements Cesium3DTileContent
  15. * @private
  16. */
  17. class Composite3DTileContent {
  18. constructor(tileset, tile, resource, contents) {
  19. this._tileset = tileset;
  20. this._tile = tile;
  21. this._resource = resource;
  22. if (!defined(contents)) {
  23. contents = [];
  24. }
  25. this._contents = contents;
  26. this._metadata = undefined;
  27. this._group = undefined;
  28. this._ready = false;
  29. }
  30. get featurePropertiesDirty() {
  31. const contents = this._contents;
  32. const length = contents.length;
  33. for (let i = 0; i < length; ++i) {
  34. if (contents[i].featurePropertiesDirty) {
  35. return true;
  36. }
  37. }
  38. return false;
  39. }
  40. set featurePropertiesDirty(value) {
  41. const contents = this._contents;
  42. const length = contents.length;
  43. for (let i = 0; i < length; ++i) {
  44. contents[i].featurePropertiesDirty = value;
  45. }
  46. }
  47. /**
  48. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  49. * always returns <code>0</code>. Instead call <code>featuresLength</code> for a tile in the composite.
  50. */
  51. get featuresLength() {
  52. return 0;
  53. }
  54. /**
  55. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  56. * always returns <code>0</code>. Instead call <code>pointsLength</code> for a tile in the composite.
  57. */
  58. get pointsLength() {
  59. return 0;
  60. }
  61. /**
  62. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  63. * always returns <code>0</code>. Instead call <code>trianglesLength</code> for a tile in the composite.
  64. */
  65. get trianglesLength() {
  66. return 0;
  67. }
  68. /**
  69. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  70. * always returns <code>0</code>. Instead call <code>geometryByteLength</code> for a tile in the composite.
  71. */
  72. get geometryByteLength() {
  73. return 0;
  74. }
  75. /**
  76. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  77. * always returns <code>0</code>. Instead call <code>texturesByteLength</code> for a tile in the composite.
  78. */
  79. get texturesByteLength() {
  80. return 0;
  81. }
  82. /**
  83. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  84. * always returns <code>0</code>. Instead call <code>batchTableByteLength</code> for a tile in the composite.
  85. */
  86. get batchTableByteLength() {
  87. return 0;
  88. }
  89. get innerContents() {
  90. return this._contents;
  91. }
  92. /**
  93. * Returns true when the tile's content is ready to render; otherwise false
  94. *
  95. *
  96. * @type {boolean}
  97. * @readonly
  98. * @private
  99. */
  100. get ready() {
  101. return this._ready;
  102. }
  103. get tileset() {
  104. return this._tileset;
  105. }
  106. get tile() {
  107. return this._tile;
  108. }
  109. get url() {
  110. return this._resource.getUrlComponent(true);
  111. }
  112. /**
  113. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  114. * both stores the content metadata and propagates the content metadata to all of its children.
  115. * @private
  116. * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
  117. */
  118. get metadata() {
  119. return this._metadata;
  120. }
  121. set metadata(value) {
  122. this._metadata = value;
  123. const contents = this._contents;
  124. const length = contents.length;
  125. for (let i = 0; i < length; ++i) {
  126. contents[i].metadata = value;
  127. }
  128. }
  129. /**
  130. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  131. * always returns <code>undefined</code>. Instead call <code>batchTable</code> for a tile in the composite.
  132. */
  133. get batchTable() {
  134. return undefined;
  135. }
  136. /**
  137. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  138. * both stores the group metadata and propagates the group metadata to all of its children.
  139. * @private
  140. * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
  141. */
  142. get group() {
  143. return this._group;
  144. }
  145. set group(value) {
  146. this._group = value;
  147. const contents = this._contents;
  148. const length = contents.length;
  149. for (let i = 0; i < length; ++i) {
  150. contents[i].group = value;
  151. }
  152. }
  153. static async fromTileType(
  154. tileset,
  155. tile,
  156. resource,
  157. arrayBuffer,
  158. byteOffset,
  159. factory,
  160. ) {
  161. byteOffset = byteOffset ?? 0;
  162. const uint8Array = new Uint8Array(arrayBuffer);
  163. const view = new DataView(arrayBuffer);
  164. byteOffset += sizeOfUint32; // Skip magic
  165. const version = view.getUint32(byteOffset, true);
  166. if (version !== 1) {
  167. throw new RuntimeError(
  168. `Only Composite Tile version 1 is supported. Version ${version} is not.`,
  169. );
  170. }
  171. byteOffset += sizeOfUint32;
  172. // Skip byteLength
  173. byteOffset += sizeOfUint32;
  174. const tilesLength = view.getUint32(byteOffset, true);
  175. byteOffset += sizeOfUint32;
  176. // For caching purposes, models within the composite tile must be
  177. // distinguished. To do this, add a query parameter ?compositeIndex=i.
  178. // Since composite tiles may contain other composite tiles, check for an
  179. // existing prefix and separate them with underscores. e.g.
  180. // ?compositeIndex=0_1_1
  181. let prefix = resource.queryParameters.compositeIndex;
  182. if (defined(prefix)) {
  183. // We'll be adding another value at the end, so add an underscore.
  184. prefix = `${prefix}_`;
  185. } else {
  186. // no prefix
  187. prefix = "";
  188. }
  189. const promises = [];
  190. promises.length = tilesLength;
  191. for (let i = 0; i < tilesLength; ++i) {
  192. const tileType = getMagic(uint8Array, byteOffset);
  193. // Tile byte length is stored after magic and version
  194. const tileByteLength = view.getUint32(
  195. byteOffset + sizeOfUint32 * 2,
  196. true,
  197. );
  198. const contentFactory = factory[tileType];
  199. // Label which content within the composite this is
  200. const compositeIndex = `${prefix}${i}`;
  201. const childResource = resource.getDerivedResource({
  202. queryParameters: {
  203. compositeIndex: compositeIndex,
  204. },
  205. });
  206. if (defined(contentFactory)) {
  207. promises[i] = Promise.resolve(
  208. contentFactory(tileset, tile, childResource, arrayBuffer, byteOffset),
  209. );
  210. } else {
  211. throw new RuntimeError(
  212. `Unknown tile content type, ${tileType}, inside Composite tile`,
  213. );
  214. }
  215. byteOffset += tileByteLength;
  216. }
  217. const innerContents = await Promise.all(promises);
  218. const content = new Composite3DTileContent(
  219. tileset,
  220. tile,
  221. resource,
  222. innerContents,
  223. );
  224. return content;
  225. }
  226. /**
  227. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  228. * always returns <code>false</code>. Instead call <code>hasProperty</code> for a tile in the composite.
  229. */
  230. hasProperty(batchId, name) {
  231. return false;
  232. }
  233. /**
  234. * Part of the {@link Cesium3DTileContent} interface. <code>Composite3DTileContent</code>
  235. * always returns <code>undefined</code>. Instead call <code>getFeature</code> for a tile in the composite.
  236. */
  237. getFeature(batchId) {
  238. return undefined;
  239. }
  240. applyDebugSettings(enabled, color) {
  241. const contents = this._contents;
  242. const length = contents.length;
  243. for (let i = 0; i < length; ++i) {
  244. contents[i].applyDebugSettings(enabled, color);
  245. }
  246. }
  247. applyStyle(style) {
  248. const contents = this._contents;
  249. const length = contents.length;
  250. for (let i = 0; i < length; ++i) {
  251. contents[i].applyStyle(style);
  252. }
  253. }
  254. update(tileset, frameState) {
  255. const contents = this._contents;
  256. const length = contents.length;
  257. let ready = true;
  258. for (let i = 0; i < length; ++i) {
  259. contents[i].update(tileset, frameState);
  260. ready = ready && contents[i].ready;
  261. }
  262. if (!this._ready && ready) {
  263. this._ready = true;
  264. }
  265. }
  266. /**
  267. * Find an intersection between a ray and the tile content surface that was rendered. The ray must be given in world coordinates.
  268. *
  269. * @param {Ray} ray The ray to test for intersection.
  270. * @param {FrameState} frameState The frame state.
  271. * @param {Cartesian3|undefined} [result] The intersection or <code>undefined</code> if none was found.
  272. * @returns {Cartesian3|undefined} The intersection or <code>undefined</code> if none was found.
  273. *
  274. * @private
  275. */
  276. pick(ray, frameState, result) {
  277. if (!this._ready) {
  278. return undefined;
  279. }
  280. let intersection;
  281. let minDistance = Number.POSITIVE_INFINITY;
  282. const contents = this._contents;
  283. const length = contents.length;
  284. for (let i = 0; i < length; ++i) {
  285. const candidate = contents[i].pick(ray, frameState, result);
  286. if (!defined(candidate)) {
  287. continue;
  288. }
  289. const distance = Cartesian3.distance(ray.origin, candidate);
  290. if (distance < minDistance) {
  291. intersection = candidate;
  292. minDistance = distance;
  293. }
  294. }
  295. if (!defined(intersection)) {
  296. return undefined;
  297. }
  298. return result;
  299. }
  300. isDestroyed() {
  301. return false;
  302. }
  303. destroy() {
  304. const contents = this._contents;
  305. const length = contents.length;
  306. for (let i = 0; i < length; ++i) {
  307. contents[i].destroy();
  308. }
  309. return destroyObject(this);
  310. }
  311. }
  312. const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  313. export default Composite3DTileContent;