Alright, found some more time to work on this.
I am running DijkstraOneToMany
on a QueryGraph
. Might that be the problem? If I call .calcPoints()
on a returned Path
it crashes stating that java.lang.IllegalStateException: Edge soandso not found with adjNode:foobar. found edges were:meep->bla, whatnot->thing
Indeed, if I print whether the edges in the path exist:
def edgeExistsIn(graph: GraphHopperStorage)(e: Int) = {
e < graph.getEdges()
}
val dbg = paths.map(p => p.getEdges().asScala.map(_.value).map(edgeExistsIn(graph))).toSeq
println(dbg)
I get output such as:
List(ArrayBuffer(false), ArrayBuffer(false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false), ArrayBuffer(false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false), ArrayBuffer(false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false))
Indicating that at the start and end of the paths found are edges that don’t exist in the actual data. AKA, virtual edges. Those have IDs larger than what is returned by GraphHopperStorage#getEdges(), right?
Is DijkstraOneToMany not supposed to be used with QueryGraph
s? Do I have to use a different API? The HashMap based one works fine, I suppose it takes care of the virtual bits in the Path. Do I have to manually filter out all virtual edges and nodes from the paths? Is there a ready made method for this? Thanks!
Addendum:
If I filter out aforementioned edges:
def cleanPath(p: Path): Path = {
val realPath = new Path(graph)
val realEdges = p.getEdges().asScala.map(_.value).filter(edgeExistsIn(graph))
realEdges.foreach(realPath.addEdge)
realPath
}
and then run .calcPoints()
on those supposedly real paths, I get:
[error] (run-main-19) java.lang.IllegalStateException: fromNode < 0 should not happen
[error] java.lang.IllegalStateException: fromNode < 0 should not happen
[error] at com.graphhopper.routing.Path.getFromNode(Path.java:105)
[error] at com.graphhopper.routing.Path.calcPoints(Path.java:281)
[error] at io.doerfler.TilesHopperMain$.$anonfun$main$55(TilesHopperMain.scala:277)
Guess, I have to set to fromNode
manually. fwiw, I first tried copying the virtual path’s fromNode
:
val fromNodeF = classOf[Path].getDeclaredField("fromNode")
fromNodeF.setAccessible(true)
val fromNode = fromNodeF.get(virtualPath).asInstanceOf[Int]
realPath.setFromNode(fromNode)
Having to use reflection is, of course, a strong indicator that I’m rubbing the cat the wrong way. There just has to be an easier way to do this.
As expected, this only got me an exception saying the node was out of bounds. Of course, the fromNode
might as well be a virtual node, too.
So, I now set the fromNode
to the base node of the first actual edge if there is any real edge left in the path. Some paths consist just of virtual edges. So, finally:
def cleanPath(p: Path): Option[Path] = {
val realPath = new Path(graph)
val realEdges = p.getEdges().asScala.map(_.value).filter(edgeExistsIn(graph)).toSeq
realEdges.foreach(realPath.addEdge)
for {
fe <- realEdges.headOption
feis = upgrade(fe)
bn = feis.getBaseNode
_ = realPath.setFromNode(bn)
} yield realPath
}
(and:)
def upgrade(e: Int): EdgeIteratorState =
graph.getEdgeIteratorState(e, Integer.MIN_VALUE)
gives me actual, real paths based on the virtual ones found by DijkstraOneToMany used with a QueryGraph that I can turn into a PointList
and dump in a gpx file for viewing.