Recommended way to replace an OSM building

I am building an app that will allow users to update the height and/or the number of storeys of an OSM building. The new values will be stored in an external database an loaded when needed.

What is the best way to replace the building feature? I assume that it is not possible modify the geometry.

My initial idea is to first hide the feature using the tileSet style and then replace the geometry either with a geoJSON or with an extruded polygon. In both cases I need the coordinates of the vertices of the polygon footprint. Currently I am getting these externally from the osm ID.

Two question:

  1. Is this the right approach?
  2. Is there a way to get the footprint coordinates from the feature?

Hi there,

Generally, 3D Tiles is a format that is optimized for runtime performance rather than being the source of truth for a scene, especially in regards to the geometry. So, though some have done some exploration around this topic, edits and updates are generally not the most optimal use of 3D Tiles in it’s current iteration.

However, I think your approach of hiding the original feature with 3D Tiles Styling, and adding a new geometry is very workable, especially if you don’t expect a large magnitude of edits. Any data source like GeoJSON, entity, or primitive should do the trick.

If you do expect a large amount of geometry edits, let us know. You may run into a performance bottleneck, but there may be strategies to work around it.

1 Like

Thanks @Gabby_Getz

It will be just a few hundreds for now. Hopefully it will be fine.

In case it is useful to someone else. This is my approach. It assumes that you have an array of building objects with footprints in WKT and some other properties. I get these from a separate database.

const buildingTileset = viewer.scene.primitives.add(
  Cesium.createOsmBuildings({
    defaultColor: Cesium.Color.fromBytes(200, 208, 212, 125),
  })
);

let showConditions = [];
for (let building of buildings) {
  let footprintWkt = building.footprint;
  let footprint = footprintWkt
    .substring(10, footprintWkt.length - 2)
    .replace(/, /g, " ")
    .split(" ");

  const buildingEntity = viewer.entities.add({
    name: building.name,
    polygon: {
      hierarchy: Cesium.Cartesian3.fromDegreesArray(footprint),
      extrudedHeight: building.height,
      extrudedHeightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
      material: Cesium.Color.fromBytes(20, 146, 153, 200),
      closeTop: true,
      closeBottom: true,
    },
  });
  buildingEntity.addProperty("osm_id");
  buildingEntity.osm_id = building.osm_id;
  showConditions.push(`(\${feature['elementId']} !== ${building.osm_id})`);
}
let showCondition = showConditions.join(" && ");
buildingTileset.style = new Cesium.Cesium3DTileStyle({
  show: showCondition,
  color: {
    conditions: [
      // [true, "color('#C4CBD1')"] If you want a custom colour.
    ]
  }
});
2 Likes