Kia ora!
When calculating a route, I have the issue of my source
and target
(unique coordinate pairs) snapping to the same point, which is not the nearest point to one or both of the source
or target
.
For example:
Source: -41.16895294189453 175.00115966796875
Target: -41.165096282958984 174.99754333496094
Snapped point (for each source and target):
-41.17054882281755 174.99392423765192
-41.17054882281755 174.99392423765192
i.e. while the source
and target
coordinates are unique, the snapped point found for each is the same, and thus a) a matrix request returns 0
, and b) a route request fails to find a path.
If the nearest point to both the source
and target
is a shared point on the graph (e.g. the end of the nearest road), I would expect this behaviour. However, in the given example, visualised below, the source
(red) should snap to the point GraphHopper has calculated (green), while the target
(blue) should snap to its nearest edge (to its North), i.e. not the green point.
Could this be a rounding error on the source/target coordinates? In this example, if the library rounds each coordinate to 2dp
when identifying a snapped point, the source
and target
coordinates would be viewed as equivalent, for example.
Else, have I made a flawed assumption at some stage? I’ve included my code (from RoutingProfile.computeRoute(...)
) at the end of this post.
Two side questions:
- A few of the snapped points land upon a walking trail, not upon a road, despite using
APIEnums.Profile.DRIVING_CAR
. Is there an additional parameter I need to set to ensure we always snap to a road? - Is there a way for me to replicate the above visualisation in Java, to confirm exactly which edge the
.pbf
file believes is closest?
// the existing code
if (directedSegment) {
resp = mGraphHopper.constructFreeHandRoute(req);
} else {
mGraphHopper.setSimplifyResponse(geometrySimplify);
resp = mGraphHopper.route(req);
// start debugging code
try {
double[] radii = radiuses.clone();
List<GHPoint> points = req.getPoints();
GHResponse ghRsp = new GHResponse();
Object routingTemplate = new ViaRoutingTemplate(req, ghRsp, mGraphHopper.getLocationIndex(), mGraphHopper.getEncodingManager());
String vehicle = req.getVehicle();
FlagEncoder encoder = mGraphHopper.getEncodingManager().getEncoder(vehicle);
EdgeFilter edgeFilter = mGraphHopper.getEdgeFilterFactory().createEdgeFilter(req.getAdditionalHints(), encoder, mGraphHopper.getGraphHopperStorage());
((RoutingTemplate)routingTemplate).setEdgeFilter(edgeFilter);
List<QueryResult> qResults = ((RoutingTemplate) routingTemplate).lookup(points, encoder);
if (points.size() == qResults.size()) {
for (int placeIndex = 0; placeIndex < points.size(); placeIndex++) {
QueryResult qr = qResults.get(placeIndex);
GHPoint3D gh3d = qr.getSnappedPoint();
if (radii != null && qr.isValid() && qr.getQueryDistance() > radii[placeIndex] && radii[placeIndex] != -1.0) {
ghRsp.addError(new PointNotFoundException("Cannot find point " + placeIndex + ": " + points.get(placeIndex) + " within a radius of " + radii[placeIndex] + " meters.", placeIndex));
} else {
// print the snapped point to see if the coords for the snapped sources and targets are unique (which they may not be in all cases).
// note: this will always occur with a sufficiently large search radius.
System.out.println("\t\t" + gh3d.lat + "\t" + gh3d.lon + "\t3" + "\t\t" + gh3d.ele);
}
}
}
} catch (Exception e) {
// do nothing
}
// end debug code
// continue existing code
if (DebugUtility.isDebug() && !directedSegment) {
LOGGER.info("visited_nodes.average - " + resp.getHints().get("visited_nodes.average", ""));
}
if (DebugUtility.isDebug() && directedSegment) {
LOGGER.info("skipped segment - " + resp.getHints().get("skipped_segment", ""));
}
endUseGH();
}
Cheers,
Mak.