Cast for two

Thursday, July 19, 2007

Calculating the length of Google Maps line segments

A few days ago, I decided to bike home from work (from Brussels to Leuven). Inspired by the "gefietst" blog en based upon the route here I made my adapted route to get to my home. The bike trip went well. Of course, I was wandering how long the bike trip was. Since I have a basic bike with no equipement to measure this I had to resort to the Google Maps info. I was almost sure that a webservice would exist that calculated the length of linesegments of Google Maps or from a KML file but after some searching I found no easy way to do this via the web. (If somebody would be aware of such a service, please drop me a line in the comments) Therefore, I decided to write a small Python script to calculate the lenght of all lines drawn on a Google Map. Just go to your map, click on "Link to this page", copy the URL and fill the URL in the Python script. Run the Python script and, bingo, you have the length in kilometers for every continuous linesegment. Here's the code:

alt : http://lode.nachtergaele.googlepages.com/distance_print.html

The output of the above script is:


distance of fietsweg is 36.35 kilometer

Of course, this calculation is only an approximation since the trajectory is only an approximation (albeit a pretty good one) of the real route I followed and no heigth information is taken into account. Still I guess that its accurate upto a few kilometers. If somebody has a spare Bluetooth GPS receiver, you can always send me one ;-).

The calculation of the distance in kilometer between two points is based on the code in Ruby and the examples from the zips project a sourceforge. The coordinates of the linesegments are obtained from the KML file that Google Maps generates when appending &output=kml to the URL from 'link to this page'. The KML file is parsed using the Python minidom module. I hope that in the future Google will provide a "&output=jsonp&callback=calcfunc" so that a simple webpage with some Javascript can calculate the length. But that's for another programming project.

9 comments:

Dikkie said...

How do I run such a script myself?

cast42 said...
This comment has been removed by the author.
cast42 said...

@dikkie download to a file with extention .py and feed the file to the python interpreter. On osx Python is installed by default, on windoze it's a bit more difficult. But as I explained, I'm working on a more user friendly version that boils down to pasting an URL and pushing a button. In the mean while, you can calculate distances here So stay tuned.

Dikkie said...

Thanks a lot. Btw, I also found this one.

cast42 said...

That's also a nice one, but I would like to create the routes with Google Maps and then be able to calculate the distance. A such I can keep the map stored. The drawback of this mapplet is that you can not store the map after chalking the route on the map.

Glenn said...

cast42,
This tool to save routes on a map seems to do what you are looking for.

cast42 said...

There's now a recipe for this:
Recipe 576782: Calculate distance from .kmz files

Anonymous said...

Hi!

I found your app is exactly what I need, however, kml format has probably changed since 2007 or at least I couldn't use it.

I changed your code a little to make it work with the new format

here it is:

#!/usr/bin/python
from xml.dom import minidom
import urllib,sys
import math

# This is the link to the google map
filename=sys.argv[1];
# Calculate distance based on http://highearthorbit.com/projects/geolocation/gpx.rb
# See also : http://zips.sourceforge.net/
def distance_in_km(lat1, lon1, lat2, lon2):
rtheta = math.radians(lon1 - lon2)
rlat1 = math.radians(lat1)
rlat2 = math.radians(lat2)
dist = math.sin(rlat1) * math.sin(rlat2) + math.cos(rlat1) * math.cos(rlat2) * math.cos(rtheta)
dist = math.degrees(math.acos(dist))
return (dist * 60.0 * 1.1515 * 1.609344) # distance in km

def getText(nodelist):
rc = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
return rc

# Retrieve the KML file
#sock =urllib.urlopen(url+"&output=kml")
#htmlSource = sock.read()
#sock.close()

f=open(filename);
strkml=f.read();

xmldoc = minidom.parseString(strkml);
placemarks = xmldoc.getElementsByTagName('kml')[0].getElementsByTagName('Document')[0].getElementsByTagName('Placemark')
first=True;
distance=0;
for placemark in placemarks:
name = getText(placemark.getElementsByTagName('name')[0].childNodes)
linestrings = placemark.getElementsByTagName('Point')
for linestring in linestrings:
coordinates = linestring.getElementsByTagName('coordinates')[0].childNodes
listofpoints = getText(coordinates)
points = listofpoints.split(',')
#distance = 0.0
point=points;
values = point;#.split(',')
if len(values) == 3:
(x,y,z) = float(values[0]), float(values[1]), float(values[2])
if first:
first = False
(x0,y0,z0) = (x,y,z)
else:
dist = distance_in_km(x0,y0,x,y)
# print 'dist='+str(dist);
distance += dist
x0 = x
y0 = y
else:
print 'len points='+str(len(points));
print "Total distance is %.2f kilometer" % distance;


hope the indentation works fine

mehageg at nana10 dot co dot il

cast42 said...

I put the updated code into an pastebin:
http://pastebin.ca/1886961