GIS的学习(三十一)osmdroid实现室外的线路规划方案总结

      在手机进行室外线路规划,需要采用第三方的线路规划算法,在osmbonuspack中线路规划算法,需要实现RoadManager抽象类:

package org.osmdroid.bonuspack.routing;

import java.util.ArrayList;

import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.overlay.PathOverlay;

import android.content.Context;
import android.graphics.Paint;

/**
 * Generic class to get a route between a start and a destination point, 
 * going through a list of waypoints. 
 * @see MapQuestRoadManager
 * @see GoogleRoadManager
 * @see OSRMRoadManager
 * 
 * @author M.Kergall
 */
public abstract class RoadManager {
	
	protected String mOptions;
	
	public abstract Road getRoad(ArrayList<GeoPoint> waypoints);
	
	public RoadManager(){
		mOptions = "";
	}
	
	/**
	 * Add an option that will be used in the route request. 
	 * Note that some options are set in the request in all cases. 
	 * @param requestOption see provider documentation. 
	 * Just one example: "routeType=bicycle" for MapQuest; "mode=bicycling" for Google. 
	 */
	public void addRequestOption(String requestOption){
		mOptions += "&" + requestOption;
	}
	
	protected String geoPointAsString(GeoPoint p){
		StringBuffer result = new StringBuffer();
		double d = p.getLatitudeE6()*1E-6;
		result.append(Double.toString(d));
		d = p.getLongitudeE6()*1E-6;
		result.append("," + Double.toString(d));
		return result.toString();
	}
	
	public static PathOverlay buildRoadOverlay(Road road, Paint paint, Context context){
		PathOverlay roadOverlay = new PathOverlay(0, context);
		roadOverlay.setPaint(paint);
		if (road != null) {
			ArrayList<GeoPoint> polyline = road.mRouteHigh;
			for (GeoPoint p:polyline){
				roadOverlay.addPoint(p);
			}
		}
		return roadOverlay;
	}
	
	/**
	 * Builds an overlay for the road shape with a default (and nice!) color. 
	 * @return route shape overlay
	 */
	public static PathOverlay buildRoadOverlay(Road road, Context context){
		Paint paint = new Paint();
		paint.setColor(0x800000FF);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(5);
		return buildRoadOverlay(road, paint, context);
	}

}

 

三种方案:

第一种方案:google线路规划方案:GoogleRoadManager

package org.osmdroid.bonuspack.routing;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.bonuspack.utils.HttpConnection;
import org.osmdroid.bonuspack.utils.PolylineEncoder;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

/** class to get a route between a start and a destination point, 
 * going through a list of waypoints. <br>
 * https://developers.google.com/maps/documentation/directions/<br>
 * Note that displaying a route provided by Google on a non-Google map (like OSM) is not allowed by Google T&C. 
 * @author M.Kergall
 */
public class GoogleRoadManager extends RoadManager {
	
	static final String GOOGLE_DIRECTIONS_SERVICE = "http://maps.googleapis.com/maps/api/directions/xml?";
	
	/**
	 * Build the URL to Google Directions service returning a route in XML format
	 */
	protected String getUrl(ArrayList<GeoPoint> waypoints) {
		StringBuffer urlString = new StringBuffer(GOOGLE_DIRECTIONS_SERVICE);
		urlString.append("origin=");
		GeoPoint p = waypoints.get(0);
		urlString.append(geoPointAsString(p));
		urlString.append("&destination=");
		int destinationIndex = waypoints.size()-1;
		p = waypoints.get(destinationIndex);
		urlString.append(geoPointAsString(p));
		
		for (int i=1; i<destinationIndex; i++){
			if (i == 1)
				urlString.append("&waypoints=");
			else
				urlString.append("%7C"); // the pipe (|), url-encoded
			p = waypoints.get(i);
			urlString.append(geoPointAsString(p));
		}
		urlString.append("&units=metric&sensor=false");
		Locale locale = Locale.getDefault();
		urlString.append("&language="+locale.getLanguage());
		urlString.append(mOptions);
		return urlString.toString();
	}
	
	/** 
	 * @param waypoints: list of GeoPoints. Must have at least 2 entries, start and end points. 
	 * @return the road
	 */
	@Override public Road getRoad(ArrayList<GeoPoint> waypoints) {
		String url = getUrl(waypoints);
		Log.d(BonusPackHelper.LOG_TAG, "GoogleRoadManager.getRoad:"+url);
		Road road = null;
		HttpConnection connection = new HttpConnection();
		connection.doGet(url);
		InputStream stream = connection.getStream();
		if (stream != null)
				road = getRoadXML(stream);
		connection.close();
		if (road == null || road.mRouteHigh.size()==0){
			//Create default road:
			road = new Road(waypoints);
		} else {
			//finalize road data update:
			for (RoadLeg leg : road.mLegs){
				road.mDuration += leg.mDuration;
				road.mLength += leg.mLength;
			}
			road.mStatus = Road.STATUS_OK;
		}
		Log.d(BonusPackHelper.LOG_TAG, "GoogleRoadManager.getRoad - finished");
		return road;
	}

