The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Geo::Google::PolylineEncoder - encode lat/lons to Google Maps Polylines

SYNOPSIS

  use Geo::Google::PolylineEncoder;

  my $points = [
                # can also take points as [lat, lon]
                { lat => 38.5, lon => -120.2 },
                { lat => 40.7, lon => -120.95 },
                { lat => 43.252, lon => -126.453 },
               ];
  my $encoder = Geo::Google::PolylineEncoder->new;
  my $eline   = $encoder->encode( $points );
  print $eline->{num_levels};  # 18
  print $eline->{zoom_factor}; # 2
  print $eline->{points};      # _p~iF~ps|U_ulLnnqC_mqNvxq`@
  print $eline->{levels};      # POP

  # in Javascript, assuming eline was encoded as JSON:
  # ... load GMap2 ...
  var opts = {
    points: eline.points,
    levels: eline.levels,
    numLevels: eline.num_levels,
    zoomFactor: eline.zoom_factor,
  };
  var line = GPolyline.fromEncoded( opts );

DESCRIPTION

This module encodes a list of lat/lon points representing a polyline into a format for use with Google Maps. This format is described here:

http://code.google.com/apis/maps/documentation/polylinealgorithm.html

The module is a port of Mark McClure's PolylineEncoder.js with some tweaks. The original can be found here:

http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/

CONSTRUCTOR & ACCESSORS

new( [%args] )

Create a new encoder. Arguments are optional and correspond to the accessor with the same name: "num_levels", "zoom_factor", "visible_threshold", "force_endpoints", etc...

Note: there's nothing stopping you from setting these properties each time you "encode" a polyline.

num_levels

How many different levels of magnification the polyline has. Default: 18.

zoom_factor

The change in magnification between those levels (see "num_levels"). Default: 2.

visible_threshold

Indicates the length of a barely visible object at the highest zoom level. Default: 0.00001. err.. units.

force_endpoints

Indicates whether or not the endpoints should be visible at all zoom levels. force_endpoints is. Probably should stay true regardless. Default: 1=true.

escape_encoded_points

Indicates whether or not the encoded points should have escape characters escaped, eg:

  $points =~ s/\\/\\\\/g;

This is useful if you'll be evalling the resulting strings, or copying them into a static document.

Warning: don't turn this on if you'll be passing the encoded points straight on to your application, or you'll get unexpected results (ie: lines that start out right, but end up horribly wrong). It may even crash your browser.

Default: 0=false.

lons_first

Specifies the order in which coordinates passed as arrayrefs to "encode" should be interpreted:

  # false: lat, lon
  $encoder->encode([
     [ 38.5, -120.2 ],
     [ 40.7, -120.95 ],
  ]);

  # true: lon, lat
  $encoder->encode([
     [ -120.2, 38.5 ],
     [ -120.95, 40.7 ],
  ]);

Default: 0 = lat,lon

(Yes, the default feels wrong to the mathematician in me, but that's how Google Maps do it, so for sake of consistency...)

METHODS

encode( \@points );

Encode the points into a string for use with Google Maps GPolyline.fromEncoded using a variant of the Douglas-Peucker algorithm to set levels, and the Polyline encoding algorithm defined by Google.

Expects a reference to a @points array:

  [
   { lat => 38.5, lon => -120.2 },
   { lat => 40.7, lon => -120.95 },
   { lat => 43.252, lon => -126.453 },
  ];

The individual points can also be given as arrayrefs:

  [
   [ 38.5, -120.2 ],
   [ 40.7, -120.95 ],
   [ 43.252, -126.453 ],
  ];

Note: I tried to avoid this initially, because there's no standard for which should come first: lats or lons. But I agree, it's more convenient in some cases so I've given you enough rope to hang yourself... Of course you can easily unhang yourself: the order for arrayrefs defaults to lat, lon, but you can change that by setting "lons_first".

Returns a hashref containing:

  {
   points => 'encoded points string',
   levels => 'encoded levels string',
   num_levels => int($num_levels),
   zoom_factor => int($zoom_factor),
  };

You can then use the JSON modules (or XML, or whatever) to pass the encoded values to your Javascript application for use there.

decode_points( $encoded_polyline );

Given an encoded polyline, returns the points:

  [
   { lat => 38.5, lon => -120.2 },
   { lat => 40.7, lon => -120.95 },
   { lat => 43.252, lon => -126.453 },
  ];

Note that these will likely be slightly different from the original points due to rounding errors during both "encode" & decoding.

decode_levels( $encoded_levels );

Given encoded levels, returns the levels:

  [ 17, 16, 17 ]

WHY DO MY LINES LOOK FUNNY?

Do your lines all go through the north pole? Maybe you have your lons & lats mixed up... If so and you're using point arrays, you can set "lons_first".

Do your points not show up at particular zoom levels? That's not a bug, it's a feature! Try playing with "visible_threshold".

Do your encoded lines cause your browser to crash? Sounds like a bug - file it!

BUGS

https://rt.cpan.org/Dist/Display.html?Queue=Geo-Google-PolylineEncoder

TODO

More optimization: encoding big files is *slow*. Maybe XS implementation if there's enough demand for it?

AUTHORS

Robert Rothenberg <rrwo@cpan.org>

Steve Purkis <spurkis@cpan.org>

Ported from Mark McClure's PolylineEncoder.js which can be found here: http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoderClass.html

Some encoding ideas borrowed from Geo::Google.

Bringing distance calcs in-line was Joel Rosenberg's idea: http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/gmap_polyline_encoder.rb.txt

COPYRIGHT

Copyright (c) 2008-2010 Steve Purkis. Released under the same terms as Perl itself.

SEE ALSO

http://code.google.com/apis/maps/documentation/polylinealgorithm.html, http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoderClass.html (JavaScript implementation), http://www.usnaviguide.com/google-encode.htm (similar implementation in perl), Geo::Google, JSON::Any