viewer.camera.flyTo - if there is no pitch (-90) , and you set the roll, the heading changes

991 views
Skip to first unread message

Alberto Acevedo

unread,
Aug 17, 2016, 5:31:07 PM8/17/16
to cesium-dev

If there is no pitch (-90) , and you set the roll, the heading changes.
In my tests I set to pitch to -89 same thing, -88 same thing, -87 and lower pitch values and the roll actually get set.

Below I modified the camera tutorial in SandCastle to show the issue. Select Fly to Location with heading, pitch and roll and you will see the current pitch, heading, and roll values in  log.

Thanks,

Alberto

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
var clock = viewer.clock;

function flyToSanDiego() {
    Sandcastle.declare(flyToSanDiego);
    viewer.camera.flyTo({
        destination : Cesium.Cartesian3.fromDegrees(-117.16, 32.71, 15000.0)
    });
}

function flyToHeadingPitchRoll() {
    Sandcastle.declare(flyToHeadingPitchRoll);
    viewer.camera.flyTo({
        destination : Cesium.Cartesian3.fromDegrees(-122.22, 46.12, 5000000.0),
        orientation : {
            heading : 0,
            pitch : Cesium.Math.toRadians(-90),
            roll : Cesium.Math.toRadians(30)
        },
        complete: function ()
            {
                var item = {};
                    if (!isNaN(viewer.scene.camera.pitch))
                {
                     //item.pitch = Cesium.Math.toDegrees(viewer.scene.camera.pitch) ;
                     //item.pitch = Cesium.Math.toRadians(item.pitch);
                     item.pitch =  Cesium.Math.zeroToTwoPi( viewer.scene.camera.pitch);
                     item.pitch = Cesium.Math.toDegrees(item.pitch);
                }
                if (!isNaN(viewer.scene.camera.roll))
                {
                    item.roll =  viewer.scene.camera.roll;
                    item.roll = Cesium.Math.zeroToTwoPi(item.roll );
                    item.roll = Cesium.Math.toDegrees( item.roll);
                }
                if (!isNaN(viewer.scene.camera.heading))
                {
                    item.heading =  viewer.scene.camera.heading;
                    item.heading = Cesium.Math.zeroToTwoPi(item.heading );
                    item.heading = Cesium.Math.toDegrees( item.heading);
                }
                console.log ("pitch = " + item.pitch + "  roll = " + item.roll + "  heading =" + item.heading);
            }
    });
   
          
   
}

function flyToLocation() {
    Sandcastle.declare(flyToLocation);

    // Create callback for browser's geolocation
    function fly(position) {
        viewer.camera.flyTo({
            destination : Cesium.Cartesian3.fromDegrees(position.coords.longitude, position.coords.latitude, 1000.0)
        });
    }

    // Ask browser for location, and fly there.
    navigator.geolocation.getCurrentPosition(fly);
}

function viewRectangle() {
    Sandcastle.declare(viewRectangle);

    var west = -77.0;
    var south = 38.0;
    var east = -72.0;
    var north = 42.0;

    var rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north);
    viewer.camera.setView({
        destination: rectangle
    });

    // Show the rectangle.  Not required; just for show.
    viewer.entities.add({
        rectangle : {
            coordinates : rectangle,
            fill : false,
            outline : true,
            outlineColor : Cesium.Color.WHITE
        }
    });
}

function flyToRectangle() {
    Sandcastle.declare(flyToRectangle);

    var west = -90.0;
    var south = 38.0;
    var east = -87.0;
    var north = 40.0;
    var rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north);

    viewer.camera.flyTo({
        destination : rectangle
    });

    // Show the rectangle.  Not required; just for show.
    viewer.entities.add({
        rectangle : {
            coordinates : rectangle,
            fill : false,
            outline : true,
            outlineColor : Cesium.Color.WHITE
        }
    });
}

function setReferenceFrame() {
    Sandcastle.declare(setReferenceFrame);

    var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
    var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);

    // View in east-north-up frame
    var camera = viewer.camera;
    camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;
    camera.lookAtTransform(transform, new Cesium.Cartesian3(-120000.0, -120000.0, 120000.0));

    // Show reference frame.  Not required.
    scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
        modelMatrix : transform,
        length : 100000.0
    }));
}

function setHeadingPitchRoll() {
    Sandcastle.declare(setHeadingPitchRoll);
   
    var camera = viewer.camera;
    camera.setView({
        destination : Cesium.Cartesian3.fromDegrees(-75.5847, 40.0397, 1000.0),
        orientation: {
            heading : -Cesium.Math.PI_OVER_TWO,
            pitch : -Cesium.Math.PI_OVER_FOUR,
            roll : 0.0
        }
    });
}

function icrf(scene, time) {
    if (scene.mode !== Cesium.SceneMode.SCENE3D) {
        return;
    }

    var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
    if (Cesium.defined(icrfToFixed)) {
        var camera = viewer.camera;
        var offset = Cesium.Cartesian3.clone(camera.position);
        var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed);
        camera.lookAtTransform(transform, offset);
    }
}

