How to get the OSM resource reference for a node/edge in the match result?

In order to identify the street name(s) for a map matched track/segment I would need the reference to the OSM resource. Is this information available in the match result?
If yes, how can this information been accessed?

Many thanks in advance!

Street names are the only properties which should be already available via edgeIteratorState.getName

Other properties you would need a ID mapping, see this example on how to do this

Thanks for the hint, I have tried to implement the mapping as in the referenced example but in the version map-matching 0.5.
The problem is OSMWayId is always 0.
I assume the reason is that method storeOsmWayID is private in version 0.5 and protected in version 0.6, right?
Do I need to change to newest version in order to implement the OSM id mapping?

Many thanks!

Werner

For 0.5 it is not possible due to this private method, yes.
And 0.6 is subject to change and not released yet (therefor the SNAPSHOT in the version), but you’d need that.

Thanks for the fast reply!
Is there a chance to get the protected method storeOsmWayID() backported to version 0.5?
I think this would be highly benefitial for the stable version!

Thanks
Werner

There are no plans to backport features yet, only if there are critical or security bugs.

Hi karussell,

I tried your graphhopper-osm-id-mapping example and id works as expected.
But I can’t get it to work with mappping of internal node ids to osm node ids.
I’m getting some osm node with match.getEdgeState().getBaseNode() but they are not even near the osm way with match.getEdgeState().getEdge()

Could you pleaes have a look?

public class OSMReaderOSM extends OSMReader {

   public OSMReaderOSM( GraphHopperStorage ghStorage )
   {
      super( ghStorage );
   }

   @Override
   boolean addNode( OSMNode node )
   {
      boolean result = super.addNode( node );

      if( result )
      {
         int internalNodeId = this.getNodeMap().get( node.getId() );

         if( internalNodeId >= 0 )
         {
            storeOsmNodeID( internalNodeId, node.getId() );
         }
      }

      return result;
   }

   protected void storeOsmNodeID( int nodeId, long osmNodeId )
   {
   }
}


   public class MyGraphHopper extends GraphHopper {

      // mapping of internal edge ID to OSM way ID
      private DataAccess edgeMapping;
      private DataAccess nodeMapping;
      private BitUtil bitUtil;

      @Override
      public boolean load( String graphHopperFolder )
      {
         boolean loaded = super.load( graphHopperFolder );

         Directory dir = getGraphHopperStorage().getDirectory();
         bitUtil = BitUtil.get( dir.getByteOrder() );


         edgeMapping = dir.find( "edge_mapping" );
         nodeMapping = dir.find( "node_mapping" );

         if( loaded )
         {
            edgeMapping.loadExisting();
            nodeMapping.loadExisting();
         }

         return loaded;
      }

      @Override
      protected DataReader createReader( GraphHopperStorage ghStorage )
      {
         OSMReader reader = new OSMReaderOSM( ghStorage )
         {

            {
               edgeMapping.create( 1000 );
               nodeMapping.create( 1000 );
            }

            @Override
            protected void storeOsmWayID( int internalEdgeId, long osmWayId )
            {
               super.storeOsmWayID( internalEdgeId, osmWayId );

               long pointer = 8L * internalEdgeId;
               edgeMapping.ensureCapacity( pointer + 8L );
               edgeMapping.setInt( pointer + 0, bitUtil.getIntLow( osmWayId ) );
               edgeMapping.setInt( pointer + 4, bitUtil.getIntHigh( osmWayId ) );
            }

            @Override
            protected void storeOsmNodeID( int internalNodeId, long osmNodeId )
            {
               long pointer = 8L * internalNodeId;
               nodeMapping.ensureCapacity( pointer + 8L );
               nodeMapping.setInt( pointer + 0, bitUtil.getIntLow( osmNodeId ) );
               nodeMapping.setInt( pointer + 4, bitUtil.getIntHigh( osmNodeId ) );

               //System.out.println( internalNodeId + " -> " + osmNodeId );
            }

            @Override
            protected void finishedReading()
            {
               super.finishedReading();
               edgeMapping.flush();
               nodeMapping.flush();
            }
         };

         return initOSMReader( reader );
      }

      public long getOSMWay( int internalEdgeId )
      {
         long pointer = 8L * internalEdgeId;
         return bitUtil.combineIntsToLong( edgeMapping.getInt( pointer ), edgeMapping.getInt( pointer + 4L ) );
      }

      public long getOsmNode( int internalNodeId )
      {
         long pointer = 8L * internalNodeId;
         return bitUtil.combineIntsToLong( nodeMapping.getInt( pointer ), nodeMapping.getInt( pointer + 4L ) );
      }
   }

