planetiler icon indicating copy to clipboard operation
planetiler copied to clipboard

[FEATURE] Include node/way/relation in the feature ID

Open jameswestman opened this issue 2 years ago • 4 comments

Is your feature request related to a problem? Please describe.

As far as I can tell, for OpenStreetMap features, Planetiler uses the OSM ID for the MVT feature ID. However, it doesn't say whether it's a node, way, or relation, which is a problem because the IDs are not unique between those, i.e. there can be both a node #1000 and a way #1000.

Describe the solution you'd like I'd like to have some kind of encoding in the feature ID to describe the source of the ID--OSM node, OSM way, Natural Earth, etc. This could be done, for example, using the lower 3 bits of the ID.

Describe alternatives you've considered

I tried patching the OpenMapTiles schema repo to include the OSM ID with type in a tag, but this incurs a heavy tile size increase (around 10% on the small extract I tried) because they're all mostly different.

jameswestman avatar Oct 30 '22 03:10 jameswestman

I'll write what I've learned so far while troubleshooting #215 in regards to IDs , @msbarry will hopefully correct my mistakes and give some further feedback:

  • all IDs in the result (i.e. .mbtiles file) are allocated with AtomicLong idGenerator (calling incrementAndGet())
  • how that relates to your feature request: AFAIK source IDs usually do not make it into the result
    • one exception I've stumbled upon so far: Natural Earth features should have ne_id tag thanks to https://github.com/onthegomap/planetiler/blob/main/planetiler-core/src/main/java/com/onthegomap/planetiler/reader/NaturalEarthReader.java#L172
  • how that relates to #215: idGenerator is (also) called in multi-threaded stages, hence we're getting different IDs if generating same desired result twice from same source data
  • TL;DR: if we solve this in a certain way (maintaining source IDs, etc.), it should also help with #215

phanecak-maptiler avatar Nov 07 '22 09:11 phanecak-maptiler

We can expose a setId method on Feature, alongside the existing getSourceId. That would provide a Profile-facing API to set the MVT id, but to make it useful we would also need to:

  • Expose whether something is an OSM node, way or relation through SourceFeature. We could assume points are nodes, and have a binary isRelation to distinguish polygons coming from ways or relations, but that would exclude cases where we might would to generate a Point geometry for a polygon label, or generate a centerline Line for a polygon label.

  • Store the OSM type as part of the 64-bit long. What I usually do is only use the bottom 53 bits of the long; we'd need 2 bits (bits 51-52) to encode the enum: NOT_OSM, NODE, WAY, RELATION and the rest of the lower bits for the source ID. Using only 53 bits means working in JavaScript is easier. But this feels too specific and can be handled on the Profile side instead of being defaulted in planetiler-core.

  • If we want to track not only NOT_OSM but the specific Source, we would need some consistent ordering of Sources; Right now it seems like the main way to address a specific Source is by name e.g. osm, but if there was a stable integer index for each Source the profile's setId could use that to encode those into high bytes as well. (This could also be done by having a singleton mapping sourceName to an ID in the profile but that seems messy)

bdon avatar Feb 03 '23 13:02 bdon

#514 should be all that is needed for setting sourceID (not sure about tile features yet); the actual construction of a feature ID from OSM IDs can be something like the below (not tested heavily):

long tile_feature_id;
if (sourceFeature instanceof OsmSourceFeature osmFeature) {
  var element = osmFeature.originalElement();
  tile_feature_id = element.id();
  long elem_type;
  if (element instanceof OsmElement.Relation) {
    elem_type = 0x3;
  } else if (element instanceof OsmElement.Way) {
    elem_type = 0x2;
  } else { // is node
    elem_type = 0x1;
  }
  tile_feature_id |= (elem_type << 51);
  features.point("toilets").setSourceId(tile_feature_id);
}

bdon avatar Mar 14 '23 09:03 bdon

With the addition of setId on FeatureCollector I think this issue can be closed on planetiler-core - the specific format of integer feature IDs is left up to the specific profile.

The default vector tile feature IDs should default to OSM IDs now, but with no distinguishing of nodes/ways/relations.

bdon avatar Mar 19 '23 13:03 bdon