function viewInICRF() {
    Sandcastle.declare(viewInICRF);

    viewer.camera.flyHome(0);
   
    clock.multiplier = 3 * 60 * 60;
    scene.preRender.addEventListener(icrf);
    scene.globe.enableLighting = true;
}

var viewChanged = document.getElementById('viewChanged');

var removeStart;
var removeEnd;

function cameraEvents() {
    Sandcastle.declare(cameraEvents);
   
    var camera = viewer.camera;
    removeStart = camera.moveStart.addEventListener(function() {
        viewChanged.style.display = 'block';
    });
    removeEnd = camera.moveEnd.addEventListener(function() {
        viewChanged.style.display = 'none';
    });
}

var removeChanged;

function cameraChanges() {
    Sandcastle.declare(cameraChanges);

    var i = 0;
    removeChanged = viewer.camera.changed.addEventListener(function(percentage) {
        ++i;
        console.log('camera changed: ' + i + ', ' + percentage);
    });
}

function flyInACity() {
    Sandcastle.declare(flyInACity);
   
    var camera = scene.camera;
    camera.flyTo({
        destination : Cesium.Cartesian3.fromDegrees(-73.98580932617188, 40.74843406689482, 363.34038727246224),
        complete : function() {
            setTimeout(function() {
                camera.flyTo({
                    destination : Cesium.Cartesian3.fromDegrees(-73.98585975679403, 40.75759944127251, 186.50838555841779),
                    orientation : {
                        heading : Cesium.Math.toRadians(200.0),
                        pitch : Cesium.Math.toRadians(-50.0)
                    },
                    easingFunction : Cesium.EasingFunction.LINEAR_NONE
                });
            }, 1000);
        }
    });
}

Sandcastle.addToolbarMenu([{
    text : 'Camera Options'
}, {
    text : 'Fly in a city',
    onselect : function() {
        flyInACity();
        Sandcastle.highlight(flyInACity);
    }
}, {
    text : 'Fly to San Diego',
    onselect : function() {
        flyToSanDiego();
        Sandcastle.highlight(flyToSanDiego);
    }
}, {
    text : 'Fly to Location with heading, pitch and roll',
    onselect : function() {
        flyToHeadingPitchRoll();
        Sandcastle.highlight(flyToHeadingPitchRoll);
    }
}, {
    text : 'Fly to My Location',
    onselect : function() {
        flyToLocation();
        Sandcastle.highlight(flyToLocation);
    }
}, {
    text : 'Fly to Rectangle',
    onselect : function() {
        flyToRectangle();
        Sandcastle.highlight(flyToRectangle);
    }
}, {
    text : 'View a Rectangle',
    onselect : function() {
        viewRectangle();
        Sandcastle.highlight(viewRectangle);
    }
}, {
    text : 'Set camera reference frame',
    onselect : function() {
        setReferenceFrame();
        Sandcastle.highlight(setReferenceFrame);
    }
}, {
    text : 'Set camera with heading, pitch, and roll',
    onselect : function() {
        setHeadingPitchRoll();
        Sandcastle.highlight(setHeadingPitchRoll);
    }
}, {
    text : 'View in ICRF',
    onselect : function() {
        viewInICRF();
        Sandcastle.highlight(viewInICRF);
    }
}, {
    text : 'Move events',
    onselect : function() {
        cameraEvents();
        Sandcastle.highlight(cameraEvents);
    }
}, {
    text : 'Camera changed event',
    onselect : function() {
        cameraChanges();
        Sandcastle.highlight(cameraChanges);
    }
}]);

Sandcastle.reset = function() {
    viewer.entities.removeAll();
    scene.primitives.removeAll();
    scene.tweens.removeAll();

    if (Cesium.defined(removeStart)) {
        removeStart();
        removeEnd();

        viewChanged.style.display = 'none';
       
        removeStart = undefined;
        removeEnd = undefined;
    }

    if (Cesium.defined(removeChanged)) {
        removeChanged();
        removeChanged = undefined;
    }
   
    viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

    clock.multiplier = 1.0;
    scene.preRender.removeEventListener(icrf);
    scene.globe.enableLighting = false;
};

scene.morphComplete.addEventListener(function() {
    Sandcastle.reset();
});

Hannah Pinkos

unread,
Aug 18, 2016, 10:42:44 AM8/18/16
to cesium-dev
Hello,

This sounds like Gimbal lock.  When you rotate one axis 90 degrees, it aligns the remaining two axis and you lose a degree of freedom.  In this case, changing the pitch to -90 makes heading and roll the same thing.
This gif gives a good visual representation of what is going on: https://groups.google.com/forum/?hl=en#!topic/cesium-dev/t9y1klM-_jU

Best,

Hannah
Reply all
Reply to author
Forward
0 new messages