【问题标题】:How to add markers on cesium terrain如何在铯地形上添加标记
【发布时间】:2020-06-16 21:00:42
【问题描述】:

为了在 cesium 中添加地形标记,我使用了sampleTerrain 函数来获取高度。

我可以在山顶上添加一个标记,但该标记远离鼠标点击。如何在 Cesium 地形上添加标记,以便将标记准确添加到点击位置?

作为参考,我将代码放在这里:

async leftClickInputAction(event:{position: {x:number, y:number}}):Promise<any> {

let positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
let positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
await Cesium.sampleTerrain(this.cesium.viewer.terrainProvider, 9, [positionCartographic]);

let height = positionCartographic.height;
let cart3_with_height = Cesium.Cartesian3.fromRadians(positionCartographic.longitude, positionCartographic.latitude, positionCartographic.height );
let window_coordinates = this.cesium.calcService.toFixes7Obj(Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.cesium.viewer.scene,cart3_with_height));
positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
positionCartographic.height = height;*/

let lngDeg:number = Cesium.Math.toDegrees(positionCartographic.longitude);
let latDeg:number = Cesium.Math.toDegrees(positionCartographic.latitude);
let position: [number, number, number] = [lngDeg, latDeg, positionCartographic.height];
let color:string = this.cesium.positionFormService.getSelectedColor();
let marker_picker = {position};
if(color != "blue") marker_picker['color'] = color;
this.cesium.queryParamsHelperService.addMarker(marker_picker);

【问题讨论】:

    标签: javascript maps cesium


    【解决方案1】:

    这一行是你的问题:

        let positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
    

    pickEllipsoid 函数从 WGS84 椭球中挑选值(认为“类似于海平面”,但不要将其与实际 MSL 混淆)。这个函数永远不会从山顶返回一个点。

    当然,您通过调用sampleTerrain 增强了此功能,这很好,但不能解决问题。 “拾取”错过了山顶,最终在椭圆体上远远低于山后拾取了一个点,而不是靠近用户认为他们点击的位置。

    您可以使用另一个函数viewer.scene.pickPosition,它将通过从 WebGL 的深度缓冲区中读取位置来返回位置。这意味着该功能仅在近距离时可靠,例如当相机足够近以看到个别山脉时,而不是缩小到整个地球。但它确实可以让你选择山顶之类的。

    Here's a Sandcastle demo。它使用从Picking Demo 提取的代码并经过修改以在珠穆朗玛峰上工作。

    var terrain = Cesium.createDefaultTerrainProviderViewModels();
    var viewer = new Cesium.Viewer('cesiumContainer', {
        animation: false,
        timeline: false,
        geocoder : false,
        selectionIndicator : false,
        infoBox : false,
        terrainProviderViewModels: terrain,
        selectedTerrainProviderViewModel: terrain[1]
    });
    
    function lookAtMtEverest() {
        var target = new Cesium.Cartesian3(300770.50872389384, 5634912.131394585, 2978152.2865545116);
        var offset = new Cesium.Cartesian3(6344.974098678562, -793.3419798081741, 2499.9508860763162);
        viewer.camera.lookAt(target, offset);
        viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
    }
    
    lookAtMtEverest();
    
    var labelEntity = viewer.entities.add({
        label : {
            show : false,
            showBackground : true,
            font : '14px monospace',
            horizontalOrigin : Cesium.HorizontalOrigin.LEFT,
            verticalOrigin : Cesium.VerticalOrigin.TOP,
            pixelOffset : new Cesium.Cartesian2(15, 0)
        }
    });
    
    var sceneModeWarningPosted = false;
    
    // Mouse over the globe to see the cartographic position
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    handler.setInputAction(function(movement) {
        var foundPosition = false;
        var scene = viewer.scene;
        var pickedObject = scene.pick(movement.endPosition);
        if (scene.pickPositionSupported) {
            if (scene.mode === Cesium.SceneMode.SCENE3D) {
                var cartesian = viewer.scene.pickPosition(movement.endPosition);
    
                if (Cesium.defined(cartesian)) {
                    var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
                    var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(3);
                    var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(3);
                    var heightString = cartographic.height.toFixed(2);
    
                    labelEntity.position = cartesian;
                    labelEntity.label.show = true;
                    labelEntity.label.text =
                        'Lon: ' + ('   ' + longitudeString).slice(-8) + '\u00B0' +
                        '\nLat: ' + ('   ' + latitudeString).slice(-8) + '\u00B0' +
                        '\nAlt: ' + ('   ' + heightString).slice(-7) + 'm';
    
                    var camera = scene.camera;
                    labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, camera.frustum.near * 1.5 - Cesium.Cartesian3.distance(cartesian, camera.position));
    
                    foundPosition = true;
                }
            } else if (!sceneModeWarningPosted) {
                sceneModeWarningPosted = true;
                console.log("pickPosition is currently only supported in 3D mode.");
            }
        }
    
        if (!foundPosition) {
            labelEntity.label.show = false;
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    

    【讨论】:

    • 是的,您可以关闭 baseLayerPicker,但您应该使用地形源,这样山脉才能保持原状。 Scene.pickPosition 在缺少地形时无法正常工作。
    • 我使用了assets.agi.com/stk-terrain/world的地形源,当baseLayerPicker = false时它不起作用
    【解决方案2】:

    我用过:

         let ray = this.cesium.viewer.camera.getPickRay(event.position);
          let positionCartesian3 = this.cesium.viewer.scene.globe.pick(ray, this.cesium.viewer.scene);
          let positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
          let lngDeg: number = Cesium.Math.toDegrees(positionCartographic.longitude);
          let latDeg: number = Cesium.Math.toDegrees(positionCartographic.latitude);
           position = [lngDeg, latDeg, positionCartographic.height];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-25
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      相关资源
      最近更新 更多