Rafael Sanches

July 23, 2009

Retrieve driving directions from google maps with server-side HTTP calls and show results with static maps for WAP

Filed under: maps — Tags: , , , , , , , , , — mufumbo @ 8:32 am

Edit may 2010: Google has released the directions API. Documentation is available here.

Mobile phones are not famous for supporting javascript. A problem arises when you need to use google API to retrieve the driver directions for a mobile site, or when you just don’t want your site to be overloaded with the complete maps toolkit to show a simple map.

Google provides a good directions-static demo but, unfortunately, it’s javascript-only. They don’t have any example or documentation about how to generate the directions through server side HTTP call.

The driving direction API doesn’t seem to be 100%. I wasn’t able to find examples of how to use the directions API with google maps API-V3 javascript, it seems that it’s not ready yet. I’ve founded this issue tracking in gmaps-api-issues (by the way, the most voted issue) that says that there isn’t support for google maps directions through server side http calls.

Putting all together: I have decided to check what HTTP calls the directions API of google maps API-V2 does and to use it in the server side. I don’t know if it’s forbidden in the terms of service, but it works!

Basically, my PHP server-side is doing the exact same thing that the google directions-static demo is doing in javascript (checkout the source code of the page). It retrieves the answer from the server and write the coordinates information in the  static maps URL.

Note that HttpHelper::doGET downloads the string, you can substitute that part with CURL or fopen. Here is the code to make the HTTP calls to get the driving directions and to create the static map image link:

<?php
class GoogleGeo {
    public static function buildStaticMap($center, $markers=array(), $width=400, $height=400, $zoom=12, $directions=null) {
        $strMarkers = "";
        foreach($markers as $marker) {
            if (!empty($strMarkers)) $strMarkers .= '|';
            $strMarkers .= urlencode($marker);
        }
        if ($width > 640) $width = 640;
        if (!empty($center)) {
            $center = "&center=".$center;
        }
        if (!empty($strMarkers)) {
            $strMarkers = "&markers=".$strMarkers;
        }
        if ($zoom > 0) {
            $zoom = "&zoom=$zoom";
        }

        $steps = "";
        if (!empty($directions)) {
            foreach($directions['Directions']['Routes'][0]['Steps'] as $step) {
                $lat = $step['Point']['coordinates'][1];
                $lon = $step['Point']['coordinates'][0];
                if (!empty($steps)) $steps .= "|";
                $steps .= $lat.",".$lon;
            }
            if (!empty($steps)) {
                $steps .= "|".$directions['Directions']['Routes'][0]['End']['coordinates'][1].",".$directions['Directions']['Routes'][0]['End']['coordinates'][0];
                $steps = "&path=rgb:0x0000ff,weight:5|".$steps;
            }
        }

        $staticMap = "http://maps.google.com/staticmap?maptype=mobile&size=".$width."x$height&maptype=roadmap&key=".GOOGLE_MAPS_KEY."&sensor=false$strMarkers$center$zoom$steps";
        return $staticMap;
    }

    public static function retrieveDirections ($from, $to) {
        $params = array('key' => GOOGLE_MAPS_KEY, 'output' => 'json', 'q' => "from: $from to: $to");
        $url = "http://maps.google.com/maps/nav";
        $result = HttpHelper::doGET($url, $params);
        $result = json_decode($result, true);
        return $result;
    }
}
?>

A example how to use this code is:

<?php
...
    /* FROM and TO coordinates */
    $markers = array("37.262568,-121.962232,redr", "37.229898,-121.971853,blueg");
    /* Get the driving directions from google api */
    $directions = GoogleGeo::retrieveDirections("485 Alberto Way, Suite 210. Los Gatos, CA 95032", "14109 Winchester Bl, Los Gatos, CA");
    /* Create the map image url with the directions coordinates */
    $staticMap = GoogleGeo::buildStaticMap(null, $markers, 640, 240, null, $directions);
....
?>

In this way you will have $staticMap with a value similar to the image urls in the directions-static demo. In this case it will be:

http://maps.google.com/staticmap?maptype=mobile&size=640×240&maptype=roadmap&key=YOUR_GOOGLE_KEY&sensor=false&markers=37.262568%2C-121.962232%2Credr|37.229898%2C-121.971853%2Cblueg&path=rgb:0x0000ff,weight:5|37.22898,-121.97104|37.22818,-121.97112|37.22597,-121.97231|37.22892,-121.98063|37.23713,-121.97714|37.26301,-121.96088|37.262282,-121.961628

The variable $directions will contain a array with the complete direction steps, so you can easily loop through it and print it out on your WAP application.

Advertisements

