Skip to content

Commit

Permalink
Proper download script; using setuptools; better division of labor.
Browse files Browse the repository at this point in the history
  • Loading branch information
ninowalker committed Oct 21, 2010
1 parent 0e5e886 commit 4ea5ed9
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 32 deletions.
46 changes: 22 additions & 24 deletions osm_downloader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,25 @@ def __init__(self, *bounds):

@property
def url(self):
#print "http://api.openstreetmap.org/api/0.6/map?bbox=%f,%f,%f,%f" % self.bounds
return "http://api.openstreetmap.org/api/0.6/map?bbox=%f,%f,%f,%f" % self.bounds

class Region(object):
def __init__(self, bounds, step=0.04, overlap=0.001, name=None):
def __init__(self, bounds):
self.bounds = bounds
if not name:
name = datetime.datetime.now().strftime("%Y-%m-%d_%H%M")
self.name = name
self.step = step
self.overlap = overlap

def tiles(self):
minx = self.step * math.floor( self.left / self.step )
maxx = self.step * math.ceil( self.right / self.step )
miny = self.step * math.floor( self.bottom / self.step )
maxy = self.step * math.ceil( self.top / self.step )

for x in frange(miny, maxy, self.step):
for y in frange(minx, maxx, self.step):
yield Tile(x - self.overlap,
y - self.overlap,
x + self.overlap + self.step,
y + self.overlap + self.step)

def tiles(self, step=0.04, overlap=0.001):
minx = step * math.floor( self.left / step )
maxx = step * math.ceil( self.right / step )
miny = step * math.floor( self.bottom / step )
maxy = step * math.ceil( self.top / step )

for y in frange(miny, maxy, step):
for x in frange(minx, maxx, step):
yield Tile(x - overlap,
y - overlap,
x + overlap + step,
y + overlap + step)

@property
def left(self): return self.bounds[0]
Expand All @@ -69,12 +65,14 @@ def right(self): return self.bounds[2]
def top(self): return self.bounds[3]

class Downloader(object):
def __init__(self, dir, max_age=None):
def __init__(self, dir, max_age=None, prefix="osm"):
self.dir = dir
self.max_age = max_age
self.prefix = prefix

def download(self, region, callback=None):
tiles = list(region.tiles())
def download(self, region, step=0.04, overlap=0.001, callback=None):
tiles = list(region.tiles(step=step, overlap=overlap))
print "Downloading %f,%f to %f,%f (%d tiles)..." % (region.bounds + (len(tiles),))
pbar = ProgressBar(maxval=len(tiles))
pbar.start()
for i,tile in enumerate(tiles):
Expand All @@ -86,14 +84,14 @@ def download(self, region, callback=None):
print "Downloads complete"

def _download(self, tile):
filename = os.path.join(self.dir, "%f_%f__%f_%f.osm.xml" % tile.bounds)
filename = os.path.join(self.dir, (self.prefix + "_%f_%f__%f_%f.osm.xml") % tile.bounds)
if os.path.exists(filename):
if not self.max_age:
return filename
if os.stat(filename)[stat.ST_MTIME] + self.max_age > time.time():
return filename
d = urllib.urlopen(tile.url).read()
with open(os.path.join(self.dir, filename),"w") as f:
with open(filename, "w") as f:
f.write(d)
return filename

Expand Down
53 changes: 53 additions & 0 deletions osm_downloader/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python
from optparse import OptionParser
from osm_downloader import Downloader, Region

def main():
usage = """usage: python osm_downloader.py [options] (-b <left,bottom,right,top>|-c <lat,lng> -r <range in meters>"""
parser = OptionParser(usage=usage)
parser.add_option("-s", "--step",
type="float", dest="step", default=0.04,
help="the step size of the tile to download")
parser.add_option("-o", "--overlap",
type="float", dest="overlap", default=0.001,
help="the area to overlap to avoid lost nodes")
parser.add_option("-d", "--dir",
dest="dir", default=".",
help="download directory", metavar="DIR")
parser.add_option("-a", "--max_age",
type="int", dest="max_age", default=60*24*7,
help="max age of the file", metavar="DIR")
parser.add_option("-c", "--center",
dest="center",
help="center point")
parser.add_option("-b", "--bounds",
dest="bounds",
help="left,bottom,right,top")
parser.add_option("-r", "--range",
dest="range", default=None, type="int",
help="the range in meters")

(opts, args) = parser.parse_args()

if len(args) != 0:
parser.print_help()
exit(-1)

d = Downloader(opts.dir, opts.max_age)

if opts.range and opts.center:
lat, lng = map(float, opts.center.split(","))
r = opts.range * (1 / 111044.736) # meters * ( 1 arc degree / x meters) = arc degrees (at the equator)
print "Downloading within %f degrees of %f, %f" % (r, lat, lng)
d.download(Region((lng-r, lat-r, lng+r, lat+r)), step=opts.step)

elif opts.bounds:
d.download(Region(map(float, opts.bounds.split(","))), step=opts.step)

else:
parser.print_help()
exit(-1)


if __name__=='__main__':
main()
12 changes: 8 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from distutils.core import setup
from setuptools import setup

setup(name = "osm_donwloader",
setup(name = "osm_downloader",
version = "0.0.1",
description = "A set of tools for downloading OSM files via the API.",
author = "Nino Walker",
author_email = "[email protected]",
url = "http://www.github.com/ninowalker/osm-donwloader",
packages = ['osm_downloader'],
scripts = ['osm_download.py'],
long_description = """A dirt simple utility for downloading OSM data.""",
license = "MIT License."
license = "MIT License.",
entry_points = {
'console_scripts': [
'osm_download = osm_downloader.main:main',
],
}
)
8 changes: 4 additions & 4 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
class Tester(unittest.TestCase):

def testGeneratesNum(self):
self.assertEquals(len(list(Region((0,0,0.04,0.04), step=0.01).tiles())),
self.assertEquals(len(list(Region((0,0,0.04,0.04)).tiles(step=0.01))),
16)
self.assertEquals(len(list(Region((0,0,0.01,0.01), step=0.01).tiles())),
self.assertEquals(len(list(Region((0,0,0.01,0.01)).tiles(step=0.01))),
1)
self.assertEquals(len(list(Region((0,0,0.1,0.01), step=0.01).tiles())),
self.assertEquals(len(list(Region((0,0,0.1,0.01)).tiles(step=0.01))),
10)
self.assertEquals(len(list(Region((-180,-90,180,90), step=1).tiles())),
self.assertEquals(len(list(Region((-180,-90,180,90)).tiles(1))),
360*180)


Expand Down

0 comments on commit 4ea5ed9

Please sign in to comment.