Cesium 如何在 zoom-in/zoom-out 时缩放多边形以匹配 Lat-Lon 位置

Cesium how to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out

我正在寻找 Cesium Guru 来帮助我找到我需要的东西。我是 Cesium 的新手,但我一直在使用教程和我继承的一些现有代码。

在我的 Cesium 应用程序中,我输入我的地址,视图放大到我的街道。耶!然后我拉近一点,这样我就可以在我的房子周围画一个多边形。现有代码在这方面做得很好。然而,当我缩小然后再次放大时,我的多边形不符合我家的 Lat-Lon 位置

Does Cesium contain a utility to scale pixels to lat-lon coordinates or do I need to use something like distanceToBoundingSphere(boundingSphere) and calculate it myself? I only want the x,y coordinates; I don't care about height at all.

我一直在查看演示和教程,但到目前为止还没有找到我想要的东西。也许我找到了一些接近的东西,但我还不知道我是否找到了它。求助!

============================代码=========== =======================

正在收集多边形的位置:

单击一次仅捕获该点的坐标,并在用户将鼠标拖动到新点时绘制多段线。因此,一堆折线和每个点的坐标集合。

    positionHandler.setInputAction(function (click) {
        cartesian = scene.camera.pickEllipsoid(click.position, ellipsoid);
        if (cartesian) {
            var setCartographic = ellipsoid.cartesianToCartographic(cartesian);
            asset.latlonalt.push(
                Cesium.Math.toDegrees(setCartographic.latitude).toFixed(15),
                Cesium.Math.toDegrees(setCartographic.longitude).toFixed(15),
                Cesium.Math.toDegrees(setCartographic.height).toFixed(15)
            );
            lla.push(Cesium.Math.toDegrees(setCartographic.longitude), Cesium.Math.toDegrees(setCartographic.latitude));
            if (lla.length >= 4) {
                self.loggingMessage((lla.length / 2) + ' Points Added');
            }
            Cesium.sampleTerrain(terrainProvider, 11, [cartographic])
                .then(function (updatedPositions) {
                    asset.latlonalt[2] = updatedPositions[0].height;
                    stage = 1;
                });
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

DoubleClick 然后获取在 singleClick 函数中捕获的坐标并调用 self.createAsset('add', asset) 来创建多边形。

    positionHandler.setInputAction(function (doubleClick){
        if (asset.shape == 'Polygon') {
            var len = asset.latlonalt.length;
            if(len > 9) {
                asset.rad = (len / 3);
                console.log("Creating Asset");
                self.loggingMessage("Creating Asset");
                socket.emit('newElement', asset.cType, asset);
                self.createAsset('add', asset);
                viewer.entities.remove(entity);
                viewer.entities.remove(newCircle);
                viewer.entities.remove(newPolygon);
                viewer.entities.remove(newOutline);
                positionHandler = positionHandler && positionHandler.destroy();
            }else{
                console.log('3+ Positions Required');
                loggingMessage('3+ Positions Required.');
            }
        }
    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

创建多边形:

            var newPolygon = viewer.entities.add({
                name : asset.id,
                polygon : {
                    hierarchy : Cesium.Cartesian3.fromDegreesArray(vertices),
                    material : rgba[0],
                    outline : true,
                    outlineColor : rgba[1]
                }
            });
            var newLabel = viewer.entities.add({
                position: Cesium.Cartesian3.fromDegrees(asset.latlonalt[1], asset.latlonalt[0], 1000),
                name: asset.id,
                label: {
                    text: asset.name,
                    font : '16px Helvetica'
                }
            });
            var newPoint = viewer.entities.add({
                position: Cesium.Cartesian3.fromDegrees(asset.latlonalt[1], asset.latlonalt[0], 0),
                name: asset.id,
                point : {
                pixelSize : 5,
                    color : Cesium.Color.RED,
                    outlineColor : Cesium.Color.RED,
                    outlineWidth : 2
                }
            });
            self.currentGeometry[asset.id] = {shape: newPolygon, label: newLabel, point: newPoint};

看起来我们正在使用 Terrain(我认为)。

我应该对哪些号码感兴趣:

收集坐标时,只有第一个z不为零:

我采用该值并填充其他 z 值:

现在我已经添加了 z 值,createAsset 方法中出现错误。我需要跟踪该问题以查看结果。现在,它看起来像这样:

真的很大而且轮廓没有被删除。

一个问题涉及很多,但我会尝试解决其中的关键部分。

首先,Cartesian3 class 本身。在内部,在构建之后,这个 class 包含 x, y, z 个成员,这些成员包含 314923.1 这样的值。您可能应该将这些视为黑盒、不透明的值。事实上,它们表示笛卡尔坐标位置,以米为单位,距离地球中心,这是渲染引擎所需要的,但通常对人类制图师没有用。要理解的关键是 z 将始终填充一个真实值,这并不意味着在创建值时是否考虑了高度。

有一个单独的 class Cartographic that contains the familiar Longitude (Radians), Latitude (Radians), and Altitude (in meters) values. Generally these must be converted to Cartesian3 before being handed off to the rendering engine. This conversion requires knowledge of the Ellipsoid(默认为 WGS84 椭球),因此,零高度值表示位于该椭球上的一个点(通常意味着该点是地形打开时在地下)。

各种辅助函数采用通用值(例如以度为单位的 lon/lat)并转换为这两种格式中的任何一种。这些辅助函数中的一些不包含高度参数,而另一些则包含它。这两个 classes 的文档列举了这些助手。

关闭地形后,通过鼠标单击获得准确的 lon/lat 很简单,但由于使用了透视 3D 相机,打开地形后会更加复杂。如果没有地形,您可以像在上面的第一个代码示例中所做的那样调用 scene.camera.pickEllipsoid,并获得确切的位置。但是当地形打开时,即使在平坦的平原上单击也会计算出错误的坐标,在您正在查看的地形下方和后面找到一个地下点。

随意搜索并没有找到正确的代码,但黄金标准似乎是 baked into the existing camera controller here。它看起来像这样:

    var depthIntersection;
    if (scene.pickPositionSupported) {
        depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
    }

    var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
    var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);

    var pickDistance = defined(depthIntersection) ?
        Cartesian3.distance(depthIntersection, camera.positionWC) :
        Number.POSITIVE_INFINITY;
    var rayDistance = defined(rayIntersection) ?
        Cartesian3.distance(rayIntersection, camera.positionWC) :
        Number.POSITIVE_INFINITY;

    if (pickDistance < rayDistance) {
        return Cartesian3.clone(depthIntersection, result);
    }

    return Cartesian3.clone(rayIntersection, result);

此代码尝试采用双管齐下的方法:它尝试像以前一样选择椭球体,并且还尝试从 "depth buffer" 中选择,这是允许 Cesium 的 3D 图形系统的一部分检查渲染时多边形与相机的距离。将两个结果进行比较,以离相机较近的为准。这完全避免了 sampleTerrain 调用的需要,因为鼠标位置已用于直接在 space 中选择笛卡尔点,其中多边形被渲染(这可能是地形,但甚至可能是建筑物的顶部等)。

在你的下一个代码块中,你使用 asset.latlonalt 来填充 lonlat,但是你将 alt 硬编码为 01000 而不是来自相同的数据结构。这可能是高度信息丢失的地方,如果它是从那里开始的(它不是,如果你只是选择椭圆体本身,尽管它可能会被 sampleTerrain 稍后添加。当心sampleTerrain 是异步的,因为地形块是从服务器加载的)。如果您决定尝试深度拾取技术,它将直接产生 Cartesian3,因此您不必担心转换它或保留高度等问题。

最后一条评论,最新版本的 Cesium 确实支持 GroundPrimitive that allows 。这不会使您免于 "pick" 正确 lon/lat 的需要(考虑到透视地形),但会允许多边形放置在凹凸不平的表面上而不是粘在上面。