You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

528 lines
16 KiB
JavaScript

import arraySlice from "../Core/arraySlice.js";
import Cartesian2 from "../Core/Cartesian2.js";
import Cartesian3 from "../Core/Cartesian3.js";
import Color from "../Core/Color.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
import Ellipsoid from "../Core/Ellipsoid.js";
import NearFarScalar from "../Core/NearFarScalar.js";
import Rectangle from "../Core/Rectangle.js";
import TaskProcessor from "../Core/TaskProcessor.js";
import when from "../ThirdParty/when.js";
import BillboardCollection from "./BillboardCollection.js";
import Cesium3DTilePointFeature from "./Cesium3DTilePointFeature.js";
import HorizontalOrigin from "./HorizontalOrigin.js";
import LabelCollection from "./LabelCollection.js";
import LabelStyle from "./LabelStyle.js";
import PolylineCollection from "./PolylineCollection.js";
import VerticalOrigin from "./VerticalOrigin.js";
/**
* Creates a batch of points or billboards and labels.
*
* @alias Vector3DTilePoints
* @constructor
*
* @param {Object} options An object with following properties:
* @param {Uint16Array} options.positions The positions of the polygons.
* @param {Number} options.minimumHeight The minimum height of the terrain covered by the tile.
* @param {Number} options.maximumHeight The maximum height of the terrain covered by the tile.
* @param {Rectangle} options.rectangle The rectangle containing the tile.
* @param {Cesium3DTileBatchTable} options.batchTable The batch table for the tile containing the batched polygons.
* @param {Uint16Array} options.batchIds The batch ids for each polygon.
*
* @private
*/
function Vector3DTilePoints(options) {
// released after the first update
this._positions = options.positions;
this._batchTable = options.batchTable;
this._batchIds = options.batchIds;
this._rectangle = options.rectangle;
this._minHeight = options.minimumHeight;
this._maxHeight = options.maximumHeight;
this._billboardCollection = undefined;
this._labelCollection = undefined;
this._polylineCollection = undefined;
this._verticesPromise = undefined;
this._packedBuffer = undefined;
this._ready = false;
this._readyPromise = when.defer();
this._resolvedPromise = false;
}
Object.defineProperties(Vector3DTilePoints.prototype, {
/**
* Gets the number of points.
*
* @memberof Vector3DTilePoints.prototype
*
* @type {Number}
* @readonly
*/
pointsLength: {
get: function () {
return this._billboardCollection.length;
},
},
/**
* Gets the texture atlas memory in bytes.
*
* @memberof Vector3DTilePoints.prototype
*
* @type {Number}
* @readonly
*/
texturesByteLength: {
get: function () {
var billboardSize = this._billboardCollection.textureAtlas.texture
.sizeInBytes;
var labelSize = this._labelCollection._textureAtlas.texture.sizeInBytes;
return billboardSize + labelSize;
},
},
/**
* Gets a promise that resolves when the primitive is ready to render.
* @memberof Vector3DTilePoints.prototype
* @type {Promise<void>}
* @readonly
*/
readyPromise: {
get: function () {
return this._readyPromise.promise;
},
},
});
function packBuffer(points, ellipsoid) {
var rectangle = points._rectangle;
var minimumHeight = points._minHeight;
var maximumHeight = points._maxHeight;
var packedLength = 2 + Rectangle.packedLength + Ellipsoid.packedLength;
var packedBuffer = new Float64Array(packedLength);
var offset = 0;
packedBuffer[offset++] = minimumHeight;
packedBuffer[offset++] = maximumHeight;
Rectangle.pack(rectangle, packedBuffer, offset);
offset += Rectangle.packedLength;
Ellipsoid.pack(ellipsoid, packedBuffer, offset);
return packedBuffer;
}
var createVerticesTaskProcessor = new TaskProcessor(
"createVectorTilePoints",
5
);
var scratchPosition = new Cartesian3();
function createPoints(points, ellipsoid) {
if (defined(points._billboardCollection)) {
return;
}
var positions;
if (!defined(points._verticesPromise)) {
positions = points._positions;
var packedBuffer = points._packedBuffer;
if (!defined(packedBuffer)) {
// Copy because they may be the views on the same buffer.
positions = points._positions = arraySlice(positions);
points._batchIds = arraySlice(points._batchIds);
packedBuffer = points._packedBuffer = packBuffer(points, ellipsoid);
}
var transferrableObjects = [positions.buffer, packedBuffer.buffer];
var parameters = {
positions: positions.buffer,
packedBuffer: packedBuffer.buffer,
};
var verticesPromise = (points._verticesPromise = createVerticesTaskProcessor.scheduleTask(
parameters,
transferrableObjects
));
if (!defined(verticesPromise)) {
// Postponed
return;
}
verticesPromise.then(function (result) {
points._positions = new Float64Array(result.positions);
points._ready = true;
});
}
if (points._ready && !defined(points._billboardCollection)) {
positions = points._positions;
var batchTable = points._batchTable;
var batchIds = points._batchIds;
var billboardCollection = (points._billboardCollection = new BillboardCollection(
{ batchTable: batchTable }
));
var labelCollection = (points._labelCollection = new LabelCollection({
batchTable: batchTable,
}));
var polylineCollection = (points._polylineCollection = new PolylineCollection());
polylineCollection._useHighlightColor = true;
var numberOfPoints = positions.length / 3;
for (var i = 0; i < numberOfPoints; ++i) {
var id = batchIds[i];
var position = Cartesian3.unpack(positions, i * 3, scratchPosition);
var b = billboardCollection.add();
b.position = position;
b._batchIndex = id;
var l = labelCollection.add();
l.text = " ";
l.position = position;
l._batchIndex = id;
var p = polylineCollection.add();
p.positions = [Cartesian3.clone(position), Cartesian3.clone(position)];
}
points._positions = undefined;
points._packedBuffer = undefined;
}
}
/**
* Creates features for each point and places it at the batch id index of features.
*
* @param {Vector3DTileContent} content The vector tile content.
* @param {Cesium3DTileFeature[]} features An array of features where the point features will be placed.
*/
Vector3DTilePoints.prototype.createFeatures = function (content, features) {
var billboardCollection = this._billboardCollection;
var labelCollection = this._labelCollection;
var polylineCollection = this._polylineCollection;
var batchIds = this._batchIds;
var length = batchIds.length;
for (var i = 0; i < length; ++i) {
var batchId = batchIds[i];
var billboard = billboardCollection.get(i);
var label = labelCollection.get(i);
var polyline = polylineCollection.get(i);
features[batchId] = new Cesium3DTilePointFeature(
content,
batchId,
billboard,
label,
polyline
);
}
};
/**
* Colors the entire tile when enabled is true. The resulting color will be (batch table color * color).
*
* @param {Boolean} enabled Whether to enable debug coloring.
* @param {Color} color The debug color.
*/
Vector3DTilePoints.prototype.applyDebugSettings = function (enabled, color) {
if (enabled) {
Color.clone(color, this._billboardCollection._highlightColor);
Color.clone(color, this._labelCollection._highlightColor);
Color.clone(color, this._polylineCollection._highlightColor);
} else {
Color.clone(Color.WHITE, this._billboardCollection._highlightColor);
Color.clone(Color.WHITE, this._labelCollection._highlightColor);
Color.clone(Color.WHITE, this._polylineCollection._highlightColor);
}
};
function clearStyle(polygons, features) {
var batchIds = polygons._batchIds;
var length = batchIds.length;
for (var i = 0; i < length; ++i) {
var batchId = batchIds[i];
var feature = features[batchId];
feature.show = true;
feature.pointSize = Cesium3DTilePointFeature.defaultPointSize;
feature.color = Cesium3DTilePointFeature.defaultColor;
feature.pointOutlineColor =
Cesium3DTilePointFeature.defaultPointOutlineColor;
feature.pointOutlineWidth =
Cesium3DTilePointFeature.defaultPointOutlineWidth;
feature.labelColor = Color.WHITE;
feature.labelOutlineColor = Color.WHITE;
feature.labelOutlineWidth = 1.0;
feature.font = "30px sans-serif";
feature.labelStyle = LabelStyle.FILL;
feature.labelText = undefined;
feature.backgroundColor = new Color(0.165, 0.165, 0.165, 0.8);
feature.backgroundPadding = new Cartesian2(7, 5);
feature.backgroundEnabled = false;
feature.scaleByDistance = undefined;
feature.translucencyByDistance = undefined;
feature.distanceDisplayCondition = undefined;
feature.heightOffset = 0.0;
feature.anchorLineEnabled = false;
feature.anchorLineColor = Color.WHITE;
feature.image = undefined;
feature.disableDepthTestDistance = 0.0;
feature.horizontalOrigin = HorizontalOrigin.CENTER;
feature.verticalOrigin = VerticalOrigin.CENTER;
feature.labelHorizontalOrigin = HorizontalOrigin.RIGHT;
feature.labelVerticalOrigin = VerticalOrigin.BASELINE;
}
}
var scratchColor = new Color();
var scratchColor2 = new Color();
var scratchColor3 = new Color();
var scratchColor4 = new Color();
var scratchColor5 = new Color();
var scratchColor6 = new Color();
var scratchScaleByDistance = new NearFarScalar();
var scratchTranslucencyByDistance = new NearFarScalar();
var scratchDistanceDisplayCondition = new DistanceDisplayCondition();
/**
* Apply a style to the content.
*
* @param {Cesium3DTileStyle} style The style.
* @param {Cesium3DTileFeature[]} features The array of features.
*/
Vector3DTilePoints.prototype.applyStyle = function (style, features) {
if (!defined(style)) {
clearStyle(this, features);
return;
}
var batchIds = this._batchIds;
var length = batchIds.length;
for (var i = 0; i < length; ++i) {
var batchId = batchIds[i];
var feature = features[batchId];
if (defined(style.show)) {
feature.show = style.show.evaluate(feature);
}
if (defined(style.pointSize)) {
feature.pointSize = style.pointSize.evaluate(feature);
}
if (defined(style.color)) {
feature.color = style.color.evaluateColor(feature, scratchColor);
}
if (defined(style.pointOutlineColor)) {
feature.pointOutlineColor = style.pointOutlineColor.evaluateColor(
feature,
scratchColor2
);
}
if (defined(style.pointOutlineWidth)) {
feature.pointOutlineWidth = style.pointOutlineWidth.evaluate(feature);
}
if (defined(style.labelColor)) {
feature.labelColor = style.labelColor.evaluateColor(
feature,
scratchColor3
);
}
if (defined(style.labelOutlineColor)) {
feature.labelOutlineColor = style.labelOutlineColor.evaluateColor(
feature,
scratchColor4
);
}
if (defined(style.labelOutlineWidth)) {
feature.labelOutlineWidth = style.labelOutlineWidth.evaluate(feature);
}
if (defined(style.font)) {
feature.font = style.font.evaluate(feature);
}
if (defined(style.labelStyle)) {
feature.labelStyle = style.labelStyle.evaluate(feature);
}
if (defined(style.labelText)) {
feature.labelText = style.labelText.evaluate(feature);
} else {
feature.labelText = undefined;
}
if (defined(style.backgroundColor)) {
feature.backgroundColor = style.backgroundColor.evaluateColor(
feature,
scratchColor5
);
}
if (defined(style.backgroundPadding)) {
feature.backgroundPadding = style.backgroundPadding.evaluate(feature);
}
if (defined(style.backgroundEnabled)) {
feature.backgroundEnabled = style.backgroundEnabled.evaluate(feature);
}
if (defined(style.scaleByDistance)) {
var scaleByDistanceCart4 = style.scaleByDistance.evaluate(feature);
scratchScaleByDistance.near = scaleByDistanceCart4.x;
scratchScaleByDistance.nearValue = scaleByDistanceCart4.y;
scratchScaleByDistance.far = scaleByDistanceCart4.z;
scratchScaleByDistance.farValue = scaleByDistanceCart4.w;
feature.scaleByDistance = scratchScaleByDistance;
} else {
feature.scaleByDistance = undefined;
}
if (defined(style.translucencyByDistance)) {
var translucencyByDistanceCart4 = style.translucencyByDistance.evaluate(
feature
);
scratchTranslucencyByDistance.near = translucencyByDistanceCart4.x;
scratchTranslucencyByDistance.nearValue = translucencyByDistanceCart4.y;
scratchTranslucencyByDistance.far = translucencyByDistanceCart4.z;
scratchTranslucencyByDistance.farValue = translucencyByDistanceCart4.w;
feature.translucencyByDistance = scratchTranslucencyByDistance;
} else {
feature.translucencyByDistance = undefined;
}
if (defined(style.distanceDisplayCondition)) {
var distanceDisplayConditionCart2 = style.distanceDisplayCondition.evaluate(
feature
);
scratchDistanceDisplayCondition.near = distanceDisplayConditionCart2.x;
scratchDistanceDisplayCondition.far = distanceDisplayConditionCart2.y;
feature.distanceDisplayCondition = scratchDistanceDisplayCondition;
} else {
feature.distanceDisplayCondition = undefined;
}
if (defined(style.heightOffset)) {
feature.heightOffset = style.heightOffset.evaluate(feature);
}
if (defined(style.anchorLineEnabled)) {
feature.anchorLineEnabled = style.anchorLineEnabled.evaluate(feature);
}
if (defined(style.anchorLineColor)) {
feature.anchorLineColor = style.anchorLineColor.evaluateColor(
feature,
scratchColor6
);
}
if (defined(style.image)) {
feature.image = style.image.evaluate(feature);
} else {
feature.image = undefined;
}
if (defined(style.disableDepthTestDistance)) {
feature.disableDepthTestDistance = style.disableDepthTestDistance.evaluate(
feature
);
}
if (defined(style.horizontalOrigin)) {
feature.horizontalOrigin = style.horizontalOrigin.evaluate(feature);
}
if (defined(style.verticalOrigin)) {
feature.verticalOrigin = style.verticalOrigin.evaluate(feature);
}
if (defined(style.labelHorizontalOrigin)) {
feature.labelHorizontalOrigin = style.labelHorizontalOrigin.evaluate(
feature
);
}
if (defined(style.labelVerticalOrigin)) {
feature.labelVerticalOrigin = style.labelVerticalOrigin.evaluate(feature);
}
}
};
/**
* @private
*/
Vector3DTilePoints.prototype.update = function (frameState) {
createPoints(this, frameState.mapProjection.ellipsoid);
if (!this._ready) {
return;
}
this._polylineCollection.update(frameState);
this._billboardCollection.update(frameState);
this._labelCollection.update(frameState);
if (!this._resolvedPromise) {
this._readyPromise.resolve();
this._resolvedPromise = true;
}
};
/**
* Returns true if this object was destroyed; otherwise, false.
* <p>
* If this object was destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
* </p>
*
* @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
*/
Vector3DTilePoints.prototype.isDestroyed = function () {
return false;
};
/**
* Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
* release of WebGL resources, instead of relying on the garbage collector to destroy this object.
* <p>
* Once an object is destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
* assign the return value (<code>undefined</code>) to the object as done in the example.
* </p>
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
*/
Vector3DTilePoints.prototype.destroy = function () {
this._billboardCollection =
this._billboardCollection && this._billboardCollection.destroy();
this._labelCollection =
this._labelCollection && this._labelCollection.destroy();
this._polylineCollection =
this._polylineCollection && this._polylineCollection.destroy();
return destroyObject(this);
};
export default Vector3DTilePoints;