Polygon anchor point(center point)

Hello. I am working with geojson data and load data with using
Cesium.GeoJsonDataSource(). I access entities and they are Polygon.

I want to access lat lon point of Polyon Center(Anchor point). Because I want to put label to center of each polygon.How can I do this?

If you have the lat, long stored in the GeoJSON properties, you could access them directly when you load the GeoJSON. Here’s the code I use:

var dataSource = new Cesium.GeoJsonDataSource();

viewer.dataSources.add(dataSource);

dataSource.loadUrl(’…/…/SampleData/predios_FeatureCollection.geojson’).then(function() {

//Get the array of entities

var entities = dataSource.entities.entities;

var labels = scene.primitives.add(new Cesium.LabelCollection());

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

var entity = entities[i];

var id = entity.id;

var coordinadas = entity.properties.coordinates;

var coordsArreglo = coordinadas.split(’,’);

var lat = coordsArreglo[0];

var lon = coordsArreglo[1];

// Etiquetas para GeoJSON

labels.add({

position : Cesium.Cartesian3.fromDegrees(lat, lon),

text : id,

// CSS font-family

font : ‘8px SoberanaSans’,

fillColor : Cesium.Color.WHITE,

outlineColor : Cesium.Color.BLACK,

outlineWidth : 1,

style : Cesium.LabelStyle.FILL_AND_OUTLINE

});

}

});

While Zach’s code will work, a cleaner solution is to use the existing Entity label capabilities rather than maintain your own LabelCollection primitive. This allows someone to select/zoom to a feature when it’s clicked on, for example. It will also automatically get rid of the labels when the GeoJSON is unloaded. Finally, I also added code to get the real surface center of the polygon, rather than just using the first point. I’m also actively working on changes to make the below code easier to write/read; for example we’ll be removing the requirement to explicitly have “new Cesium.ConstantProperty” everywhere if you are using static values and you’ll be able to use a template object, as Zach does for the lower level Label primitive. I’ve also floated around the idea of auto-computing centroid positions for all GeoJSON polygon/polylines, rather than having to explicitly set them like I do here.

//Get the array of entities

var entities = dataSource.entities.entities;

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

var entity = entities[i];

var name = entity.name;

//Make sure it’s a polygon and doesn’t already have a position.

if (!entity.position && entity.polygon) {

var center = Cesium.BoundingSphere.fromPoints(entity.polygon.positions.getValue()).center;

Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(center, center);

entity.position = new Cesium.ConstantPositionProperty(center);

}

//Set up the label.

var label = new Cesium.LabelGraphics();

label.text = new Cesium.ConstantProperty(name);

label.font = new Cesium.ConstantProperty(‘12pt SoberanaSans’);

label.fillColor = new Cesium.ConstantProperty(Cesium.Color.WHITE);

label.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK);

label.outlineWidth = new Cesium.ConstantProperty(1);

label.style = new Cesium.ConstantProperty(Cesium.LabelStyle.FILL_AND_OUTLINE)

entity.label = label;

}

Thank you very much, I will try your solutions.

I tried your solution. Label is rendering but label is rendering below globe. I want to render label on globe surface.

Matthew’s cleaner solution is way more sustainable. Here’s my results:

It appears that the Label graphics are being rendered half inside the GeoJSON at times. Zooming in makes it better for some but not all. Not sure if it’s a GeoJSON rendering problem or if there’s a way to assign the z value higher than the GeoJSON polygons.

Trying

scene.globe.depthTestingAgainstTerrain = true;

``

(as per the post “label is rendering under ground”), I couldn’t get any results.

If you need a temporary workaround, try my above code using LabelCollection. It looks like this:

