Refactoring: change parser location, remove todo
This commit is contained in:
parent
e44f763405
commit
fab1df33a6
11 changed files with 422 additions and 461 deletions
|
@ -3,35 +3,24 @@ package net.osmand.plus.onlinerouting.engine;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.plus.onlinerouting.parser.GpxParser;
|
||||
import net.osmand.plus.onlinerouting.parser.GraphhopperParser;
|
||||
import net.osmand.plus.onlinerouting.parser.OrsParser;
|
||||
import net.osmand.plus.onlinerouting.parser.OsrmParser;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public enum EngineType {
|
||||
GRAPHHOPPER("Graphhopper", GraphhopperParser.class),
|
||||
OSRM("OSRM", OsrmParser.class),
|
||||
ORS("Openroute Service", OrsParser.class),
|
||||
GPX("GPX", GpxParser.class);
|
||||
GRAPHHOPPER("Graphhopper"),
|
||||
OSRM("OSRM"),
|
||||
ORS("Openroute Service"),
|
||||
GPX("GPX");
|
||||
|
||||
private final String title;
|
||||
private final Class<? extends ResponseParser> parserClass;
|
||||
|
||||
EngineType(String title, Class<? extends ResponseParser> parserClass) {
|
||||
EngineType(String title) {
|
||||
this.title = title;
|
||||
this.parserClass = parserClass;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public Class<? extends ResponseParser> getParserClass() {
|
||||
return parserClass;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EngineType getTypeByName(@Nullable String name) {
|
||||
if (!Algorithms.isEmpty(name)) {
|
||||
|
|
|
@ -6,6 +6,8 @@ import androidx.annotation.Nullable;
|
|||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.parser.GpxParser;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -38,7 +40,7 @@ public class GpxEngine extends OnlineRoutingEngine {
|
|||
@NonNull
|
||||
@Override
|
||||
public String getStandardUrl() {
|
||||
return ""; // TODO will be determined in the future
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,4 +56,9 @@ public class GpxEngine extends OnlineRoutingEngine {
|
|||
params.add(EngineParameter.CUSTOM_URL);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseParser createParser() {
|
||||
return new GpxParser();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,23 @@ package net.osmand.plus.onlinerouting.engine;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.parser.JSONParser;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||
import net.osmand.router.TurnType;
|
||||
import net.osmand.util.GeoPolylineParserUtil;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -55,6 +67,12 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
vehicles.add(new VehicleType("small_truck", R.string.routing_engine_vehicle_type_small_truck));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseParser createParser() {
|
||||
return new GraphhopperParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeFullUrl(@NonNull StringBuilder sb,
|
||||
@NonNull List<LatLon> path) {
|
||||
|
@ -77,4 +95,148 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
sb.append('&').append("details=").append("lanes");
|
||||
}
|
||||
|
||||
private static class GraphhopperParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encoded = root.getString("points");
|
||||
List<LatLon> points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5);
|
||||
if (isEmpty(points)) return null;
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
|
||||
JSONArray instructions = root.getJSONArray("instructions");
|
||||
List<RouteDirectionInfo> directions = new ArrayList<>();
|
||||
for (int i = 0; i < instructions.length(); i++) {
|
||||
JSONObject instruction = instructions.getJSONObject(i);
|
||||
int distance = (int) Math.round(instruction.getDouble("distance"));
|
||||
String description = instruction.getString("text");
|
||||
String streetName = instruction.getString("street_name");
|
||||
int timeInSeconds = Math.round(instruction.getInt("time") / 1000f);
|
||||
JSONArray interval = instruction.getJSONArray("interval");
|
||||
int startPointOffset = interval.getInt(0);
|
||||
int endPointOffset = interval.getInt(1);
|
||||
|
||||
float averageSpeed = (float) distance / timeInSeconds;
|
||||
TurnType turnType = parseTurnType(instruction, leftSideNavigation);
|
||||
RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType);
|
||||
|
||||
direction.routePointOffset = startPointOffset;
|
||||
direction.setDescriptionRoute(description);
|
||||
direction.setStreetName(streetName);
|
||||
direction.setDistance(distance);
|
||||
directions.add(direction);
|
||||
}
|
||||
return new OnlineRoutingResponse(route, directions);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TurnType parseTurnType(@NonNull JSONObject instruction,
|
||||
boolean leftSide) throws JSONException {
|
||||
int sign = instruction.getInt("sign");
|
||||
TurnType turnType = identifyTurnType(sign, leftSide);
|
||||
|
||||
if (turnType == null) {
|
||||
turnType = TurnType.straight();
|
||||
} else if (turnType.isRoundAbout()) {
|
||||
if (instruction.has("exit_number")) {
|
||||
int exit = instruction.getInt("exit_number");
|
||||
turnType.setExitOut(exit);
|
||||
}
|
||||
if (instruction.has("turn_angle")) {
|
||||
float angle = (float) instruction.getDouble("turn_angle");
|
||||
turnType.setTurnAngle(angle);
|
||||
}
|
||||
} else {
|
||||
// TODO turnType.setTurnAngle()
|
||||
}
|
||||
|
||||
return turnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TurnType identifyTurnType(int sign, boolean leftSide) {
|
||||
Integer id = null;
|
||||
|
||||
if (sign == -98) {
|
||||
// an U-turn without the knowledge
|
||||
// if it is a right or left U-turn
|
||||
id = TurnType.TU;
|
||||
|
||||
} else if (sign == -8) {
|
||||
// a left U-turn
|
||||
leftSide = false;
|
||||
id = TurnType.TU;
|
||||
|
||||
} else if (sign == -7) {
|
||||
// keep left
|
||||
id = TurnType.KL;
|
||||
|
||||
} else if (sign == -6) {
|
||||
// not yet used: leave roundabout
|
||||
|
||||
} else if (sign == -3) {
|
||||
// turn sharp left
|
||||
id = TurnType.TSHL;
|
||||
|
||||
} else if (sign == -2) {
|
||||
// turn left
|
||||
id = TurnType.TL;
|
||||
|
||||
} else if (sign == -1) {
|
||||
// turn slight left
|
||||
id = TurnType.TSLL;
|
||||
|
||||
} else if (sign == 0) {
|
||||
// continue on street
|
||||
id = TurnType.C;
|
||||
|
||||
} else if (sign == 1) {
|
||||
// turn slight right
|
||||
id = TurnType.TSLR;
|
||||
|
||||
} else if (sign == 2) {
|
||||
// turn right
|
||||
id = TurnType.TR;
|
||||
|
||||
} else if (sign == 3) {
|
||||
// turn sharp right
|
||||
id = TurnType.TSHR;
|
||||
|
||||
} else if (sign == 4) {
|
||||
// the finish instruction before the last point
|
||||
id = TurnType.C;
|
||||
|
||||
} else if (sign == 5) {
|
||||
// the instruction before a via point
|
||||
|
||||
} else if (sign == 6) {
|
||||
// the instruction before entering a roundabout
|
||||
id = TurnType.RNDB;
|
||||
|
||||
} else if (sign == 7) {
|
||||
// keep right
|
||||
id = TurnType.KR;
|
||||
|
||||
} else if (sign == 8) {
|
||||
// a right U-turn
|
||||
id = TurnType.TRU;
|
||||
}
|
||||
|
||||
return id != null ? TurnType.valueOf(id, leftSide) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "paths";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import android.content.Context;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -14,7 +12,6 @@ import net.osmand.plus.onlinerouting.EngineParameter;
|
|||
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
import net.osmand.plus.routing.RouteProvider;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -109,30 +106,7 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
protected ResponseParser createParser() {
|
||||
try {
|
||||
return getType().getParserClass().newInstance();
|
||||
} catch (IllegalAccessException e) {
|
||||
LOG.debug("Error when create parser: " + e.getMessage());
|
||||
} catch (InstantiationException e) {
|
||||
LOG.debug("Error when create parser: " + e.getMessage());
|
||||
}
|
||||
return ResponseParser.emptyParser();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||
List<Location> result = new ArrayList<>();
|
||||
if (!isEmpty(route)) {
|
||||
for (LatLon pt : route) {
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = pt.getLatitude();
|
||||
wpt.lon = pt.getLongitude();
|
||||
result.add(RouteProvider.createLocation(wpt));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
protected abstract ResponseParser createParser();
|
||||
|
||||
@NonNull
|
||||
public Map<String, String> getParams() {
|
||||
|
|
|
@ -3,11 +3,20 @@ package net.osmand.plus.onlinerouting.engine;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.parser.JSONParser;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -55,6 +64,12 @@ public class OrsEngine extends OnlineRoutingEngine {
|
|||
vehicles.add(new VehicleType("wheelchair", R.string.routing_engine_vehicle_type_wheelchair));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseParser createParser() {
|
||||
return new OrsParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeFullUrl(@NonNull StringBuilder sb,
|
||||
@NonNull List<LatLon> path) {
|
||||
|
@ -77,4 +92,38 @@ public class OrsEngine extends OnlineRoutingEngine {
|
|||
}
|
||||
}
|
||||
|
||||
private static class OrsParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
JSONArray array = root.getJSONObject("geometry").getJSONArray("coordinates");
|
||||
List<LatLon> points = new ArrayList<>();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONArray point = array.getJSONArray(i);
|
||||
double lon = Double.parseDouble(point.getString(0));
|
||||
double lat = Double.parseDouble(point.getString(1));
|
||||
points.add(new LatLon(lat, lon));
|
||||
}
|
||||
if (!isEmpty(points)) {
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
new OnlineRoutingResponse(route, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "error";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "features";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,31 @@ package net.osmand.plus.onlinerouting.engine;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.parser.JSONParser;
|
||||
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||
import net.osmand.plus.routing.RouteCalculationResult;
|
||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||
import net.osmand.router.TurnType;
|
||||
import net.osmand.util.GeoPolylineParserUtil;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
import static net.osmand.util.Algorithms.objectEquals;
|
||||
|
||||
public class OsrmEngine extends OnlineRoutingEngine {
|
||||
|
||||
|
@ -48,6 +63,12 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
|||
vehicles.add(new VehicleType("foot", R.string.routing_engine_vehicle_type_foot));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseParser createParser() {
|
||||
return new OsrmParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeFullUrl(@NonNull StringBuilder sb,
|
||||
@NonNull List<LatLon> path) {
|
||||
|
@ -67,4 +88,167 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
|||
sb.append('&').append("steps=true");
|
||||
}
|
||||
|
||||
private static class OsrmParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encodedPoints = root.getString("geometry");
|
||||
List<LatLon> points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5);
|
||||
if (isEmpty(points)) return null;
|
||||
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
List<RouteDirectionInfo> directions = new ArrayList<>();
|
||||
int startSearchingId = 0;
|
||||
JSONArray legs = root.getJSONArray("legs");
|
||||
for (int i = 0; i < legs.length(); i++) {
|
||||
JSONObject leg = legs.getJSONObject(i);
|
||||
if (!leg.has("steps")) continue;
|
||||
|
||||
JSONArray steps = leg.getJSONArray("steps");
|
||||
for (int j = 0; j < steps.length(); j++) {
|
||||
JSONObject instruction = steps.getJSONObject(j);
|
||||
JSONObject maneuver = instruction.getJSONObject("maneuver");
|
||||
String maneuverType = maneuver.getString("type");
|
||||
|
||||
JSONArray location = maneuver.getJSONArray("location");
|
||||
double lon = location.getDouble(0);
|
||||
double lat = location.getDouble(1);
|
||||
Integer routePointOffset = getLocationIndexInList(route, startSearchingId, lat, lon);
|
||||
if (routePointOffset == null) continue;
|
||||
startSearchingId = routePointOffset;
|
||||
|
||||
// in meters
|
||||
int distance = (int) Math.round(instruction.getDouble("distance"));
|
||||
// in seconds
|
||||
int duration = (int) Math.round(instruction.getDouble("duration"));
|
||||
|
||||
float averageSpeed = (float) distance / duration;
|
||||
TurnType turnType = parseTurnType(maneuver, leftSideNavigation);
|
||||
RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType);
|
||||
direction.setDistance(distance);
|
||||
|
||||
String streetName = instruction.getString("name");
|
||||
String description = "";
|
||||
if (!objectEquals(maneuverType, "arrive")) {
|
||||
description = RouteCalculationResult.toString(turnType, app, false) + " " + streetName;
|
||||
}
|
||||
description = description.trim();
|
||||
|
||||
direction.setStreetName(streetName);
|
||||
direction.setDescriptionRoute(description);
|
||||
direction.routePointOffset = routePointOffset;
|
||||
directions.add(direction);
|
||||
}
|
||||
}
|
||||
|
||||
return new OnlineRoutingResponse(route, directions);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Integer getLocationIndexInList(@NonNull List<Location> locations,
|
||||
int startIndex, double lat, double lon) {
|
||||
for (int i = startIndex; i < locations.size(); i++) {
|
||||
Location l = locations.get(i);
|
||||
if (MapUtils.areLatLonEqual(l, lat, lon)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TurnType parseTurnType(@NonNull JSONObject maneuver,
|
||||
boolean leftSide) throws JSONException {
|
||||
TurnType turnType = null;
|
||||
|
||||
String type = maneuver.getString("type");
|
||||
String modifier = null;
|
||||
if (maneuver.has("modifier")) {
|
||||
modifier = maneuver.getString("modifier");
|
||||
}
|
||||
|
||||
if (objectEquals(type, "roundabout")
|
||||
|| objectEquals(type, "rotary")
|
||||
|| objectEquals(type, "roundabout turn")) {
|
||||
if (maneuver.has("exit")) {
|
||||
int exit = maneuver.getInt("exit");
|
||||
turnType = TurnType.getExitTurn(exit, 0.0f, leftSide);
|
||||
} else if (modifier != null) {
|
||||
// for simple roundabout turn without "exit" parameter
|
||||
turnType = identifyTurnType(modifier, leftSide);
|
||||
}
|
||||
} else {
|
||||
// for other maneuver types find TurnType
|
||||
// like a basic turn into direction of the modifier
|
||||
if (modifier != null) {
|
||||
turnType = identifyTurnType(modifier, leftSide);
|
||||
}
|
||||
}
|
||||
if (turnType == null) {
|
||||
turnType = TurnType.straight();
|
||||
}
|
||||
|
||||
int bearingBefore = maneuver.getInt("bearing_before");
|
||||
int bearingAfter = maneuver.getInt("bearing_after");
|
||||
float angle = (float) MapUtils.degreesDiff(bearingAfter, bearingBefore);
|
||||
turnType.setTurnAngle(angle);
|
||||
|
||||
return turnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TurnType identifyTurnType(@NonNull String modifier,
|
||||
boolean leftSide) {
|
||||
Integer id = null;
|
||||
switch (modifier) {
|
||||
case "uturn":
|
||||
id = TurnType.TU;
|
||||
break;
|
||||
|
||||
case "sharp right":
|
||||
id = TurnType.TSHR;
|
||||
break;
|
||||
|
||||
case "right":
|
||||
id = TurnType.TR;
|
||||
break;
|
||||
|
||||
case "slight right":
|
||||
id = TurnType.TSLR;
|
||||
break;
|
||||
|
||||
case "straight":
|
||||
id = TurnType.C;
|
||||
break;
|
||||
|
||||
case "slight left":
|
||||
id = TurnType.TSLL;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
id = TurnType.TL;
|
||||
break;
|
||||
|
||||
case "sharp left":
|
||||
id = TurnType.TSHL;
|
||||
break;
|
||||
}
|
||||
return id != null ? TurnType.valueOf(id, leftSide) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "routes";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ public class GpxParser extends ResponseParser {
|
|||
@Override
|
||||
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||
@NonNull String content) {
|
||||
return parseGpx(content) != null; // TODO may be there should be another check
|
||||
return parseGpx(content) != null;
|
||||
}
|
||||
|
||||
private GPXFile parseGpx(@NonNull String content) {
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
package net.osmand.plus.onlinerouting.parser;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||
import net.osmand.router.TurnType;
|
||||
import net.osmand.util.GeoPolylineParserUtil;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public class GraphhopperParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encoded = root.getString("points");
|
||||
List<LatLon> points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5);
|
||||
if (isEmpty(points)) return null;
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
|
||||
JSONArray instructions = root.getJSONArray("instructions");
|
||||
List<RouteDirectionInfo> directions = new ArrayList<>();
|
||||
for (int i = 0; i < instructions.length(); i++) {
|
||||
JSONObject instruction = instructions.getJSONObject(i);
|
||||
int distance = (int) Math.round(instruction.getDouble("distance"));
|
||||
String description = instruction.getString("text");
|
||||
String streetName = instruction.getString("street_name");
|
||||
int timeInSeconds = Math.round(instruction.getInt("time") / 1000f);
|
||||
JSONArray interval = instruction.getJSONArray("interval");
|
||||
int startPointOffset = interval.getInt(0);
|
||||
int endPointOffset = interval.getInt(1);
|
||||
|
||||
float averageSpeed = (float) distance / timeInSeconds;
|
||||
TurnType turnType = parseTurnType(instruction, leftSideNavigation);
|
||||
RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType);
|
||||
|
||||
direction.routePointOffset = startPointOffset;
|
||||
direction.setDescriptionRoute(description);
|
||||
direction.setStreetName(streetName);
|
||||
direction.setDistance(distance);
|
||||
directions.add(direction);
|
||||
}
|
||||
return new OnlineRoutingResponse(route, directions);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TurnType parseTurnType(@NonNull JSONObject instruction,
|
||||
boolean leftSide) throws JSONException {
|
||||
int sign = instruction.getInt("sign");
|
||||
TurnType turnType = identifyTurnType(sign, leftSide);
|
||||
|
||||
if (turnType == null) {
|
||||
turnType = TurnType.straight();
|
||||
} else if (turnType.isRoundAbout()) {
|
||||
if (instruction.has("exit_number")) {
|
||||
int exit = instruction.getInt("exit_number");
|
||||
turnType.setExitOut(exit);
|
||||
}
|
||||
if (instruction.has("turn_angle")) {
|
||||
float angle = (float) instruction.getDouble("turn_angle");
|
||||
turnType.setTurnAngle(angle);
|
||||
}
|
||||
} else {
|
||||
// TODO turnType.setTurnAngle()
|
||||
}
|
||||
|
||||
return turnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TurnType identifyTurnType(int sign, boolean leftSide) {
|
||||
Integer id = null;
|
||||
|
||||
if (sign == -98) {
|
||||
// an U-turn without the knowledge
|
||||
// if it is a right or left U-turn
|
||||
id = TurnType.TU;
|
||||
|
||||
} else if (sign == -8) {
|
||||
// a left U-turn
|
||||
leftSide = false;
|
||||
id = TurnType.TU;
|
||||
|
||||
} else if (sign == -7) {
|
||||
// keep left
|
||||
id = TurnType.KL;
|
||||
|
||||
} else if (sign == -6) {
|
||||
// not yet used: leave roundabout
|
||||
|
||||
} else if (sign == -3) {
|
||||
// turn sharp left
|
||||
id = TurnType.TSHL;
|
||||
|
||||
} else if (sign == -2) {
|
||||
// turn left
|
||||
id = TurnType.TL;
|
||||
|
||||
} else if (sign == -1) {
|
||||
// turn slight left
|
||||
id = TurnType.TSLL;
|
||||
|
||||
} else if (sign == 0) {
|
||||
// continue on street
|
||||
id = TurnType.C;
|
||||
|
||||
} else if (sign == 1) {
|
||||
// turn slight right
|
||||
id = TurnType.TSLR;
|
||||
|
||||
} else if (sign == 2) {
|
||||
// turn right
|
||||
id = TurnType.TR;
|
||||
|
||||
} else if (sign == 3) {
|
||||
// turn sharp right
|
||||
id = TurnType.TSHR;
|
||||
|
||||
} else if (sign == 4) {
|
||||
// the finish instruction before the last point
|
||||
id = TurnType.C;
|
||||
|
||||
} else if (sign == 5) {
|
||||
// the instruction before a via point
|
||||
|
||||
} else if (sign == 6) {
|
||||
// the instruction before entering a roundabout
|
||||
id = TurnType.RNDB;
|
||||
|
||||
} else if (sign == 7) {
|
||||
// keep right
|
||||
id = TurnType.KR;
|
||||
|
||||
} else if (sign == 8) {
|
||||
// a right U-turn
|
||||
id = TurnType.TRU;
|
||||
}
|
||||
|
||||
return id != null ? TurnType.valueOf(id, leftSide) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "paths";
|
||||
}
|
||||
}
|
|
@ -50,8 +50,19 @@ public abstract class JSONParser extends ResponseParser {
|
|||
return obj.has(getRootArrayKey());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException;
|
||||
|
||||
@NonNull
|
||||
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||
protected abstract String getRootArrayKey();
|
||||
|
||||
@NonNull
|
||||
protected abstract String getErrorMessageKey();
|
||||
|
||||
@NonNull
|
||||
protected static List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||
List<Location> result = new ArrayList<>();
|
||||
if (!isEmpty(route)) {
|
||||
for (LatLon pt : route) {
|
||||
|
@ -63,15 +74,4 @@ public abstract class JSONParser extends ResponseParser {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException;
|
||||
|
||||
@NonNull
|
||||
protected abstract String getRootArrayKey();
|
||||
|
||||
@NonNull
|
||||
protected abstract String getErrorMessageKey();
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package net.osmand.plus.onlinerouting.parser;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public class OrsParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
JSONArray array = root.getJSONObject("geometry").getJSONArray("coordinates");
|
||||
List<LatLon> points = new ArrayList<>();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONArray point = array.getJSONArray(i);
|
||||
double lon = Double.parseDouble(point.getString(0));
|
||||
double lat = Double.parseDouble(point.getString(1));
|
||||
points.add(new LatLon(lat, lon));
|
||||
}
|
||||
if (!isEmpty(points)) {
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
new OnlineRoutingResponse(route, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "error";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "features";
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
package net.osmand.plus.onlinerouting.parser;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.routing.RouteCalculationResult;
|
||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||
import net.osmand.router.TurnType;
|
||||
import net.osmand.util.GeoPolylineParserUtil;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
import static net.osmand.util.Algorithms.objectEquals;
|
||||
|
||||
public class OsrmParser extends JSONParser {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encodedPoints = root.getString("geometry");
|
||||
List<LatLon> points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5);
|
||||
if (isEmpty(points)) return null;
|
||||
|
||||
List<Location> route = convertRouteToLocationsList(points);
|
||||
List<RouteDirectionInfo> directions = new ArrayList<>();
|
||||
int startSearchingId = 0;
|
||||
JSONArray legs = root.getJSONArray("legs");
|
||||
for (int i = 0; i < legs.length(); i++) {
|
||||
JSONObject leg = legs.getJSONObject(i);
|
||||
if (!leg.has("steps")) continue;
|
||||
|
||||
JSONArray steps = leg.getJSONArray("steps");
|
||||
for (int j = 0; j < steps.length(); j++) {
|
||||
JSONObject instruction = steps.getJSONObject(j);
|
||||
JSONObject maneuver = instruction.getJSONObject("maneuver");
|
||||
String maneuverType = maneuver.getString("type");
|
||||
|
||||
JSONArray location = maneuver.getJSONArray("location");
|
||||
double lon = location.getDouble(0);
|
||||
double lat = location.getDouble(1);
|
||||
Integer routePointOffset = getLocationIndexInList(route, startSearchingId, lat, lon);
|
||||
if (routePointOffset == null) continue;
|
||||
startSearchingId = routePointOffset;
|
||||
|
||||
// in meters
|
||||
int distance = (int) Math.round(instruction.getDouble("distance"));
|
||||
// in seconds
|
||||
int duration = (int) Math.round(instruction.getDouble("duration"));
|
||||
|
||||
float averageSpeed = (float) distance / duration;
|
||||
TurnType turnType = parseTurnType(maneuver, leftSideNavigation);
|
||||
RouteDirectionInfo direction = new RouteDirectionInfo(averageSpeed, turnType);
|
||||
direction.setDistance(distance);
|
||||
|
||||
String streetName = instruction.getString("name");
|
||||
String description = "";
|
||||
if (!objectEquals(maneuverType, "arrive")) {
|
||||
description = RouteCalculationResult.toString(turnType, app, false) + " " + streetName;
|
||||
}
|
||||
description = description.trim();
|
||||
|
||||
direction.setStreetName(streetName);
|
||||
direction.setDescriptionRoute(description);
|
||||
direction.routePointOffset = routePointOffset;
|
||||
directions.add(direction);
|
||||
}
|
||||
}
|
||||
|
||||
return new OnlineRoutingResponse(route, directions);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Integer getLocationIndexInList(@NonNull List<Location> locations,
|
||||
int startIndex, double lat, double lon) {
|
||||
for (int i = startIndex; i < locations.size(); i++) {
|
||||
Location l = locations.get(i);
|
||||
if (MapUtils.areLatLonEqual(l, lat, lon)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TurnType parseTurnType(@NonNull JSONObject maneuver,
|
||||
boolean leftSide) throws JSONException {
|
||||
TurnType turnType = null;
|
||||
|
||||
String type = maneuver.getString("type");
|
||||
String modifier = null;
|
||||
if (maneuver.has("modifier")) {
|
||||
modifier = maneuver.getString("modifier");
|
||||
}
|
||||
|
||||
if (objectEquals(type, "roundabout")
|
||||
|| objectEquals(type, "rotary")
|
||||
|| objectEquals(type, "roundabout turn")) {
|
||||
if (maneuver.has("exit")) {
|
||||
int exit = maneuver.getInt("exit");
|
||||
turnType = TurnType.getExitTurn(exit, 0.0f, leftSide);
|
||||
} else if (modifier != null) {
|
||||
// for simple roundabout turn without "exit" parameter
|
||||
turnType = identifyTurnType(modifier, leftSide);
|
||||
}
|
||||
} else {
|
||||
// for other maneuver types find TurnType
|
||||
// like a basic turn into direction of the modifier
|
||||
if (modifier != null) {
|
||||
turnType = identifyTurnType(modifier, leftSide);
|
||||
}
|
||||
}
|
||||
if (turnType == null) {
|
||||
turnType = TurnType.straight();
|
||||
}
|
||||
|
||||
int bearingBefore = maneuver.getInt("bearing_before");
|
||||
int bearingAfter = maneuver.getInt("bearing_after");
|
||||
float angle = (float) MapUtils.degreesDiff(bearingAfter, bearingBefore);
|
||||
turnType.setTurnAngle(angle);
|
||||
|
||||
return turnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TurnType identifyTurnType(@NonNull String modifier,
|
||||
boolean leftSide) {
|
||||
Integer id = null;
|
||||
switch (modifier) {
|
||||
case "uturn":
|
||||
id = TurnType.TU;
|
||||
break;
|
||||
|
||||
case "sharp right":
|
||||
id = TurnType.TSHR;
|
||||
break;
|
||||
|
||||
case "right":
|
||||
id = TurnType.TR;
|
||||
break;
|
||||
|
||||
case "slight right":
|
||||
id = TurnType.TSLR;
|
||||
break;
|
||||
|
||||
case "straight":
|
||||
id = TurnType.C;
|
||||
break;
|
||||
|
||||
case "slight left":
|
||||
id = TurnType.TSLL;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
id = TurnType.TL;
|
||||
break;
|
||||
|
||||
case "sharp left":
|
||||
id = TurnType.TSHL;
|
||||
break;
|
||||
}
|
||||
return id != null ? TurnType.valueOf(id, leftSide) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "routes";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue