#!/usr/bin/perl
# geohash_sample.pl - use KML to display points and bounding boxes
# for one point as you drop the number of digits in the Geo Hash
# (http://geohash.com) representation of that point.
#
# I've been exploring using geohashes as a way of dropping precision
# for privacy protection from coordinates. I wanted to visualize
# what would happen as I dropped digits of precision.
#
# usage:
# ./geohash_sample.pl lat lng > foo.kml
# Written by Rich Gibson, and released into the public domain.
# see mappinghacks.com
use Data::Dumper;
use Geo::Hash;
my $gh = new Geo::Hash;
my ($lat, $lng) = @ARGV;;
$h = $gh->encode($lat, $lng);
warn "geohash: $h for lat/lng ($lat, $lng)\n";
print kml_header('geohash data');
foreach my $i (0..length($h)-1) {
my $hsmall = substr($h, 0, length($h) -$i);
my ($latrange, $lngrange) = $gh->decode_to_interval($hsmall);
my ($lat, $lng) = $gh->decode($hsmall);
# calculate distance between the corners of the bounding box.
$d1 = dist($latrange->[0],$lngrange->[0], $latrange->[1], $lngrange->[0]);
$d1 = sprintf("%5.7f", $d1);
if ($d1 < 1) {
$d1 = ($d1 * 5280) . " feet";
} else {
$d1 = $d1 . " miles";
}
# prints lat/lng ranges
#warn "($latrange->[0],$lngrange->[0]), ($latrange->[1], $lngrange->[0])\t = $d1\n";
$t = "\t" x (1 - ( int(length($hsmall)/8)) );
warn "$hsmall\t$t center ($lat, $lng) bbox diagonal distance= $d1\n";
print polygon("level $i $hsmall bbox", $latrange->[0],$lngrange->[0], $latrange->[1], $lngrange->[1]);
print qq(
l$i
$lat,$lng
]]>
#foo
$lng, $lat,0
);
}
print kml_footer();
sub polygon {
my ($name, $lat1, $lng1, $lat2, $lng2) = @_;
return qq(
$name
#PolyStyle
1
$lng1, $lat1, 0 $lng2, $lat1,0 $lng2, $lat2,0, $lng1, $lat2,0 $lng1, $lat1, 0
);
}
sub dist {
# allow dist to be called as either $self->dist() or dist()
my @parms = @_;
my $pi = atan2(1,1) * 4;
my $lat1 = $parms[0]/180 * $pi ;
my $long1 = $parms[1]/180 * $pi;
my $lat2 = $parms[2]/180 * $pi;
my $long2 = $parms[3]/180 * $pi;
$a = $long1 - $long2;
if ($a < 0) {$a = -$a;}
if ($a > $pi) {$a = 2 * $pi;}
my $dist;
eval {
$dist = acos(sin($lat2) * sin($lat1) + cos($lat2)*cos($lat1)*cos($a)) * 3958;
};
return ($dist);
}
sub acos {
atan2( sqrt(1-$_[0] * $_[0]), $_[0])
}
sub kml_header {
my ($folder_name) = @_;
return qq(
sample of geohashes data
$folder_name
0
);
}
sub kml_footer {
return qq(
)
}