diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java index 41e10b1dd3..0efd91e759 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/EngineType.java @@ -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 parserClass; - EngineType(String title, Class parserClass) { + EngineType(String title) { this.title = title; - this.parserClass = parserClass; } public String getTitle() { return title; } - public Class getParserClass() { - return parserClass; - } - @NonNull public static EngineType getTypeByName(@Nullable String name) { if (!Algorithms.isEmpty(name)) { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java index 557a98dc86..1f6146273d 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java @@ -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(); + } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java index 908973b6b4..14852e2633 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/GraphhopperEngine.java @@ -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 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 points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5); + if (isEmpty(points)) return null; + List route = convertRouteToLocationsList(points); + + JSONArray instructions = root.getJSONArray("instructions"); + List 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"; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java index 119b63ee9c..b2bba21ca6 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OnlineRoutingEngine.java @@ -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 convertRouteToLocationsList(@NonNull List route) { - List 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 getParams() { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java index 61f3097b04..d80d3df3c1 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OrsEngine.java @@ -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 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 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 route = convertRouteToLocationsList(points); + new OnlineRoutingResponse(route, null); + } + return null; + } + + @NonNull + @Override + protected String getErrorMessageKey() { + return "error"; + } + + @NonNull + @Override + protected String getRootArrayKey() { + return "features"; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java index 1da2ed215e..19860ee15c 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/engine/OsrmEngine.java @@ -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 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 points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5); + if (isEmpty(points)) return null; + + List route = convertRouteToLocationsList(points); + List 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 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"; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java index 8f5db5fde7..92621b2b3f 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GpxParser.java @@ -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) { diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java deleted file mode 100644 index 331221ad09..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/GraphhopperParser.java +++ /dev/null @@ -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 points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5); - if (isEmpty(points)) return null; - List route = convertRouteToLocationsList(points); - - JSONArray instructions = root.getJSONArray("instructions"); - List 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"; - } -} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java index b01af0c444..e0676f68c2 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/JSONParser.java @@ -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 convertRouteToLocationsList(@NonNull List route) { + protected abstract String getRootArrayKey(); + + @NonNull + protected abstract String getErrorMessageKey(); + + @NonNull + protected static List convertRouteToLocationsList(@NonNull List route) { List 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(); } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java deleted file mode 100644 index f067baf61e..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OrsParser.java +++ /dev/null @@ -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 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 route = convertRouteToLocationsList(points); - new OnlineRoutingResponse(route, null); - } - return null; - } - - @NonNull - @Override - protected String getErrorMessageKey() { - return "error"; - } - - @NonNull - @Override - protected String getRootArrayKey() { - return "features"; - } -} diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java b/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java deleted file mode 100644 index 8c93f1750e..0000000000 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/parser/OsrmParser.java +++ /dev/null @@ -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 points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5); - if (isEmpty(points)) return null; - - List route = convertRouteToLocationsList(points); - List 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 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"; - } -}