	protected Road getRoadXML(InputStream is) {
		GoogleDirectionsHandler handler = new GoogleDirectionsHandler();
		try {
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			parser.parse(is, handler);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return handler.mRoad;
	}

}

 

第二种算法采用MapQuest 算法的API

       使用的详细说明,参数的详细讲解,参考以下文档

                http://open.mapquestapi.com/directions/

 

            It uses MapQuest open, public and free API, based on OpenStreetMap data.

package org.osmdroid.bonuspack.routing;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.bonuspack.utils.HttpConnection;
import org.osmdroid.bonuspack.utils.PolylineEncoder;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;

/** class to get a route between a start and a destination point, 
 * going through a list of waypoints. 
 * 
 * It uses MapQuest open, public and free API, based on OpenStreetMap data. <br>
 * See http://open.mapquestapi.com/guidance
 * @return a "Road" object. 
 * 
 * @author M.Kergall
 */
public class MapQuestRoadManager extends RoadManager {
	
	static final String MAPQUEST_GUIDANCE_SERVICE = "http://open.mapquestapi.com/guidance/v0/route?";
	
	/**
	 * Build the URL to MapQuest service returning a route in XML format
	 * @param waypoints: array of waypoints, as [lat, lng], from start point to end point. 
	 */
	protected String getUrl(ArrayList<GeoPoint> waypoints) {
		StringBuffer urlString = new StringBuffer(MAPQUEST_GUIDANCE_SERVICE);
		urlString.append("from=");
		GeoPoint p = waypoints.get(0);
		urlString.append(geoPointAsString(p));
		
		for (int i=1; i<waypoints.size(); i++){
			p = waypoints.get(i);
			urlString.append("&to="+geoPointAsString(p));
		}
		
		urlString.append("&outFormat=xml");
		urlString.append("&shapeFormat=cmp"); //encoded polyline, much faster
		
		urlString.append("&narrativeType=text"); //or "none"
		//Locale locale = Locale.getDefault();
		//urlString.append("&locale="+locale.getLanguage()+"_"+locale.getCountry());
		
		urlString.append("&unit=k&fishbone=false");
		
		//urlString.append("&generalizeAfter=500" /*+&generalize=2"*/); 
			//500 points max, 2 meters tolerance
		
		//Warning: MapQuest Open API doc is sometimes WRONG:
		//- use unit, not units
		//- use fishbone, not enableFishbone
		//- locale (fr_FR, en_US) is supported but not documented. 
		//- generalize and generalizeAfter are not properly implemented
		urlString.append(mOptions);
		return urlString.toString();
	}
	
	/**
	 * @param waypoints: list of GeoPoints. Must have at least 2 entries, start and end points. 
	 * @return the road
	 */
	@Override public Road getRoad(ArrayList<GeoPoint> waypoints) {
		String url = getUrl(waypoints);
		Log.d(BonusPackHelper.LOG_TAG, "MapQuestRoadManager.getRoute:"+url);
		Road road = null;
		HttpConnection connection = new HttpConnection();
		connection.doGet(url);
		InputStream stream = connection.getStream();
		if (stream != null)
				road = getRoadXML(stream, waypoints);
		if (road == null || road.mRouteHigh.size()==0){
			//Create default road:
			road = new Road(waypoints);
		}
		connection.close();
		Log.d(BonusPackHelper.LOG_TAG, "MapQuestRoadManager.getRoute - finished");
		return road;
	}

