Retrieve OSM node and way ID

hi,
i saw several discussion on this topics and compiled from them this:

public class MyGraphHopper extends GraphHopper {
	private DataAccess edgeMapping;
	private DataAccess nodeMapping;
	private BitUtil bitUtil;
	private Directory dir;
	private OSMReaderOSM reader;

	@Override
	public boolean load(String graphHopperFolder) {
		boolean loaded = super.load(graphHopperFolder);
		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) {
		this.reader = new OSMReaderOSM(ghStorage, this.dir);
		return initDataReader(reader);
	}

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

	@Override
	public List<Path> calcPaths(GHRequest request, GHResponse rsp) {
		return super.calcPaths(request, rsp);
	}

	public long getOSMNode(int internalNodeId) {
		if (internalNodeId >= getGraphHopperStorage().getNodes()) {
			return -1;
		}
		long pointer = 8L * internalNodeId;
		long res = bitUtil.combineIntsToLong(nodeMapping.getInt(pointer), nodeMapping.getInt(pointer + 4L));
		return res;
	}
}

and the extended OSMReaderOSM:

.....

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

		if (result) {
			int internalNodeId = this.getNodeMap().get(node.getId());
			storeOsmNodeID(internalNodeId, node.getId());
		}
		return result;
	}

	protected void storeOsmNodeID(int nodeId, long osmNodeId) {
		if (nodeId > 0) {
			long pointer = 8L * nodeId;
			nodeMapping.ensureCapacity(pointer + 8L);

			nodeMapping.setInt(pointer, bitUtil.getIntLow(osmNodeId));
			nodeMapping.setInt(pointer + 4, bitUtil.getIntHigh(osmNodeId));
		}
	}

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

		long pointer = 8L * edgeId;
		edgeMapping.ensureCapacity(pointer + 8L);

		edgeMapping.setInt(pointer, bitUtil.getIntLow(osmWayId));
		edgeMapping.setInt(pointer + 4, bitUtil.getIntHigh(osmWayId));
	}
....

Is this the way to do it?

actually i found out an easier way for node IDs? Instead of overwriting addNode(), just overwrite addTowerNode() method:

@Override
	int addTowerNode(long osmId, double lat, double lon, double ele) {
		if (nodeAccess.is3D())
			nodeAccess.setNode(nextTowerId, lat, lon, ele);
		else
			nodeAccess.setNode(nextTowerId, lat, lon);

		int id = -(nextTowerId + 3);
		getNodeMap().put(osmId, id);
		storeOsmNodeID(id, osmId);
		nextTowerId++;
		return id;
	}

I haven’t read every line, but overall I would have done it the same way.

actually i found out an easier way for node IDs? Instead of overwriting addNode(), just overwrite addTowerNode() method:

If you only want to do this for tower nodes, you can do this.

OK, thanks for review. That i have to post a question into the matching discussion, cos when i translate the matching result to OSM nodes and ways, i get very weirg results :slight_smile:

See my comment here

I’m very late to the party but as the conversation on this page helped me get the OSM node ids from GraphHopper I thought I’d contribute just in case anyone else finds themselves here…

One basic point that was missed in the conversation is that the internal node ids returned by routing and map-matching are the nextTowerId and nextPillarId values. Internally GraphHopper stores both values in a single map, by adding 3 (to avoid zero id conflict I think) and converting tower ids to negative.

Anyway here’s my code…

public class MyOSMReader extends OSMReader {

private static final BitUtil bitUtil = BitUtil.LITTLE;
private final DataAccess towerNodeMapping;
private final DataAccess pillarNodeMapping;
private final DataAccess edgeMapping;

public MyOSMReader(GraphHopperStorage ghStorage) {
    super(ghStorage);
    Directory dir = ghStorage.getDirectory();
    towerNodeMapping = dir.find("tower_node_mapping");
    towerNodeMapping.create(2000);
    pillarNodeMapping = dir.find("pillar_node_mapping");
    pillarNodeMapping.create(2000);
    edgeMapping = dir.find("edge_mapping");
    edgeMapping.create(1000);
}

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

