Garmin Contour Maps from USGS National Elevation Dataset
Overview
- Download pre-packaged NED tiles from USGS, 1 degree square each.
- Split tiles into subtiles.
- Generate contour shapefiles from each subtile.
- Convert contours to OSM.
- Create Garmin map from OSM files.
Contour Generator Script
#!/usr/bin/perl
use strict;
my %apps = (
gdalwarp => 'gdalwarp',
gdal_contour => 'gdal_contour',
ogr2osm => '/path/to/ogr2osm.py',
mkgmap => '/path/to/mkgmap.jar',
);
my $interval = 5;
# family ID must match TYP file
my $fam = 3758;
my $typ = '/path/to/M0000eae.TYP';
my $style = ['/path/to/mkgmap/resources/styles/', 'style-name'];
my @tiles;
my $mapid = shift;
my $desc = shift;
print "map: $mapid\n";
my ($xtiles, $ytiles) = (8,8);
mkdir for qw/work-tiles work-contour work-osm/;
while (my $source = shift)
{
my ($tile) = $source =~ /(n\d{2}w\d{3})/;
my ($oy, $ox) = $tile =~ /n(\d{2})w(\d{3})/;
$ox = -$ox;
$oy--;
for my $tx(1..$xtiles)
{
for my $ty(1..$ytiles)
{
my @box = ($ox + ($tx-1)/$xtiles, $oy + ($ty-1)/$ytiles,
$ox + ($tx )/$xtiles, $oy + ($ty )/$ytiles);
my $newtile = "${tile}_${tx}_${ty}";
print "$newtile -> @box\n";
unlink "work-tiles/$newtile.tif";
system($apps{gdalwarp}, '-t_srs', 'EPSG:4326', '-te', @box,
$source, "work-tiles/$newtile.tif") and die;
push @tiles, $newtile;
}
}
}
open my $template, '>', 'work-osm/template.args';
for my $tile(@tiles)
{
print "$tile contours\n";
unlink "work-contour/$tile-ele.$_" for qw/shp shx prj dbf/;
system($apps{gdal_contour}, '-a', 'ele', '-i', $interval, "work-tiles/$tile.tif", "work-contour/$tile-ele.shp")
and die;
system('python', $apps{ogr2osm},
'-t', 'elevation', '-o', "work-osm/$tile-ele.osm",
"work-contour/$tile-ele.shp") and die;
print $template "mapname: $mapid\n";
print $template "input-file: $tile-ele.osm\n\n";
$mapid++;
}
chdir 'work-osm';
system('java', '-jar', $apps{mkgmap}, "--family-id=$fam",
"--description=NED Contours $desc",
"--style-file=$style->[0]", "--style=$style->[1]",
'--reduce-point-density=8', '--remove-short-arcs',
'--draw-priority=40', '--transparent',
'--gmapsupp', '--tdbfile', $typ, '-c', 'template.args');
Edit the variables at the top of the script to point to your
mkgmap
jar, style file, TYP file and family ID, and desired contour interval in meters. When called as
nedosm.pl mapid description tile ...
this script will divide each NED tile into 64 subtiles, create a contour shapefile for each one, and convert these to OSM format. The osm files can be converted to a garmin map with
mkgmap
.
mapid
should be an 8-digit Garmin map number,
description
is a map description to show on the GPS.
Translation module for ogr2osm.py
This simply sorts the contours into major, medium, and minor intervals that can be displayed at different zoom levels. Save as
translations/elevation.py
in the current directory (
ogr2osm.py
does NOT look in its own install directory for this)
def translateAttributes(attrs):
if not attrs: return
tags = {'contour': 'elevation'}
if 'ele' in attrs:
ele = attrs['ele']
tags['ele'] = str(int(float(ele)))
if (float(ele) % 100) == 0:
tags['contour_ext'] = 'elevation_major';
elif (float(ele) % 25) == 0:
tags['contour_ext'] = 'elevation_medium';
else:
tags['contour_ext'] = 'elevation_minor';
return tags
TYP file for custom rendering
A Garmin TYP format file can be added to the map to customize the rendering on the GPS.
Limitations
ogr2osm.py
runs somewhat slowly because it performs much more processing than necessary for this simple data.
The translation module has the contour intervals for major/minor har-dcoded.
Artifacts will appear at the borders between subtiles (discontinuous contour lines).
--
StephenCavilia - 05 Aug 2011