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;
}
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
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.
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
@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