PolygonGeometry coordinates different from SphereGeometry and CylinderGeometry?

1. A concise explanation of the problem you're experiencing:

I'm relatively new at Cesium, and in spite of lots of googling, I'm stuck at this:

For spheres and cylinders I create a geometry (ie Cesium.SphereGeometry), and then a Cesium.GeometryInstance, and then a Cesium.Primitive.

All of this is done without reference to any particular latitude or longitude.

I then position the primitive on the earth as follows:

var position_on_ellipsoid = Cesium.Ellipsoid.WGS84.cartographicToCartesian(Cesium.Cartographic.fromDegrees( longitude,latitude, height ));

var sphere_model_matrix = Cesium.Transforms.eastNorthUpToFixedFrame(position_on_ellipsoid);

primitive.modelMatrix = sphere_model_matrix;

This works well - I can easily re-position a primitive by simply recomputing the modelMatrix without even knowing what the primitive is.

For PolygonGeometry, created through Cesium.PolygonGeometry.fromPositions(), the positions seem to be defined in terms of fixed latitude and longitude. ie

var positions = Cesium.Cartesian3.fromDegreesArrayHeights([
    -80.0, 45.0, 0,
    -85.0, 45.0, 0,
    -85.0, 40.0, 0,
    -80.0, 40.0, 0
]);

Using Cesium.PolygonGeometry( { polygonHierarchy : hierarchy}), the positions seems to be in radians relative to an origin at the north pole. A height of zero seems to be the surface of the earth.

Using this (below) to move the primitive at the origin shifts the primitive up by an earth's radius.

var model_matrix = Cesium.Transforms.eastNorthUpToFixedFrame(position_on_ellipsoid);

primitive.modelMatrix = model_matrix;

So to fix things (sort of), I translate the matrix down by the radius of the earth 6371000m (not quite correct I presume because the model used takes into account the non-spherical shape of the earth).

So how can I achieve this better (ie move a polygon byusing modelMatrix), presumably without having to fudge the earths radius? Or at least how can I get the earth's exact radius at a particular latitude and longitude?

2. A minimal code example. If you've found a bug, this helps us reproduce and repair it:

//this runs in the sandcastle. You need to manually zoom in to see the red polygon / box better.

function get_xyz_translation_matrix(x,y,z )
{
    
     var instance_matrix = Cesium.Matrix4.IDENTITY.clone();
      
     instance_matrix[Cesium.Matrix4.COLUMN3ROW0]= x;
     instance_matrix[Cesium.Matrix4.COLUMN3ROW1]= y;
     instance_matrix[Cesium.Matrix4.COLUMN3ROW2]= z;
     
     return instance_matrix;
    
}

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

var scene = viewer.scene;

var latitude =45;
var longitude =-80;
var height = 0;

var polygon_bottom_height_m = 0;
var polygon_top_height_m = 50000.0;

var x = 10000.0/ 6371000.0;
var y = 20000.0/ 6371000.0;
var z = 0.20 ;

var positions = Cesium.Cartesian3.unpackArray([-x, y, z,
                                              x, y, z,
                                              x, -y, z,
                                             -x, -y, z,
                                            ]);

// console.log(JSON.stringify( positions));

var holes = ;

var hierarchy = new Cesium.PolygonHierarchy(positions, holes);

var geometry = new Cesium.PolygonGeometry(
            {
                    polygonHierarchy : hierarchy,

                    extrudedHeight: polygon_bottom_height_m,
                    height : polygon_top_height_m,
                    vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL,
                    perPositionHeight : false
              });

var geometry_instance = new Cesium.GeometryInstance(
                {
                    geometry : geometry,

                    attributes :
                                    {
                                             color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
                                      }
                });

var primitive = new Cesium.Primitive(
                {
                     geometryInstances : geometry_instance,
                     appearance : new Cesium.PerInstanceColorAppearance(
                                        {
                                            translucent : true
                                           })
                });

var position_on_ellipsoid = Cesium.Ellipsoid.WGS84.cartographicToCartesian(Cesium.Cartographic.fromDegrees( longitude , latitude , height ));

var start_matrix = Cesium.Matrix4.IDENTITY.clone();
var result_matrix= Cesium.Matrix4.IDENTITY.clone();

Cesium.Matrix4.multiply(get_xyz_translation_matrix(0,0,-6371000 ), start_matrix, result_matrix );
start_matrix = result_matrix;
Cesium.Matrix4.multiply(Cesium.Transforms.eastNorthUpToFixedFrame(position_on_ellipsoid), start_matrix, result_matrix );

var model_matrix = result_matrix;

console.log( result_matrix.toString());

primitive.modelMatrix = model_matrix;

scene.primitives.add(primitive );

3. Context. Why do you need to do this? We might know a better way to accomplish your goal:

I am moving spheres and cylinder primitives around nicely by simply setting the primitive.modelMatrix this way. It would make adding polygons much easier if I can move them using primitive.modelMatrix as well, rather than recreate them with new points. I'd like to keep using primitives because the program I am modifying is already based on them

4. The Cesium version you're using, your operating system and browser.
Cesium 1.35, Windows 10 64 bit, Firefox 54.0.1 (32 bit)

Hi there,

Thank you for the thorough explanation! Unfortunately, you’ve found a surprisingly tricky problem, as discussed in the thread here: https://groups.google.com/forum/?hl=en#!searchin/cesium-dev/polygon|sort:relevance/cesium-dev/rYgMMei6_AQ/owQaKpOFCwAJ

In short, Cesium doesn’t have native support for applying a transformation matrix to polygons, since polygons are basically just defined on a per position basis. As you’ve noticed, doing the computation yourself can get a bit messy if you want your points to lie on the ellipsoid surface because the earth isn’t a perfect sphere. In practice, depending on your use case, you may be able to get away with an approximation. Another potential work around is creating a 3D model of the polygon, which will be easier to transform around the globe. Otherwise unfortunately, the solution is to transform each poly position to a cart3, transform it, then convert it back to a cartographic point (lat/long) and correct the height.

Hope that helps,

  • Rachel

Hi Rachel,

That for the advice - I really appreciate it. I'm glad I wasn't missing something more obvious. I'll now move ahead with various workarounds.

-Peter