Clamping 3dpolygons to the ground

Hi All!

I’ve been trying to work this out for a while

When i draw objects into cesium map they are exactly how I want them to be, clamped to ground with correct height.

const cartographicCoords = vertexLocations.map(({ longitude, latitude }) =>
Cesium.Cartographic.fromDegrees(longitude, latitude)
);
const terrainHeights = await Cesium.sampleTerrainMostDetailed(
this.viewer.terrainProvider,
cartographicCoords
);

const clampedCoords = vertexLocations.map((vertex, index) => ({
…vertex,
height: terrainHeights[index]?.height || 0,
}));

const baseTerrainHeight = clampedCoords[0]?.height || 0;
const extrudedHeight = baseTerrainHeight + height;
const cartesianCoords = clampedCoords.map(({ longitude, latitude, height }) =>
Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
);
const entity = this.viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(cartesianCoords),
material: Cesium.Color.fromCssColorString(polygonType.fillColor),
extrudedHeight: baseTerrainHeight + height,
height: baseTerrainHeight,
closeTop: true,
closeBottom: true
},
userData: { vertices: clampedCoords, height }
});

I am having trouble storing this object to a json file where i can load it again later - the json looks like this

{
“objects”: [
{
“id”: “fb2697dc-da3a-4684-ae44-c53a93794a9d”,
“name”: “Polygon 1738365868906”,
“type”: “Polygon3D”,
“baseTerrainHeight”: -29.138465356242214,
“extrudedHeight”: -9.138465356242214,
“vertices”: [
{
“longitude”: 115.71771796477525,
“latitude”: -33.02759515832507,
“height”: -29.138465356242214
},
{
“longitude”: 115.71704703935087,
“latitude”: -33.02875379004531,
“height”: -29.097115691800845
},
{
“longitude”: 115.71879040525089,
“latitude”: -33.02853717270545,
“height”: -28.128355173115068
}
],
“parent”: “#”,
“material”: {
“red”: 0,
“green”: 0.5019607843137255,
“blue”: 0,
“alpha”: 0.6
},
“outlineColor”: {
“red”: 0,
“green”: 0.5019607843137255,
“blue”: 0,
“alpha”: 1
},
“borderWidth”: 1,
“show”: true
}
]
}

No matter what i do, the reloaded polygon is floating in the air. it seems to start rendering the polygon base local height zero (terrain height at this location is around -29.5)

here is the code that adds it back

else if (object.type === “Polygon3D”) {
console.log(" Adding a 3D Polygon with extruded height.");

    this.viewer.entities.add({
        id: object.id,
        polygon: {
            hierarchy: new Cesium.PolygonHierarchy(object.vertices.map(v =>
                Cesium.Cartesian3.fromDegrees(v.longitude, v.latitude, v.height || object.baseTerrainHeight)
            )),
            material: materialColor,
            outline: true,
            outlineColor: outlineColor,
            extrudedHeight: object.extrudedHeight,
            closeTop: true,
            closeBottom: true
        },
        show: object.show ?? true,
        userData: object
    });

i didn’t work out how to store the objects better but when adding them back to the map i was able to add them in a way that clamps them. I added the heightReference and ExtrudedHeightReference values and it worked the way i wanted it to.

 this.viewer.entities.add({
        id: object.id,
        polygon: {
            hierarchy: new Cesium.PolygonHierarchy(object.vertices.map(v =>
                Cesium.Cartesian3.fromDegrees(v.longitude, v.latitude, v.height || object.baseTerrainHeight)
            )),
            material: materialColor,
            outline: true,
            outlineColor: outlineColor,
            extrudedHeight: object.extrudedHeight,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // Clamp the base to the ground
            extrudedHeightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, // Extrude relative to the ground
            closeTop: true,
            closeBottom: true
        },
        show: object.show ?? true,
        userData: object
    });
1 Like

I’m glad you found a solution @Neil_McIntyre! Using height references is definitely the most straightforward way of addressing this. There should be no need to manually sample heights at all with this method.

Does this cover your use case? Or are there any remaining questions here?