23 Comments »

  1. Although this is well-researched and well-executed — and well-documented — the http://maps.google.com/maps/nav service is not available outside the Javascript API. See para 10.1 of the Terms of Service http://code.google.com/apis/maps/terms.html and Google’s take on it at http://groups.google.com/group/Google-Maps-API/browse_thread/thread/6daebf2e2404e418/

    Even if you argue that this isn’t using the Javascript API and isn’t subject to those Terms, it becomes subject to the Maps Terms at http://www.google.com/intl/en_us/help/terms_maps.html and 2(a) prohibits it.

    Sorry.

    Comment by Andrew Leach — July 23, 2009 @ 4:19 pm

  2. It’s a shame the Google TOS bans this:

    There *is* an Australian mobile site that generates static Google maps with directions. I would be interested to know if the implemenation is legitimate and if so, how they do it.

    To try go to:
    http://virgin.truelocal.com.au/m1.5/welcome.action
    Click on “Get Directions”
    Enter addresses:
    10 elizabeth st melbourne
    10 collins st melbourne

    Regards Brett S

    Comment by Brett S — August 10, 2009 @ 1:30 am

    • Hi Brett,

      I think that their solution is even worst than mine for the TOS. Since they proxy the download of the image using the session of the user. Mine one is the user calling directly the image from google. Maybe they do the proxy for the requests don’t arrive with a refer to google.

      Do you think that google actually monitors who is using this? I mean, they said that they would provide an API for this like 2 years ago and until today there is nothing. Maybe they know that people use it in this way but just close their eyes. What do you think?

      Thank you for commenting
      Rafael

      Comment by mufumbo — August 12, 2009 @ 12:29 am

  3. Hi Rafael,

    I thought the TrueLocal implementation was suspect.

    Rather than getting directions from: http://maps.google.com/maps/nav

    How about doing something like this:
    http://maps.google.com/?saddr=1+Start+St+StartCity+Country&daddr=2+End+St+EndCity+Country&output=kml

    The result is a kml file. The parameters are documented here:

    http://mapki.com/wiki/Google_Map_Parameters

    Cheers

    Brett S

    Comment by Brett S — August 12, 2009 @ 2:47 am

  4. Hi Rafael,

    I work in Java. So I use a URLConnection and BuffereredReader rather than JavaScript. I’m not familiar with PHP so, I don’t know if there is an equivalent.

    However, (as you say) there are too many coorordinates returned. I found a 30km journey returned 180 coordinate pairs from the direction line. Since the static map URL cannot be more than 2KB I found I had to sample every 3rd one to create a line. Suprisingly, the result didn’t look too bad.

    Cheers

    Brett

    Comment by Brett S — August 12, 2009 @ 5:29 am

  5. You might find that something like a Douglas-Peucker point reduction method produces even better results.

    All of this can be done server-side.

    Hopefully Google will implement encoded polylines on static maps sooner rather than later, too.

    Andrew

    Comment by Andrew Leach — August 12, 2009 @ 3:12 pm

    • Hi Andrew,

      Awesome! Do you know if the kml solution is compliant with the google terms? If it’s i will implement it asap, otherwise i just keep the other mashup while they don’t complain 🙂

      Thanks for posting
      Rafael

      Comment by mufumbo — August 12, 2009 @ 7:29 pm

      • I guess it’s allowed, although if you’re particularly concerned you should consult a lawyer. I can’t think that any of Term 2 (http://www.google.com/intl/en_us/help/terms_maps.html) prohibits it, even 2(a). I believe it’s a standard form of request: using KML allows you to load the route into Google Earth.

        Andrew

        Comment by Andrew Leach — August 12, 2009 @ 11:07 pm

      • hey Andrew,

        Great news for me! When I have some free time and if it’s a feasible solution I will be posting the Ramer-Douglas-Peucker algorithm with the KML+PHP solution here.

        Thanks!
        Rafael

        Comment by mufumbo — August 12, 2009 @ 11:29 pm

      • If that idea is good I can provide an API, on my server, for those who don’t want to implement this by themselves.

        Comment by mufumbo — August 12, 2009 @ 11:31 pm

  6. Hi,

    Thanks for the suggestion Andrew. I will probably try average sampling first as it will be faster. However, if the results aren’t up to scratch I will give Douglas and Peucker’s clever method a try.

    I’m not a lawyer (so my opinion doesn’t count for much here), but I think the kml method shouldn’t violate Google’s TOS. I do something similar for another mashup that does a local business search and displays the results as a map and text.

    Cheers

    Brett

    Comment by Brett S — August 13, 2009 @ 12:03 am

  7. I was looking through your code and I was not able to get it to run. I am new to the google maps and curl. I was wondering if you could explain how to use the curl inplace of httphelper::doGet . I was looking through curl and I was not able to get anything to work. Thanks – good explanation

    Comment by Todd — August 19, 2009 @ 7:47 pm

    • hi,
      you have everything in this example: http://www.php.net/manual/en/function.curl-exec.php

      
      // create a new cURL resource
      $ch = curl_init();
      
      // set URL and other appropriate options
      curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
      curl_setopt($ch, CURLOPT_HEADER, 0);
      
      // grab URL and pass it to the browser
      curl_exec($ch);
      
      // close cURL resource, and free up system resources
      curl_close($ch);
      
      

      Comment by mufumbo — August 28, 2009 @ 7:39 pm

  8. Hello Rafael

    This thing is really great, when api is in javascript.
    I need to calculate the driving distance between two latlong points
    for my requirement i don’t need the directions or the map to display
    I am having the latlong points in database, i need the driving distance between these latlong points

    can you tell me how to achieve this in php
    can you provide me the code

    i would be really thankful to you
    your help would be really appreciated

    Regards
    Sameer

    i got your e mail address from Google maps api group as i am also a member of that group

    Comment by sameer — August 31, 2009 @ 8:53 pm

    • Hi sameer,

      Have you already tried to do:
      $directions = GoogleGeo::retrieveDirections(LATONE, LATTWO);

      let me know if it works,
      thanks

      Comment by mufumbo — August 31, 2009 @ 9:48 pm

      • @ Rafael

        I am just a beginner in programming
        shall i use the following code, and what changes shall i do in it so that it gives me the distance between two lat long points
        and where shall i add — // $directions = GoogleGeo::retrieveDirections(LATONE, LATTWO);
        ##–

        640) $width = 640;
        if (!empty($center)) {
        $center = “&center=”.$center;
        }
        if (!empty($strMarkers)) {
        $strMarkers = “&markers=”.$strMarkers;
        }
        if ($zoom > 0) {
        $zoom = “&zoom=$zoom”;
        }

        $steps = “”;
        if (!empty($directions)) {
        foreach($directions[‘Directions’][‘Routes’][0][‘Steps’] as $step) {
        $lat = $step[‘Point’][‘coordinates’][1];
        $lon = $step[‘Point’][‘coordinates’][0];
        if (!empty($steps)) $steps .= “|”;
        $steps .= $lat.”,”.$lon;
        }
        if (!empty($steps)) {
        $steps .= “|”.$directions[‘Directions’][‘Routes’][0][‘End’][‘coordinates’][1].”,”.$directions[‘Directions’][‘Routes’][0][‘End’][‘coordinates’][0];
        $steps = “&path=rgb:0x0000ff,weight:5|”.$steps;
        }
        }

        $staticMap = “http://maps.google.com/staticmap?maptype=mobile&size=”.$width.”x$height&maptype=roadmap&key=”.GOOGLE_MAPS_KEY.”&sensor=false$strMarkers$center$zoom$steps”;
        return $staticMap;
        }

        public static function retrieveDirections ($from, $to) {
        $params = array(‘key’ => GOOGLE_MAPS_KEY, ‘output’ => ‘json’, ‘q’ => “from: $from to: $to”);
        $url = “http://maps.google.com/maps/nav”;
        $result = HttpHelper::doGET($url, $params);
        $result = json_decode($result, true);
        return $result;

        }
        }
        ?>
        –##

        BRegards
        Sameer

        Comment by sameer — September 1, 2009 @ 10:37 am

  9. Hello Rafael

    Can you please help me …

    Regards
    Sameer

    Comment by sameer — September 2, 2009 @ 8:29 am

    • Hello Rafael…
      your code so awesome..
      Your code is very helping me..

      how to check distance..
      because i need to compare many point
      for get the near distance..

      sorry.. my english is so bad..
      i hope u understand what i mean

      Comment by krisnaputra — September 26, 2009 @ 7:30 pm

      • Hi, why you need to check the distance? I guess that google already give you the nearest distance. or not?

        Comment by mufumbo — September 28, 2009 @ 6:34 pm

  10. hii.. Rafael..
    i check distance because i have many landmark with type same..
    i need distance nearest from my landmark

    other question..
    I try your code above..
    but can not run..

    this is error..

    Fatal error: Class ‘HttpHelper’ not found in C:\xampp\htdocs\…\….

    what should i do…???

    please help me..

    thanks full
    krisna putra

    Comment by krisna — September 29, 2009 @ 4:01 am

  11. Hi. I am looking to get the distance between multiple points so as to make a travelling salesman like situation for a plumbing company who has to go to many locations in a day. Can I access the travelling distance between two points so as to plot out the quickest route? The algorithm itself is going to be challenging especially when considering I want to make it so that it will work with multiple technicians going out. Basically take a long list of addresses and find the two (or more)shortest routes to hit all the houses. So it is going to be tough but the first thing I need is to access the distances between these destinations. Can this be done?

    Comment by Andy B — June 15, 2010 @ 5:59 pm

  12. […] il link al sito che mi ha salvato e da cui ho preso il “grosso” del codice. AKPC_IDS += […]

    Pingback by Google Maps Driving Directions | ilCaimano — June 18, 2010 @ 5:23 pm


RSS feed for comments on this post. TrackBack URI

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: