#!/usr/bin/perl # wp2html - waypoint list to HTML conversion # Copyright (c) 2000-2003 by Ian Kluft # Redistribution permitted by the author under the conditions of the # GNU General Public License Version 2. # http://www.kluft.com/~ikluft/opensource/GPLv2.txt # # This program uses waypoint files from gpstrans as its input. # See gpstrans at http://gpstrans.sf.net/ # If you don't have gpstrans (or can't use it because you don't have a # Garmin GPS, make your waypoint input entries look like this: # WFDSITE12/31/198900:00:0037°06'07.7"-121°51'49.9" # where is CTRL-I (ASCII 9). Coordinates may be in # degrees/decimal minutes or degrees/minutes/decimal seconds. # # After your initial HTML export, you may set up a ~/.waypoints-key file # to customize the waypoints HTML output. A sample follows: #---------------------------------------------------------------------- # =category aprs Waypoints received via APRS packets # =category aviation Aviation # =category friends Friends' Residences # =category restaurant Restaurants # # JOE friends [hide] Joe's house # KO6YQ aprs KO6YQ packet received via APRS # RHV aviation Reid-Hillview Airport, San Jose # TA-SSJ restaurant Tony & Alba's Pizza & Pasta on Santa Teresa Blvd in South San Jose (recurring SBAY Pizza location) # WSP-WG restaurant Willow Street Pizza at Westgate Mall, San Jose # W6PIY-1 aprs W6PIY-1 packet received via APRS (West Valley ARA) # R* restaurant Restaurant #---------------------------------------------------------------------- # The format of the ~/.waypoints-key file is as follows: # 1) a line starting with "#" is a comment, which is ignored # 2) a line starting with "=category" is a category definition # It takes two parameters: a short one-word name and a title # 3) all other non-blank lines are waypoint keys. # They take 3 parameters: the waypoint name (must match name from GPS), # the category (must match a category definition above), and a plain # text description. If the description begins with "[hide]", then # the waypoint will be omitted unless the --nohide command line option # is set. # # Command line usage: # wp2html [--nohide] [--category=catname] [--name=wpname] [--table-only] # --nohide don't omit hidden waypoints # --category only use waypoints from this category # --name only use waypoints with this name/pattern # --table-only output waypoint table only, not an entire HTML page use strict; use Getopt::Long; my ( %maps, %key, %key_cat, $nohide, $table_only, @waypoints, $filter_cat, $filter_name ); # map configuration %maps = ( # Google Local search "google local" => 'http://local.google.com/local?near=@lat_n@,@lon_n@', "google - pizza" => 'http://local.google.com/local?q=pizza&near=@lat_n@,@lon_n@', "google - restaurant" => 'http://local.google.com/local?q=restaurant&near=@lat_n@,@lon_n@', # MapQuest road map "mapquest" => 'http://www.mapquest.com/cgi-bin/ia_find?link=btwn/twn-map_results&event=latlng_search&type=dec&lat=@lat_n@&lng=@lon_n@&zoom_in=2', # TopoZone topographic map "topozone" => 'http://www.topozone.com/map.asp?lat=@lat_n@&lon=@lon_n@', # Heavens Above - sky viewing info "heavens-above" => 'http://www.heavens-above.com/main.asp?Loc=@name@&Lat=@lat_n@&Lng=@lon_n@&TZ=PST', # Tiger maps - roads, etc "tiger" => 'http://tiger.census.gov/cgi-bin/mapbrowse-tbl?lat=@lat_n@&lon=@lon_n@&wid=0.10&ht=0.10&mlat=@lat_n@&mlon=@lon_n@&msym=redpin&off=CITIES&mlabel=@name@', # AirNav - nearest airport search "airnav" => 'http://airnav.com/cgi-bin/airport-search?lat=@lat_n@&ns=N&lon=@lon_n@&ew=e&fieldtypes=a&use=u&fuel=0&mindistance=0&maxdistance=50&distanceunits=nm', # Geocaching - nearest geocache site "geocaching" => 'http://www.geocaching.com/seek/nearest.aspx?origin_lat=@lat_n@&origin_long=@lon_n@', # GeoURL - registered URLs near a point "geourl" => 'http://geourl.org/near/?lat=@lat_n@&lon=@lon_n@&dist=100', # SideBit - GeoURL mapping "sidebit" => 'http://www.sidebit.com/ProjectGeoURLMap.php?lat=@lat_n@&lon=@lon_n@', # Confluence.org - degree line intersections or "confluences" "confluence" => 'http://confluence.org/confluence.php?lat=@lat_n@&lon=@lon_n@', # Acme Mapper - aerial photos "acmemap" => 'http://mapper.acme.com/?lat=@lat_n@&long=@lon_n@&scale=13&theme=Image&dot=Yes', # FindU - APRS positions "findu" => 'http://www.findu.com/cgi-bin/near.cgi?lat=@lat_n@&lon=@lon_n@', # MapTech - topo map "maptech" => 'http://mapserver.maptech.com/api/espn/index.cfm?lat=@lat_n@&lon=@lon_n@&scale=100000&zoom=50&type=1&icon=0&&scriptfile=http://mapserver.maptech.com/api/espn/index.cfm', # add more lat/lon-based searches here ); # function to normalize latitude and longitude from deg/min/sec to decimal sub normalize { my ( $str ) = @_; if ( $str =~ /(-{0,1})([0-9]+)°([0-9.]+)'([0-9.]+)"/o ) { my $coord = ( $2 + 0.0 ) + ( $3 / 60.0 ) + ( $4 / 3600.0 ); if ( $1 eq "-" ) { $coord = -$coord; } return $coord; } elsif ( $str =~ /(-{0,1})([0-9]+)°([0-9.]+)'/o ) { my $coord = ( $2 + 0.0 ) + ( $3 / 60.0 ); if ( $1 eq "-" ) { $coord = -$coord; } return $coord; } return $str; } # comparison function to sort waypoints by category and name sub bycat { my $key_a = keymatch($a->{name}); my $key_b = keymatch($b->{name}); if (( !defined $key_a ) and ( !defined $key_b )) { return $a->{name} cmp $b->{name}; } elsif (( defined $key_a ) and ( !defined $key_b )) { return -1; } elsif (( !defined $key_a ) and ( defined $key_b )) { return 1; } elsif ( $key_a->{category} ne $key_b->{category}) { return $key_a->{category} cmp $key_b->{category}; } #if (( !defined $key{$a->{name}}) and ( !defined $key{$b->{name}})) { # return $a->{name} cmp $b->{name}; #} elsif (( defined $key{$a->{name}}) and ( !defined $key{$b->{name}})) { # return -1; #} elsif (( !defined $key{$a->{name}}) and ( defined $key{$b->{name}})) { # return 1; #} elsif ( $key{$a->{name}}{category} ne $key{$b->{name}}{category}) { # return $key{$a->{name}}{category} cmp $key{$b->{name}}{category}; #} return $a->{name} cmp $b->{name}; } # comparison of key names allowing for wildcards sub keymatch { my ( $keyname ) = @_; # check the raw name first without any processing if ( defined $key{$keyname}) { # a direct match, so "hide" parameter determines success if ( $key{$keyname}{attr}{hide}) { return; } else { return $key{$keyname}; } } # check for wildcards - substrings with "*" appended my $wcname = $keyname; while ( length($wcname)) { if ( defined $key{$wcname."*"}) { # a match, so "hide" parameter determines success if ( $key{$wcname."*"}{attr}{hide}) { return; } else { return $key{$wcname."*"}; } } $wcname = substr ( $wcname, 0, length($wcname) - 1 ); } # check for global wildcard if ( defined $key{"*"}) { # a match, so "hide" parameter determines success if ( $key{"*"}{attr}{hide}) { return; } else { return $key{"*"}; } } # if we fell through, default is to display it - return empty record return; } # enumerate coordinates by different formats sub enumerate_coord { my ( $coord ) = @_; my $coord_n = normalize( $coord ); my @results; # decimal degrees push @results, sprintf( "%6.6f°", $coord_n); # degrees and decimal minutes my ( $deg, $min, $sec ); $deg = int($coord_n); $min = (abs($coord_n) - abs($deg))*60.0; push @results, sprintf( "%d° %6.4f'", $deg, $min ); # degrees, minutes and decimal seconds $deg = int($coord_n); $min = int((abs($coord_n) - abs($deg))*60.0); $sec = ((abs($coord_n) - abs($deg))*60.0 - $min)*60.0; push @results, sprintf( "%d° %d' %6.2f\"", $deg, $min, $sec ); return @results; } # command-line processing $nohide = $table_only = 0; # flags default to off GetOptions ( "nohide" => \$nohide, "category:s" => \$filter_cat, "name:s" => \$filter_name, "table-only" => \$table_only, ); # grab waypoints keys if present if ( -f $ENV{HOME}."/.waypoints-key" ) { if ( open ( key_fd, $ENV{HOME}."/.waypoints-key" )) { while ( ) { /^\s*$/ and next; # ignore blank lines /^\s*#/ and next; # ignore comments chomp; # eat newline if ( /^=category\s+([^\s]+)\s+(.*)/ ) { $key_cat{$1} = $2; } elsif ( /^([^\s]+)\s+([^\s]+)\s+(\[[^\]]*\]){0,1}\s*(.*)/ ) { my ( $name, $cat, $attrstr, $value ) = ( $1, $2, $3, $4 ); $key{$name} = {}; $key{$name}{text} = $value; $key{$name}{category} = $cat; if ( length ( $attrstr ) > 0 ) { $key{$name}{attr} = {}; $attrstr =~ s/^\[//; $attrstr =~ s/\]$//; my $attr; foreach $attr ( split( /,/, $attrstr )) { if ( $attr =~ /^([^=]+)=(.*)/ ) { $key{$name}{attr}{$1}=$2; } else { $key{$name}{attr}{$attr}=1; } } } } } close key_fd; } } # per-waypoint processing while ( <> ) { chomp; /^W\s+/ or next; my ( undef, $name, $comment, $date, $lat, $lon ) = split ( /\t/ ); $name =~ s/^\s*//o; $name =~ s/\s*$//o; $name =~ s/^$/\ /o; $comment =~ s/^\s*//o; $comment =~ s/\s*$//o; $comment =~ s/^$/\ /o; $date =~ s/^\s*//o; $date =~ s/\s*$//o; $date =~ s/^$/\ /o; $lat =~ s/^\s*//o; $lat =~ s/\s*$//o; $lat =~ s/^$/\ /o; $lon =~ s/^\s*//o; $lon =~ s/\s*$//o; $lon =~ s/^$/\ /o; # normalize latitude and longitude my ( $lat_n, $lon_n ); $lat_n = normalize($lat); $lon_n = normalize($lon); # generate map URLs my @map_links = (); my ( $map ); foreach $map ( sort keys %maps ) { my $url = $maps{$map}; $url =~ s/\@lat\@/$lat/g; $url =~ s/\@lon\@/$lon/g; $url =~ s/\@lat_n\@/$lat_n/g; $url =~ s/\@lon_n\@/$lon_n/g; $url =~ s/\@name\@/$name/g; push @map_links, "$map"; } #print "name=$name comment=$comment lat=$lat lon=$lon\n"; if ( $nohide or keymatch($name)) { my $waypoint = {}; $waypoint->{name} = $name; $waypoint->{comment} = $comment; $waypoint->{lat} = $lat; $waypoint->{lon} = $lon; $waypoint->{map_links} = \@map_links; push @waypoints, $waypoint; } } if ( ! $table_only ) { # HTML heading print "\n"; print "\n"; print "GPS Waypoints\n"; print "\n"; print "\n"; print "
\n"; print "\n"; print "

