Sunday, March 17, 2013

Maidenhead Grid Square KML Generator

Someone recently asked me to generate maidenhead grid square KML for Google Earth.  Being a GIS hacker and amateur radio enthusiast, I just could not resist.  For this effort, I did not go any further than the second tile level (though it would not be difficult to do so).  I first needed to store grid field characters, grid square characters and the number of degrees for a field and square.

field_characters = 'ABCDEFGHIJKLMNOPQR'

square_characters = '0123456789'

field_lon_degrees = 20
field_lat_degrees = 10

square_lon_degrees = 2
square_lat_degrees = 1

That was easy!  With these utility variables defined, we have everything that is needed to generate the grid square bounding boxes.  By the end of the for-loops below, our field_grid_squares list will contain the grid name, centroid and bounding box for each 1st level grid square.

field_grid_squares = []

for lon in xrange(-180, 180, field_lon_degrees):
  for lat in xrange(-90, 90, field_lat_degrees):

    field_lon_character = field_characters[ int((lon + 180) / field_lon_degrees) ]
    field_lat_character = field_characters[ int((lat + 90) / field_lat_degrees) ]

    field_grid_box = [
      (lon, lat),
      (lon + field_lon_degrees, lat),
      (lon + field_lon_degrees, lat + field_lat_degrees),
      (lon, lat + field_lat_degrees)
    ]
   
    field_grid_centroid = (lon + field_lon_degrees/2.0, lat + field_lat_degrees/2.0)


    field = '%s%s' % (field_lon_character, field_lat_character)



    field_grid_squares.append( (field, field_grid_centroid, field_grid_box) )



Grid square bounding boxes were generated in a similar fashion.  Placemark KML was generated for all geometries by using the template below.  Because grid squares cover the entire earth, we need to make sure the data loads efficiently.  Loading data efficiently in Google Earth via KML is as much of an art as it is science.  It is what I like to call, a balancing act!  In this case, we're talking simple squares so it's easy stuff.  We just need to be sure to apply proper LOD / bounding box parameters to prevent all of the grid squares from being loaded at any point in time.  

<Placemark>
<name>[NAME]</name>
<Region>
<Lod>
<minLodPixels>128</minLodPixels>
</Lod>
<LatLonAltBox>
<north>[NORTH]</north>
<south>[SOUTH]</south>
<east>[EAST]</east>
<west>[WEST]</west>
<minAltitude>[MIN_ALT]</minAltitude>
<maxAltitude>[MAX_ALT]</maxAltitude>
<altitudeMode>absolute</altitudeMode>
</LatLonAltBox>
</Region>
<LineString>
<coordinates>
[COORDS]
</coordinates>
</LineString>
<styleUrl>#s</styleUrl>
</Placemark>

A couple of for loops and swaps later and we are ready to fly our grid squares!  The image below shows a shot of our grid squares from an eye-point altitude of 28000 km.





The first observation you should make is that there are no visible grid squares!  This is by-design and quite a good thing.  Let's zoom in to an eye-point of 20000 km to see what happens.






There they are!  You can now clearly identify 20 grid squares.  Let's see what happens when we lower our eye-point to 10000 km.





Now we can see many more grid squares across the Earth.  Observe how many squares are missing along the edges.  This is a natural / desirable artifact of the culling process.  By lowering the  eye-point to 5000 km, the labels become visible.




This is where things start to get interesting.  From the image above, you can tell that if we continue to zoom there will not be much left to see.  Naturally, this would be an excellent opportunity to load in more detailed squares.  Let's zoom in to an eye-point of 2000 km.



Notice how the curvature of Earth is more apparent.  Square names can now be clearly identified from the map.  And why not, one final shot from 760km.



1 comment:

Malcolm VE2DDZ said...

Thanks for this. Very interesting and useful.