Polygon dragging across large areas

Hello, Firstly a massive thank you to the Cesium team!

The code below allows dragging of a polygon (paste into sandcastle, click it to start drag, then click again to stop). Dragging within a relatively smaller area of the starting Cartesian quadrant works fine. When moving across the globe the shape gets distorted. To drag the shape I am keeping track of the delta's of the y and z Cartesian's and keep updated the polygon coordinates.

Any help in understanding this behavior would be appreciated and also if there is a another way of "dragging" shapes with multiple positions. Thanks!

var viewer = new Cesium.Viewer('cesiumContainer', {
            animation: false,
            timeline: false,
            geocoder: false,
            navigationHelpButton: false,
            //sceneModePicker: false,
            sceneMode: Cesium.SceneMode.SCENE2D
        });

        //this is cos we dont want to display the sphere part below the ground
        //viewer.scene.globe.depthTestAgainstTerrain = true;

        var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
            url: '//assets.agi.com/stk-terrain/world', //assets.agi.com/stk-terrain/world
            requestWaterMask: true
        });
        //viewer.terrainProvider = cesiumTerrainProviderMeshes;

        //morph then fly to
        var scene = viewer.scene;

        viewer.camera.flyTo({
            duration: 1,
            destination: Cesium.Cartesian3.fromDegrees(18.0, -33.00, 30000000.0)
        });

        var positions = Cesium.Cartesian3.fromDegreesArray([
                      20.0, -33.00,
                      20.0, -38.5,
                      25.0, -38.5,
                      25.0, -33.00]);
       
        var entity = {
            polygon: {
                hierarchy: new Cesium.CallbackProperty(function () {
                        return positions;
                    }, false),
                material: Cesium.Color.YELLOW.withAlpha(0.35),
                outline: true,
                outlineColor: Cesium.Color.BLACK,
                height: 10
            }
        };

        console.log('polygon positions', positions);

        viewer.entities.add(entity);
        
        var mouseHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

        var startPosition = null;
        var endPosition = null;
        var previousEndPosition = null;

        var deltaX = 0.0;
        var deltaY = 0.0;
        var deltaZ = 0.0;

        var count = 0;
        var ellipsoid = viewer.scene.globe.ellipsoid;

        mouseHandler.setInputAction(function (movement) {
            //console.log(movement);

            if (movement.position != null) {
                count++;

                var cartesian = viewer.camera.pickEllipsoid(movement.position);
                if (cartesian) {
                    
                    if (count == 1) {
                        startPosition = cartesian;
                        previousEndPosition = cartesian;
                    }

                    if (count == 2) {
                        count = 0;

                        endPosition = cartesian;
                        console.log('start', startPosition);
                        console.log('end', endPosition);

                    }
                                        
                    scene.screenSpaceCameraController.enableRotate = false;
                }
            }

        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        mouseHandler.setInputAction(function (movement) {
            
            if (count == 1 && startPosition && movement.endPosition != null) {
                                            
                //var ray = viewer.camera.getPickRay(movement.endPosition);
                //var intersection = scene.globe.pick(ray, scene);
          
                var cartesian = viewer.camera.pickEllipsoid(movement.endPosition);

                //var ray = viewer.camera.getPickRay(movement.endPosition);
                //var cartesian = viewer.scene.globe.pick(ray, scene);

                if (cartesian) {

                    //console.log(intersection);
                    endPosition = cartesian;

                    if (count == 1) {

                        //console.log('start', startPosition);
                        console.log('end', endPosition);

                        deltaX = endPosition.x - previousEndPosition.x;
                        deltaY = endPosition.y - previousEndPosition.y;
                        deltaZ = endPosition.z - previousEndPosition.z;
                                                
                        for (var i=0;i <= positions.length - 1;i++) {
                            
                            var pos = positions[i];
                            
                            //if (endPosition.y < 0) {
                            // pos.y = pos.y - deltaY;
                            //}
                            //else
                            // pos.y = pos.y + deltaY;

                            //if (endPosition.z < 0) {
                            // pos.z = pos.z + deltaZ;
                            //}
                            //else
                            // pos.z = pos.z - deltaZ;
                            
                            pos.y = pos.y + deltaY;
                            pos.z = pos.z + deltaZ;
                            pos.x = pos.x + deltaX;
                            
                        }

                        //positions[0].x = positions[0].x + deltaX;
                        //positions[0].y = positions[0].y + deltaY;
                        //positions[0].z = positions[0].z + deltaZ;
                     
                        console.log('delta', deltaX, deltaY, deltaZ);

                        console.log('positions delta', positions[0]);
                        
                        previousEndPosition = endPosition;
                    }
                }
            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

        mouseHandler.setInputAction(
            function () {
                scene.screenSpaceCameraController.enableRotate = true;
                
            },
            Cesium.ScreenSpaceEventType.LEFT_UP
        );

Hello,

Adding to the cartesian values doesn’t guarantee that the points will be in relatively the same position as it moves across the ellipsoid surface because they need to be projected back onto the ellipsoid surface. Converting the positions to Cartographic coordinates, adding the longitude/latitude delta values, then converting them back to cartesian coordinates should fix the problem. There are functions on the Ellipsoid to help convert between the two coordinate systems.

Best,

Hannah

Hellos,

Thank you so much! Converting the lat, lng delta's works. Will be able to drag anything now :slight_smile:

I pasted below the full working sandcastle (Dragging is relative to where you start picking with the mouse).

Regards,
Priaash

var viewer = new Cesium.Viewer('cesiumContainer', {
        animation: false,
            timeline: false,
            geocoder: false,
            navigationHelpButton: false,
            //sceneModePicker: false,
            sceneMode: Cesium.SceneMode.SCENE3D
        });

        //this is cos we dont want to display the sphere part below the ground
        //viewer.scene.globe.depthTestAgainstTerrain = true;

        var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
            url: '//assets.agi.com/stk-terrain/world', //assets.agi.com/stk-terrain/world
            requestWaterMask: true
        });
        //viewer.terrainProvider = cesiumTerrainProviderMeshes;

        //morph then fly to
        var scene = viewer.scene;

        viewer.camera.flyTo({
            duration: 1,
            destination: Cesium.Cartesian3.fromDegrees(18.0, -33.00, 1800000.0)
        });

        var positions = Cesium.Cartesian3.fromDegreesArray([
                      23.0, -33.00,
                      23.0, -35.5,
                      25.0, -35.5,
                      25.0, -33.00]);

        var entity = {
            polygon: {
                hierarchy: new Cesium.CallbackProperty(function () {
                        return positions;
                    }, false),
                material: Cesium.Color.YELLOW.withAlpha(0.35),
                outline: true,
                outlineColor: Cesium.Color.BLACK,
                height: 10
            }
        };

        var pointPosition = Cesium.Cartesian3.fromDegrees(23.0, -33);

        var point = {
            position: new Cesium.CallbackProperty(function () {
                return pointPosition;
            }, false),
            point: {
                pixelSize: 10,
                color: Cesium.Color.YELLOW
            }
        };

        console.log('polygon positions', positions);

        viewer.entities.add(entity);

        viewer.entities.add(point);

        var mouseHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

        var startPosition = null;
        var endPosition = null;
        var previousEndPosition = null;

        var deltaX = 0.0;
        var deltaY = 0.0;
        var deltaZ = 0.0;

        var count = 0;
        var ellipsoid = scene.globe.ellipsoid;//Cesium.Ellipsoid.WGS84;

        mouseHandler.setInputAction(function (movement) {

            if (movement.position != null) {
                count++;

                var cartesian = viewer.camera.pickEllipsoid(movement.position, ellipsoid);
                if (cartesian) {
                    
                    var cartographic = ellipsoid.cartesianToCartographic(cartesian);

                    if (count == 1) {
                        startPosition = cartographic;
                        previousEndPosition = cartographic;
                    }

                    if (count == 2) {
                        count = 0;
                    }
                                        
                    scene.screenSpaceCameraController.enableRotate = false;
                }
            }

        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        mouseHandler.setInputAction(function (movement) {
            
            if (count == 1 && startPosition && movement.endPosition != null) {
          
                var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, ellipsoid);
             
                if (cartesian) {
                    
                    var cartographic = ellipsoid.cartesianToCartographic(cartesian);
                                     
                    // polygon
                    endPosition = cartographic;

                    var deltaLng = endPosition.longitude - previousEndPosition.longitude;
                    var deltaLat = endPosition.latitude - previousEndPosition.latitude;
                    //var deltaHeight = endPosition.height - previousEndPosition.height;

                    var cartoDeltaConvert = new Cesium.Cartographic(deltaLng, deltaLat);

                    //var carteDeltaConvert = ellipsoid.cartographicToCartesian(cartoDeltaConvert);
                    //console.log(carteDeltaConvert);

                    //$.each(positions, function (i, pos) {
                    for (var i=0;i <= positions.length - 1;i++) {
                            
                        var pos = positions[i];
                       
                        //pos.x = pos.x + carteDeltaConvert.x;

                        var carto = ellipsoid.cartesianToCartographic(pos);
                        carto.latitude = carto.latitude + cartoDeltaConvert.latitude;
                        carto.longitude = carto.longitude + cartoDeltaConvert.longitude;
                        var carte = ellipsoid.cartographicToCartesian(carto);
                        
                        //pos = carte;
                        pos.x = carte.x;
                        pos.y = carte.y;
                        pos.z = carte.z;
                    }

                    //positions[0].x = positions[0].x + carteDeltaConvert.x;
                    //positions[0].y = positions[0].y + carteDeltaConvert.y;
                    //positions[0].z = positions[0].z + carteDeltaConvert.z;

                    // point
                    var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
                    var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
                    var height = cartographic.height;
                    //var cartoConvert = new Cesium.Cartographic(Cesium.Math.toRadians(longitudeString),
                    // Cesium.Math.toRadians(latitudeString),
                    // height);
                    var carteConvert = ellipsoid.cartographicToCartesian(cartographic);
                    pointPosition = carteConvert;
                    
                    //
                    previousEndPosition = endPosition;
                }

            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

        mouseHandler.setInputAction(
            function () {
                scene.screenSpaceCameraController.enableRotate = true;
            },
            Cesium.ScreenSpaceEventType.LEFT_UP
        );