Tag: maidenhead

  • More radio amateur grid squares

    Toronto, as understood by the Maidenhead Locator system

    After yesterday’s post, I went a bit nuts with working out the whole amateur radio grid locator thing (not that I’m currently likely to use it, though). I’d hoped to provide a shapefile of the entire world, but that would be too big for the format’s 2GB file size limit.

    What I can give you, though, is:

    • A Perl program that will generate a shapefile of an entire Maidenhead grid field, down to the subsquare level: make_grid.pl. You’ll need Geo::Shapelib to make this work. 324 (= 182) of these files would cover the whole world, and at 8MB or so a pop, things get unwieldy quickly.
    • A Google Earth KML file covering the whole world in 20° by 10° grid fields: Maidenhead_Locator_World_Grid. (If you’re feeling nerdy, here it is in Shapefile format: Maidenhead_Locator_World_Grid-shp).

    If anyone would like their grid square in Google Earth format, let me know, or read on …

    Making KML Files

    Several people have asked, so here’s how you convert to KML. You’ll need the OGR toolkit installed, which comes in several open-source geo software bundles: FWTools/osgeo4w/QGis. Let’s assume we want to make the grid square ‘EN’.

      1. Run make_grid.pl:
        make_grid.pl en
      2. Convert to KML using ogr2ogr:
        ogr2ogr -f KML EN-maidenhead_grid.kml EN-maidenhead_grid.shp
      3. Alternatively, if you just want to extract a square (say EN82), you can use ogr2ogr’s ‘where’ clause to select just the geometry you want:
        ogr2ogr -f KML -where "Square='82'" EN82-maidenhead_grid.kml EN-maidenhead_grid.shp

     

  • Maidenhead Grid Locator, in Perl

    Amateur radio operators sometimes use the Maidenhead Grid Locator Square system to identify location. Here’s my attempt at a translator, written in slightly squirrelly Perl:

    #!/usr/bin/perl -w
    # maidenhead - 6 character locator
    # created by scruss/VA3PID on 02011/04/01
    # RCS/CVS: $Id: maidenhead,v 1.3 2011/04/03 11:04:38 scruss Exp $
    
    use strict;
    sub latlong2maidenhead;
    sub maidenhead2latlong;
    
    if ( $#ARGV >= 1 ) {    # two or more args
                            # convert lat/long to grid
      print latlong2maidenhead( $ARGV[0], $ARGV[1] ), "\n";
    }
    elsif ( $#ARGV == 0 ) {    # one arg
                               # convert grid to lat/long
      print join( ", ", maidenhead2latlong( $ARGV[0] ) ), "\n";
    }
    else {                     # no args
    
      # print usage
      print 'Usage: ', $0, ' dd.dddddd ddd.dddddd', "\n",
        ' or', "\n",
        $0, ' grid_location', "\n";
    }
    exit;
    
    sub maidenhead2latlong {
    
      # convert a Maidenhead Grid location (eg FN03ir)
      #  to decimal degrees
      # this code could be cleaner/shorter/clearer
      my @locator =
        split( //, uc(shift) );    # convert arg to upper case array
      my $lat      = 0;
      my $long     = 0;
      my $latdiv   = 0;
      my $longdiv  = 0;
      my @divisors = ( 72000, 36000, 7200, 3600, 300, 150 )
        ;                          # long,lat field size in seconds
      my $max = ( $#locator > $#divisors ) ? $#divisors : $#locator;
    
      for ( my $i = 0 ; $i <= $max ; $i++ ) {
        if ( int( $i / 2 ) % 2 ) {    # numeric
          if ( $i % 2 ) {             # lat
            $latdiv = $divisors[$i];    # save for later
            $lat += $locator[$i] * $latdiv;
          }
          else {                        # long
            $longdiv = $divisors[$i];
            $long += $locator[$i] * $longdiv;
          }
        }
        else {                          # alpha
          my $val = ord( $locator[$i] ) - ord('A');
          if ( $i % 2 ) {               # lat
            $latdiv = $divisors[$i];    # save for later
            $lat += $val * $latdiv;
          }
          else {                        # long
            $longdiv = $divisors[$i];
            $long += $val * $longdiv;
          }
        }
      }
      $lat  += ( $latdiv / 2 );         # location of centre of square
      $long += ( $longdiv / 2 );
      return ( ( $lat / 3600 ) - 90, ( $long / 3600 ) - 180 );
    }
    
    sub latlong2maidenhead {
    
      # convert a WGS84 coordinate in decimal degrees
      #  to a Maidenhead grid location
      my ( $lat, $long ) = @_;
      my @divisors =
        ( 72000, 36000, 7200, 3600, 300, 150 );    # field size in seconds
      my @locator = ();
    
      # add false easting and northing, convert to seconds
      $lat  = ( $lat + 90 ) * 3600;
      $long = ( $long + 180 ) * 3600;
      for ( my $i = 0 ; $i < 3 ; $i++ ) {
        foreach ( $long, $lat ) {
          my $div  = shift(@divisors);
          my $part = int( $_ / $div );
          if ( $i == 1 ) {    # do the numeric thing for 2nd pair
            push @locator, $part;
          }
          else {              # character thing for 1st and 3rd pair
            push @locator,
              chr( ( ( $i < 1 ) ? ord('A') : ord('a') ) + $part );
          }
          $_ -= ( $part * $div );    # leaves remainder in $long or $lat
        }
      }
      return join( '', @locator );
    }
    

    Grid square to lat/long and grid square shapefiles to follow.