我目前正在使用一个使用Cesium Viewer的应用程序。我需要能够显示将动态更新的形状集合。我无法理解最好的方法。
我目前正在使用实体并使用CallbackProperties来更新形状。
你可以通过这个到沙堡来了解我是如何做到这一点的。有一个多边形对象被用作cesiumCallback的基础,它正在被另一段代码编辑。 (使用setTimeout模拟)
var viewer = new Cesium.Viewer('cesiumContainer', {});
var polygon = {};
polygon.coordinates = [
{longitude: 0, latitude: 0, altitude: 0},
{longitude: 10, latitude: 10, altitude: 0},
{longitude: 10, latitude: 0, altitude: 0}
];
// converts generic style options to cesium one (aka color -> material)
var polOpts = {};
// function for getting location
polOpts.hierarchy = new Cesium.CallbackProperty(function() {
var hierarchy = [];
for (var i = 0; i < polygon.coordinates.length; i++) {
var coordinate = polygon.coordinates[i];
hierarchy.push(Cesium.Cartesian3.fromDegrees(coordinate.longitude, coordinate.latitude, coordinate.altitude));
}
return hierarchy;
}, false);
viewer.entities.add({polygon: polOpts});
setInterval(function(polygon){
polygon.coordinates[0].longitude--;
}.bind(this, polygon), 1000);
传入的多边形是一个通常描述多边形的类,因此它有一个坐标和样式选项数组,以及一个调用此方法renderPolygon传递的render方法。 这种渲染形状的方法适用于我需要的所有东西,但效果不是很好。形状更新有两种情况,一种形状将在很长一段时间内更新,速度很慢,例如每几秒一次。另一种形状将在几秒钟内多次更新,例如数千次,然后长时间不再更换,如果有的话。
我有两个想法来解决这个问题。
创意1: 有两个方法,一个renderDynamicPolygon和一个renderStaticPolygon。 renderDynamicPolygon方法将使用cesiumCallbackProperties执行上述功能。这将用于在更新的短时间内多次更新的形状。 一旦更新完成,renderStaticPolygon方法将替换使用具有常量值的callbackProperties的实体属性。
这会产生许多其他工作,以确保形状处于正确状态,并且无法帮助长时间缓慢更新的形状。
创意2: 与原语的工作方式类似,我尝试删除旧实体,并在每次需要更新时再次添加更新的属性,但这会导致闪烁,与原语不同,我找不到实体的异步属性。 / p>
我也尝试过使用原语。它对折线非常有用,我只需删除旧折线并添加一个带有更新属性的新线。我也使用async = false来确保没有闪烁。我遇到的这个问题并非所有形状都可以使用基元创建。 (这是真的吗?)
我尝试的另一件事是使用几何和实例使用几何实例。在完成cesium网站上的教程之后,我能够渲染一些形状,并且可以更新外观,但发现几乎不可能弄清楚如何正确更新形状,并且很难让它们到达看起来正确。形状需要具有正确的形状,填充颜色和不透明度以及笔触颜色,不透明度和重量。我试图使用polygonOutlineGeometry,但没有运气。
实施此操作的最佳方法是什么?其中一个选项是正确的方式还是有其他方法这样做我还没有发现?
[编辑]我添加了一个答案,我已经得到了,但仍然没有完成并寻找答案。
答案 0 :(得分:1)
我已经提出了一个非常好的解决方案,但它仍然有一个小问题。
我做了很多显示实体的方法。我正在调用一个渲染和一个绘画。渲染使用带有Cesium.CallbackProperty
属性isConstant
的{{1}},并使用true
isConstantProperty
进行绘制。
然后我创建了一个函数来将实体从渲染更改为绘制和反面。它遍历实体回调属性,并使用setCallback属性用正确的函数和isConstant值覆盖属性。
实施例: 我根据我定义的圆形对象创建了一个椭圆。
false
因此,在更新形状时(当用户绘制形状时),将使用isConstant为false来呈现形状。 然后在绘图完成后,使用以下代码转换为绘制版本:
// isConst is True if it is being "painted" and false if it is being "rendered"
ellipse: lenz.util.extend(this._getStyleOptions(circle), {
semiMinorAxis: new Cesium.CallbackProperty(
this._getRadius.bind(this, circle),
isConst
),
semiMajorAxis: new Cesium.CallbackProperty(
this._getRadius.bind(this, circle),
isConst
),
})
这非常有效。我可以绘制数百个形状,而框架几乎没有掉落。我在我的更改之前和之后附加了612个实体的铯地图的屏幕截图,使用chrome渲染工具在右上方显示帧速率。
之前:以fps 0.9锁定 注意:我编辑了ui的其余部分,女巫使地球看起来被切断了,抱歉
在变化之后:fps保持在59.9,几乎完美!
每当实体被转换为&#39;从使用常量到非常量回调属性,它和相同类型的所有其他实体再次闪烁。我无法找到更好的方法来进行此转换。我觉得仍然有一些我想念的东西。
答案 1 :(得分:0)
您可以尝试使用PositionPropertyArray
作为多边形的层次结构,SampledPositionProperty
用于任何动态位置,ConstantPositionProperty
用于任何静态位置。我不确定它是否会比你的解决方案更好,但它可能值得测试。以下是一个可以将其粘贴到Cesium Sandcastle中的工作原理示例:
var viewer = new Cesium.Viewer('cesiumContainer', {});
// required if you want no interpolation of position between times
var noInterpolation = {
type: 'No Interpolation',
getRequiredDataPoints: function (degree) {
return 2;
},
interpolateOrderZero: function (x, xTable, yTable, yStride, result) {
if (!Cesium.defined(result)) {
result = new Array(yStride);
}
for (var i = 0; i < yStride; i++) {
result[i] = yTable[i];
}
return result;
}
};
var start = viewer.clock.currentTime;
// set up the sampled position property
var sampledPositionProperty = new Cesium.SampledPositionProperty();
sampledPositionProperty.forwardExtrapolationType = Cesium.ExtrapolationType.HOLD;
sampledPositionProperty.addSample(start, new Cesium.Cartesian3.fromDegrees(0, 0)); // initial position
sampledPositionProperty.setInterpolationOptions({
interpolationAlgorithm: noInterpolation
});
// set up the sampled position property array
var positions = [
sampledPositionProperty,
new Cesium.ConstantPositionProperty(new Cesium.Cartesian3.fromDegrees(10, 10)),
new Cesium.ConstantPositionProperty(new Cesium.Cartesian3.fromDegrees(10, 0))
];
// add the polygon to Cesium viewer
var polygonEntity = new Cesium.Entity({
polygon: {
hierarchy: new Cesium.PositionPropertyArray(positions)
}
});
viewer.zoomTo(viewer.entities.add(polygonEntity));
// add a sample every second
var counter = 1;
setInterval(function(positionArray) {
var time = new Cesium.JulianDate.addSeconds(start, counter, new Cesium.JulianDate());
var position = new Cesium.Cartesian3.fromDegrees(-counter, 0);
positionArray[0].addSample(time, position);
counter++;
}.bind(this, positions), 1000);
关于这一点的一个好处是你可以将时间轴开始/结束时间设置为合理的范围,并使用它在样本范围内的任何时间查看多边形,这样你就可以看到多边形的历史记录(参见{ {3}}了解如何更改时间轴开始/结束时间)。此外,您不需要使用计时器来设置位置,时间内置于SampledPositionProperty
(尽管您仍然可以异步添加样本)。
但是,这也意味着位置取决于时间轴中的当前时间而不是实时数组值。如果你不是一次性添加所有样本,你可能需要在某个地方跟踪时间。
我以前从未使用过省略号,但semiMinorAxis
和semiMajorAxis
属性,因此您仍然可以使用here。
当然,如果仍存在性能问题,这并不重要。希望它会得到改善,因为您不需要从头开始重新创建每个回调的数组,并且根据您获取数据以更新多边形的方式,您可以一次添加多个样本。这只是猜测,但需要考虑。
Cesium可以处理添加到采样位置的相当多的样本,例如在上面的代码中,如果你将一百万个样本添加到需要几秒钟加载它们的位置,但是在任何时候都可以渲染多边形任何表现问题。要测试它,不要使用计时器添加样本,只需将它们全部直接添加到属性中。
for (var i = 0; i < 1000000; i++) {
var time = new Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());
var position = new Cesium.Cartesian3.fromDegrees(-(i % 2), 0);
positions[0].addSample(time, position);
}
但是,如果遇到内存问题SampledProperty
。解决方法是定期创建一个包含新位置属性的新数组,并使用先前的位置属性数组的setValue()
方法清除以前的值,或者使用TimeIntervalCollectionProperty
currently there is no way to remove samples from a position property without accessing private variables并删除时间使用as in this answer方法的间隔。