This could be virtual nodes too and you’ll need to use the queryGraph or fetch the underlying edge. See discussion: How to expand a matched trip along the graph or Retrieve closest Tower Node id of a given virtual node id or What are virtual edges and how are they used in the current Map Matching implementation?

Hi karussel,

even with

EdgeExplorer ee = graph.createEdgeExplorer();
// ...
EdgeIterator iter = ee.setBaseNode( match.getEdgeState().getBaseNode() );
while( iter.next() )  {
   osmNodeId = hopper.getOsmNode( iter.getAdjNode() );
   // draw
}

I’m getting not the expected result, instead valid osm node ids are returned but they are not even near the matched way.
Maybe the mapping LongIntMap osmNodeIdToInternalNodeMap; in OSMReader is not the real mapping for the imported data?

Make sure the node IDs are not virtual i.e. lower than graph.getNodes

Even the neighboring nodes can be virtual if e.g. two query points are on the same edge.

It seems I’m not getting virtual nodes. Take a look at this data

graph.getNodes() = 60351
match.getEdgeState().getBaseNode() = 680

By using the mapping

long osmNodeId = hopper.getOsmNode( match.getEdgeState().getBaseNode() );
long osmWayId = hopper.getOSMWay( match.getEdgeState().getEdge() );

I’m getting the desired osm way id but not the osm node id

osmNodeId = 21521975
osmWayId = 38623452

Thanks for your input so far

Ah, okay. Please try with disabling subnetwork removal and see if it works:

prepare.min_network_size=0
prepare.min_one_way_network_size=0

I.e. the internal node change directly after the import (inPlaceNodeRemove) and you would need to change the mapping too: https://github.com/graphhopper/graphhopper/blob/master/core/src/main/java/com/graphhopper/storage/BaseGraph.java#L626

Unfortunately it does not work with the new parameters.

I tried the following:

  • added configuration in already imported graphhopper data in properties file
  • removed graphhopper data and created new cache with

hopper.setMinNetworkSize( 0, 0 );
hopper.importOrLoad();

BaseGraph#inPlaceNodeRemove seems to be the problem, but following the changes to the ids looks like a lot of work for which I don’t have time right now unfortunatley.

It’s a pity that graphhopper(-map-matching) does not support this use-case natively.
I will have to use the workaround by querying the osm node id with osm way id and gpx pair.

Remove the full folder and re-import again. IF you use the config (hopper.init(cmdLineArgs)) you do not need to set this in the Java API.

Yes, we plan to do so but as you mention: this is all work :wink:

Yep, I already removed the full folder (that was what I meant with “removed graphhopper data”),
I tried all options (using the init, editing the config and setting with java-api) while always removing the full folder.

Strange, as you can see here we do not call ghStorage.optimize(); if both properties are 0 or negative.

Can you confirm inPlaceNodeRemove is not called afterwards? If yes, then there is something else wrong.

Yep, I already removed the full folder (that was what I meant with “removed graphhopper data”),

I was a bit irritated as you said you edited the properties file in the graphhopper folder

It was my first attempt to just edit the property file. Then I removed the full folder and tried an re-import with your suggested settings (by init or setMinNetworkSize)

Anyway you are right, inPlaceNodeRemove does not get called. Do you have a suggestion where I should look next?

1 Like

I think the problem is your setOSMId hook. If the ID is a pillar node it should not be used. See here about tower vs. pillar nodes.

Let me think more about this and how to make it easy and working

Hi karussell, any news on some working storeOsmNodeID hook?

No, too many things on the table.