Plot a route on a map

Today I was working on plotting a set of geo-locations on google map. These lat/lon were part of a gpx file recorded on a motorcycle trip (auto-logs every x interval). So here is how I formulate the problem statement.

gpx route plot on google map

route plot

Problem:

Plot all geo-coordinates on a google map, centered and scaled for the selected route.

Solution:

  1. Parse the gpx file & extract required co-ordinates.
  2. Use Google Map V3 javascript library & plot all the points
  3. Step 2 would do the plot, however the map is required to be centered. In order to find the center location find min/max of lat/lon.
  4. 	 
    public static Double[] getCenterLatLon(List trackPoints){
    		Double[] center = new Double[2];
    		Double minLat = 999.0;
    		Double maxLat = -999.0;
    		Double minLon = 999.0;
    		Double maxLon = -999.0;
    		Double lat, lon;
    		for(TrackPoint tp:trackPoints){
    			lat = tp.getLatitude();
    			lon = tp.getLongitude();
    
    			if(minLat>lat){
    				minLat = lat;
    			}else if(maxLat<lat){ 
    				maxLat = lat; 
    			}
    
    			if(minLon>lon){
    				minLon = lon;
    			}else if(maxLon<lon){
    				maxLon = lon;
    			}
    
    		}
    		center[0] = (maxLat+minLat)/2;
    		center[1] = (maxLon+minLon)/2;
    
    		return center;
    	}
  5. Now our maps needs to be scaled & normalized to the size of our map canvas. This can be done by setting zoom option to the required level. On the map zoom level scales the map to by certain factor (*2). Read here for more on how google map zoom works. However above technique requires us to find the radius of our plot first. Here is a detailed writeup on understanding relation between earth’s curvature and lat/lons. We use Haversine forumla to compute our distance in miles.
    
    public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
    	double earthRadius = 3958.75;
    	double dLat = Math.toRadians(lat2-lat1);
    	double dLng = Math.toRadians(lng2-lng1);
    	double sindLat = Math.sin(dLat / 2);
    	double sindLng = Math.sin(dLng / 2);
    	double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
    	            * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
    	double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    	double dist = earthRadius * c;
    
    	return dist;
    }
    
    

    Above snippet is taken from here.

  6. Once we have the radius, we can translate this into a zoom level on map. I found it kind of an approximation technique.
    
    public static long googleRadiusToZoomLevel(Double radius){
    	return Math.round(16-Math.log(radius)/Math.log(2));
    }
    
  7. We are all set. Additionally you may want to scale size of your markers with change in zoom level. Here is one way of doing it.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s