Geo-Google

 view release on metacpan or  search on metacpan

lib/Geo/Google.pm  view on Meta::CPAN

			. "Geo::Google::Location"
			. " object, or subclass thereof");
	    return undef;
	}
  }

  # construct the google search text
  my $googlesearch = "from: " . join(', ', $locations[0]->lines);
  for (my $i=1; $i<=$#locations; $i++){
	$googlesearch .= " to:" . join(', ', $locations[$i]->lines);
  }
  my $page = get( sprintf( LQ, uri_escape( $googlesearch ) ) );

  # See if google returned no results
  if ( $page =~ /did\snot\smatch\sany\slocations/i ) {
    $self->error( "Google couldn't find one of the locations you provided for your directions query") and return undef;
  }
  # See if google didn't recognize an input, but suggested
  # a correction to the input that it does recognize
  elsif ( $page =~ m#didyou#s )
  {
    # Parse the JSON to unescape the escaped unicode characters in the URLs we need to parse
    my ( $strJSON ) = $page =~ m#loadVPage\((.+), "\w+"\);}//]]>#s;
    my $suggestion_json = $json->jsonToObj($strJSON);
    # Did you mean:</span><div class="ref"><a href="/maps?v=1&amp;ie=UTF8&amp;hl=en&amp;ct=clnk&amp;cd=1&amp;saddr=695+Charles+E+Young+Dr+S,+Los+Angeles,+Los+Angeles,+California+90024,+United+States&amp;daddr=10948+Weyburn+Ave,+Los+Angeles,+CA+90024+...
    my ( $first_suggestion ) = $suggestion_json->{panel} =~ m#(saddr=.+?)" onclick#s;
    # Get the directions using google's first suggestion
    $page = get ( _html_unescape("http://maps.google.com/maps?output=js&$1") );

    # warn the user using the error method, but don't return undef.
    $self->error("Google suggested a different address for your query.  Using the google suggestion instead.");
  }
  # attept to locate the JSON formatted data block
  if ($page =~ m#loadVPage\((.+), "\w+"\);}//]]>#s) {
    # Extract the JSON data structure from the response.
    $response_json = $json->jsonToObj( $1 );
  }
  else {
    $self->error( "Unable to locate the JSON format data in Google's response.") and return undef;
  }

  my @points;
  my @enc_points;
  for (my $i = 0; $i<=$#{$response_json->{"overlays"}->{"polylines"}}; $i++) {
    $enc_points[$i] = $response_json->{"overlays"}->{"polylines"}->[$i]->{"points"};
    $points[$i] = [ _decode($enc_points[$i]) ];
  }

  # extract a series of directions from HTML inside the panel 
  # portion of the JSON data response, stuffing them in @html_segs
  my @html_segs;
  my $stepsfound = 0;

  my $panel = $response_json->{'panel'};
  $panel =~ s/&#160;/ /g;

  my @subpaths = $panel =~ m#(<table class="(ddrsteps(?: pw)?|ddwpt_table|dirsegment)".+?</table>\s*</div>)#gs; #ddspt_table
  #my ( $subpanel ) = $response_json->{'panel'} =~ m#<table class="ddrsteps pw">(.+)</table>#s;

  foreach my $subpath ( @subpaths ) {
    my @segments = split m#</tr>\s*<tr#s, $subpath;
    foreach my $segment ( @segments ) {
      #skip irrelevant waypoint rows
      if ( $subpath =~ m#ddwpt_table#s && $segment !~ m#ddptlnk#s ) { next }

      my ( $id, $pointIndex ) = $segment =~ m#id="(.+?)" polypoint="(.+?)"#s;
      my ( $html )       = $segment =~ m#"dirsegtext_\d+_\d+">(.+?)</td>#s;
      my ( $distance )   = $segment =~ m#"sxdist".+?>(.+?)<#s;
      my ( $time )       = $segment =~ m#"segtime nw pw">(.+?)<#s;

      if ( ! defined( $id ) ) {
        if ( $subpath =~ m#waypoint="(.+?)"#s ) {
          $id = "waypoint_$1";
	  $html = $locations[$1]->title();
          ($pointIndex)  = $segment =~ m#polypoint="(.+?)"#s;
        }
      }

      next unless $id;

      if ( ! $time ) {
        #some segments are different (why? what is the pattern?)
        my ( $d2, $t2 ) = $segment =~ m#timedist ul.+?>(.+?)\(about&\#160;(.+?)\)</td>#s;
        $time = $t2;
        $distance ||= $d2;
      }

      #some segments have no associated point, e.g. when there are long-distance driving segments

      #some segments have time xor distance (not both)
      $distance   ||= ''; $distance = decode_entities( $distance ); $distance =~ s/\s+/ /g;
      $time       ||= ''; $time     = decode_entities( $time     ); $time =~ s/\s+/ /g;

      push (@html_segs, {
        distance   => $distance,
        time       => $time,
        pointIndex => $pointIndex,
        id         => $id,
        html       => $html
      });
      $stepsfound++;
    }
  }

  if ($stepsfound == 0) {
    $self->error("Found the HTML directions from the JSON "
      . "reponse, but was not able to extract "
      . "the driving directions from the HTML") and return undef;
  }
  my @segments = ();
  # Problem:  When you create a Geo::Google::Location by
  # looking it up on Google from an address, it returns coordinates
  # with millionth of a degree precision.  Coordinates that come out 
  # the polyline string only have hundred thousandth of a degree
  # precision.  This means that the correlation algorithm won't find
  # the start, stop or waypoints in the polyline unless we round
  # start, stop and waypoint coordinates to the hundred-thousandth
  # degree precision.
  foreach my $location (@locations) {
    $location->{'latitude'} = sprintf("%3.5f", $location->{'latitude'} );
    $location->{'longitude'} = sprintf("%3.5f", $location->{'longitude'} );



( run in 1.271 second using v1.01-cache-2.11-cpan-71847e10f99 )