| 1 |
# vim:et sts=4 sw=4: |
|---|
| 2 |
|
|---|
| 3 |
import sys, math, optparse, ModestMaps |
|---|
| 4 |
|
|---|
| 5 |
class BadComposure(Exception): |
|---|
| 6 |
pass |
|---|
| 7 |
|
|---|
| 8 |
parser = optparse.OptionParser(usage="""compose.py [options] file |
|---|
| 9 |
|
|---|
| 10 |
There are three ways to set a map coverage area. |
|---|
| 11 |
|
|---|
| 12 |
1) Center, zoom, and dimensions: create a map of the specified size, |
|---|
| 13 |
centered on a given geographical point at a given zoom level: |
|---|
| 14 |
|
|---|
| 15 |
python compose.py -p OPENSTREETMAP -d 800 800 -c 37.8 -122.3 -z 11 out.jpg |
|---|
| 16 |
|
|---|
| 17 |
2) Extent and dimensions: create a map of the specified size that |
|---|
| 18 |
adequately covers the given geographical extent: |
|---|
| 19 |
|
|---|
| 20 |
python compose.py -p MICROSOFT_ROAD -d 800 800 -e 36.9 -123.5 38.9 -121.2 out.png |
|---|
| 21 |
|
|---|
| 22 |
3) Extent and zoom: create a map at the given zoom level that covers |
|---|
| 23 |
the precise geographical extent, at whatever pixel size is necessary: |
|---|
| 24 |
|
|---|
| 25 |
python compose.py -p BLUE_MARBLE -e 36.9 -123.5 38.9 -121.2 -z 9 out.jpg""") |
|---|
| 26 |
|
|---|
| 27 |
parser.add_option('-v', '--verbose', dest='verbose', |
|---|
| 28 |
help='Make a bunch of noise', |
|---|
| 29 |
action='store_true') |
|---|
| 30 |
|
|---|
| 31 |
parser.add_option('-c', '--center', dest='center', nargs=2, |
|---|
| 32 |
help='Center. lat, lon, e.g.: 37.804 -122.263', type='float', |
|---|
| 33 |
action='store') |
|---|
| 34 |
|
|---|
| 35 |
parser.add_option('-e', '--extent', dest='extent', nargs=4, |
|---|
| 36 |
help='Geographical extent. Two lat, lon pairs', type='float', |
|---|
| 37 |
action='store') |
|---|
| 38 |
|
|---|
| 39 |
parser.add_option('-z', '--zoom', dest='zoom', |
|---|
| 40 |
help='Zoom level', type='int', |
|---|
| 41 |
action='store') |
|---|
| 42 |
|
|---|
| 43 |
parser.add_option('-d', '--dimensions', dest='dimensions', nargs=2, |
|---|
| 44 |
help='Pixel dimensions of image', type='int', |
|---|
| 45 |
action='store') |
|---|
| 46 |
|
|---|
| 47 |
parser.add_option('-p', '--provider', dest='provider', |
|---|
| 48 |
type='choice', help='Map Provider, one of: ' + ', '.join(ModestMaps.builtinProviders.keys()), |
|---|
| 49 |
choices=ModestMaps.builtinProviders.keys(), |
|---|
| 50 |
action='store') |
|---|
| 51 |
|
|---|
| 52 |
parser.add_option('-k', '--apikey', dest='apikey', |
|---|
| 53 |
help='API key for map providers that need one, e.g. CloudMade', type='str', |
|---|
| 54 |
action='store') |
|---|
| 55 |
|
|---|
| 56 |
if __name__ == '__main__': |
|---|
| 57 |
|
|---|
| 58 |
(options, args) = parser.parse_args() |
|---|
| 59 |
|
|---|
| 60 |
try: |
|---|
| 61 |
try: |
|---|
| 62 |
outfile = args[0] |
|---|
| 63 |
except IndexError: |
|---|
| 64 |
raise BadComposure('Error: Missing output file.') |
|---|
| 65 |
|
|---|
| 66 |
try: |
|---|
| 67 |
if options.provider.startswith('CLOUDMADE_'): |
|---|
| 68 |
if not options.apikey: |
|---|
| 69 |
raise BadComposure("Error: Cloudmade provider requires an API key. Register at http://developers.cloudmade.com/") |
|---|
| 70 |
|
|---|
| 71 |
provider = ModestMaps.builtinProviders[options.provider](options.apikey) |
|---|
| 72 |
else: |
|---|
| 73 |
provider = ModestMaps.builtinProviders[options.provider]() |
|---|
| 74 |
except KeyError: |
|---|
| 75 |
raise BadComposure('Error: bad provider "%s".' % options.provider) |
|---|
| 76 |
|
|---|
| 77 |
if options.center and options.extent: |
|---|
| 78 |
raise BadComposure("Error: bad map coverage, center and extent can't both be set.") |
|---|
| 79 |
|
|---|
| 80 |
elif options.extent and options.dimensions and options.zoom: |
|---|
| 81 |
raise BadComposure("Error: bad map coverage, dimensions and zoom can't be set together with extent.") |
|---|
| 82 |
|
|---|
| 83 |
elif options.center and options.zoom and options.dimensions: |
|---|
| 84 |
lat, lon = options.center[0], options.center[1] |
|---|
| 85 |
width, height = options.dimensions[0], options.dimensions[1] |
|---|
| 86 |
|
|---|
| 87 |
dimensions = ModestMaps.Core.Point(width, height) |
|---|
| 88 |
center = ModestMaps.Geo.Location(lat, lon) |
|---|
| 89 |
zoom = options.zoom |
|---|
| 90 |
|
|---|
| 91 |
map = ModestMaps.mapByCenterZoom(provider, center, zoom, dimensions) |
|---|
| 92 |
|
|---|
| 93 |
elif options.extent and options.dimensions: |
|---|
| 94 |
latA, lonA = options.extent[0], options.extent[1] |
|---|
| 95 |
latB, lonB = options.extent[2], options.extent[3] |
|---|
| 96 |
width, height = options.dimensions[0], options.dimensions[1] |
|---|
| 97 |
|
|---|
| 98 |
dimensions = ModestMaps.Core.Point(width, height) |
|---|
| 99 |
locationA = ModestMaps.Geo.Location(latA, lonA) |
|---|
| 100 |
locationB = ModestMaps.Geo.Location(latB, lonB) |
|---|
| 101 |
|
|---|
| 102 |
map = ModestMaps.mapByExtent(provider, locationA, locationB, dimensions) |
|---|
| 103 |
|
|---|
| 104 |
elif options.extent and options.zoom: |
|---|
| 105 |
latA, lonA = options.extent[0], options.extent[1] |
|---|
| 106 |
latB, lonB = options.extent[2], options.extent[3] |
|---|
| 107 |
|
|---|
| 108 |
locationA = ModestMaps.Geo.Location(latA, lonA) |
|---|
| 109 |
locationB = ModestMaps.Geo.Location(latB, lonB) |
|---|
| 110 |
zoom = options.zoom |
|---|
| 111 |
|
|---|
| 112 |
map = ModestMaps.mapByExtentZoom(provider, locationA, locationB, zoom) |
|---|
| 113 |
|
|---|
| 114 |
else: |
|---|
| 115 |
raise BadComposure("Error: not really sure what's going on.") |
|---|
| 116 |
|
|---|
| 117 |
except BadComposure, e: |
|---|
| 118 |
print >> sys.stderr, parser.usage |
|---|
| 119 |
print >> sys.stderr, '' |
|---|
| 120 |
print >> sys.stderr, '%s --help for possible options.' % __file__ |
|---|
| 121 |
print >> sys.stderr, '' |
|---|
| 122 |
print >> sys.stderr, e |
|---|
| 123 |
sys.exit(1) |
|---|
| 124 |
|
|---|
| 125 |
if options.verbose: |
|---|
| 126 |
print map.coordinate, map.offset, '->', outfile, (map.dimensions.x, map.dimensions.y) |
|---|
| 127 |
|
|---|
| 128 |
map.draw(options.verbose).save(outfile) |
|---|