#!/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 <<END_OF_USAGE; Usage: $0 -g <graticule[:<graticule>]> [-i <input file>] [-n <name>] [-l] [-v] -g: graticule of interest (format: "<latitude>,<longitude>") add more with colon separator -i: input file to use (file format: "YYYY-MM-DD,<DOW>,<LAT>,<LON>") 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 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. * You may wish to pre-process the source file to only show dates of interest. E.g.: grep "^2009" allcoords.csv | $0 -g 49,-123:49,-122:48,-123 > 2009.kml Reference: * $GEOHASH_URL 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 <graticule> 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 { debuglog( "grat = [$opt{g}]" ); my @grats = split /:/, $opt{g}; debuglog( "grats = [" . ( join ", ", @grats ) . "]" ); #my $grat = $opt{g}; ( my $kml_name = $opt{n} ) =~ s/$KML_NAME_GRAT_VAR/$opt{g}/; my $src_name = "[$opt{i}]"; $src_name = "<standard input>" if ( $opt{i} eq "-" ); debuglog( "src_name = [$src_name]" ); debuglog( "grats = [" . ( join ":", @grats ) . "]" ); #debuglog( "grat_lat = [$grat_lat]" ); #debuglog( "grat_lon = [$grat_lon]" ); debuglog( "kml_name = [$kml_name]" ); use FileHandle; my $output = *STDOUT; my $input = new FileHandle; if ( ! open $input, $opt{i} ) { die "cannot open [$src_name]: $!\n"; } logit( "Generating KML for $kml_name..." ); print $output <<END_OF_HEADER; <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <name>$kml_name</name> <open>1</open> END_OF_HEADER my( $date, $dow, $rawlat, $rawlon ); my( $year, $yearmon, $oldyear, $oldyearmon ); my( $lat, $lon ); my( $label, $pagename ); $label = ""; $oldyear = 0; $oldyearmon = ""; while ( <$input> ) { chomp; if ( $_ eq "" ) { next; } ( $date, $dow, $rawlat, $rawlon ) = split /,/; ( $yearmon, $year ) = ( $date =~ m/((....)-..)-../ ); debuglog( "[$date] [$dow] [$rawlat] [$rawlon]; [$year] [$yearmon]" ); # create folders per year if ( $oldyear ne $year ) { if ( $oldyear > 0 ) { print $output "</Folder> <!-- y: $oldyear -->\n"; } debuglog( "processing year [$year]..." ); print $output "<Folder><name>${year}</name>\n"; } $oldyear = $year; # create folders per month if ( $oldyearmon ne $yearmon ) { if ( $oldyearmon ne "" ) { print $output "</Folder> <!-- ym: $oldyearmon -->\n"; } debuglog( " for [$yearmon]..." ); print $output "<Folder><name>${yearmon}</name>\n"; } $oldyearmon = $yearmon; foreach my $grat ( @grats ) { my ( $grat_lat, $grat_lon ) = ( split /,/, $grat ); if ( ! $grat_lat || ! $grat_lon ) { usage( "error: cannot parse latitude or longitude from graticule specified [$grat]" ); } $lat = $grat_lat + $rawlat; $lon = ( $grat_lon > 0 ? $grat_lon + $rawlon : $grat_lon - $rawlon ); debuglog( "[$lat],[$lon]" ); if ( $LABEL ) { $label = "<name>$date</name>"; } $pagename = "${date}_${grat_lat}_${grat_lon}"; print $output <<END_OF_DAY; <Placemark>$label<description><![CDATA[ <a href="$GEOHASH_URL/$pagename">$pagename</a><br> lat: $lat<br>lon: $lon<br>Dow: $dow ]]></description><Point><coordinates>${lon},${lat}</coordinates></Point></Placemark> END_OF_DAY } } print $output "</Folder></Folder></Document></kml>\n"; } parse_args(); generate_kml(); exit 0;
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#9 | 7516 | Marc Wensauer | save point for Globalhash support | ||
#8 | 7433 | Marc Wensauer |
Add some whitespace -- just a dummy change to see if the review daemon is working now. |
||
#7 | 7313 | Marc Wensauer | More fixes to usage typos | ||
#6 | 7312 | Marc Wensauer | Fix typo in usage | ||
#5 | 7311 | Marc Wensauer |
Fleshed out examples in usage section of generator script. Corrected minor bug in verify script. |
||
#4 | 7288 | Marc Wensauer |
Reworked the way multiple place markers for multiple graticules are generated. As a side benefit, the global Geohash points can be generated through this as well, specifying a graticule of 0,0. |
||
#3 | 7286 | Marc Wensauer | Added support to specify multiple graticules; other minor cosmetic changes. | ||
#2 | 7285 | Marc Wensauer | Minor fix to add line ending to last line of KML file generated. | ||
#1 | 7280 | Marc Wensauer |
Perl version of the script, with more features. Also, it's much much faster than the Bash script. |