Implement GPX online routing, step 1
This commit is contained in:
parent
dd1c4b5311
commit
584e7dbf6d
18 changed files with 778 additions and 455 deletions
|
@ -53,6 +53,8 @@ public class Algorithms {
|
||||||
public static final int XML_FILE_SIGNATURE = 0x3c3f786d;
|
public static final int XML_FILE_SIGNATURE = 0x3c3f786d;
|
||||||
public static final int OBF_FILE_SIGNATURE = 0x08029001;
|
public static final int OBF_FILE_SIGNATURE = 0x08029001;
|
||||||
public static final int SQLITE_FILE_SIGNATURE = 0x53514C69;
|
public static final int SQLITE_FILE_SIGNATURE = 0x53514C69;
|
||||||
|
public static final int BZIP_FILE_SIGNATURE = 0x425a;
|
||||||
|
public static final int GZIP_FILE_SIGNATURE = 0x1f8b;
|
||||||
|
|
||||||
public static String normalizeSearchText(String s) {
|
public static String normalizeSearchText(String s) {
|
||||||
boolean norm = false;
|
boolean norm = false;
|
||||||
|
@ -358,6 +360,14 @@ public class Algorithms {
|
||||||
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
|
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int readSmallInt(InputStream in) throws IOException {
|
||||||
|
int ch1 = in.read();
|
||||||
|
int ch2 = in.read();
|
||||||
|
if ((ch1 | ch2) < 0)
|
||||||
|
throw new EOFException();
|
||||||
|
return ((ch1 << 8) + ch2);
|
||||||
|
}
|
||||||
|
|
||||||
public static String capitalizeFirstLetterAndLowercase(String s) {
|
public static String capitalizeFirstLetterAndLowercase(String s) {
|
||||||
if (s != null && s.length() > 1) {
|
if (s != null && s.length() > 1) {
|
||||||
// not very efficient algorithm
|
// not very efficient algorithm
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||||
|
import net.osmand.plus.onlinerouting.engine.GpxEngine;
|
||||||
import net.osmand.plus.onlinerouting.engine.GraphhopperEngine;
|
import net.osmand.plus.onlinerouting.engine.GraphhopperEngine;
|
||||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
||||||
import net.osmand.plus.onlinerouting.engine.OrsEngine;
|
import net.osmand.plus.onlinerouting.engine.OrsEngine;
|
||||||
|
@ -27,6 +28,8 @@ public class OnlineRoutingFactory {
|
||||||
return new OsrmEngine(params);
|
return new OsrmEngine(params);
|
||||||
case ORS:
|
case ORS:
|
||||||
return new OrsEngine(params);
|
return new OrsEngine(params);
|
||||||
|
case GPX:
|
||||||
|
return new GpxEngine(params);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Online routing type {" + type.name() + "} not supported");
|
"Online routing type {" + type.name() + "} not supported");
|
||||||
|
|
|
@ -9,7 +9,8 @@ import net.osmand.osm.io.NetworkUtils;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
||||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
|
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||||
|
import net.osmand.plus.onlinerouting.parser.ResponseParser.OnlineRoutingResponse;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
@ -19,12 +20,14 @@ import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import static net.osmand.util.Algorithms.isEmpty;
|
import static net.osmand.util.Algorithms.isEmpty;
|
||||||
|
|
||||||
|
@ -88,7 +91,8 @@ public class OnlineRoutingHelper {
|
||||||
boolean leftSideNavigation) throws IOException, JSONException {
|
boolean leftSideNavigation) throws IOException, JSONException {
|
||||||
String url = engine.getFullUrl(path);
|
String url = engine.getFullUrl(path);
|
||||||
String content = makeRequest(url);
|
String content = makeRequest(url);
|
||||||
return engine.parseServerResponse(content, app, leftSideNavigation);
|
ResponseParser parser = engine.getResponseParser();
|
||||||
|
return parser.parseResponse(content, app, leftSideNavigation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -98,7 +102,7 @@ public class OnlineRoutingHelper {
|
||||||
StringBuilder content = new StringBuilder();
|
StringBuilder content = new StringBuilder();
|
||||||
BufferedReader reader;
|
BufferedReader reader;
|
||||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||||
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
reader = new BufferedReader(new InputStreamReader(getInputStream(connection)));
|
||||||
} else {
|
} else {
|
||||||
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
|
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
|
||||||
}
|
}
|
||||||
|
@ -113,6 +117,17 @@ public class OnlineRoutingHelper {
|
||||||
return content.toString();
|
return content.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(@NonNull HttpURLConnection connection) throws IOException {
|
||||||
|
// todo check file signature correctly
|
||||||
|
// InputStream is = connection.getInputStream();
|
||||||
|
// int header = Algorithms.readTwoInt(is);
|
||||||
|
// boolean isGzipFile = header == Algorithms.GZIP_FILE_SIGNATURE;
|
||||||
|
// if (isGzipFile) {
|
||||||
|
// return new GZIPInputStream(connection.getInputStream());
|
||||||
|
// }
|
||||||
|
return connection.getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
public void saveEngine(@NonNull OnlineRoutingEngine engine) {
|
public void saveEngine(@NonNull OnlineRoutingEngine engine) {
|
||||||
deleteInaccessibleParameters(engine);
|
deleteInaccessibleParameters(engine);
|
||||||
String key = createEngineKeyIfNeeded(engine);
|
String key = createEngineKeyIfNeeded(engine);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
public class VehicleType {
|
public class VehicleType {
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
@StringRes
|
@StringRes
|
||||||
private final int titleId;
|
private final int titleId;
|
||||||
|
|
|
@ -3,23 +3,35 @@ package net.osmand.plus.onlinerouting.engine;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
public enum EngineType {
|
public enum EngineType {
|
||||||
GRAPHHOPPER("Graphhopper"),
|
GRAPHHOPPER("Graphhopper", GraphhopperParser.class),
|
||||||
OSRM("OSRM"),
|
OSRM("OSRM", OsrmParser.class),
|
||||||
ORS("Openroute Service");
|
ORS("Openroute Service", OrsParser.class),
|
||||||
|
GPX("GPX", GpxParser.class);
|
||||||
|
|
||||||
private final String title;
|
private final String title;
|
||||||
|
private final Class<? extends ResponseParser> parserClass;
|
||||||
|
|
||||||
EngineType(String title) {
|
EngineType(String title, Class<? extends ResponseParser> parserClass) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.parserClass = parserClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends ResponseParser> getParserClass() {
|
||||||
|
return parserClass;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static EngineType getTypeByName(@Nullable String name) {
|
public static EngineType getTypeByName(@Nullable String name) {
|
||||||
if (!Algorithms.isEmpty(name)) {
|
if (!Algorithms.isEmpty(name)) {
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package net.osmand.plus.onlinerouting.engine;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||||
|
import net.osmand.plus.onlinerouting.VehicleType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GpxEngine extends OnlineRoutingEngine {
|
||||||
|
|
||||||
|
public GpxEngine(@Nullable Map<String, String> params) {
|
||||||
|
super(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public EngineType getType() {
|
||||||
|
return EngineType.GPX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void makeFullUrl(@NonNull StringBuilder sb,
|
||||||
|
@NonNull List<LatLon> path) {
|
||||||
|
for (int i = 0; i < path.size(); i++) {
|
||||||
|
LatLon point = path.get(i);
|
||||||
|
sb.append(point.getLongitude()).append(',').append(point.getLatitude());
|
||||||
|
if (i < path.size() - 1) {
|
||||||
|
sb.append(';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String getStandardUrl() {
|
||||||
|
return ""; // TODO will be determined in the future
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void collectAllowedVehicles(@NonNull List<VehicleType> vehicles) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||||
|
params.add(EngineParameter.KEY);
|
||||||
|
params.add(EngineParameter.CUSTOM_NAME);
|
||||||
|
params.add(EngineParameter.NAME_INDEX);
|
||||||
|
params.add(EngineParameter.CUSTOM_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,23 +3,14 @@ package net.osmand.plus.onlinerouting.engine;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.Location;
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||||
import net.osmand.plus.onlinerouting.VehicleType;
|
import net.osmand.plus.onlinerouting.VehicleType;
|
||||||
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static net.osmand.util.Algorithms.isEmpty;
|
import static net.osmand.util.Algorithms.isEmpty;
|
||||||
|
|
||||||
|
@ -42,8 +33,13 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void collectAllowedParameters() {
|
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||||
allowParameters(EngineParameter.API_KEY);
|
params.add(EngineParameter.KEY);
|
||||||
|
params.add(EngineParameter.VEHICLE_KEY);
|
||||||
|
params.add(EngineParameter.CUSTOM_NAME);
|
||||||
|
params.add(EngineParameter.NAME_INDEX);
|
||||||
|
params.add(EngineParameter.CUSTOM_URL);
|
||||||
|
params.add(EngineParameter.API_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,146 +77,4 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
||||||
sb.append('&').append("details=").append("lanes");
|
sb.append('&').append("details=").append("lanes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public 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";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,19 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||||
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
|
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
|
||||||
import net.osmand.plus.onlinerouting.VehicleType;
|
import net.osmand.plus.onlinerouting.VehicleType;
|
||||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
import net.osmand.plus.onlinerouting.parser.ResponseParser;
|
||||||
import net.osmand.plus.routing.RouteProvider;
|
import net.osmand.plus.routing.RouteProvider;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.apache.commons.logging.Log;
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -34,19 +31,22 @@ import static net.osmand.util.Algorithms.isEmpty;
|
||||||
|
|
||||||
public abstract class OnlineRoutingEngine implements Cloneable {
|
public abstract class OnlineRoutingEngine implements Cloneable {
|
||||||
|
|
||||||
|
protected static final Log LOG = PlatformUtil.getLog(OnlineRoutingEngine.class);
|
||||||
|
|
||||||
public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_";
|
public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_";
|
||||||
public final static VehicleType CUSTOM_VEHICLE = new VehicleType("", R.string.shared_string_custom);
|
public final static VehicleType CUSTOM_VEHICLE = new VehicleType("", R.string.shared_string_custom);
|
||||||
|
|
||||||
private final Map<String, String> params = new HashMap<>();
|
private final Map<String, String> params = new HashMap<>();
|
||||||
private final List<VehicleType> allowedVehicles = new ArrayList<>();
|
private final List<VehicleType> allowedVehicles = new ArrayList<>();
|
||||||
private final Set<EngineParameter> allowedParameters = new HashSet<>();
|
private final Set<EngineParameter> allowedParameters = new HashSet<>();
|
||||||
|
private ResponseParser responseParser;
|
||||||
|
|
||||||
public OnlineRoutingEngine(@Nullable Map<String, String> params) {
|
public OnlineRoutingEngine(@Nullable Map<String, String> params) {
|
||||||
if (!isEmpty(params)) {
|
if (!isEmpty(params)) {
|
||||||
this.params.putAll(params);
|
this.params.putAll(params);
|
||||||
}
|
}
|
||||||
collectAllowedVehiclesInternal();
|
collectAllowedVehiclesInternal();
|
||||||
collectAllowedParametersInternal();
|
collectAllowedParameters(allowedParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -100,31 +100,25 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
||||||
@NonNull
|
@NonNull
|
||||||
public abstract String getStandardUrl();
|
public abstract String getStandardUrl();
|
||||||
|
|
||||||
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
|
@NonNull
|
||||||
@NonNull OsmandApplication app,
|
public ResponseParser getResponseParser() {
|
||||||
boolean leftSideNavigation) throws JSONException {
|
if (responseParser == null) {
|
||||||
JSONObject root = parseRootResponseObject(content);
|
responseParser = createParser();
|
||||||
return root != null ? parseServerResponse(root, app, leftSideNavigation) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
|
||||||
@NonNull OsmandApplication app,
|
|
||||||
boolean leftSideNavigation) throws JSONException;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException {
|
|
||||||
JSONObject fullJSON = new JSONObject(content);
|
|
||||||
String responseArrayKey = getRootArrayKey();
|
|
||||||
JSONArray array = null;
|
|
||||||
if (fullJSON.has(responseArrayKey)) {
|
|
||||||
array = fullJSON.getJSONArray(responseArrayKey);
|
|
||||||
}
|
}
|
||||||
return array != null && array.length() > 0 ? array.getJSONObject(0) : null;
|
return responseParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
protected abstract String getRootArrayKey();
|
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
|
@NonNull
|
||||||
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||||
|
@ -171,23 +165,12 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
||||||
return Collections.unmodifiableList(allowedVehicles);
|
return Collections.unmodifiableList(allowedVehicles);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectAllowedParametersInternal() {
|
protected abstract void collectAllowedParameters(@NonNull Set<EngineParameter> params);
|
||||||
allowedParameters.clear();
|
|
||||||
allowParameters(EngineParameter.KEY, EngineParameter.VEHICLE_KEY,
|
|
||||||
EngineParameter.CUSTOM_NAME, EngineParameter.NAME_INDEX, EngineParameter.CUSTOM_URL);
|
|
||||||
collectAllowedParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void collectAllowedParameters();
|
|
||||||
|
|
||||||
public boolean isParameterAllowed(EngineParameter key) {
|
public boolean isParameterAllowed(EngineParameter key) {
|
||||||
return allowedParameters.contains(key);
|
return allowedParameters.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void allowParameters(@NonNull EngineParameter... allowedParams) {
|
|
||||||
allowedParameters.addAll(Arrays.asList(allowedParams));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getSelectedVehicleName(@NonNull Context ctx) {
|
private String getSelectedVehicleName(@NonNull Context ctx) {
|
||||||
String key = get(EngineParameter.VEHICLE_KEY);
|
String key = get(EngineParameter.VEHICLE_KEY);
|
||||||
|
@ -216,20 +199,6 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
||||||
return CUSTOM_VEHICLE;
|
return CUSTOM_VEHICLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkServerResponse(@NonNull StringBuilder errorMessage,
|
|
||||||
@NonNull String content) throws JSONException {
|
|
||||||
JSONObject obj = new JSONObject(content);
|
|
||||||
String messageKey = getErrorMessageKey();
|
|
||||||
if (obj.has(messageKey)) {
|
|
||||||
String message = obj.getString(messageKey);
|
|
||||||
errorMessage.append(message);
|
|
||||||
}
|
|
||||||
return obj.has(getRootArrayKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected abstract String getErrorMessageKey();
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
|
@ -251,21 +220,4 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
||||||
return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis();
|
return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OnlineRoutingResponse {
|
|
||||||
private List<Location> route;
|
|
||||||
private List<RouteDirectionInfo> directions;
|
|
||||||
|
|
||||||
public OnlineRoutingResponse(List<Location> route, List<RouteDirectionInfo> directions) {
|
|
||||||
this.route = route;
|
|
||||||
this.directions = directions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Location> getRoute() {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RouteDirectionInfo> getDirections() {
|
|
||||||
return directions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,20 +3,14 @@ package net.osmand.plus.onlinerouting.engine;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.Location;
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||||
import net.osmand.plus.onlinerouting.VehicleType;
|
import net.osmand.plus.onlinerouting.VehicleType;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static net.osmand.util.Algorithms.isEmpty;
|
import static net.osmand.util.Algorithms.isEmpty;
|
||||||
|
|
||||||
|
@ -39,8 +33,13 @@ public class OrsEngine extends OnlineRoutingEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void collectAllowedParameters() {
|
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||||
allowParameters(EngineParameter.API_KEY);
|
params.add(EngineParameter.KEY);
|
||||||
|
params.add(EngineParameter.VEHICLE_KEY);
|
||||||
|
params.add(EngineParameter.CUSTOM_NAME);
|
||||||
|
params.add(EngineParameter.NAME_INDEX);
|
||||||
|
params.add(EngineParameter.CUSTOM_URL);
|
||||||
|
params.add(EngineParameter.API_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,35 +77,4 @@ public class OrsEngine extends OnlineRoutingEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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,28 +3,16 @@ package net.osmand.plus.onlinerouting.engine;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.osmand.Location;
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||||
import net.osmand.plus.onlinerouting.VehicleType;
|
import net.osmand.plus.onlinerouting.VehicleType;
|
||||||
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static net.osmand.util.Algorithms.isEmpty;
|
import static net.osmand.util.Algorithms.isEmpty;
|
||||||
import static net.osmand.util.Algorithms.objectEquals;
|
|
||||||
|
|
||||||
public class OsrmEngine extends OnlineRoutingEngine {
|
public class OsrmEngine extends OnlineRoutingEngine {
|
||||||
|
|
||||||
|
@ -45,7 +33,12 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void collectAllowedParameters() {
|
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||||
|
params.add(EngineParameter.KEY);
|
||||||
|
params.add(EngineParameter.VEHICLE_KEY);
|
||||||
|
params.add(EngineParameter.CUSTOM_NAME);
|
||||||
|
params.add(EngineParameter.NAME_INDEX);
|
||||||
|
params.add(EngineParameter.CUSTOM_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -74,164 +67,4 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
||||||
sb.append('&').append("steps=true");
|
sb.append('&').append("steps=true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public 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 getErrorMessageKey() {
|
|
||||||
return "message";
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected String getRootArrayKey() {
|
|
||||||
return "routes";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package net.osmand.plus.onlinerouting.parser;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities;
|
||||||
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
public class GpxParser extends ResponseParser {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||||
|
@NonNull OsmandApplication app,
|
||||||
|
boolean leftSideNavigation) {
|
||||||
|
GPXFile gpxFile = parseGpx(content);
|
||||||
|
return gpxFile != null ? new OnlineRoutingResponse(parseGpx(content)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||||
|
@NonNull String content) {
|
||||||
|
return parseGpx(content) != null; // TODO may be there should be another check
|
||||||
|
}
|
||||||
|
|
||||||
|
private GPXFile parseGpx(@NonNull String content) {
|
||||||
|
InputStream gpxStream = null;
|
||||||
|
try {
|
||||||
|
gpxStream = new ByteArrayInputStream(content.getBytes("UTF-8"));
|
||||||
|
return GPXUtilities.loadGPXFile(gpxStream);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
LOG.debug("Error when parsing GPX from server response: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package net.osmand.plus.onlinerouting.parser;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.routing.RouteProvider;
|
||||||
|
|
||||||
|
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 abstract class JSONParser extends ResponseParser {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||||
|
@NonNull OsmandApplication app,
|
||||||
|
boolean leftSideNavigation) throws JSONException {
|
||||||
|
JSONObject root = parseRootResponseObject(content);
|
||||||
|
return root != null ? parseServerResponse(root, app, leftSideNavigation) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException {
|
||||||
|
JSONObject fullJSON = new JSONObject(content);
|
||||||
|
String key = getRootArrayKey();
|
||||||
|
JSONArray array = null;
|
||||||
|
if (fullJSON.has(key)) {
|
||||||
|
array = fullJSON.getJSONArray(key);
|
||||||
|
}
|
||||||
|
return array != null && array.length() > 0 ? array.getJSONObject(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||||
|
@NonNull String content) throws JSONException {
|
||||||
|
JSONObject obj = new JSONObject(content);
|
||||||
|
String messageKey = getErrorMessageKey();
|
||||||
|
if (obj.has(messageKey)) {
|
||||||
|
String message = obj.getString(messageKey);
|
||||||
|
errorMessage.append(message);
|
||||||
|
}
|
||||||
|
return obj.has(getRootArrayKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
187
OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java
Normal file
187
OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package net.osmand.plus.onlinerouting.parser;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class ResponseParser {
|
||||||
|
|
||||||
|
protected static final Log LOG = PlatformUtil.getLog(ResponseParser.class);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||||
|
@NonNull OsmandApplication app,
|
||||||
|
boolean leftSideNavigation) throws JSONException;
|
||||||
|
|
||||||
|
public abstract boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||||
|
@NonNull String content) throws JSONException;
|
||||||
|
|
||||||
|
public static ResponseParser emptyParser() {
|
||||||
|
return new ResponseParser() {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||||
|
@NonNull OsmandApplication app,
|
||||||
|
boolean leftSideNavigation) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||||
|
@NonNull String content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OnlineRoutingResponse {
|
||||||
|
|
||||||
|
private List<Location> route;
|
||||||
|
private List<RouteDirectionInfo> directions;
|
||||||
|
private GPXFile gpxFile;
|
||||||
|
|
||||||
|
// constructor for JSON responses
|
||||||
|
public OnlineRoutingResponse(List<Location> route, List<RouteDirectionInfo> directions) {
|
||||||
|
this.route = route;
|
||||||
|
this.directions = directions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor for GPX responses
|
||||||
|
public OnlineRoutingResponse(GPXFile gpxFile) {
|
||||||
|
this.gpxFile = gpxFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Location> getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RouteDirectionInfo> getDirections() {
|
||||||
|
return directions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPXFile getGpxFile() {
|
||||||
|
return gpxFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -462,7 +462,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
||||||
boolean resultOk = false;
|
boolean resultOk = false;
|
||||||
try {
|
try {
|
||||||
String response = helper.makeRequest(exampleCard.getEditedText());
|
String response = helper.makeRequest(exampleCard.getEditedText());
|
||||||
resultOk = requestedEngine.checkServerResponse(errorMessage, response);
|
resultOk = requestedEngine.getResponseParser().isResultOk(errorMessage, response);
|
||||||
} catch (IOException | JSONException e) {
|
} catch (IOException | JSONException e) {
|
||||||
errorMessage.append(e.toString());
|
errorMessage.append(e.toString());
|
||||||
}
|
}
|
||||||
|
@ -514,6 +514,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
||||||
} else {
|
} else {
|
||||||
apiKeyCard.hide();
|
apiKeyCard.hide();
|
||||||
}
|
}
|
||||||
|
if (engine.isParameterAllowed(EngineParameter.VEHICLE_KEY)) {
|
||||||
|
vehicleCard.show();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
vehicleCard.hide();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (vehicleCard.equals(card)) {
|
} else if (vehicleCard.equals(card)) {
|
||||||
VehicleType vt = engine.getSelectedVehicleType();
|
VehicleType vt = engine.getSelectedVehicleType();
|
||||||
|
|
|
@ -23,7 +23,7 @@ import net.osmand.plus.R;
|
||||||
import net.osmand.plus.TargetPointsHelper;
|
import net.osmand.plus.TargetPointsHelper;
|
||||||
import net.osmand.plus.TargetPointsHelper.TargetPoint;
|
import net.osmand.plus.TargetPointsHelper.TargetPoint;
|
||||||
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
||||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
|
import net.osmand.plus.onlinerouting.parser.ResponseParser.OnlineRoutingResponse;
|
||||||
import net.osmand.plus.render.NativeOsmandLibrary;
|
import net.osmand.plus.render.NativeOsmandLibrary;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.plus.settings.backend.CommonPreference;
|
import net.osmand.plus.settings.backend.CommonPreference;
|
||||||
|
@ -1228,16 +1228,28 @@ public class RouteProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException {
|
private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException {
|
||||||
OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper();
|
OsmandApplication app = params.ctx;
|
||||||
String stringKey = params.mode.getRoutingProfile();
|
OnlineRoutingHelper helper = app.getOnlineRoutingHelper();
|
||||||
|
OsmandSettings settings = app.getSettings();
|
||||||
|
String engineKey = params.mode.getRoutingProfile();
|
||||||
OnlineRoutingResponse response =
|
OnlineRoutingResponse response =
|
||||||
helper.calculateRouteOnline(stringKey, getPathFromParams(params), params.leftSide);
|
helper.calculateRouteOnline(engineKey, getPathFromParams(params), params.leftSide);
|
||||||
|
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
params.intermediates = null;
|
if (response.getGpxFile() != null) {
|
||||||
return new RouteCalculationResult(response.getRoute(), response.getDirections(), params, null, false);
|
GPXRouteParamsBuilder builder = new GPXRouteParamsBuilder(response.getGpxFile(), settings);
|
||||||
} else {
|
params.gpxRoute = builder.build(app);
|
||||||
return new RouteCalculationResult("Route is empty");
|
return calculateGpxRoute(params);
|
||||||
|
}
|
||||||
|
List<Location> route = response.getRoute();
|
||||||
|
List<RouteDirectionInfo> directions = response.getDirections();
|
||||||
|
if (!Algorithms.isEmpty(route) && !Algorithms.isEmpty(directions)) {
|
||||||
|
params.intermediates = null;
|
||||||
|
return new RouteCalculationResult(route, directions, params, null, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new RouteCalculationResult("Route is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<LatLon> getPathFromParams(RouteCalculationParams params) {
|
private static List<LatLon> getPathFromParams(RouteCalculationParams params) {
|
||||||
|
|
Loading…
Reference in a new issue