How to drag a billboard vertically

I’m able to drag a billboard vertically with the code below. I’m calculating the new height by finding the intersection of a plane tangent to the surface origin of the billboard and the ray of the mouse move position. If you run the code in SandCastle you will
notice that the calculation of the height is not accurate. I had to multiply the height from the intersection by 10 to be able to see the billboard moving up. The lack of accuracy is telling that finding the new height with the intersection of the ray with the plane is incorrect. I used to do this type of calculations in World Wind by finding the intersection of the ray against a line composed of the billboard origin and the its surface normal Is there a better way to calculate the height when dragging up or down?

Thanks,

Alberto

var viewer = new Cesium.Viewer(‘cesiumContainer’);

var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : ‘https://assets.agi.com/stk-terrain/world’,
requestWaterMask : true,
requestVertexNormals : true
});
//viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.terrainProvider = cesiumTerrainProviderMeshes;

    var scene = viewer.scene;
    var camera = viewer.camera;
    var pinBuilder = new Cesium.PinBuilder();
    var position = Cesium.Cartesian3.fromRadians(camera.positionCartographic.longitude, camera.positionCartographic.latitude, 1000);
    var entity = viewer.entities.add({
        position: position,
        billboard: {
            image: pinBuilder.fromColor(Cesium.Color.SALMON, 48),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM
        },
        label : {
            text : '1000'
        }
    });
    function relevantSource() {
        var dragging = false;
        var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
        handler.setInputAction(
            function(click) {
                var pickedObject = scene.pick(click.position);
                if (Cesium.defined(pickedObject) && (pickedObject.id === entity)) {
                    entity.billboard.scale = 1.2;
                    dragging = true;
                    scene.screenSpaceCameraController.enableRotate = false;
                }
            },
            Cesium.ScreenSpaceEventType.LEFT_DOWN
        );
        handler.setInputAction(
            function(movement) {
                if (dragging) {
                    var cartesian =  entity.position.getValue(Cesium.JulianDate.fromDate(new Date()));
                    var cartographic =  viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
                    var ray =  viewer.scene.camera.getPickRay(movement.endPosition);
                    var rayCartesian = viewer.scene.globe.pick(ray, viewer.scene);
                    var rayCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(rayCartesian);
                    var surfaceNormalCartesian = viewer.scene.globe.ellipsoid.geodeticSurfaceNormal(cartesian );
                    var SurfaceCartesian = Cesium.Ellipsoid.WGS84.cartographicToCartesian(new Cesium.Cartographic(cartographic.longitude, cartographic.latitude,0));
                    var plane = Cesium.Plane.fromPointNormal(SurfaceCartesian, surfaceNormalCartesian);// plane tangent to origin
                    var newCartesian = new Cesium.Cartesian3();
                    newCartesian =  Cesium.IntersectionTests.rayPlane(ray, plane);
                    var newCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(newCartesian);
                    var height = newCartographic.height;
                    height *=10;
                    entity.label.text =  height.toFixed(2);
                    cartographic.height = height;
                    entity.position.setValue(Cesium.Ellipsoid.WGS84.cartographicToCartesian(cartographic)); 
                    console.log(height);
                }
            },
            Cesium.ScreenSpaceEventType.MOUSE_MOVE
        );
        handler.setInputAction(
            function() {
                entity.billboard.scale = 1;
                dragging = false;
                scene.screenSpaceCameraController.enableRotate = true;
            },
            Cesium.ScreenSpaceEventType.LEFT_UP
        );
    }
    relevantSource();
    camera.flyTo({
        destination: Cesium.Cartesian3.fromRadians(camera.positionCartographic.longitude, camera.positionCartographic.latitude, 300000)
    });

Hello Alberto,

How about something like this? This creates a plane perpendicular to the camera and intersects the ray with that plane.

It works great from a tilted/side view, I’m not sure the best way to do this kind of dragging from a top-down view. But maybe this will give you some ideas:

 function(movement) {
                if (dragging) {
                    var cartesian =  entity.position.getValue(Cesium.JulianDate.fromDate(new Date()));
                    var cartographic = scene.globe.ellipsoid.cartesianToCartographic(cartesian);
                    var surfaceNormal = scene.globe.ellipsoid.geodeticSurfaceNormal(cartesian);
                    var planeNormal = Cesium.Cartesian3.subtract(scene.camera.position, cartesian, new Cesium.Cartesian3());
                    planeNormal = Cesium.Cartesian3.normalize(planeNormal, planeNormal);
                    var ray =  viewer.scene.camera.getPickRay(movement.endPosition);
                    var plane = Cesium.Plane.fromPointNormal(cartesian, planeNormal);
                    var newCartesian =  Cesium.IntersectionTests.rayPlane(ray, plane);
                    var newCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(newCartesian);
                    var height = newCartographic.height;
                    cartographic.height = height;
                    entity.label.text =  height.toFixed(2);
                    entity.position.setValue(scene.globe.ellipsoid.cartographicToCartesian(cartographic));
                }
            },

``

Best,

Hannah

Hanna,

Works great!!

Thanks for your help,

Alberto