#!/usr/bin/perl use strict; use warnings; # gen_geohash_kml.pl - generate a KML file from Geohash data # globals use vars qw/ %opt $VERBOSE $GEOHASH_URL $KML_NAME_GRAT_VAR $DEF_KML_NAME $LABEL /; $VERBOSE = 0; $GEOHASH_URL = "http://wiki.xkcd.com/geohashing"; $KML_NAME_GRAT_VAR = "{graticule}"; $DEF_KML_NAME = "Geohash History for $KML_NAME_GRAT_VAR"; $LABEL = 0; sub usage { if ( @_ ) { print STDERR ( join " ", @_ ) . "\n"; } print STDERR <]> [-i ] [-n ] [-l] [-v] -g: graticule of interest (format: ",") add more with colon separator -i: input file to use (file format: "YYYY-MM-DD,,,") default: '-' for standard input -n: name of top-level KML folder holding place markers default: "$DEF_KML_NAME" "$KML_NAME_GRAT_VAR" is replaced with actual graticule(s) supplied -l: generate a label for each place marker corresponding to its date default is to suppress a label for the place marker -v: enable verbose logging Notes: * You can get *all* retro Geohash data from: http://www.amipsychic.net/geohashing.html * Resulting KML file is displayed to standard out. * The resulting KML file will organize the place markers into folders by: Graticule -> Year -> Year-Month Reference: * $GEOHASH_URL Examples: * You can choose to generate a resulting KML file from the source data all in one command, like this: \$ wget -O - http://www.amipsychic.net/coords/allcoords.csv.bz2 | bzip2 -d | gen_geohash_kml.pl -g 49,-123 > Van_all.kml ...or first stage the data to a local file: \$ wget -O - http://www.amipsychic.net/coords/allcoords.csv.bz2 | bzip2 -d > allcoords.csv ...and then generate the KML file from the local file: \$ gen_geohash_kml.pl -g 48,-123:49,-123 -i allcoords.csv > VicVan_all.kml * You may wish to pre-process the source file to only show dates of interest: \$ grep "^2009" allcoords.csv | gen_geohash_kml.pl -g 49,-123:49,-122:48,-122 > VanSurBham_2009.kml * Use of -l and -n flag: \$ sed -nre '/-(07-01|12-25)/p' allcoords.csv | gen_geohash_kml.pl \\ -g 48,-123 -l -n "Canada/Xmas Day in {graticule}" > Vic_7.1_12.25.kml * Multiple graticules since a particular date: \$ sed -ne '/^2008-05-21/,\$p' allcoords.csv | gen_geohash_kml.pl \\ -g 49,-123:48,-123:49,-122:48,-122 > VanVicSurBham_since_2008-05-21.kml END_OF_USAGE exit 2; } sub logit { print STDERR ( join " ", @_ ) . "\n"; } sub debuglog { if ( $VERBOSE == 1 ) { &logit; } } sub parse_args { use Getopt::Std; getopts( "hg:i:n:lv", \%opt ) or usage( "error: invalid arguments" ); debuglog( "validating parameters..." ); if ( $opt{h} ) { usage(); } if ( ! $opt{g} ) { usage( "error: -g not specified" ); } if ( ! $opt{i} ) { $opt{i} = "-"; } if ( $opt{i} ne "-" && ! -r $opt{i} ) { usage( "error: cannot read input file [$opt{i}]" ); } if ( ! $opt{n} ) { $opt{n} = $DEF_KML_NAME; } if ( $opt{l} ) { $LABEL = 1; } if ( $opt{v} ) { $VERBOSE = 1; } debuglog( "resulting parameters:" ); debuglog( "opt-g: $opt{g}" ); debuglog( "opt-i: $opt{i}" ); debuglog( "opt-n: $opt{n}" ); debuglog( "opt-l: " . ( defined $opt{l} ? $opt{l} : "undef" ) ); debuglog( "opt-v: " . ( defined $opt{v} ? $opt{v} : "undef" ) ); } sub generate_kml { my @grats = split /:/, $opt{g}; ( my $kml_name = $opt{n} ) =~ s/$KML_NAME_GRAT_VAR/$opt{g}/; my $src_name = "[$opt{i}]"; $src_name = "" if ( $opt{i} eq "-" ); debuglog( "src_name = [$src_name]" ); debuglog( "grats = [" . ( join " -|- ", @grats ) . "]" ); debuglog( "kml_name = [$kml_name]" ); use FileHandle; my $output = *STDOUT; my $input = new FileHandle; my @input; if ( ! open $input, $opt{i} ) { die "cannot open [$src_name]: $!\n"; } # the max amount of data we're dealing with is reasonable to load debuglog( "slurping in $src_name to array..." ); @input = <$input>; if ( ! close $input ) { warn "trouble closing file: $!\n"; } logit( "Generating KML for $kml_name..." ); print $output < $kml_name 1 END_OF_HEADER my( $date, $dow, $rawlat, $rawlon ); my( $year, $yearmon, $oldyear, $oldyearmon ); my( $lat, $lon ); my( $label, $pagename ); foreach my $grat ( @grats ) { my $grat_lat = 1000; my $grat_lon = 1000; ( $grat_lat, $grat_lon ) = ( split /,/, $grat ); if ( $grat_lat == 1000 || $grat_lon == 1000 ) { usage( "error: cannot parse latitude or longitude from graticule specified [$grat]" ); } debuglog( "[$grat]..." ); print $output "${grat}\n"; $label = ""; $oldyear = 0; $oldyearmon = ""; foreach ( @input ) { debuglog( "input: $_" ); chomp; if ( $_ eq "" ) { next; } ( $date, $dow, $rawlat, $rawlon ) = split /,/; ( $yearmon, $year ) = ( $date =~ m/((....)-..)-../ ); debuglog( "[$date] [$dow] [$rawlat] [$rawlon]; [$year] [$yearmon]" ); # close month folder if month changes if ( $oldyearmon ne $yearmon ) { if ( $oldyearmon ne "" ) { print $output " \n"; } # close year folder if year changes if ( $oldyear ne $year ) { if ( $oldyear > 0 ) { print $output " \n"; } debuglog( "processing year [$year]..." ); print $output "${year}\n"; } $oldyear = $year; debuglog( " for [$yearmon]..." ); print $output "${yearmon}\n"; } $oldyearmon = $yearmon; $lat = $grat_lat + $rawlat; $lon = ( $grat_lon >= 0 ? $grat_lon + $rawlon : $grat_lon - $rawlon ); debuglog( "[$lat],[$lon]" ); if ( $LABEL ) { $label = "$date"; } $pagename = "${date}_${grat_lat}_${grat_lon}"; print $output <$label$pagename
lat: $lat
lon: $lon
Dow: $dow ]]>
${lon},${lat} END_OF_DAY } # close out yearmon and year folders print $output "
\n"; print $output "
\n"; # close graticule folder print $output " \n"; } # write out footer print $output "
\n"; } parse_args(); generate_kml(); exit 0;