Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions lib/Geo/Hash.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package Geo::Hash;

use warnings;
use strict;
use POSIX qw/ceil/;
use Carp;

=head1 NAME
Expand All @@ -16,6 +17,10 @@ This document describes Geo::Hash version 0.03

our $VERSION = '0.03';

use constant LOG2_OF_10 => log(10) / log(2);
use constant LOG2_OF_180 => log(180) / log(2);
use constant LOG2_OF_360 => log(360) / log(2);

=head1 SYNOPSIS

use Geo::Hash;
Expand Down Expand Up @@ -58,14 +63,25 @@ sub _mid {
return ( $ar->[$wh][0] + $ar->[$wh][1] ) / 2;
}

# The number of bits necessary to represent the specified number of
# decimal digits
sub _d2b { int( shift() * 3.32192809488736 + 1 ) }

sub _bits_for_number {
sub _num_of_decimal_places($) {
my $n = shift;
return 0 unless $n =~ s/.*\.//;
return _d2b( length $n );
return length $n;
}

sub _length_for_bits($$) {
my ( $bits, $is_lat ) = @_;
my $q = int( $bits / 5 );
my $r = $bits % 5;
if ( $r == 0 ) {
return $q * 2;
}
elsif ( $r <= ( $is_lat ? 2 : 3 ) ) {
return $q * 2 + 1;
}
else {
return $q * 2 + 2;
}
}

=head2 C<< precision >>
Expand All @@ -79,9 +95,11 @@ lat, lon pair.

sub precision {
my ( $self, $lat, $lon ) = @_;
my $lab = _bits_for_number( $lat ) + 8;
my $lob = _bits_for_number( $lon ) + 9;
return int( ( ( $lab > $lob ? $lab : $lob ) + 1 ) / 2.5 );
my $lat_bit = ceil( _num_of_decimal_places( $lat ) * LOG2_OF_10 + LOG2_OF_180 );
my $lon_bit = ceil( _num_of_decimal_places( $lon ) * LOG2_OF_10 + LOG2_OF_360 );
my $lat_len = _length_for_bits( $lat_bit, 1 );
my $lot_len = _length_for_bits( $lon_bit, 0 );
return $lat_len > $lot_len ? $lat_len : $lot_len;
}

=head2 C<< encode >>
Expand Down
17 changes: 17 additions & 0 deletions t/precision.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use strict;
use warnings;
use Test::More;
use Geo::Hash;

my $gh = Geo::Hash->new;
is $gh->precision('45', '-120'), 4;
is $gh->precision('45.0', '-120'), 5;
is $gh->precision('45', '-120.0'), 5;
is $gh->precision('45.00', '-120'), 6;
is $gh->precision('45', '-120.00'), 7;
is $gh->precision('45.000', '-120'), 8;
is $gh->precision('45', '-120.000'), 8;
is $gh->precision('45.00000', '-120'), 10;
is $gh->precision('45', '-120.00000'), 11;

done_testing;