【问题标题】:Cesium how to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out铯如何在放大/缩小时缩放多边形以匹配经纬度位置
【发布时间】:2016-06-26 01:12:12
【问题描述】:

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

在我的 Cesium 应用程序中,我输入我的地址,然后视图会放大到我的街道。耶!然后我拉近一点,这样我就可以在我的房子周围画一个多边形。现有的代码很好地做到了这一点。但是当我缩小然后再次放大时,我的多边形不会与我家的经纬度位置保持一致

Cesium 是否包含将像素缩放到经纬度坐标的实用程序 还是我需要使用类似的工具 distanceToBoundingSphere(boundingSphere) 并自己计算?一世 只想要 x,y 坐标;我根本不在乎身高。

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

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

收集多边形的位置:

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

    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};

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

我应该对哪些数字感兴趣:

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

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

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

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

【问题讨论】:

  • 欢迎来到铯,露西小姐。您的应用是否偶然使用了 Terrain?如果是这样,您可能会在适当的高度看到您的房子,但在零高度(WGS84 参考高度)处绘制了一个多边形。这种“地下多边形”通常会随着相机的移动而漂移。
  • 没错!我可以移动相机并放大或缩小,直到多边形与我的房子相匹配,当我移动地球时,多边形会远离我的房子。如果你所说的地形是指树木、汽车、草和其他东西,那么是的,它一定是使用地形。好的。我将对此进行更多研究。也许你可以给我一个答案,我会给你分数。 :-)
  • 等一下...代码只考虑了 x,y 坐标。你是说只需添加 z 坐标,我的多边形就会留在我的房子里吗?
  • “使用地形”我的意思是,如果您靠近一些山脉,并将相机向地平线倾斜,您会看到山脉垂直向上,而不是山脉平放在 WGS84 椭球上的照片。如果是前者(3D 山脉),那么是的,地形正在使用中,即使在平坦区域,您也必须将多边形定位在非零高度。我看到你添加了对 sampleTerrain 的调用,这解决了问题吗?
  • 我相信我们正在使用地形。我能做的最好的就是屏幕帽。不,我没有添加 sampleTerrrain(它已经存在)。但我开始看到可能是什么问题。当它只收集坐标时,我不知道他为什么在该方法(第一个代码块)中使用 sampleTerrain。即使在 sampleTerrain 方法中 updatedPositions[0].height 是正确的,z 值似乎也不会被填充。也许我们应该在实际创建多边形的代码中使用 sampleTerrain(第三个代码块)。我在顶点数组上填充 z 值。

标签: javascript node.js cesium


【解决方案1】:

一个问题有很多内容,但我会尝试解决这个问题的关键部分。

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

有一个单独的类Cartographic 包含熟悉的经度(弧度)、纬度(弧度)和高度(以米为单位)值。通常,这些必须转换为Cartesian3,然后才能移交给渲染引擎。此转换需要了解Ellipsoid(默认为 WGS84 椭球),因此,零高度值表示位于该椭球上的点(通常意味着打开地形时该点位于地下)。

各种辅助函数采用通用值(例如以度为单位的 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);

这段代码尝试了一个两管齐下的方法:它尝试像以前一样选择椭球体,并且还尝试从“深度缓冲区”中进行选择,它是 3D 图形系统的一部分,它允许 Cesium 检查如何渲染时远离相机的多边形。将两个结果进行比较,以更接近相机的为准。这完全避免了调用sampleTerrain 的需要,因为鼠标位置已用于直接选择空间中渲染多边形的笛卡尔点(这可能是地形,但甚至可能是建筑物的顶部等) )。

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

最后一条评论,Cesium 的最新版本确实支持GroundPrimitive,它允许polygons to drape on terrain。这不会让您不必“挑选”正确的经度/纬度开始(考虑到透视地形),但会允许多边形放置在凹凸不平的表面上并且不会穿过。

【讨论】:

  • 好消息!!!我不希望多边形覆盖在地形上,因为我只是想定义一个周长(有点像宠物的隐形围栏)。好的。我将深入研究您提供的信息,并“希望”让我的多边形在缩放和移动相机时保持在适当的位置。谢谢你。 :-)
  • 嗨,露西小姐,我看到了您的后续问题,但还没有时间考虑完整的回复。实际上它看起来像它刚刚被删除。无论如何,您可以从viewer.scene.globe 获得“地球”参考,并且您的笛卡尔3 中包含高度是正确的。
  • 嗨,埃马克!是的,我刚刚删除了它,因为我认为这个问题也可能太多了。我开始掌握它,但我仍然不知道如何获得定义(即 Cesium.defined(depthIntersection) 和 Cesium.defined(rayIntersection))以及如何将 scene.pickPositionSupported 设置为 true。所以,我发布了另一个小得多的问题。当它在那里时,我会发布给你。
  • 期待更多问题 :) 同时,scene.pickPositionSupported 反映了浏览器功能(WebGL 的 Fragment Depth 扩展可用),我认为它在 IE 11 中不可用,但在大多数情况下可用Chrome、Firefox 和 Edge 中的图形硬件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 2021-01-04
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
相关资源
最近更新 更多