Vector3DTileContent.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. import Cartesian3 from "../Core/Cartesian3.js";
  2. import defaultValue from "../Core/defaultValue.js";
  3. import defined from "../Core/defined.js";
  4. import deprecationWarning from "../Core/deprecationWarning.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import Ellipsoid from "../Core/Ellipsoid.js";
  8. import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js";
  9. import ComponentDatatype from "../Core/ComponentDatatype.js";
  10. import CesiumMath from "../Core/Math.js";
  11. import Matrix4 from "../Core/Matrix4.js";
  12. import Rectangle from "../Core/Rectangle.js";
  13. import RuntimeError from "../Core/RuntimeError.js";
  14. import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js";
  15. import Cesium3DTileFeatureTable from "./Cesium3DTileFeatureTable.js";
  16. import Vector3DTilePoints from "./Vector3DTilePoints.js";
  17. import Vector3DTilePolygons from "./Vector3DTilePolygons.js";
  18. import Vector3DTilePolylines from "./Vector3DTilePolylines.js";
  19. import Vector3DTileClampedPolylines from "./Vector3DTileClampedPolylines.js";
  20. import decodeVectorPolylinePositions from "../Core/decodeVectorPolylinePositions.js";
  21. /**
  22. * Represents the contents of a
  23. * {@link https://github.com/CesiumGS/3d-tiles/tree/vctr/TileFormats/VectorData|Vector}
  24. * tile in a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification|3D Tiles} tileset.
  25. * <p>
  26. * Implements the {@link Cesium3DTileContent} interface.
  27. * </p>
  28. *
  29. * @alias Vector3DTileContent
  30. * @constructor
  31. *
  32. * @private
  33. */
  34. function Vector3DTileContent(tileset, tile, resource, arrayBuffer, byteOffset) {
  35. this._tileset = tileset;
  36. this._tile = tile;
  37. this._resource = resource;
  38. this._polygons = undefined;
  39. this._polylines = undefined;
  40. this._points = undefined;
  41. this._metadata = undefined;
  42. this._batchTable = undefined;
  43. this._features = undefined;
  44. /**
  45. * Part of the {@link Cesium3DTileContent} interface.
  46. */
  47. this.featurePropertiesDirty = false;
  48. this._group = undefined;
  49. this._ready = false;
  50. // This is here for backwards compatibility and can be removed when readyPromise is removed.
  51. this._resolveContent = undefined;
  52. this._readyPromise = new Promise((resolve) => {
  53. this._resolveContent = resolve;
  54. });
  55. initialize(this, arrayBuffer, byteOffset);
  56. }
  57. Object.defineProperties(Vector3DTileContent.prototype, {
  58. featuresLength: {
  59. get: function () {
  60. return defined(this._batchTable) ? this._batchTable.featuresLength : 0;
  61. },
  62. },
  63. pointsLength: {
  64. get: function () {
  65. if (defined(this._points)) {
  66. return this._points.pointsLength;
  67. }
  68. return 0;
  69. },
  70. },
  71. trianglesLength: {
  72. get: function () {
  73. let trianglesLength = 0;
  74. if (defined(this._polygons)) {
  75. trianglesLength += this._polygons.trianglesLength;
  76. }
  77. if (defined(this._polylines)) {
  78. trianglesLength += this._polylines.trianglesLength;
  79. }
  80. return trianglesLength;
  81. },
  82. },
  83. geometryByteLength: {
  84. get: function () {
  85. let geometryByteLength = 0;
  86. if (defined(this._polygons)) {
  87. geometryByteLength += this._polygons.geometryByteLength;
  88. }
  89. if (defined(this._polylines)) {
  90. geometryByteLength += this._polylines.geometryByteLength;
  91. }
  92. return geometryByteLength;
  93. },
  94. },
  95. texturesByteLength: {
  96. get: function () {
  97. if (defined(this._points)) {
  98. return this._points.texturesByteLength;
  99. }
  100. return 0;
  101. },
  102. },
  103. batchTableByteLength: {
  104. get: function () {
  105. return defined(this._batchTable)
  106. ? this._batchTable.batchTableByteLength
  107. : 0;
  108. },
  109. },
  110. innerContents: {
  111. get: function () {
  112. return undefined;
  113. },
  114. },
  115. /**
  116. * Returns true when the tile's content is ready to render; otherwise false
  117. *
  118. * @memberof Vector3DTileContent.prototype
  119. *
  120. * @type {boolean}
  121. * @readonly
  122. * @private
  123. */
  124. ready: {
  125. get: function () {
  126. return this._ready;
  127. },
  128. },
  129. /**
  130. * Gets the promise that will be resolved when the tile's content is ready to render.
  131. *
  132. * @memberof Vector3DTileContent.prototype
  133. *
  134. * @type {Promise<Vector3DTileContent>}
  135. * @readonly
  136. * @deprecated
  137. * @private
  138. */
  139. readyPromise: {
  140. get: function () {
  141. deprecationWarning(
  142. "Vector3DTileContent.readyPromise",
  143. "Vector3DTileContent.readyPromise was deprecated in CesiumJS 1.104. It will be removed in 1.107. Wait for Vector3DTileContent.ready to return true instead."
  144. );
  145. return this._readyPromise;
  146. },
  147. },
  148. tileset: {
  149. get: function () {
  150. return this._tileset;
  151. },
  152. },
  153. tile: {
  154. get: function () {
  155. return this._tile;
  156. },
  157. },
  158. url: {
  159. get: function () {
  160. return this._resource.getUrlComponent(true);
  161. },
  162. },
  163. metadata: {
  164. get: function () {
  165. return this._metadata;
  166. },
  167. set: function (value) {
  168. this._metadata = value;
  169. },
  170. },
  171. batchTable: {
  172. get: function () {
  173. return this._batchTable;
  174. },
  175. },
  176. group: {
  177. get: function () {
  178. return this._group;
  179. },
  180. set: function (value) {
  181. this._group = value;
  182. },
  183. },
  184. });
  185. function createColorChangedCallback(content) {
  186. return function (batchId, color) {
  187. if (defined(content._polygons)) {
  188. content._polygons.updateCommands(batchId, color);
  189. }
  190. };
  191. }
  192. function getBatchIds(featureTableJson, featureTableBinary) {
  193. let polygonBatchIds;
  194. let polylineBatchIds;
  195. let pointBatchIds;
  196. let i;
  197. const numberOfPolygons = defaultValue(featureTableJson.POLYGONS_LENGTH, 0);
  198. const numberOfPolylines = defaultValue(featureTableJson.POLYLINES_LENGTH, 0);
  199. const numberOfPoints = defaultValue(featureTableJson.POINTS_LENGTH, 0);
  200. if (numberOfPolygons > 0 && defined(featureTableJson.POLYGON_BATCH_IDS)) {
  201. const polygonBatchIdsByteOffset =
  202. featureTableBinary.byteOffset +
  203. featureTableJson.POLYGON_BATCH_IDS.byteOffset;
  204. polygonBatchIds = new Uint16Array(
  205. featureTableBinary.buffer,
  206. polygonBatchIdsByteOffset,
  207. numberOfPolygons
  208. );
  209. }
  210. if (numberOfPolylines > 0 && defined(featureTableJson.POLYLINE_BATCH_IDS)) {
  211. const polylineBatchIdsByteOffset =
  212. featureTableBinary.byteOffset +
  213. featureTableJson.POLYLINE_BATCH_IDS.byteOffset;
  214. polylineBatchIds = new Uint16Array(
  215. featureTableBinary.buffer,
  216. polylineBatchIdsByteOffset,
  217. numberOfPolylines
  218. );
  219. }
  220. if (numberOfPoints > 0 && defined(featureTableJson.POINT_BATCH_IDS)) {
  221. const pointBatchIdsByteOffset =
  222. featureTableBinary.byteOffset +
  223. featureTableJson.POINT_BATCH_IDS.byteOffset;
  224. pointBatchIds = new Uint16Array(
  225. featureTableBinary.buffer,
  226. pointBatchIdsByteOffset,
  227. numberOfPoints
  228. );
  229. }
  230. const atLeastOneDefined =
  231. defined(polygonBatchIds) ||
  232. defined(polylineBatchIds) ||
  233. defined(pointBatchIds);
  234. const atLeastOneUndefined =
  235. (numberOfPolygons > 0 && !defined(polygonBatchIds)) ||
  236. (numberOfPolylines > 0 && !defined(polylineBatchIds)) ||
  237. (numberOfPoints > 0 && !defined(pointBatchIds));
  238. if (atLeastOneDefined && atLeastOneUndefined) {
  239. throw new RuntimeError(
  240. "If one group of batch ids is defined, then all batch ids must be defined"
  241. );
  242. }
  243. const allUndefinedBatchIds =
  244. !defined(polygonBatchIds) &&
  245. !defined(polylineBatchIds) &&
  246. !defined(pointBatchIds);
  247. if (allUndefinedBatchIds) {
  248. let id = 0;
  249. if (!defined(polygonBatchIds) && numberOfPolygons > 0) {
  250. polygonBatchIds = new Uint16Array(numberOfPolygons);
  251. for (i = 0; i < numberOfPolygons; ++i) {
  252. polygonBatchIds[i] = id++;
  253. }
  254. }
  255. if (!defined(polylineBatchIds) && numberOfPolylines > 0) {
  256. polylineBatchIds = new Uint16Array(numberOfPolylines);
  257. for (i = 0; i < numberOfPolylines; ++i) {
  258. polylineBatchIds[i] = id++;
  259. }
  260. }
  261. if (!defined(pointBatchIds) && numberOfPoints > 0) {
  262. pointBatchIds = new Uint16Array(numberOfPoints);
  263. for (i = 0; i < numberOfPoints; ++i) {
  264. pointBatchIds[i] = id++;
  265. }
  266. }
  267. }
  268. return {
  269. polygons: polygonBatchIds,
  270. polylines: polylineBatchIds,
  271. points: pointBatchIds,
  272. };
  273. }
  274. const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  275. function createFloatingPolylines(options) {
  276. return new Vector3DTilePolylines(options);
  277. }
  278. function createClampedPolylines(options) {
  279. return new Vector3DTileClampedPolylines(options);
  280. }
  281. function initialize(content, arrayBuffer, byteOffset) {
  282. byteOffset = defaultValue(byteOffset, 0);
  283. const uint8Array = new Uint8Array(arrayBuffer);
  284. const view = new DataView(arrayBuffer);
  285. byteOffset += sizeOfUint32; // Skip magic number
  286. const version = view.getUint32(byteOffset, true);
  287. if (version !== 1) {
  288. throw new RuntimeError(
  289. `Only Vector tile version 1 is supported. Version ${version} is not.`
  290. );
  291. }
  292. byteOffset += sizeOfUint32;
  293. const byteLength = view.getUint32(byteOffset, true);
  294. byteOffset += sizeOfUint32;
  295. if (byteLength === 0) {
  296. content._ready = true;
  297. content._resolveContent(content);
  298. return;
  299. }
  300. const featureTableJSONByteLength = view.getUint32(byteOffset, true);
  301. byteOffset += sizeOfUint32;
  302. if (featureTableJSONByteLength === 0) {
  303. throw new RuntimeError(
  304. "Feature table must have a byte length greater than zero"
  305. );
  306. }
  307. const featureTableBinaryByteLength = view.getUint32(byteOffset, true);
  308. byteOffset += sizeOfUint32;
  309. const batchTableJSONByteLength = view.getUint32(byteOffset, true);
  310. byteOffset += sizeOfUint32;
  311. const batchTableBinaryByteLength = view.getUint32(byteOffset, true);
  312. byteOffset += sizeOfUint32;
  313. const indicesByteLength = view.getUint32(byteOffset, true);
  314. byteOffset += sizeOfUint32;
  315. const positionByteLength = view.getUint32(byteOffset, true);
  316. byteOffset += sizeOfUint32;
  317. const polylinePositionByteLength = view.getUint32(byteOffset, true);
  318. byteOffset += sizeOfUint32;
  319. const pointsPositionByteLength = view.getUint32(byteOffset, true);
  320. byteOffset += sizeOfUint32;
  321. const featureTableJson = getJsonFromTypedArray(
  322. uint8Array,
  323. byteOffset,
  324. featureTableJSONByteLength
  325. );
  326. byteOffset += featureTableJSONByteLength;
  327. const featureTableBinary = new Uint8Array(
  328. arrayBuffer,
  329. byteOffset,
  330. featureTableBinaryByteLength
  331. );
  332. byteOffset += featureTableBinaryByteLength;
  333. let batchTableJson;
  334. let batchTableBinary;
  335. if (batchTableJSONByteLength > 0) {
  336. // PERFORMANCE_IDEA: is it possible to allocate this on-demand? Perhaps keep the
  337. // arraybuffer/string compressed in memory and then decompress it when it is first accessed.
  338. //
  339. // We could also make another request for it, but that would make the property set/get
  340. // API async, and would double the number of numbers in some cases.
  341. batchTableJson = getJsonFromTypedArray(
  342. uint8Array,
  343. byteOffset,
  344. batchTableJSONByteLength
  345. );
  346. byteOffset += batchTableJSONByteLength;
  347. if (batchTableBinaryByteLength > 0) {
  348. // Has a batch table binary
  349. batchTableBinary = new Uint8Array(
  350. arrayBuffer,
  351. byteOffset,
  352. batchTableBinaryByteLength
  353. );
  354. // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed
  355. batchTableBinary = new Uint8Array(batchTableBinary);
  356. byteOffset += batchTableBinaryByteLength;
  357. }
  358. }
  359. const numberOfPolygons = defaultValue(featureTableJson.POLYGONS_LENGTH, 0);
  360. const numberOfPolylines = defaultValue(featureTableJson.POLYLINES_LENGTH, 0);
  361. const numberOfPoints = defaultValue(featureTableJson.POINTS_LENGTH, 0);
  362. const totalPrimitives = numberOfPolygons + numberOfPolylines + numberOfPoints;
  363. const batchTable = new Cesium3DTileBatchTable(
  364. content,
  365. totalPrimitives,
  366. batchTableJson,
  367. batchTableBinary,
  368. createColorChangedCallback(content)
  369. );
  370. content._batchTable = batchTable;
  371. if (totalPrimitives === 0) {
  372. return;
  373. }
  374. const featureTable = new Cesium3DTileFeatureTable(
  375. featureTableJson,
  376. featureTableBinary
  377. );
  378. const region = featureTable.getGlobalProperty("REGION");
  379. if (!defined(region)) {
  380. throw new RuntimeError(
  381. "Feature table global property: REGION must be defined"
  382. );
  383. }
  384. const rectangle = Rectangle.unpack(region);
  385. const minHeight = region[4];
  386. const maxHeight = region[5];
  387. const modelMatrix = content._tile.computedTransform;
  388. let center = featureTable.getGlobalProperty(
  389. "RTC_CENTER",
  390. ComponentDatatype.FLOAT,
  391. 3
  392. );
  393. if (defined(center)) {
  394. center = Cartesian3.unpack(center);
  395. Matrix4.multiplyByPoint(modelMatrix, center, center);
  396. } else {
  397. center = Rectangle.center(rectangle);
  398. center.height = CesiumMath.lerp(minHeight, maxHeight, 0.5);
  399. center = Ellipsoid.WGS84.cartographicToCartesian(center);
  400. }
  401. const batchIds = getBatchIds(featureTableJson, featureTableBinary);
  402. byteOffset += (4 - (byteOffset % 4)) % 4;
  403. if (numberOfPolygons > 0) {
  404. featureTable.featuresLength = numberOfPolygons;
  405. const polygonCounts = defaultValue(
  406. featureTable.getPropertyArray(
  407. "POLYGON_COUNTS",
  408. ComponentDatatype.UNSIGNED_INT,
  409. 1
  410. ),
  411. featureTable.getPropertyArray(
  412. "POLYGON_COUNT",
  413. ComponentDatatype.UNSIGNED_INT,
  414. 1
  415. ) // Workaround for old vector tilesets using the non-plural name
  416. );
  417. if (!defined(polygonCounts)) {
  418. throw new RuntimeError(
  419. "Feature table property: POLYGON_COUNTS must be defined when POLYGONS_LENGTH is greater than 0"
  420. );
  421. }
  422. const polygonIndexCounts = defaultValue(
  423. featureTable.getPropertyArray(
  424. "POLYGON_INDEX_COUNTS",
  425. ComponentDatatype.UNSIGNED_INT,
  426. 1
  427. ),
  428. featureTable.getPropertyArray(
  429. "POLYGON_INDEX_COUNT",
  430. ComponentDatatype.UNSIGNED_INT,
  431. 1
  432. ) // Workaround for old vector tilesets using the non-plural name
  433. );
  434. if (!defined(polygonIndexCounts)) {
  435. throw new RuntimeError(
  436. "Feature table property: POLYGON_INDEX_COUNTS must be defined when POLYGONS_LENGTH is greater than 0"
  437. );
  438. }
  439. // Use the counts array to determine how many position values we want. If we used the byte length then
  440. // zero padding values would be included and cause the delta zig-zag decoding to fail
  441. const numPolygonPositions = polygonCounts.reduce(function (total, count) {
  442. return total + count * 2;
  443. }, 0);
  444. const numPolygonIndices = polygonIndexCounts.reduce(function (
  445. total,
  446. count
  447. ) {
  448. return total + count;
  449. },
  450. 0);
  451. const indices = new Uint32Array(arrayBuffer, byteOffset, numPolygonIndices);
  452. byteOffset += indicesByteLength;
  453. const polygonPositions = new Uint16Array(
  454. arrayBuffer,
  455. byteOffset,
  456. numPolygonPositions
  457. );
  458. byteOffset += positionByteLength;
  459. let polygonMinimumHeights;
  460. let polygonMaximumHeights;
  461. if (
  462. defined(featureTableJson.POLYGON_MINIMUM_HEIGHTS) &&
  463. defined(featureTableJson.POLYGON_MAXIMUM_HEIGHTS)
  464. ) {
  465. polygonMinimumHeights = featureTable.getPropertyArray(
  466. "POLYGON_MINIMUM_HEIGHTS",
  467. ComponentDatatype.FLOAT,
  468. 1
  469. );
  470. polygonMaximumHeights = featureTable.getPropertyArray(
  471. "POLYGON_MAXIMUM_HEIGHTS",
  472. ComponentDatatype.FLOAT,
  473. 1
  474. );
  475. }
  476. content._polygons = new Vector3DTilePolygons({
  477. positions: polygonPositions,
  478. counts: polygonCounts,
  479. indexCounts: polygonIndexCounts,
  480. indices: indices,
  481. minimumHeight: minHeight,
  482. maximumHeight: maxHeight,
  483. polygonMinimumHeights: polygonMinimumHeights,
  484. polygonMaximumHeights: polygonMaximumHeights,
  485. center: center,
  486. rectangle: rectangle,
  487. boundingVolume: content.tile.boundingVolume.boundingVolume,
  488. batchTable: batchTable,
  489. batchIds: batchIds.polygons,
  490. modelMatrix: modelMatrix,
  491. });
  492. }
  493. if (numberOfPolylines > 0) {
  494. featureTable.featuresLength = numberOfPolylines;
  495. const polylineCounts = defaultValue(
  496. featureTable.getPropertyArray(
  497. "POLYLINE_COUNTS",
  498. ComponentDatatype.UNSIGNED_INT,
  499. 1
  500. ),
  501. featureTable.getPropertyArray(
  502. "POLYLINE_COUNT",
  503. ComponentDatatype.UNSIGNED_INT,
  504. 1
  505. ) // Workaround for old vector tilesets using the non-plural name
  506. );
  507. if (!defined(polylineCounts)) {
  508. throw new RuntimeError(
  509. "Feature table property: POLYLINE_COUNTS must be defined when POLYLINES_LENGTH is greater than 0"
  510. );
  511. }
  512. let widths = featureTable.getPropertyArray(
  513. "POLYLINE_WIDTHS",
  514. ComponentDatatype.UNSIGNED_SHORT,
  515. 1
  516. );
  517. if (!defined(widths)) {
  518. widths = new Uint16Array(numberOfPolylines);
  519. for (let i = 0; i < numberOfPolylines; ++i) {
  520. widths[i] = 2.0;
  521. }
  522. }
  523. // Use the counts array to determine how many position values we want. If we used the byte length then
  524. // zero padding values would be included and cause the delta zig-zag decoding to fail
  525. const numPolylinePositions = polylineCounts.reduce(function (total, count) {
  526. return total + count * 3;
  527. }, 0);
  528. const polylinePositions = new Uint16Array(
  529. arrayBuffer,
  530. byteOffset,
  531. numPolylinePositions
  532. );
  533. byteOffset += polylinePositionByteLength;
  534. const tileset = content._tileset;
  535. const examineVectorLinesFunction = tileset.examineVectorLinesFunction;
  536. if (defined(examineVectorLinesFunction)) {
  537. const decodedPositions = decodeVectorPolylinePositions(
  538. new Uint16Array(polylinePositions),
  539. rectangle,
  540. minHeight,
  541. maxHeight,
  542. Ellipsoid.WGS84
  543. );
  544. examineVectorLines(
  545. decodedPositions,
  546. polylineCounts,
  547. batchIds.polylines,
  548. batchTable,
  549. content.url,
  550. examineVectorLinesFunction
  551. );
  552. }
  553. let createPolylines = createFloatingPolylines;
  554. if (defined(tileset.classificationType)) {
  555. createPolylines = createClampedPolylines;
  556. }
  557. content._polylines = createPolylines({
  558. positions: polylinePositions,
  559. widths: widths,
  560. counts: polylineCounts,
  561. batchIds: batchIds.polylines,
  562. minimumHeight: minHeight,
  563. maximumHeight: maxHeight,
  564. center: center,
  565. rectangle: rectangle,
  566. boundingVolume: content.tile.boundingVolume.boundingVolume,
  567. batchTable: batchTable,
  568. classificationType: tileset.classificationType,
  569. keepDecodedPositions: tileset.vectorKeepDecodedPositions,
  570. });
  571. }
  572. if (numberOfPoints > 0) {
  573. const pointPositions = new Uint16Array(
  574. arrayBuffer,
  575. byteOffset,
  576. numberOfPoints * 3
  577. );
  578. byteOffset += pointsPositionByteLength;
  579. content._points = new Vector3DTilePoints({
  580. positions: pointPositions,
  581. batchIds: batchIds.points,
  582. minimumHeight: minHeight,
  583. maximumHeight: maxHeight,
  584. rectangle: rectangle,
  585. batchTable: batchTable,
  586. });
  587. }
  588. }
  589. function createFeatures(content) {
  590. const featuresLength = content.featuresLength;
  591. if (!defined(content._features) && featuresLength > 0) {
  592. const features = new Array(featuresLength);
  593. if (defined(content._polygons)) {
  594. content._polygons.createFeatures(content, features);
  595. }
  596. if (defined(content._polylines)) {
  597. content._polylines.createFeatures(content, features);
  598. }
  599. if (defined(content._points)) {
  600. content._points.createFeatures(content, features);
  601. }
  602. content._features = features;
  603. }
  604. }
  605. Vector3DTileContent.prototype.hasProperty = function (batchId, name) {
  606. return this._batchTable.hasProperty(batchId, name);
  607. };
  608. Vector3DTileContent.prototype.getFeature = function (batchId) {
  609. //>>includeStart('debug', pragmas.debug);
  610. const featuresLength = this.featuresLength;
  611. if (!defined(batchId) || batchId < 0 || batchId >= featuresLength) {
  612. throw new DeveloperError(
  613. `batchId is required and between zero and featuresLength - 1 (${
  614. featuresLength - 1
  615. }).`
  616. );
  617. }
  618. //>>includeEnd('debug');
  619. if (!defined(this._features)) {
  620. createFeatures(this);
  621. }
  622. return this._features[batchId];
  623. };
  624. Vector3DTileContent.prototype.applyDebugSettings = function (enabled, color) {
  625. if (defined(this._polygons)) {
  626. this._polygons.applyDebugSettings(enabled, color);
  627. }
  628. if (defined(this._polylines)) {
  629. this._polylines.applyDebugSettings(enabled, color);
  630. }
  631. if (defined(this._points)) {
  632. this._points.applyDebugSettings(enabled, color);
  633. }
  634. };
  635. Vector3DTileContent.prototype.applyStyle = function (style) {
  636. if (!defined(this._features)) {
  637. createFeatures(this);
  638. }
  639. if (defined(this._polygons)) {
  640. this._polygons.applyStyle(style, this._features);
  641. }
  642. if (defined(this._polylines)) {
  643. this._polylines.applyStyle(style, this._features);
  644. }
  645. if (defined(this._points)) {
  646. this._points.applyStyle(style, this._features);
  647. }
  648. };
  649. Vector3DTileContent.prototype.update = function (tileset, frameState) {
  650. let ready = true;
  651. if (defined(this._polygons)) {
  652. this._polygons.classificationType = this._tileset.classificationType;
  653. this._polygons.debugWireframe = this._tileset.debugWireframe;
  654. this._polygons.update(frameState);
  655. ready = ready && this._polygons.ready;
  656. }
  657. if (defined(this._polylines)) {
  658. this._polylines.update(frameState);
  659. ready = ready && this._polylines.ready;
  660. }
  661. if (defined(this._points)) {
  662. this._points.update(frameState);
  663. ready = ready && this._points.ready;
  664. }
  665. if (defined(this._batchTable) && ready) {
  666. if (!defined(this._features)) {
  667. createFeatures(this);
  668. }
  669. this._batchTable.update(tileset, frameState);
  670. this._ready = true;
  671. this._resolveContent(this);
  672. }
  673. };
  674. Vector3DTileContent.prototype.getPolylinePositions = function (batchId) {
  675. const polylines = this._polylines;
  676. if (!defined(polylines)) {
  677. return undefined;
  678. }
  679. return polylines.getPositions(batchId);
  680. };
  681. Vector3DTileContent.prototype.isDestroyed = function () {
  682. return false;
  683. };
  684. Vector3DTileContent.prototype.destroy = function () {
  685. this._polygons = this._polygons && this._polygons.destroy();
  686. this._polylines = this._polylines && this._polylines.destroy();
  687. this._points = this._points && this._points.destroy();
  688. this._batchTable = this._batchTable && this._batchTable.destroy();
  689. return destroyObject(this);
  690. };
  691. function examineVectorLines(
  692. positions,
  693. counts,
  694. batchIds,
  695. batchTable,
  696. url,
  697. callback
  698. ) {
  699. const countsLength = counts.length;
  700. let polylineStart = 0;
  701. for (let i = 0; i < countsLength; i++) {
  702. const count = counts[i] * 3;
  703. const linePositions = positions.slice(polylineStart, polylineStart + count);
  704. polylineStart += count;
  705. callback(linePositions, batchIds[i], url, batchTable);
  706. }
  707. }
  708. export default Vector3DTileContent;