在cesium

时间:2015-09-30 15:17:51

标签: cesium

我目前正在使用一个使用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,但没有运气。

实施此操作的最佳方法是什么?其中一个选项是正确的方式还是有其他方法这样做我还没有发现?

[编辑]我添加了一个答案,我已经得到了,但仍然没有完成并寻找答案。

2 个答案:

答案 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的其余部分,女巫使地球看起来被切断了,抱歉 enter image description here

在变化之后:fps保持在59.9,几乎完美!

enter image description here

每当实体被转换为&#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(尽管您仍然可以异步添加样本)。

但是,这也意味着位置取决于时间轴中的当前时间而不是实时数组值。如果你不是一次性添加所有样本,你可能需要在某个地方跟踪时间。

我以前从未使用过省略号,但semiMinorAxissemiMajorAxis属性,因此您仍然可以使用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方法的间隔。