Algorithm-GooglePolylineEncoding

 view release on metacpan or  search on metacpan

xt/rt74303.t  view on Meta::CPAN

    my $pointsRef     = shift;
    my @points        = @{$pointsRef};
    my $encodedPoints = '';
    $encodedPoints = &createEncodings( \@points );
    return ($encodedPoints);
}

# ############## Numeric subroutines below #############################
# Documentation from Google http://www.google.com/apis/maps/documentation/polylinealgorithm.html
#
#   1. Take the initial signed value:
#	  -179.9832104
#   2. Take the decimal value and multiply it by 1e5, flooring the result:
#	  -17998321
### Jidanni: they now say 'round' the result!
sub createEncodings {
    my $pointsRef      = shift;
    my @points         = @{$pointsRef};
    my $encoded_points = '';
    my $pointRef       = '';
    my @point          = ();
    my $plat           = 0;
    my $plng           = 0;
    my $lat            = 0;
    my $lng            = 0;
    my $late5          = 0;
    my $lnge5          = 0;
    my $dlat           = 0;
    my $dlng           = 0;
    my $i              = 0;

    for ( $i = 0 ; $i < scalar(@points) ; $i++ ) {

        $pointRef = $points[$i];
        @point    = @{$pointRef};
        $lat      = $point[0];
        $lng      = $point[1];
##use POSIX;
##        $late5    = floor( $lat * 1e5 );
        $late5 = sprintf "%.0f", $lat * 1e5;
##        $lnge5    = floor( $lng * 1e5 );
        $lnge5 = sprintf "%.0f", $lng * 1e5;
        $dlat  = $late5 - $plat;
        $dlng  = $lnge5 - $plng;
        $plat  = $late5;
        $plng  = $lnge5;
#warn "$dlat $dlng";
        $encoded_points .=
          &encodeSignedNumber($dlat) . &encodeSignedNumber($dlng);
    }
    return $encoded_points;
}

#   3. Convert the decimal value to binary. Note that a negative value must be inverted
#      and provide padded values toward the byte boundary:
#	  00000001 00010010 10100001 11110001
#	  11111110 11101101 10100001 00001110
#	  11111110 11101101 01011110 00001111
#   4. Shift the binary value:
#	  11111110 11101101 01011110 00001111 0
#   5. If the original decimal value is negative, invert this encoding:
#	  00000001 00010010 10100001 11110000 1
#   6. Break the binary value out into 5-bit chunks (starting from the right hand side):
#	  00001 00010 01010 10000 11111 00001
#   7. Place the 5-bit chunks into reverse order:
#	  00001 11111 10000 01010 00010 00001
#   8. OR each value with 0x20 if another bit chunk follows:
#	  100001 111111 110000 101010 100010 000001
#   9. Convert each value to decimal:
#	  33 63 48 42 34 1
#  10. Add 63 to each value:
#	  96 126 111 105 97 64
#  11. Convert each value to its ASCII equivalent:
#	  `~oia@

sub encodeSignedNumber {
    use integer;
    my $num     = shift;
    my $sgn_num = $num << 1;

    if ( $num < 0 ) {
        $sgn_num = ~($sgn_num);
    }
    return &encodeNumber($sgn_num);
}

sub encodeNumber {
    use integer;
    my $encodeString = '';
    my $num          = shift;
    my $nextValue    = 0;
    my $finalValue   = 0;

    while ( $num >= 0x20 ) {
        $nextValue = ( 0x20 | ( $num & 0x1f ) ) + 63;
        $encodeString .= chr($nextValue);
        $num >>= 5;
    }
    $finalValue = $num + 63;
    $encodeString .= chr($finalValue);
    return $encodeString;
}



( run in 1.125 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )