kevin
kevin

Reputation: 953

How do I make Cesium points rotate with the map?

I'm building a cesium app and I need my points to indicate a rotational heading. I'm using billboards to display an image I created to show this heading; however, when I rotate the globe, the points don't rotate with it, making the heading indicators incorrect.

In other words, the rotation of my billboards stay constant with the screen space, but not with the globe.

Here's an aerial view of New York. The points in question are in the lower left corner of the image. Note that the heading indicators are pointing northeast.

NYC

Here's the same view, but rotated 180° so that up is South. Now, the heading indicators are still pointing to the northwest of the screen, but I need it to be pointing to the globe's northeast, i.e. towards Manhattan.

NYC flipped

Here's the code that displays a point:

var entity = {
    id: data.cluster_number + '_' + point.id,
    name: point.id,
    position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat),
    billboard: {
        image: 'assets/img/point.png',
        color: color,
        rotation: -1 * toRadians(point.heading),
        scale: point.size * 0.07
    }
};

if (!angular.isDefined(viewer.entities.getById(entity.id))) {
    viewer.entities.add(entity);
}

What's the easiest/most effective way to get the points to rotate with the globe/map?

Upvotes: 3

Views: 3007

Answers (2)

Alberto Acevedo
Alberto Acevedo

Reputation: 1

Set the billboard's alignedAxis to Cesium.Cartesian3.UNIT_Z instead of the default screen up vector. Run following sample in SandCastle to demonstrate that it works:

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

var position = Cesium.Cartesian3.fromDegrees(-111.572177, 40.582083);

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

var ellipsoid = viewer.scene.globe.ellipsoid;
 var billboardCollection = viewer.scene.primitives.add(new Cesium.BillboardCollection(
{ scene : viewer.scene } 
));

billboardCollection.add(
{ position : position, image : '../images/facility.gif', //heightReference : Cesium.HeightReference.CLAMP_TO_GROUND, rotation: Cesium.Math.PI/4, alignedAxis : Cesium.Cartesian3.UNIT_Z } 
);

Upvotes: 0

Zac
Zac

Reputation: 2211

You need to do a few things.

1 - Update the rotation property of the billboard to be a CesiumCallbackProperty.

rotation: new Cesium.CallbackProperty(
  function () {
    return -1 * toRadians(point.heading);
  }, false);

2 - You'll need to update the heading property of the point based on the camera's heading.

point.heading = viewer.camera.heading;

3 - You'll want to update that point on an interval, either using the cesium clock:

mapContext.clock.onTick.addEventListener(function() {...});

or using JavaScripts setInterval

Once all that is set up here is how it works. The billboard on the map continuosly pulls the rotation from the point, and if it changes, it will update the billboard on the map. Each time the interval or clock ticks, the value being used changes, based on the heading of the camera.

NOTE: The heading property on the camera is in radians.

Upvotes: 1

Related Questions