use of com.graphhopper.GHResponse in project graphhopper by graphhopper.
the class RouteResourceTest method testGraphHopperWebRealExceptions.
@ParameterizedTest(name = "POST = {0}")
@ValueSource(booleans = { false, true })
public void testGraphHopperWebRealExceptions(boolean usePost) {
GraphHopperWeb hopper = new GraphHopperWeb(clientUrl(app, "/route")).setPostRequest(usePost);
// this one actually works
List<GHPoint> points = Arrays.asList(new GHPoint(42.554851, 1.536198), new GHPoint(42.510071, 1.548128));
GHResponse rsp = hopper.route(new GHRequest(points).setProfile("my_car"));
assertEquals(9204, rsp.getBest().getDistance(), 10);
// unknown profile
rsp = hopper.route(new GHRequest(points).setProfile("space_shuttle"));
assertTrue(rsp.hasErrors(), rsp.getErrors().toString());
assertTrue(rsp.getErrors().get(0).getMessage().contains("The requested profile 'space_shuttle' does not exist"), rsp.getErrors().toString());
// unknown profile via web api
Response response = clientTarget(app, "/route?profile=SPACE-SHUTTLE&point=42.554851,1.536198&point=42.510071,1.548128").request().buildGet().invoke();
assertEquals(400, response.getStatus());
String msg = (String) response.readEntity(Map.class).get("message");
assertTrue(msg.contains("The requested profile 'SPACE-SHUTTLE' does not exist"), msg);
// no points
rsp = hopper.route(new GHRequest().setProfile("my_car"));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
Throwable ex = rsp.getErrors().get(0);
assertTrue(ex instanceof IllegalArgumentException, "Wrong exception found: " + ex.getClass().getName() + ", IllegalArgumentException expected.");
assertTrue(ex.getMessage().contains("You have to pass at least one point"), ex.getMessage());
// no points without CH
rsp = hopper.route(new GHRequest().setProfile("my_car").putHint(Parameters.CH.DISABLE, true));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
ex = rsp.getErrors().get(0);
assertTrue(ex instanceof IllegalArgumentException, "Wrong exception found: " + ex.getClass().getName() + ", IllegalArgumentException expected.");
assertTrue(ex.getMessage().contains("You have to pass at least one point"), ex.getMessage());
// points out of bounds
rsp = hopper.route(new GHRequest(0.0, 0.0, 0.0, 0.0).setProfile("my_car"));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
List<Throwable> errs = rsp.getErrors();
for (int i = 0; i < errs.size(); i++) {
assertEquals(((PointOutOfBoundsException) errs.get(i)).getPointIndex(), i);
assertTrue(errs.get(i).getMessage().contains("Point 0 is out of bounds: 0.0,0.0"), errs.get(i).getMessage());
}
// todo: add a check with too few headings, but client-hc does not support headings, #2009
// too many curbsides
rsp = hopper.route(new GHRequest(points).setCurbsides(Arrays.asList("right", "left", "right")).setProfile("my_car"));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
assertTrue(rsp.getErrors().toString().contains("If you pass curbside, you need to pass exactly one curbside for every point"), rsp.getErrors().toString());
// too few point hints
rsp = hopper.route(new GHRequest(points).setPointHints(Collections.singletonList("foo")).setProfile("my_car"));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
assertTrue(rsp.getErrors().toString().contains("If you pass point_hint, you need to pass exactly one hint for every point"), rsp.getErrors().toString());
// unknown vehicle
rsp = hopper.route(new GHRequest(points).putHint("vehicle", "SPACE-SHUTTLE"));
assertFalse(rsp.getErrors().isEmpty(), "Errors expected but not found.");
ex = rsp.getErrors().get(0);
assertTrue(ex instanceof IllegalArgumentException, "Wrong exception found: " + ex.getClass().getName() + ", IllegalArgumentException expected.");
assertTrue(ex.getMessage().contains("Vehicle not supported: `space-shuttle`. Supported are: `car`" + "\nYou should consider using the `profile` parameter instead of specifying a vehicle." + "\nAvailable profiles: [my_car]"), ex.getMessage());
// an IllegalArgumentException from inside the core is written as JSON, unknown profile
response = clientTarget(app, "/route?profile=SPACE-SHUTTLE&point=42.554851,1.536198&point=42.510071,1.548128").request().buildGet().invoke();
assertEquals(400, response.getStatus());
msg = (String) response.readEntity(Map.class).get("message");
assertTrue(msg.contains("The requested profile 'SPACE-SHUTTLE' does not exist"), msg);
}
use of com.graphhopper.GHResponse in project graphhopper by graphhopper.
the class Examples method routing.
@Test
public void routing() {
// Hint: create this thread safe instance only once in your application to allow the underlying library to cache the costly initial https handshake
GraphHopperWeb gh = new GraphHopperWeb();
// insert your key here
gh.setKey(apiKey);
// change timeout, default is 5 seconds
gh.setDownloader(new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build());
// specify at least two coordinates
GHRequest req = new GHRequest().addPoint(new GHPoint(49.6724, 11.3494)).addPoint(new GHPoint(49.6550, 11.4180));
// Set vehicle like car, bike, foot, ...
req.putHint("vehicle", "bike");
// Optionally enable/disable elevation in output PointList, currently bike and foot support elevation, default is false
req.putHint("elevation", false);
// Optionally enable/disable turn instruction information, defaults is true
req.putHint("instructions", true);
// Optionally enable/disable path geometry information, default is true
req.putHint("calc_points", true);
// note: turn off instructions and calcPoints if you just need the distance or time
// information to make calculation and transmission faster
// Optionally set specific locale for instruction information, supports already over 25 languages,
// defaults to English
req.setLocale(Locale.GERMAN);
// Optionally add path details
req.setPathDetails(Arrays.asList(Parameters.Details.STREET_NAME, Parameters.Details.AVERAGE_SPEED, Parameters.Details.EDGE_ID));
GHResponse fullRes = gh.route(req);
if (fullRes.hasErrors())
throw new RuntimeException(fullRes.getErrors().toString());
// get best path (you will get more than one path here if you requested algorithm=alternative_route)
ResponsePath res = fullRes.getBest();
// get path geometry information (latitude, longitude and optionally elevation)
PointList pl = res.getPoints();
// distance of the full path, in meter
double distance = res.getDistance();
// time of the full path, in milliseconds
long millis = res.getTime();
// get information per turn instruction
InstructionList il = res.getInstructions();
for (Instruction i : il) {
// System.out.println(i.getName());
}
// get path details
List<PathDetail> pathDetails = res.getPathDetails().get(Parameters.Details.STREET_NAME);
for (PathDetail detail : pathDetails) {
// System.out.println(detail.getValue());
}
}
use of com.graphhopper.GHResponse in project graphhopper by graphhopper.
the class MapMatchingResource method match.
@POST
@Consumes({ MediaType.APPLICATION_XML, "application/gpx+xml" })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, "application/gpx+xml" })
public Response match(Gpx gpx, @Context HttpServletRequest request, @Context UriInfo uriInfo, @QueryParam(WAY_POINT_MAX_DISTANCE) @DefaultValue("1") double minPathPrecision, @QueryParam("type") @DefaultValue("json") String outType, @QueryParam(INSTRUCTIONS) @DefaultValue("true") boolean instructions, @QueryParam(CALC_POINTS) @DefaultValue("true") boolean calcPoints, @QueryParam("elevation") @DefaultValue("false") boolean enableElevation, @QueryParam("points_encoded") @DefaultValue("true") boolean pointsEncoded, @QueryParam("locale") @DefaultValue("en") String localeStr, @QueryParam("profile") String profile, @QueryParam(PATH_DETAILS) List<String> pathDetails, @QueryParam("gpx.route") @DefaultValue("true") boolean withRoute, @QueryParam("gpx.track") @DefaultValue("true") boolean withTrack, @QueryParam("traversal_keys") @DefaultValue("false") boolean enableTraversalKeys, @QueryParam("gps_accuracy") @DefaultValue("40") double gpsAccuracy, @QueryParam(MAX_VISITED_NODES) @DefaultValue("3000") int maxVisitedNodes) {
boolean writeGPX = "gpx".equalsIgnoreCase(outType);
if (gpx.trk.isEmpty()) {
throw new IllegalArgumentException("No tracks found in GPX document. Are you using waypoints or routes instead?");
}
if (gpx.trk.size() > 1) {
throw new IllegalArgumentException("GPX documents with multiple tracks not supported yet.");
}
instructions = writeGPX || instructions;
StopWatch sw = new StopWatch().start();
PMap hints = createHintsMap(uriInfo.getQueryParameters());
// add values that are not in hints because they were explicitly listed in query params
hints.putObject(MAX_VISITED_NODES, maxVisitedNodes);
String weightingVehicleLogStr = "weighting: " + hints.getString("weighting", "") + ", vehicle: " + hints.getString("vehicle", "");
if (Helper.isEmpty(profile)) {
// resolve profile and remove legacy vehicle/weighting parameters
// we need to explicitly disable CH here because map matching does not use it
PMap pMap = new PMap(hints).putObject(Parameters.CH.DISABLE, true);
profile = profileResolver.resolveProfile(pMap).getName();
removeLegacyParameters(hints);
}
hints.putObject("profile", profile);
errorIfLegacyParameters(hints);
MapMatching matching = new MapMatching(graphHopper, hints);
matching.setMeasurementErrorSigma(gpsAccuracy);
List<Observation> measurements = GpxConversions.getEntries(gpx.trk.get(0));
MatchResult matchResult = matching.match(measurements);
// TODO: Request logging and timing should perhaps be done somewhere outside
float took = sw.stop().getSeconds();
String infoStr = request.getRemoteAddr() + " " + request.getLocale() + " " + request.getHeader("User-Agent");
String logStr = request.getQueryString() + ", " + infoStr + ", took:" + took + "s, entries:" + measurements.size() + ", profile: " + profile + ", " + weightingVehicleLogStr;
logger.info(logStr);
if ("extended_json".equals(outType)) {
return Response.ok(convertToTree(matchResult, enableElevation, pointsEncoded)).header("X-GH-Took", "" + Math.round(took * 1000)).build();
} else {
Translation tr = trMap.getWithFallBack(Helper.getLocale(localeStr));
DouglasPeucker peucker = new DouglasPeucker().setMaxDistance(minPathPrecision);
PathMerger pathMerger = new PathMerger(matchResult.getGraph(), matchResult.getWeighting()).setEnableInstructions(instructions).setPathDetailsBuilders(graphHopper.getPathDetailsBuilderFactory(), pathDetails).setDouglasPeucker(peucker).setSimplifyResponse(minPathPrecision > 0);
ResponsePath responsePath = pathMerger.doWork(PointList.EMPTY, Collections.singletonList(matchResult.getMergedPath()), graphHopper.getEncodingManager(), tr);
// GraphHopper thinks an empty path is an invalid path, and further that an invalid path is still a path but
// marked with a non-empty list of Exception objects. I disagree, so I clear it.
responsePath.getErrors().clear();
GHResponse rsp = new GHResponse();
rsp.add(responsePath);
if (writeGPX) {
long time = gpx.trk.get(0).getStartTime().map(Date::getTime).orElse(System.currentTimeMillis());
return Response.ok(GpxConversions.createGPX(rsp.getBest().getInstructions(), gpx.trk.get(0).name != null ? gpx.trk.get(0).name : "", time, enableElevation, withRoute, withTrack, false, Constants.VERSION, tr), "application/gpx+xml").header("X-GH-Took", "" + Math.round(took * 1000)).build();
} else {
ObjectNode map = ResponsePathSerializer.jsonObject(rsp, instructions, calcPoints, enableElevation, pointsEncoded, took);
Map<String, Object> matchStatistics = new HashMap<>();
matchStatistics.put("distance", matchResult.getMatchLength());
matchStatistics.put("time", matchResult.getMatchMillis());
matchStatistics.put("original_distance", matchResult.getGpxEntriesLength());
map.putPOJO("map_matching", matchStatistics);
if (enableTraversalKeys) {
List<Integer> traversalKeylist = new ArrayList<>();
for (EdgeMatch em : matchResult.getEdgeMatches()) {
EdgeIteratorState edge = em.getEdgeState();
// encode edges as traversal keys which includes orientation, decode simply by multiplying with 0.5
traversalKeylist.add(GHUtility.createEdgeKey(edge.getBaseNode(), edge.getAdjNode(), edge.getEdge(), false));
}
map.putPOJO("traversal_keys", traversalKeylist);
}
return Response.ok(map).header("X-GH-Took", "" + Math.round(took * 1000)).build();
}
}
}
use of com.graphhopper.GHResponse in project graphhopper by graphhopper.
the class RouteResource method doPost.
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response doPost(@NotNull GHRequest request, @Context HttpServletRequest httpReq) {
StopWatch sw = new StopWatch().start();
if (request.getCustomModel() == null) {
if (Helper.isEmpty(request.getProfile())) {
// legacy parameter resolution (only used when there is no custom model)
enableEdgeBasedIfThereAreCurbsides(request.getCurbsides(), request);
request.setProfile(profileResolver.resolveProfile(request.getHints()).getName());
removeLegacyParameters(request.getHints());
}
} else {
if (Helper.isEmpty(request.getProfile()))
// throw a dedicated exception here, otherwise a missing profile is still caught in Router
throw new IllegalArgumentException("The 'profile' parameter is required when you use the `custom_model` parameter");
}
errorIfLegacyParameters(request.getHints());
GHResponse ghResponse = graphHopper.route(request);
boolean instructions = request.getHints().getBool(INSTRUCTIONS, true);
boolean enableElevation = request.getHints().getBool("elevation", false);
boolean calcPoints = request.getHints().getBool(CALC_POINTS, true);
boolean pointsEncoded = request.getHints().getBool("points_encoded", true);
long took = sw.stop().getNanos() / 1_000_000;
String infoStr = httpReq.getRemoteAddr() + " " + httpReq.getLocale() + " " + httpReq.getHeader("User-Agent");
String queryString = httpReq.getQueryString() == null ? "" : (httpReq.getQueryString() + " ");
// todo: vehicle/weighting will always be empty at this point...
String weightingVehicleLogStr = "weighting: " + request.getHints().getString("weighting", "") + ", vehicle: " + request.getHints().getString("vehicle", "");
String logStr = queryString + infoStr + " " + request.getPoints().size() + ", took: " + String.format("%.1f", (double) took) + " ms, algo: " + request.getAlgorithm() + ", profile: " + request.getProfile() + ", " + weightingVehicleLogStr + ", custom_model: " + request.getCustomModel();
if (ghResponse.hasErrors()) {
logger.error(logStr + ", errors:" + ghResponse.getErrors());
throw new MultiException(ghResponse.getErrors());
} else {
logger.info(logStr + ", alternatives: " + ghResponse.getAll().size() + ", distance0: " + ghResponse.getBest().getDistance() + ", weight0: " + ghResponse.getBest().getRouteWeight() + ", time0: " + Math.round(ghResponse.getBest().getTime() / 60000f) + "min" + ", points0: " + ghResponse.getBest().getPoints().size() + ", debugInfo: " + ghResponse.getDebugInfo());
return Response.ok(ResponsePathSerializer.jsonObject(ghResponse, instructions, calcPoints, enableElevation, pointsEncoded, took)).header("X-GH-Took", "" + Math.round(took)).type(MediaType.APPLICATION_JSON).build();
}
}
use of com.graphhopper.GHResponse in project graphhopper by graphhopper.
the class PtRouteResourceTest method testWalkQuery.
@Test
public void testWalkQuery() {
final Response response = clientTarget(app, "/route").queryParam("point", "36.914893,-116.76821").queryParam("point", "36.914944,-116.761472").queryParam("profile", "foot").request().buildGet().invoke();
assertEquals(200, response.getStatus());
GHResponse ghResponse = response.readEntity(GHResponse.class);
assertFalse(ghResponse.hasErrors());
}
Aggregations