	/** 
	 * XML implementation
	 * @param is: input stream to parse
	 * @return the road
	 */
	protected Road getRoadXML(InputStream is, ArrayList<GeoPoint> waypoints) {
		XMLHandler handler = new XMLHandler();
		try {
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			parser.parse(is, handler);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Road road = handler.mRoad;
		if (road != null && road.mRouteHigh.size()>0){
			road.mNodes = finalizeNodes(road.mNodes, handler.mLinks, road.mRouteHigh);
			road.buildLegs(waypoints);
			road.mStatus = Road.STATUS_OK;
		}
		return road;
	}
	
	protected ArrayList<RoadNode> finalizeNodes(ArrayList<RoadNode> mNodes, 
			ArrayList<RoadLink> mLinks, ArrayList<GeoPoint> polyline){
		int n = mNodes.size();
		if (n == 0)
			return mNodes;
		ArrayList<RoadNode> newNodes = new ArrayList<RoadNode>(n);
		RoadNode lastNode = null;
		for (int i=1; i<n-1; i++){ //1, n-1 => first and last MapQuest nodes are irrelevant.
			RoadNode node = mNodes.get(i);
			RoadLink link = mLinks.get(node.mNextRoadLink);
			if (lastNode!=null && (node.mInstructions == null || node.mManeuverType == 0)){
				//this node is irrelevant, don't keep it, 
				//but update values of last node:
				lastNode.mLength += link.mLength;
				lastNode.mDuration += (node.mDuration + link.mDuration);
			} else {
				node.mLength = link.mLength;
				node.mDuration += link.mDuration;
				int locationIndex = link.mShapeIndex;
				node.mLocation = polyline.get(locationIndex);
				newNodes.add(node);
				lastNode = node;
			}
		}
		//switch to the new array of nodes:
		return newNodes;
	}
}

 

第三种采用OSRM

package org.osmdroid.bonuspack.routing;

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.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.bonuspack.utils.HttpConnection;
import org.osmdroid.bonuspack.utils.PolylineEncoder;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
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", 0); //No instruction
		MANEUVERS.put("1", 1); //Continue
		MANEUVERS.put("2", 6); //Slight right
		MANEUVERS.put("3", 7); //Right
		MANEUVERS.put("4", 8); //Sharp right
		MANEUVERS.put("5", 12); //U-turn
		MANEUVERS.put("6", 5); //Sharp left
		MANEUVERS.put("7", 4); //Left
		MANEUVERS.put("8", 3); //Slight left
		MANEUVERS.put("9", 24); //Arrived (at waypoint)
		//MANEUVERS.put("10", 0); //"Head" => used by OSRM as the start node
		MANEUVERS.put("11-1", 27); //Round-about, 1st exit
		MANEUVERS.put("11-2", 28); //2nd exit, etc ...
		MANEUVERS.put("11-3", 29);
		MANEUVERS.put("11-4", 30);
		MANEUVERS.put("11-5", 31);
		MANEUVERS.put("11-6", 32);
		MANEUVERS.put("11-7", 33);
		MANEUVERS.put("11-8", 34); //Round-about, 8th exit
		MANEUVERS.put("15", 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, Object> DIRECTIONS;
	static {
		DIRECTIONS = new HashMap<String, Object>();
		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 */
	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. 
	 */
	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 = (HashMap<String, String>)DIRECTIONS.get(l.getLanguage());
		if (directions == null)
			directions = (HashMap<String, String>)DIRECTIONS.get("en");
		Road road = new Road();
		try {
			JSONObject jObject = new JSONObject(jString);
			String route_geometry = jObject.getString("route_geometry");
			road.mRouteHigh = 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.mLocation = road.mRouteHigh.get(positionIndex);
				node.mLength = jInstruction.getInt(2)/1000.0;
				node.mDuration = 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.mLength += node.mLength;
					lastNode.mDuration += node.mDuration;
				} else {
					node.mManeuverType = getManeuverCode(direction);
					node.mInstructions = buildInstructions(direction, roadName, directions);
					//Log.d(BonusPackHelper.LOG_TAG, direction+"=>"+node.mManeuverType+"; "+node.mInstructions);
					road.mNodes.add(node);
					lastNode = node;
				}
			}
			JSONObject jSummary = jObject.getJSONObject("route_summary");
			road.mLength = jSummary.getInt("total_distance")/1000.0;
			road.mDuration = jSummary.getInt("total_time");
		} catch (JSONException e) {
			e.printStackTrace();
			return new Road(waypoints);
		}
		if (road.mRouteHigh.size()==0){
			//Create default road:
			road = new Road(waypoints);
		} else {
			road.buildLegs(waypoints);
			BoundingBoxE6 bb = BoundingBoxE6.fromGeoPoints(road.mRouteHigh);
			//Correcting osmdroid bug #359:
			road.mBoundingBox = new BoundingBoxE6(
				bb.getLatSouthE6(), bb.getLonWestE6(), bb.getLatNorthE6(), bb.getLonEastE6());
			road.mStatus = 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;
		else 
			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;
	}
}

  

 

 

源代码下载路径:

http://osmbonuspack.googlecode.com/svn/trunk/OSMBonusPack

你可能感兴趣的:(osmdroid,OSRMRoadManager,osmbonuspack)