My need is a heavy use of routing. same as Google's Directions API. I'm looking for a viable alternative to abusing google and paying them too much.
how difficult is it to have my own server for that task?
directiongoogle-maps-apiroutingserver
My need is a heavy use of routing. same as Google's Directions API. I'm looking for a viable alternative to abusing google and paying them too much.
how difficult is it to have my own server for that task?
You need to typecast each Object on the JSON response to the proper kind.
The web service API also doesn't return the ub
property of the DirectionsResult (undocumented property), you need that as well. The DirectionsRenderer
expects ub.travelMode
, ub.origin
and ub.destination
(all strings). The origin
and destination
are only used if you enable the draggable
property on the DirectionsRendererOptions - they are basically the same value that you pass on the DirectionsService#route()
call.
Assuming you are on a browser that supports the ES5 Array#forEach
method:
function typecastRoutes(routes){
routes.forEach(function(route){
route.bounds = asBounds(route.bounds);
// I don't think `overview_path` is used but it exists on the
// response of DirectionsService.route()
route.overview_path = asPath(route.overview_polyline);
route.legs.forEach(function(leg){
leg.start_location = asLatLng(leg.start_location);
leg.end_location = asLatLng(leg.end_location);
leg.steps.forEach(function(step){
step.start_location = asLatLng(step.start_location);
step.end_location = asLatLng(step.end_location);
step.path = asPath(step.polyline);
});
});
});
}
function asBounds(boundsObject){
return new google.maps.LatLngBounds(asLatLng(boundsObject.southwest),
asLatLng(boundsObject.northeast));
}
function asLatLng(latLngObject){
return new google.maps.LatLng(latLngObject.lat, latLngObject.lng);
}
function asPath(encodedPolyObject){
return google.maps.geometry.encoding.decodePath( encodedPolyObject.points );
}
So you would use it like this:
var renderer = new google.maps.DirectionsRenderer();
function renderDirections(map, response, request){
renderer.setOptions({
directions : {
routes : typecastRoutes(response.routes),
// "ub" is important and not returned by web service it's an
// object containing "origin", "destination" and "travelMode"
ub : request
},
draggable : true,
map : map
});
}
PS: make sure you load the Geometry Library otherwise the google.maps.geometry.encoding.decodePath
method won't be available.
Yes, you can use custom tiles with Android Maps API v2 - you can see a fully working example in our OpenTripPlanner for Android app on Github. (You can also download the app directly from Google Play)
We support the following tile providers:
Our CustomUrlTileProvider class can be seen here on Github, and I've also pasted it below:
public class CustomUrlTileProvider extends UrlTileProvider {
private String baseUrl;
public CustomUrlTileProvider(int width, int height, String url) {
super(width, height);
this.baseUrl = url;
}
@Override
public URL getTileUrl(int x, int y, int zoom) {
try {
return new URL(baseUrl.replace("{z}", "" + zoom).replace("{x}", "" + x)
.replace("{y}", "" + y));
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
}
And here's the code that switches between map tile providers, based on user preference:
/**
* Changes the tiles used to display the map and sets max zoom level.
*
* @param overlayString tiles URL for custom tiles or description for
* Google ones
*/
public void updateOverlay(String overlayString) {
int tile_width = OTPApp.CUSTOM_MAP_TILE_SMALL_WIDTH;
int tile_height = OTPApp.CUSTOM_MAP_TILE_SMALL_HEIGHT;
if (overlayString == null) {
overlayString = mPrefs.getString(OTPApp.PREFERENCE_KEY_MAP_TILE_SOURCE,
mApplicationContext.getResources()
.getString(R.string.map_tiles_default_server));
}
if (mSelectedTileOverlay != null) {
mSelectedTileOverlay.remove();
}
if (overlayString.startsWith(OTPApp.MAP_TILE_GOOGLE)) {
int mapType = GoogleMap.MAP_TYPE_NORMAL;
if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_HYBRID)) {
mapType = GoogleMap.MAP_TYPE_HYBRID;
} else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_NORMAL)) {
mapType = GoogleMap.MAP_TYPE_NORMAL;
} else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_TERRAIN)) {
mapType = GoogleMap.MAP_TYPE_TERRAIN;
} else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_SATELLITE)) {
mapType = GoogleMap.MAP_TYPE_SATELLITE;
}
mMap.setMapType(mapType);
mMaxZoomLevel = mMap.getMaxZoomLevel();
} else {
if (overlayString.equals(getResources().getString(R.string.tiles_mapnik))) {
mMaxZoomLevel = getResources().getInteger(R.integer.tiles_mapnik_max_zoom);
} else if (overlayString.equals(getResources().getString(R.string.tiles_lyrk))) {
mMaxZoomLevel = getResources().getInteger(R.integer.tiles_lyrk_max_zoom);
tile_width = OTPApp.CUSTOM_MAP_TILE_BIG_WIDTH;
tile_height = OTPApp.CUSTOM_MAP_TILE_BIG_HEIGHT;
} else {
mMaxZoomLevel = getResources().getInteger(R.integer.tiles_maquest_max_zoom);
}
mMap.setMapType(GoogleMap.MAP_TYPE_NONE);
CustomUrlTileProvider mTileProvider = new CustomUrlTileProvider(
tile_width,
tile_height, overlayString);
mSelectedTileOverlay = mMap.addTileOverlay(
new TileOverlayOptions().tileProvider(mTileProvider)
.zIndex(OTPApp.CUSTOM_MAP_TILE_Z_INDEX));
if (mMap.getCameraPosition().zoom > mMaxZoomLevel) {
mMap.moveCamera(CameraUpdateFactory.zoomTo(mMaxZoomLevel));
}
}
}
Here's a screenshot of the MapQuest OpenStreetMap tiles:
For more information on making your own tiles, see the Google documentation for TileOverlay as well as the OpenStreetMap wiki for "Creating your own tiles".
Specifically, the Google documentation says:
Note that the world is projected using the Mercator projection (see Wikipedia) with the left (west) side of the map corresponding to -180 degrees of longitude and the right (east) side of the map corresponding to 180 degrees of longitude. To make the map square, the top (north) side of the map corresponds to 85.0511 degrees of latitude and the bottom (south) side of the map corresponds to -85.0511 degrees of latitude. Areas outside this latitude range are not rendered.
At each zoom level, the map is divided into tiles and only the tiles that overlap the screen are downloaded and rendered. Each tile is square and the map is divided into tiles as follows:
At zoom level 0, one tile represents the entire world. The coordinates of that tile are (x, y) = (0, 0).
At zoom level 1, the world is divided into 4 tiles arranged in a 2 x 2 grid. ...
- At zoom level N, the world is divided into 4N tiles arranged in a 2N x 2N grid.
Note that the minimum zoom level that the camera supports (which can depend on various factors) is GoogleMap.getMinZoomLevel and the maximum zoom level is GoogleMap.getMaxZoomLevel.
The coordinates of the tiles are measured from the top left (northwest) corner of the map. At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from west to east and the y values range from 0 to 2N - 1 and increase from north to south.
The formatted URLs that are used within OTP Android to reference each tile provider look like:
So, for the above providers the tile images are PNG files arranged in the directory structure indicated by the Google documentation. You would follow a similar format to create your own map tiles hosted on your own server. Note that these URLs/images must be publicly accessible to the mobile device (i.e., cannot be password protected).
Best Answer
Not exactly an answer, but have you seen The Open Source Routing Machine (OSRM)
Their routing engine works on OSM-data it seems, but it is opensource, so it could provide som pointers. And their implementation is FAST: http://map.project-osrm.org/