    if (result) {
        int internalNodeId = this.getNodeMap().get(node.getId());
        storeOsmNodeID(internalNodeId, node.getId());
    }
    return result;
}

protected void storeOsmNodeID(int nodeId, long osmNodeId) {
    final DataAccess nodeMapping;
    if (nodeId < 0) {
        // if nodeId < 0 then this is a tower node
        nodeId = -nodeId;
        nodeMapping = towerNodeMapping;
    } else {
        // if nodeId > 0 then this is a pillar node
        nodeMapping = pillarNodeMapping;
    }
    // Not sure why the node process adds 3 to the node id?
    // Possibly as tower and pillar node are internally stored in the same map,
    // The +3 removes the conflict where id == 0, which would result in tower == -0, pillar == 0
    nodeId -= 3;
    long pointer = 8L * nodeId;
    nodeMapping.ensureCapacity(pointer + 8L);
    nodeMapping.setInt(pointer, bitUtil.getIntLow(osmNodeId));
    nodeMapping.setInt(pointer + 4, bitUtil.getIntHigh(osmNodeId));
}

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

    long pointer = 8L * edgeId;
    edgeMapping.ensureCapacity(pointer + 8L);

    edgeMapping.setInt(pointer, bitUtil.getIntLow(osmWayId));
    edgeMapping.setInt(pointer + 4, bitUtil.getIntHigh(osmWayId));
}
}


public class MyGraphHopper extends GraphHopper {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());


private DataAccess edgeMapping;
private DataAccess towerNodeMapping;
private DataAccess pillarNodeMapping;
private BitUtil bitUtil;

@Override
public boolean load(String graphHopperFolder) {
    boolean loaded = super.load(graphHopperFolder);
    GraphHopperStorage ghStorage = getGraphHopperStorage();
    Directory dir = ghStorage.getDirectory();
    bitUtil = BitUtil.get(dir.getByteOrder());
    edgeMapping = dir.find("edge_mapping");
    towerNodeMapping = dir.find("tower_node_mapping");
    pillarNodeMapping = dir.find("pillar_node_mapping");

    if (loaded) {
        edgeMapping.loadExisting();
        towerNodeMapping.loadExisting();
        pillarNodeMapping.loadExisting();
    }

    return loaded;
}

@Override
protected DataReader createReader(GraphHopperStorage ghStorage) {
    MyOSMReader reader = new MyOSMReader(ghStorage);
    return initDataReader(reader);
}

@Override
protected void flush() {
    super.flush();
    towerNodeMapping.flush();
    pillarNodeMapping.flush();
    edgeMapping.flush();
}

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

public long getTowerOSMNode(int internalNodeId) {
    return getOSMNode(internalNodeId, towerNodeMapping);
}

public long getPillarOSMNode(int internalNodeId) {
    return getOSMNode(internalNodeId, pillarNodeMapping);
}

public long getOSMNode(int internalNodeId, DataAccess nodeMapping) {
    try {
        long pointer = 8L * internalNodeId;
        return bitUtil.combineIntsToLong(nodeMapping.getInt(pointer), nodeMapping.getInt(pointer + 4L));
    } catch (ArrayIndexOutOfBoundsException e) {
        logger.error("Node id ({}) out of bounds", internalNodeId);
        return -1;
    }
}
}

Note that some of the internal node ids are not connected to OSM Node ids, I think these are (barrier?) nodes created by GraphHopper.

1 Like

Hi – I am new to Graphhopper and love it.
I am wanting to get a route with all the OSM node ID’s along the route. I think this code is exactly what I need. Can you give me a few pointers on how to integrate this code (I have set up graphhoper server no worries - but not not sure where to put this class you have written etc).
Thanks :slight_smile:

@Matt_Wild these snippets are for an older version of GH. You’re in luck though, I literally just figured out how to do this for the latest version the other day, see solution in this post: OSM Data in GraphHopper 3.0

Ross – You are a legend – thanks so much :slight_smile: