Heading / pitch / roll

524 views
Skip to first unread message

HughN

unread,
Apr 25, 2017, 6:38:17 AM4/25/17
to cesium-dev
Hello,

Following on from this question: https://groups.google.com/forum/m/#!topic/cesium-dev/4j991i8iazQ if I go the JS rather than CZML route the HeadingPitchRoll demo in the Sandcastle is more-or-less what I want to achieve but with the model following a list of lat / long / height positions and heading / pitch / roll attitudes. I've been trying to use timeIntervalCollections to hold the list of data.

Please would someone be kind enough to suggest how I could best achieve this? I am really stuck.

Thank you,
Hugh

Rachel Hwang

unread,
Apr 25, 2017, 7:16:51 PM4/25/17
to cesium-dev
Hi Hugh,

If you have a long list of values that you want to use to use to update a model attribute over time, I would probably use a CallbackProperty. Here's a simple example that updates a list of positions: https://groups.google.com/d/msg/cesium-dev/4Uj-ZMBcjZM/UNjEk2NxAwAJ

In your case, you could have a list of heading/pitch/roll values and set your model's orientation property as a callback function that returns the appropriate value from a list (say, incrementing an index into your list of values.

I hope that helps! If this is still confusing, I'd be happy to write up a more specific example.

Best,
- Rachel

Matthew Amato

unread,
Apr 25, 2017, 8:31:49 PM4/25/17
to cesiu...@googlegroups.com
TimeIntervalCollection is for values that (as the name implies) that change over an interval. So if you wanted an object to "jump" from place to place, it would work but it's usually not used with positions in that way. It sounds like you want actual motion.

While a CallbackProperty could work here, if you have pre-computed or dynamically generated time-tagged values, the better solution is SampledPositionProperty for positions and SampledProperty(Quaternion) for orientation.

This example shows SampledPositionProperty in action: http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Interpolation.html&label=Showcases (we actually don't have an example for HPR orientation, but we really should)  You can create quaternions via Quaternion.fromHeadingPitchRoll

CallbackProperty is usually a catch-all for values that need to be computed on the fly or other dynamic data that we don't have structured Property implementations for.

--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

HughN

unread,
Apr 26, 2017, 5:47:07 AM4/26/17
to cesium-dev
Thank you Rachel and Matthew,

I think I am nearly there - but not quite...

The code below loads position into a sampled position property and the heading information into hdg (I plan to move this to quaternions).

For testing I've given some nominal values to pitch, heading and roll and calculated an orientation from that. As soon as I try to apply it to the entity (via the line marked 'THIS LINE') the model disappears. If you could give me the crucial clue to get me over the finish line I would be very grateful.

Thank you
Hugh

var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProviderViewModels : [], //Disable terrain changing
    infoBox : false, //Disable InfoBox widget
    selectionIndicator : false //Disable selection indicator
});

//Enable lighting based on sun/moon positions
viewer.scene.globe.enableLighting = true;

viewer.trackedEntity = entity;

//Use STK World Terrain
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
    requestWaterMask : true,
    requestVertexNormals : true
});

//Enable depth testing so things behind the terrain disappear.
viewer.scene.globe.depthTestAgainstTerrain = true;



//Set bounds of our simulation time
var start = Cesium.JulianDate.fromIso8601('2012-08-04T10:00:10Z');
var stop =  Cesium.JulianDate.fromIso8601('2012-08-04T10:03:10Z');

//Make sure viewer is at the desired time.
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
viewer.clock.multiplier = 4;

//Set timeline to simulation bounds
viewer.timeline.zoomTo(start, stop);

// Add heading
function storeHeading() {
     var hdg = new Cesium.SampledProperty(Number);
        
        //Populate it with data
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:34Z'), 88);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:35Z'), 87.6);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:36Z'), 87.6);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:37Z'), 88.3);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:38Z'), 89);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:39Z'), 89.7);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:40Z'), 89.7);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:41Z'), 90.1);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:42Z'), 90.8);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:43Z'), 90.8);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:44Z'), 90.8);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:45Z'), 91.2);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:46Z'), 91.5);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:47Z'), 90.8);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:48Z'), 90.4);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:49Z'), 90.4);
        hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:50Z'), 90.8);

    return hdg;

}

//Generate a random circular pattern with varying heights.
function computeFlight() {
    var property = new Cesium.SampledPositionProperty();
    
        // Populate it with data        
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:35Z'), Cesium.Cartesian3.fromDegrees(-60.9649963, 13.7333345, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:36Z'), Cesium.Cartesian3.fromDegrees(-60.9649353, 13.7333384, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:37Z'), Cesium.Cartesian3.fromDegrees(-60.9648476, 13.7333422, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:38Z'), Cesium.Cartesian3.fromDegrees(-60.9647331, 13.733346, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:39Z'), Cesium.Cartesian3.fromDegrees(-60.9645958, 13.733346, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:40Z'), Cesium.Cartesian3.fromDegrees(-60.9644279, 13.733346, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:41Z'), Cesium.Cartesian3.fromDegrees(-60.9642372, 13.733346, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:42Z'), Cesium.Cartesian3.fromDegrees(-60.9640236, 13.7333441, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:43Z'), Cesium.Cartesian3.fromDegrees(-60.9637871, 13.7333403, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:44Z'), Cesium.Cartesian3.fromDegrees(-60.9635239, 13.7333364, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:45Z'), Cesium.Cartesian3.fromDegrees(-60.9632378, 13.7333317, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:46Z'), Cesium.Cartesian3.fromDegrees(-60.962925, 13.7333241, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:47Z'), Cesium.Cartesian3.fromDegrees(-60.9625931, 13.7333183, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:48Z'), Cesium.Cartesian3.fromDegrees(-60.9622383, 13.7333145, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:49Z'), Cesium.Cartesian3.fromDegrees(-60.9618607, 13.7333107, 21));
        property.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:50Z'), Cesium.Cartesian3.fromDegrees(-60.9614601, 13.7333069, 21));
    
    return property;
}

//Compute the entity position property.
var position = computeFlight();
var hdg = storeHeading(0);

//
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
var orientation = new Cesium.HeadingPitchRoll( heading, pitch, roll);
    
//Actually create the entity
var entity = viewer.entities.add({

    //Set the entity availability to the same interval as the simulation time.
    availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
        start : start,
        stop : stop
    })]),

    //Use our computed positions
    position : position,

    ///////////////////////////////////////////////////////
    //compute orientation 
  //  orientation : orientation, /// THIS LINE
    
    //Load the Cesium plane model to represent the entity
    model : {
        uri : '../../SampleData/models/CesiumAir/Cesium_Air.gltf',
        minimumPixelSize : 64
    },

    //Show the path as a pink line sampled in 1 second increments.
    path : {
        resolution : 1,
        material : new Cesium.PolylineGlowMaterialProperty({
            glowPower : 0.1,
            color : Cesium.Color.YELLOW
        }),
        width : 10
    }
});

//Add button to view the path from the top down
Sandcastle.addDefaultToolbarButton('View Top Down', function() {
    viewer.trackedEntity = undefined;
    viewer.zoomTo(viewer.entities, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90)));
});

//Add button to view the path from the side
Sandcastle.addToolbarButton('View Side', function() {
    viewer.trackedEntity = undefined;
    viewer.zoomTo(viewer.entities, new Cesium.HeadingPitchRange(Cesium.Math.toRadians(-90), Cesium.Math.toRadians(-15), 7500));
});

//Add button to track the entity as it moves
Sandcastle.addToolbarButton('View Aircraft', function() {
    viewer.trackedEntity = entity;
});

To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.

HughN

unread,
Apr 27, 2017, 6:42:45 AM4/27/17
to cesium-dev
I missed the 'quarternion' from 'Cesium.Quaternion.HeadingPitchRoll( heading, pitch, roll)' but I still can't get it to work. Any suggestions appreciated!

Rachel Hwang

unread,
Apr 27, 2017, 8:43:13 AM4/27/17
to cesium-dev
Hi Hugh,

Right,

var orientation = new Cesium.HeadingPitchRoll( heading, pitch, roll);


needs to be 


var orientation = Cesium.Quaternion.fromHeadingPitchRoll(heading, pitch, roll);


I don't see anything else wrong yet, but I'll take another look later.


Cheers,

- Rachel

HughN

unread,
Apr 27, 2017, 8:57:19 AM4/27/17
to cesium-dev
Thanks Rachel,

I think that just the job. In future I'll use copy-and-paste rather than try and remember things!

Hugh Neve

unread,
Apr 27, 2017, 11:10:05 AM4/27/17
to cesiu...@googlegroups.com
Hi Rachel,

I'm struggling to use the sampled property 'hdg' in the fromHeadingPitchRoll. The error says the normalised result is not a number.

--
You received this message because you are subscribed to a topic in the Google Groups "cesium-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/cesium-dev/OGEAvmj9eGc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to cesium-dev+unsubscribe@googlegroups.com.

Rachel Hwang

unread,
Apr 28, 2017, 4:11:26 PM4/28/17
to cesium-dev, hu...@hughneve.co.uk
Hi Hugh,

Do you have an updated code sample? We might be able to take a look. One of the easiest way to share code snippets is to use Sandcastle: http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Hello%20World.html&label=Showcases

Just paste your javascript into the code panel, then press the share button at the top to save your demo and generate a sharable link.

Best,
- Rachel

Hugh Neve

unread,
Apr 28, 2017, 4:22:43 PM4/28/17
to cesiu...@googlegroups.com
Hi Rachel.


At line 310 I'd like to use the sampled values of heading in the "Quaternion.fromHeadingPitchRoll" in line 313  (and then eventually, pitch and roll).

(I'm still trying to get my head around converting to local co-ordinates so ignore any of that!)

Any assistance would be very much appreciated.

- Hugh


HughN

unread,
Apr 29, 2017, 7:42:47 AM4/29/17
to cesium-dev, hu...@hughneve.co.uk
Hi Rachel,

As soon as I try to use the sampled parameter 'hdg' in the heading/pitch/roll I get the following error:



Now I'm confused!

Now(Line 309

Rachel Hwang

unread,
May 1, 2017, 4:31:29 PM5/1/17
to cesium-dev, hu...@hughneve.co.uk
Hi Hugh,

A much better method than storing individual angle values, is to create a SampledProperty of Quaternions, like this:

hdg.addSample(Cesium.JulianDate.fromIso8601('2012-08-04T10:00:02Z'), Cesium.Quaternion.fromHeadingPitchRoll(0.0, 0.0, 0.0));

Then when you create the plane entity, you can just set it's orientation direction to the SampledProperty(Quaternion), hdg, or whatever else you want to call it. This will be easier, and more efficient.

Hope that helps!
- Rachel

Hugh Neve

unread,
May 2, 2017, 7:17:34 AM5/2/17
to cesiu...@googlegroups.com
Thanks, Rachel.

Just what I needed to know!

Reply all
Reply to author
Forward
0 new messages