package org.osmdroid.routing.provider; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.oscim.core.BoundingBox; import org.oscim.core.GeoPoint; import org.osmdroid.routing.Road; import org.osmdroid.routing.RoadManager; import org.osmdroid.routing.RoadNode; import org.osmdroid.utils.BonusPackHelper; import org.osmdroid.utils.HttpConnection; import org.osmdroid.utils.PolylineEncoder; import android.util.Log; /** * get a route between a start and a destination point. It uses OSRM, a free * open source routing service based on OpenSteetMap data. <br> * See https://github.com/DennisOSRM/Project-OSRM/wiki/Server-api<br> * It requests by default the OSRM demo site. Use setService() to request an * other (for instance your own) OSRM service. <br> * TODO: improve internationalization of instructions * @author M.Kergall */ public class OSRMRoadManager extends RoadManager { static final String OSRM_SERVICE = "http://router.project-osrm.org/viaroute?"; //Note that the result of OSRM is quite close to Cloudmade NavEngine format: //http://developers.cloudmade.com/wiki/navengine/JSON_format protected String mServiceUrl; protected String mUserAgent; /** mapping from OSRM directions to MapQuest maneuver IDs: */ static final HashMap<String, Integer> MANEUVERS; static { MANEUVERS = new HashMap<String, Integer>(); MANEUVERS.put("0", Integer.valueOf(0)); //No instruction MANEUVERS.put("1", Integer.valueOf(1)); //Continue MANEUVERS.put("2", Integer.valueOf(6)); //Slight right MANEUVERS.put("3", Integer.valueOf(7)); //Right MANEUVERS.put("4", Integer.valueOf(8)); //Sharp right MANEUVERS.put("5", Integer.valueOf(12)); //U-turn MANEUVERS.put("6", Integer.valueOf(5)); //Sharp left MANEUVERS.put("7", Integer.valueOf(4)); //Left MANEUVERS.put("8", Integer.valueOf(3)); //Slight left MANEUVERS.put("9", Integer.valueOf(24)); //Arrived (at waypoint) //MANEUVERS.put("10", Integer.valueOf(0)); //"Head" => used by OSRM as the start node MANEUVERS.put("11-1", Integer.valueOf(27)); //Round-about, 1st exit MANEUVERS.put("11-2", Integer.valueOf(28)); //2nd exit, etc ... MANEUVERS.put("11-3", Integer.valueOf(29)); MANEUVERS.put("11-4", Integer.valueOf(30)); MANEUVERS.put("11-5", Integer.valueOf(31)); MANEUVERS.put("11-6", Integer.valueOf(32)); MANEUVERS.put("11-7", Integer.valueOf(33)); MANEUVERS.put("11-8", Integer.valueOf(34)); //Round-about, 8th exit MANEUVERS.put("15", Integer.valueOf(24)); //Arrived } //From: Project-OSRM-Web / WebContent / localization / OSRM.Locale.en.js // driving directions // %s: road name // %d: direction => removed // <*>: will only be printed when there actually is a road name static final HashMap<String, HashMap<String, String>> DIRECTIONS; static { DIRECTIONS = new HashMap<String, HashMap<String, String>>(); HashMap<String, String> directions; directions = new HashMap<String, String>(); DIRECTIONS.put("en", directions); directions.put("0", "Unknown instruction< on %s>"); directions.put("1", "Continue< on %s>"); directions.put("2", "Turn slight right< on %s>"); directions.put("3", "Turn right< on %s>"); directions.put("4", "Turn sharp right< on %s>"); directions.put("5", "U-Turn< on %s>"); directions.put("6", "Turn sharp left< on %s>"); directions.put("7", "Turn left< on %s>"); directions.put("8", "Turn slight left< on %s>"); directions.put("9", "You have reached a waypoint of your trip"); directions.put("10", "<Go on %s>"); directions.put("11-1", "Enter roundabout and leave at first exit< on %s>"); directions.put("11-2", "Enter roundabout and leave at second exit< on %s>"); directions.put("11-3", "Enter roundabout and leave at third exit< on %s>"); directions.put("11-4", "Enter roundabout and leave at fourth exit< on %s>"); directions.put("11-5", "Enter roundabout and leave at fifth exit< on %s>"); directions.put("11-6", "Enter roundabout and leave at sixth exit< on %s>"); directions.put("11-7", "Enter roundabout and leave at seventh exit< on %s>"); directions.put("11-8", "Enter roundabout and leave at eighth exit< on %s>"); directions.put("11-9", "Enter roundabout and leave at nineth exit< on %s>"); directions.put("15", "You have reached your destination"); directions = new HashMap<String, String>(); DIRECTIONS.put("fr", directions); directions.put("0", "Instruction inconnue< sur %s>"); directions.put("1", "Continuez< sur %s>"); directions.put("2", "Tournez légèrement à droite< sur %s>"); directions.put("3", "Tournez à droite< sur %s>"); directions.put("4", "Tournez fortement à droite< sur %s>"); directions.put("5", "Faites demi-tour< sur %s>"); directions.put("6", "Tournez fortement à gauche< sur %s>"); directions.put("7", "Tournez à gauche< sur %s>"); directions.put("8", "Tournez légèrement à gauche< sur %s>"); directions.put("9", "Vous êtes arrivé à une étape de votre voyage"); directions.put("10", "<Prenez %s>"); directions.put("11-1", "Au rond-point, prenez la première sortie< sur %s>"); directions.put("11-2", "Au rond-point, prenez la deuxième sortie< sur %s>"); directions.put("11-3", "Au rond-point, prenez la troisième sortie< sur %s>"); directions.put("11-4", "Au rond-point, prenez la quatrième sortie< sur %s>"); directions.put("11-5", "Au rond-point, prenez la cinquième sortie< sur %s>"); directions.put("11-6", "Au rond-point, prenez la sixième sortie< sur %s>"); directions.put("11-7", "Au rond-point, prenez la septième sortie< sur %s>"); directions.put("11-8", "Au rond-point, prenez la huitième sortie< sur %s>"); directions.put("11-9", "Au rond-point, prenez la neuvième sortie< sur %s>"); directions.put("15", "Vous êtes arrivé"); directions = new HashMap<String, String>(); DIRECTIONS.put("pl", directions); directions.put("0", "Nieznana instrukcja<w %s>"); directions.put("1", "Kontynuuj jazdę<na %s>"); directions.put("2", "Skręć lekko w prawo<w %s>"); directions.put("3", "Skręć w prawo<w %s>"); directions.put("4", "Skręć ostro w prawo<w %s>"); directions.put("5", "Zawróć<na %s>"); directions.put("6", "Skręć ostro w lewo<w %s>"); directions.put("7", "Skręć w lewo<w %s>"); directions.put("8", "Skręć lekko w lewo<w %s>"); directions.put("9", "Dotarłeś do punktu pośredniego"); directions.put("10", "<Jedź %s>"); directions.put("11-1", "Wjedź na rondo i opuść je pierwszym zjazdem<w %s>"); directions.put("11-2", "Wjedź na rondo i opuść je drugim zjazdem<w %s>"); directions.put("11-3", "Wjedź na rondo i opuść je trzecim zjazdem<w %s>"); directions.put("11-4", "Wjedź na rondo i opuść je czwartym zjazdem<w %s>"); directions.put("11-5", "Wjedź na rondo i opuść je piątym zjazdem<w %s>"); directions.put("11-6", "Wjedź na rondo i opuść je szóstym zjazdem<w %s>"); directions.put("11-7", "Wjedź na rondo i opuść je siódmym zjazdem<w %s>"); directions.put("11-8", "Wjedź na rondo i opuść je ósmym zjazdem<w %s>"); directions.put("11-9", "Wjedź na rondo i opuść je dziewiątym zjazdem<w %s>"); directions.put("15", "Dotarłeś do celu podróży"); } public OSRMRoadManager() { super(); mServiceUrl = OSRM_SERVICE; mUserAgent = BonusPackHelper.DEFAULT_USER_AGENT; //set user agent to the default one. } /** * allows to request on an other site than OSRM demo site * @param serviceUrl * ... */ public void setService(String serviceUrl) { mServiceUrl = serviceUrl; } /** * allows to send to OSRM service a user agent specific to the app, instead * of the default user agent of OSMBonusPack lib. * @param userAgent * ... */ public void setUserAgent(String userAgent) { mUserAgent = userAgent; } protected String getUrl(ArrayList<GeoPoint> waypoints) { StringBuffer urlString = new StringBuffer(mServiceUrl); for (int i = 0; i < waypoints.size(); i++) { GeoPoint p = waypoints.get(i); urlString.append("&loc=" + geoPointAsString(p)); } urlString.append(mOptions); return urlString.toString(); } @Override public Road getRoad(ArrayList<GeoPoint> waypoints) { String url = getUrl(waypoints); Log.d(BonusPackHelper.LOG_TAG, "OSRMRoadManager.getRoad:" + url); //String jString = BonusPackHelper.requestStringFromUrl(url); HttpConnection connection = new HttpConnection(); connection.setUserAgent(mUserAgent); connection.doGet(url); String jString = connection.getContentAsString(); connection.close(); if (jString == null) { Log.e(BonusPackHelper.LOG_TAG, "OSRMRoadManager::getRoad: request failed."); return new Road(waypoints); } Locale l = Locale.getDefault(); HashMap<String, String> directions = DIRECTIONS.get(l.getLanguage()); if (directions == null) directions = DIRECTIONS.get("en"); Road road = new Road(); try { JSONObject jObject = new JSONObject(jString); String route_geometry = jObject.getString("route_geometry"); road.routeHigh = PolylineEncoder.decode(route_geometry, 10); JSONArray jInstructions = jObject.getJSONArray("route_instructions"); int n = jInstructions.length(); RoadNode lastNode = null; for (int i = 0; i < n; i++) { JSONArray jInstruction = jInstructions.getJSONArray(i); RoadNode node = new RoadNode(); int positionIndex = jInstruction.getInt(3); node.location = road.routeHigh.get(positionIndex); node.length = jInstruction.getInt(2) / 1000.0; node.duration = jInstruction.getInt(4); //Segment duration in seconds. String direction = jInstruction.getString(0); String roadName = jInstruction.getString(1); if (lastNode != null && "1".equals(direction) && "".equals(roadName)) { //node "Continue" with no road name is useless, don't add it lastNode.length += node.length; lastNode.duration += node.duration; } else { node.maneuverType = getManeuverCode(direction); node.instructions = buildInstructions(direction, roadName, directions); //Log.d(BonusPackHelper.LOG_TAG, direction+"=>"+node.mManeuverType+"; "+node.mInstructions); road.nodes.add(node); lastNode = node; } } JSONObject jSummary = jObject.getJSONObject("route_summary"); road.length = jSummary.getInt("total_distance") / 1000.0; road.duration = jSummary.getInt("total_time"); } catch (JSONException e) { e.printStackTrace(); return new Road(waypoints); } if (road.routeHigh.size() == 0) { //Create default road: road = new Road(waypoints); } else { road.buildLegs(waypoints); BoundingBox bb = BoundingBox.fromGeoPoints(road.routeHigh); //Correcting osmdroid bug #359: road.boundingBox = bb; // new BoundingBox( // bb.getLatSouthE6(), bb.getLonWestE6(), bb.getLatNorthE6(), bb.getLonEastE6()); road.status = Road.STATUS_OK; } Log.d(BonusPackHelper.LOG_TAG, "OSRMRoadManager.getRoad - finished"); return road; } protected int getManeuverCode(String direction) { Integer code = MANEUVERS.get(direction); if (code != null) return code.intValue(); return 0; } protected String buildInstructions(String direction, String roadName, HashMap<String, String> directions) { if (directions == null) return null; direction = directions.get(direction); if (direction == null) return null; String instructions = null; if (roadName.equals("")) //remove "<*>" instructions = direction.replaceFirst("<[^>]*>", ""); else { direction = direction.replace('<', ' '); direction = direction.replace('>', ' '); instructions = String.format(direction, roadName); } return instructions; } }