Vector3DTilePoints.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. import arraySlice from "../Core/arraySlice.js";
  2. import Cartesian2 from "../Core/Cartesian2.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Color from "../Core/Color.js";
  5. import defined from "../Core/defined.js";
  6. import destroyObject from "../Core/destroyObject.js";
  7. import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
  8. import Ellipsoid from "../Core/Ellipsoid.js";
  9. import NearFarScalar from "../Core/NearFarScalar.js";
  10. import Rectangle from "../Core/Rectangle.js";
  11. import TaskProcessor from "../Core/TaskProcessor.js";
  12. import when from "../ThirdParty/when.js";
  13. import BillboardCollection from "./BillboardCollection.js";
  14. import Cesium3DTilePointFeature from "./Cesium3DTilePointFeature.js";
  15. import HorizontalOrigin from "./HorizontalOrigin.js";
  16. import LabelCollection from "./LabelCollection.js";
  17. import LabelStyle from "./LabelStyle.js";
  18. import PolylineCollection from "./PolylineCollection.js";
  19. import VerticalOrigin from "./VerticalOrigin.js";
  20. /**
  21. * Creates a batch of points or billboards and labels.
  22. *
  23. * @alias Vector3DTilePoints
  24. * @constructor
  25. *
  26. * @param {Object} options An object with following properties:
  27. * @param {Uint16Array} options.positions The positions of the polygons.
  28. * @param {Number} options.minimumHeight The minimum height of the terrain covered by the tile.
  29. * @param {Number} options.maximumHeight The maximum height of the terrain covered by the tile.
  30. * @param {Rectangle} options.rectangle The rectangle containing the tile.
  31. * @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched polygons.
  32. * @param {Uint16Array} options.batchIds The batch ids for each polygon.
  33. *
  34. * @private
  35. */
  36. function Vector3DTilePoints(options) {
  37. // released after the first update
  38. this._positions = options.positions;
  39. this._batchTable = options.batchTable;
  40. this._batchIds = options.batchIds;
  41. this._rectangle = options.rectangle;
  42. this._minHeight = options.minimumHeight;
  43. this._maxHeight = options.maximumHeight;
  44. this._billboardCollection = undefined;
  45. this._labelCollection = undefined;
  46. this._polylineCollection = undefined;
  47. this._verticesPromise = undefined;
  48. this._packedBuffer = undefined;
  49. this._ready = false;
  50. this._readyPromise = when.defer();
  51. this._resolvedPromise = false;
  52. }
  53. Object.defineProperties(Vector3DTilePoints.prototype, {
  54. /**
  55. * Gets the number of points.
  56. *
  57. * @memberof Vector3DTilePoints.prototype
  58. *
  59. * @type {Number}
  60. * @readonly
  61. */
  62. pointsLength: {
  63. get: function () {
  64. return this._billboardCollection.length;
  65. },
  66. },
  67. /**
  68. * Gets the texture atlas memory in bytes.
  69. *
  70. * @memberof Vector3DTilePoints.prototype
  71. *
  72. * @type {Number}
  73. * @readonly
  74. */
  75. texturesByteLength: {
  76. get: function () {
  77. var billboardSize = this._billboardCollection.textureAtlas.texture
  78. .sizeInBytes;
  79. var labelSize = this._labelCollection._textureAtlas.texture.sizeInBytes;
  80. return billboardSize + labelSize;
  81. },
  82. },
  83. /**
  84. * Gets a promise that resolves when the primitive is ready to render.
  85. * @memberof Vector3DTilePoints.prototype
  86. * @type {Promise<void>}
  87. * @readonly
  88. */
  89. readyPromise: {
  90. get: function () {
  91. return this._readyPromise.promise;
  92. },
  93. },
  94. });
  95. function packBuffer(points, ellipsoid) {
  96. var rectangle = points._rectangle;
  97. var minimumHeight = points._minHeight;
  98. var maximumHeight = points._maxHeight;
  99. var packedLength = 2 + Rectangle.packedLength + Ellipsoid.packedLength;
  100. var packedBuffer = new Float64Array(packedLength);
  101. var offset = 0;
  102. packedBuffer[offset++] = minimumHeight;
  103. packedBuffer[offset++] = maximumHeight;
  104. Rectangle.pack(rectangle, packedBuffer, offset);
  105. offset += Rectangle.packedLength;
  106. Ellipsoid.pack(ellipsoid, packedBuffer, offset);
  107. return packedBuffer;
  108. }
  109. var createVerticesTaskProcessor = new TaskProcessor("createVectorTilePoints");
  110. var scratchPosition = new Cartesian3();
  111. function createPoints(points, ellipsoid) {
  112. if (defined(points._billboardCollection)) {
  113. return;
  114. }
  115. var positions;
  116. if (!defined(points._verticesPromise)) {
  117. positions = points._positions;
  118. var packedBuffer = points._packedBuffer;
  119. if (!defined(packedBuffer)) {
  120. // Copy because they may be the views on the same buffer.
  121. positions = points._positions = arraySlice(positions);
  122. points._batchIds = arraySlice(points._batchIds);
  123. packedBuffer = points._packedBuffer = packBuffer(points, ellipsoid);
  124. }
  125. var transferrableObjects = [positions.buffer, packedBuffer.buffer];
  126. var parameters = {
  127. positions: positions.buffer,
  128. packedBuffer: packedBuffer.buffer,
  129. };
  130. var verticesPromise = (points._verticesPromise = createVerticesTaskProcessor.scheduleTask(
  131. parameters,
  132. transferrableObjects
  133. ));
  134. if (!defined(verticesPromise)) {
  135. // Postponed
  136. return;
  137. }
  138. verticesPromise.then(function (result) {
  139. points._positions = new Float64Array(result.positions);
  140. points._ready = true;
  141. });
  142. }
  143. if (points._ready && !defined(points._billboardCollection)) {
  144. positions = points._positions;
  145. var batchTable = points._batchTable;
  146. var batchIds = points._batchIds;
  147. var billboardCollection = (points._billboardCollection = new BillboardCollection(
  148. { batchTable: batchTable }
  149. ));
  150. var labelCollection = (points._labelCollection = new LabelCollection({
  151. batchTable: batchTable,
  152. }));
  153. var polylineCollection = (points._polylineCollection = new PolylineCollection());
  154. polylineCollection._useHighlightColor = true;
  155. var numberOfPoints = positions.length / 3;
  156. for (var i = 0; i < numberOfPoints; ++i) {
  157. var id = batchIds[i];
  158. var position = Cartesian3.unpack(positions, i * 3, scratchPosition);
  159. var b = billboardCollection.add();
  160. b.position = position;
  161. b._batchIndex = id;
  162. var l = labelCollection.add();
  163. l.text = " ";
  164. l.position = position;
  165. l._batchIndex = id;
  166. var p = polylineCollection.add();
  167. p.positions = [Cartesian3.clone(position), Cartesian3.clone(position)];
  168. }
  169. points._positions = undefined;
  170. points._packedBuffer = undefined;
  171. }
  172. }
  173. /**
  174. * Creates features for each point and places it at the batch id index of features.
  175. *
  176. * @param {Vector3DTileContent} content The vector tile content.
  177. * @param {Cesium3DTileFeature[]} features An array of features where the point features will be placed.
  178. */
  179. Vector3DTilePoints.prototype.createFeatures = function (content, features) {
  180. var billboardCollection = this._billboardCollection;
  181. var labelCollection = this._labelCollection;
  182. var polylineCollection = this._polylineCollection;
  183. var batchIds = this._batchIds;
  184. var length = batchIds.length;
  185. for (var i = 0; i < length; ++i) {
  186. var batchId = batchIds[i];
  187. var billboard = billboardCollection.get(i);
  188. var label = labelCollection.get(i);
  189. var polyline = polylineCollection.get(i);
  190. features[batchId] = new Cesium3DTilePointFeature(
  191. content,
  192. batchId,
  193. billboard,
  194. label,
  195. polyline
  196. );
  197. }
  198. };
  199. /**
  200. * Colors the entire tile when enabled is true. The resulting color will be (batch table color * color).
  201. *
  202. * @param {Boolean} enabled Whether to enable debug coloring.
  203. * @param {Color} color The debug color.
  204. */
  205. Vector3DTilePoints.prototype.applyDebugSettings = function (enabled, color) {
  206. if (enabled) {
  207. Color.clone(color, this._billboardCollection._highlightColor);
  208. Color.clone(color, this._labelCollection._highlightColor);
  209. Color.clone(color, this._polylineCollection._highlightColor);
  210. } else {
  211. Color.clone(Color.WHITE, this._billboardCollection._highlightColor);
  212. Color.clone(Color.WHITE, this._labelCollection._highlightColor);
  213. Color.clone(Color.WHITE, this._polylineCollection._highlightColor);
  214. }
  215. };
  216. function clearStyle(polygons, features) {
  217. var batchIds = polygons._batchIds;
  218. var length = batchIds.length;
  219. for (var i = 0; i < length; ++i) {
  220. var batchId = batchIds[i];
  221. var feature = features[batchId];
  222. feature.show = true;
  223. feature.pointSize = Cesium3DTilePointFeature.defaultPointSize;
  224. feature.color = Cesium3DTilePointFeature.defaultColor;
  225. feature.pointOutlineColor =
  226. Cesium3DTilePointFeature.defaultPointOutlineColor;
  227. feature.pointOutlineWidth =
  228. Cesium3DTilePointFeature.defaultPointOutlineWidth;
  229. feature.labelColor = Color.WHITE;
  230. feature.labelOutlineColor = Color.WHITE;
  231. feature.labelOutlineWidth = 1.0;
  232. feature.font = "30px sans-serif";
  233. feature.labelStyle = LabelStyle.FILL;
  234. feature.labelText = undefined;
  235. feature.backgroundColor = new Color(0.165, 0.165, 0.165, 0.8);
  236. feature.backgroundPadding = new Cartesian2(7, 5);
  237. feature.backgroundEnabled = false;
  238. feature.scaleByDistance = undefined;
  239. feature.translucencyByDistance = undefined;
  240. feature.distanceDisplayCondition = undefined;
  241. feature.heightOffset = 0.0;
  242. feature.anchorLineEnabled = false;
  243. feature.anchorLineColor = Color.WHITE;
  244. feature.image = undefined;
  245. feature.disableDepthTestDistance = 0.0;
  246. feature.horizontalOrigin = HorizontalOrigin.CENTER;
  247. feature.verticalOrigin = VerticalOrigin.CENTER;
  248. feature.labelHorizontalOrigin = HorizontalOrigin.RIGHT;
  249. feature.labelVerticalOrigin = VerticalOrigin.BASELINE;
  250. }
  251. }
  252. var scratchColor = new Color();
  253. var scratchColor2 = new Color();
  254. var scratchColor3 = new Color();
  255. var scratchColor4 = new Color();
  256. var scratchColor5 = new Color();
  257. var scratchColor6 = new Color();
  258. var scratchScaleByDistance = new NearFarScalar();
  259. var scratchTranslucencyByDistance = new NearFarScalar();
  260. var scratchDistanceDisplayCondition = new DistanceDisplayCondition();
  261. /**
  262. * Apply a style to the content.
  263. *
  264. * @param {Cesium3DTileStyle} style The style.
  265. * @param {Cesium3DTileFeature[]} features The array of features.
  266. */
  267. Vector3DTilePoints.prototype.applyStyle = function (style, features) {
  268. if (!defined(style)) {
  269. clearStyle(this, features);
  270. return;
  271. }
  272. var batchIds = this._batchIds;
  273. var length = batchIds.length;
  274. for (var i = 0; i < length; ++i) {
  275. var batchId = batchIds[i];
  276. var feature = features[batchId];
  277. if (defined(style.show)) {
  278. feature.show = style.show.evaluate(feature);
  279. }
  280. if (defined(style.pointSize)) {
  281. feature.pointSize = style.pointSize.evaluate(feature);
  282. }
  283. if (defined(style.color)) {
  284. feature.color = style.color.evaluateColor(feature, scratchColor);
  285. }
  286. if (defined(style.pointOutlineColor)) {
  287. feature.pointOutlineColor = style.pointOutlineColor.evaluateColor(
  288. feature,
  289. scratchColor2
  290. );
  291. }
  292. if (defined(style.pointOutlineWidth)) {
  293. feature.pointOutlineWidth = style.pointOutlineWidth.evaluate(feature);
  294. }
  295. if (defined(style.labelColor)) {
  296. feature.labelColor = style.labelColor.evaluateColor(
  297. feature,
  298. scratchColor3
  299. );
  300. }
  301. if (defined(style.labelOutlineColor)) {
  302. feature.labelOutlineColor = style.labelOutlineColor.evaluateColor(
  303. feature,
  304. scratchColor4
  305. );
  306. }
  307. if (defined(style.labelOutlineWidth)) {
  308. feature.labelOutlineWidth = style.labelOutlineWidth.evaluate(feature);
  309. }
  310. if (defined(style.font)) {
  311. feature.font = style.font.evaluate(feature);
  312. }
  313. if (defined(style.labelStyle)) {
  314. feature.labelStyle = style.labelStyle.evaluate(feature);
  315. }
  316. if (defined(style.labelText)) {
  317. feature.labelText = style.labelText.evaluate(feature);
  318. } else {
  319. feature.labelText = undefined;
  320. }
  321. if (defined(style.backgroundColor)) {
  322. feature.backgroundColor = style.backgroundColor.evaluateColor(
  323. feature,
  324. scratchColor5
  325. );
  326. }
  327. if (defined(style.backgroundPadding)) {
  328. feature.backgroundPadding = style.backgroundPadding.evaluate(feature);
  329. }
  330. if (defined(style.backgroundEnabled)) {
  331. feature.backgroundEnabled = style.backgroundEnabled.evaluate(feature);
  332. }
  333. if (defined(style.scaleByDistance)) {
  334. var scaleByDistanceCart4 = style.scaleByDistance.evaluate(feature);
  335. scratchScaleByDistance.near = scaleByDistanceCart4.x;
  336. scratchScaleByDistance.nearValue = scaleByDistanceCart4.y;
  337. scratchScaleByDistance.far = scaleByDistanceCart4.z;
  338. scratchScaleByDistance.farValue = scaleByDistanceCart4.w;
  339. feature.scaleByDistance = scratchScaleByDistance;
  340. } else {
  341. feature.scaleByDistance = undefined;
  342. }
  343. if (defined(style.translucencyByDistance)) {
  344. var translucencyByDistanceCart4 = style.translucencyByDistance.evaluate(
  345. feature
  346. );
  347. scratchTranslucencyByDistance.near = translucencyByDistanceCart4.x;
  348. scratchTranslucencyByDistance.nearValue = translucencyByDistanceCart4.y;
  349. scratchTranslucencyByDistance.far = translucencyByDistanceCart4.z;
  350. scratchTranslucencyByDistance.farValue = translucencyByDistanceCart4.w;
  351. feature.translucencyByDistance = scratchTranslucencyByDistance;
  352. } else {
  353. feature.translucencyByDistance = undefined;
  354. }
  355. if (defined(style.distanceDisplayCondition)) {
  356. var distanceDisplayConditionCart2 = style.distanceDisplayCondition.evaluate(
  357. feature
  358. );
  359. scratchDistanceDisplayCondition.near = distanceDisplayConditionCart2.x;
  360. scratchDistanceDisplayCondition.far = distanceDisplayConditionCart2.y;
  361. feature.distanceDisplayCondition = scratchDistanceDisplayCondition;
  362. } else {
  363. feature.distanceDisplayCondition = undefined;
  364. }
  365. if (defined(style.heightOffset)) {
  366. feature.heightOffset = style.heightOffset.evaluate(feature);
  367. }
  368. if (defined(style.anchorLineEnabled)) {
  369. feature.anchorLineEnabled = style.anchorLineEnabled.evaluate(feature);
  370. }
  371. if (defined(style.anchorLineColor)) {
  372. feature.anchorLineColor = style.anchorLineColor.evaluateColor(
  373. feature,
  374. scratchColor6
  375. );
  376. }
  377. if (defined(style.image)) {
  378. feature.image = style.image.evaluate(feature);
  379. } else {
  380. feature.image = undefined;
  381. }
  382. if (defined(style.disableDepthTestDistance)) {
  383. feature.disableDepthTestDistance = style.disableDepthTestDistance.evaluate(
  384. feature
  385. );
  386. }
  387. if (defined(style.horizontalOrigin)) {
  388. feature.horizontalOrigin = style.horizontalOrigin.evaluate(feature);
  389. }
  390. if (defined(style.verticalOrigin)) {
  391. feature.verticalOrigin = style.verticalOrigin.evaluate(feature);
  392. }
  393. if (defined(style.labelHorizontalOrigin)) {
  394. feature.labelHorizontalOrigin = style.labelHorizontalOrigin.evaluate(
  395. feature
  396. );
  397. }
  398. if (defined(style.labelVerticalOrigin)) {
  399. feature.labelVerticalOrigin = style.labelVerticalOrigin.evaluate(feature);
  400. }
  401. }
  402. };
  403. /**
  404. * @private
  405. */
  406. Vector3DTilePoints.prototype.update = function (frameState) {
  407. createPoints(this, frameState.mapProjection.ellipsoid);
  408. if (!this._ready) {
  409. return;
  410. }
  411. this._polylineCollection.update(frameState);
  412. this._billboardCollection.update(frameState);
  413. this._labelCollection.update(frameState);
  414. if (!this._resolvedPromise) {
  415. this._readyPromise.resolve();
  416. this._resolvedPromise = true;
  417. }
  418. };
  419. /**
  420. * Returns true if this object was destroyed; otherwise, false.
  421. * <p>
  422. * If this object was destroyed, it should not be used; calling any function other than
  423. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  424. * </p>
  425. *
  426. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  427. */
  428. Vector3DTilePoints.prototype.isDestroyed = function () {
  429. return false;
  430. };
  431. /**
  432. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  433. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  434. * <p>
  435. * Once an object is destroyed, it should not be used; calling any function other than
  436. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  437. * assign the return value (<code>undefined</code>) to the object as done in the example.
  438. * </p>
  439. *
  440. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  441. */
  442. Vector3DTilePoints.prototype.destroy = function () {
  443. this._billboardCollection =
  444. this._billboardCollection && this._billboardCollection.destroy();
  445. this._labelCollection =
  446. this._labelCollection && this._labelCollection.destroy();
  447. this._polylineCollection =
  448. this._polylineCollection && this._polylineCollection.destroy();
  449. return destroyObject(this);
  450. };
  451. export default Vector3DTilePoints;