Since labels are in 3D space, what you’re seeing is the label going under polygon (and terrain if you are using it). Ideally you want the label to be either completely visible or completely invisible depending on it’s position, but this is actually a pretty hard problem to solve (not just in Cesium, but 3D globes in general). The best workaround for this is to use the labels eyeOffset property with a negative Z value. Eye offset allows you to move the rendering location of the label (or billboard) based on the viewers position. Positive X moves to the viewer’s right, Y moves up and Z moves into the screen. By using a negative Z value only, you are saying “make this label appear closer to the user than it really is.” The affect of this is that it gets rendered above the polygon. Here’s what I used for my ground based examples.

label.eyeOffset = new Cesium.ConstantProperty(new Cesium.Cartesian3(0, 0, -100000));

There are 2 drawbacks to this approach. Neither of them are a deal breaker in many use cases; but you should be aware of them.

  1. When the viewer gets within Z meters of the label, it will disappear (because it’s now behind the viewer).

  2. If you something in front of the label (like another shape or volume) by less than Z meters; the label will show up on top of that object (because we told it to be closer to us when looking at it).

Hope that helps,

Matt

Thank you very much. it is worked. I can see all labels over globe.

Thanks, Ian

Hi Ian,

Try entity.polygon.hierarchy

-Hannah

Hannah,

Thanks, this works.

var center = Cesium.BoundingSphere.fromPoints(entity.polygon.hierarchy.getValue().positions).center;

Regards

Ian

One of our guys is trying to resolve this ‘label under polygon’ issue and we’re on Cesium 1.28. Any updated ways of dealing with this?

The problem I’m running into is that labels at first appear on top of the polygon, but go behind it when the user zooms out. I draw the label with z_value = (shape_z_value) + constant, which should always be on top.

I’ve tried modifying the label.eyeOffset, but it isn’t acceptable to my users for the label to go behind the camera (and thus off the screen) when they zoom in to a particular zoom level.

I should also mention that I’m using the Primitives API, not the Entity API, so Labels aren’t associated with a shape, necessarily.

``

Hi Ashley,

If you read Matt’s explanation earlier in the thread, that suggestion of using eye offset is still probably our best workaround. Unfortunately, this label issue is a tricky one.

If the offset solution doesn’t work for you for some reason, here’s another (warning, hacky for reasons described in that thread) solution:

https://groups.google.com/d/msg/cesium-dev/ZSGJAUqnGR0/FCmPuqo1CQAJ

Use the code example in the above thread to determine whether your label is visible from current vantage, then hide the label if it doesn’t pass the visibility test.

If you just need the label to always be visible, then disable the depth test for that label as seen in this this billboard example (“disable depth test…”): http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Billboards.html&label=Showcases

Hope that helps,

  • Rachel

I'm trying this answer with code updated to match the current version of Cesium, and it does not center the label, particularly on large polygons. I'm loading the data in from a KML file, then trying to center the label.

    var kml_data = Cesium.KmlDataSource.load(url)
    kml_data.then(function(data) {
        viewer.dataSources.add(data);

        // Iterate over all the KML entities
        $.each(data.entities.values, function(i, entity) {
            var poly_center = Cesium.BoundingSphere.fromPoints(entity.polygon.hierarchy.getValue().positions).center;
            poly_center = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(poly_center);
            entity.position = poly_center;
        });
    }

Hi there,

I don’t see anything immediately wrong with your logic, but if you post a gist with your code we may be able to help you debug.

Best,

  • Rachel

Unfortunately this is for a company project so I cannot post the code. Any ideas as to what might be wrong?

Looks like your method works just fine. I created a code example here (look at the custom styling option): http://cesiumjs.org/Cesium/Apps/Sandcastle/?src=Hello%20World.html&label=Showcases&gist=834086ff0430ae5e813f36933a963acb

Note that for an irregular, non-convex shape like California, the labels will not truly be centered because the bounding sphere calculation doesn’t take the concavity into account.

Hope that helps,

  • Rachel

Are there any workaround to account for the concavity of a large geometry shape?

Hi there,

We don’t have any native support for this, but you may find this helpful: https://stackoverflow.com/questions/9692448/how-can-you-find-the-centroid-of-a-concave-irregular-polygon-in-javascript

Best,

  • Rachel