GPS Waypoints

\n"; print "
\n"; print "
\n"; } print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; if ( defined %key ) { print "\n"; } print "\n"; my ( $waypoint, $last_cat, $cols ); $cols = ( defined %key ) ? 6 : 5; foreach $waypoint ( sort bycat @waypoints ) { if (( defined $filter_name ) and $waypoint->{name} !~ /$filter_name/ ) { next; } my $keyrec = keymatch($waypoint->{name}); if ( defined $filter_cat ) { if (( defined $keyrec) and $keyrec->{category} ne $filter_cat ) { next; } } else { if (( defined $keyrec) and $keyrec->{category} ne $last_cat ) { print "\n"; print "\n"; print "\n"; } } print "\n"; my @lat_e = enumerate_coord($waypoint->{lat}); my @lon_e = enumerate_coord($waypoint->{lon}); print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; if ( defined %key ) { if ( defined $keyrec ) { print "\n"; } else { print "\n"; } } print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; $last_cat = ( defined $keyrec ) ? $keyrec->{category} : undef; } if ( ! $table_only ) { # HTML footer print "
WaypointComment
(all times GMT)
LatitudeLongitudeMapNotes
\n"; my $cat_name = (( defined $keyrec ) and length($key_cat{$keyrec->{category}})) ? "Category: " .$key_cat{$keyrec->{category}} : "Uncategorized"; print "$cat_name\n"; print "
".$waypoint->{name}."".$waypoint->{comment}."".$lat_e[0]."".$lon_e[0]."\n"; print join ( "\n
\n", @{$waypoint->{map_links}})."\n"; print "
".$keyrec->{text} ." 
".$lat_e[1]."".$lon_e[1]."
".$lat_e[2]."".$lon_e[2]."
\n"; print "\n"; print "\n"; }