Entities over a circumference

Dear all,

I think that this is not a Cesium issue, but I’m facing a strange behaviour in computing positions over a circumference. Sorry for that, but I’m a little bit rusty with trigonometry.

1. A concise explanation of the problem you’re experiencing.

I would like to calculate the evenly spaced position of some object around a circumference dynamically.

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

//Loop on the nodes

$.each(microservices,function(index,microservice){

var centerLat = 46.0702531;

var centerLon = 11.1216386;

var coordinates = pointOnCircle(radius, index, microservices.length, centerLat, centerLon);

var position = Cesium.Cartesian3.fromDegrees(coordinates.lon, coordinates.lat, settings.microservicesList.apparence.nodes.maxHeight);

var entity = microservicesNodesDataSource.entities.add({

position : position,

category : “microservice”,

    id : microservice.id,

    ellipsoid : {

    radii : new Cesium.Cartesian3(entityRadius, entityRadius, entityRadius),

    material : materialColor

    }

});

});

//The function to calculate the positions

function pointOnCircle(radius, currentPointIndex, totalPoints, centerLat, centerLon) {

var cartesianCenter = new Cesium.Cartesian3.fromDegrees(centerLon, centerLat, 0);

var theta = (Cesium.Math.TWO_PI / totalPoints);

var angle = (theta * currentPointIndex);

cartesianCenter.x = cartesianCenter.x + (radius * Math.cos(angle));

cartesianCenter.y = cartesianCenter.y + (radius * Math.sin(angle));

var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesianCenter);

var newLon = Cesium.Math.toDegrees(carto.longitude);

var newLat = Cesium.Math.toDegrees(carto.latitude);

return {lat: newLat, lon: newLon};

}

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

I have an array of elements in a JSON structure and for each element I call the pointOnCircle function in order to compute the position with the following parameters:

  1. radius : radius of the circumference
  2. index : the number of the element in the loop
  3. microservices.length : totol number of the elements to visualize
  4. centerLat : latitude of the center of the circumference
  5. centerLon : longitudeof the center of the circumference

The following image rappresents the result, as you can see not all the points are on the perimeter:

What am I doing wrong?

4. The Cesium version you’re using, your operating system and browser.

Cesium-1.41

Hi Michele,

You’re trigonometry should be fine. I think the problem is some confusion of where to use Cartographic vs Cartesian coordinates. There’s an example of creating points along a circle in this example.

Thanks, hope that helps!

Gabby

Hi Gabby,

thank you for your reply… I had a look at the example and I fixed my code as follow:

var viewer = new Cesium.Viewer(‘cesiumContainer’);

``

var input1 = {

“regions” : [

{

“id”:“reg1”,

“location”:“46.0702531,11.1216386”

},

{

“id”:“reg2”,

“location”:“41.390205,2.154007”

}

]

};

var input2 = {

“services”: [

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

    {

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

},

{

        "location":"46.0702531,11.1216386",

“region_id”: “reg1”

}

]

};

var regionNodesDataSource = new Cesium.CustomDataSource(‘regionsNodesNetwork’);

for(var i=0; i<input1.regions.length; i++){

var lat1 = parseFloat(input1.regions[i].location.split(',')[0],10);

var lon1 = parseFloat(input1.regions[i].location.split(',')[1],10);



var position1 = Cesium.Cartesian3.fromDegrees(lon1, lat1);



var materialColor = new Cesium.Color.fromCssColorString("#6e9945").withAlpha(0.5);



var regionEntity = regionNodesDataSource.entities.add({

        category : "region",

        position : position1,

        originalColor : materialColor,

        ellipse : {

            height : 15,

            semiMinorAxis : 100000,

            semiMajorAxis : 100000,

            material : materialColor

        }

});

}

var servicesNodesDataSource = new Cesium.CustomDataSource(‘servicesNodesNetwork’);

for(var t=0; t<input2.services.length; t++){

var lat2 = parseFloat(input2.services[t].location.split(',')[0],10);

var lon2 = parseFloat(input2.services[t].location.split(',')[1],10);



var position2 = computeCirclularPosition(lon2, lat2, 0.85, t, input2.services.length);



var materialColor2 = new Cesium.Color.fromCssColorString("#98D2EB").withAlpha(1.0);



var microserviceEntity = servicesNodesDataSource.entities.add({

    category : "service",

    position : position2,

    originalColor : materialColor2,

    ellipsoid : {

        radii : new Cesium.Cartesian3(8000, 8000, 8000),

        material : materialColor2

    }

});

}

viewer.dataSources.add(regionNodesDataSource).then(function() {

viewer.dataSources.add(servicesNodesDataSource).then(function(){

        viewer.zoomTo(servicesNodesDataSource, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90)));

});

});

function computeCirclularPosition(lon, lat, radius, index, numberOfPoints) {

var theta = (360/ numberOfPoints);

var radians = Cesium.Math.toRadians(theta*index);

var position = Cesium.Cartesian3.fromDegrees(lon + (radius * 1.5 * Math.cos(radians)), lat + (radius * Math.sin(radians)), 0);

return position;

}

Now it is fine and it does what I was looking for.

There are two parameters that I don’t have understood yet:

  1. the radius value passed to the computeCircularPosition function: which unit of mesure should it be? The radius of the region is in meters… but not for sure this
  2. the multiplier 1.5 in the computation of the longitude: what does it mean?

Thank you for your help!

Michele

Hi Michele,

Glad it’s working for you now!

  1. Units in Cesium are always meters and radians, unless otherwise noted. However in the computeCircularPosition function specifically, it looks like we are converting from latitude and longitude specified in degrees, so I think radius is in degrees here.

  2. I’m not sure about the 1.5 computation specifically for longitude and not latitude, perhaps there is a difference in the size of a degree of latitude versus longitude?

Thanks,
Gabby

It looks like it is just to make the track fill the Sandcastle window and compensate for the fact that the latitude lines converge at the poles which flattens the circle.

Scott

Got it, thanks Scott!

Gabby and Scott thank you for the clarifications. Now everything is more clear!