Vector3DTilePoints.js 19 KB

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