]>
Commit | Line | Data |
---|---|---|
7960fbfc RN |
1 | #!/usr/bin/env python |
2 | # | |
3 | # Inspired by MBUtils: | |
4 | # http://github.com/mapbox/mbutil | |
5 | # | |
6 | # Licensed under BSD | |
7 | # | |
8 | import sqlite3, sys, logging, time, os, re | |
9 | ||
10 | from optparse import OptionParser | |
11 | ||
12 | logger = logging.getLogger(__name__) | |
13 | ||
14 | # | |
15 | # Functions from mbutil for sqlite DB format and connections | |
16 | # utils.py: | |
17 | # | |
18 | def flip_y(zoom, y): | |
19 | return (2**zoom-1) - y | |
20 | ||
21 | def mbtiles_setup(cur): | |
22 | cur.execute(""" | |
23 | create table tiles ( | |
24 | zoom_level integer, | |
25 | tile_column integer, | |
26 | tile_row integer, | |
27 | tile_data blob); | |
28 | """) | |
29 | cur.execute("""create table metadata | |
30 | (name text, value text);""") | |
31 | cur.execute("""create unique index name on metadata (name);""") | |
32 | cur.execute("""create unique index tile_index on tiles | |
33 | (zoom_level, tile_column, tile_row);""") | |
34 | ||
35 | def mbtiles_connect(mbtiles_file): | |
36 | try: | |
37 | con = sqlite3.connect(mbtiles_file) | |
38 | return con | |
39 | except Exception, e: | |
40 | logger.error("Could not connect to database") | |
41 | logger.exception(e) | |
42 | sys.exit(1) | |
43 | ||
44 | def optimize_connection(cur): | |
45 | cur.execute("""PRAGMA synchronous=0""") | |
46 | cur.execute("""PRAGMA locking_mode=EXCLUSIVE""") | |
47 | cur.execute("""PRAGMA journal_mode=DELETE""") | |
48 | ||
49 | def optimize_database(cur): | |
50 | logger.debug('analyzing db') | |
51 | cur.execute("""ANALYZE;""") | |
52 | logger.debug('cleaning db') | |
53 | cur.execute("""VACUUM;""") | |
54 | ||
55 | # | |
56 | # End functions from mbutils | |
57 | # | |
58 | ||
59 | # Based on disk_to_mbtiles in mbutil | |
60 | def vikcache_to_mbtiles(directory_path, mbtiles_file, **kwargs): | |
61 | logger.debug("%s --> %s" % (directory_path, mbtiles_file)) | |
62 | con = mbtiles_connect(mbtiles_file) | |
63 | cur = con.cursor() | |
64 | optimize_connection(cur) | |
65 | mbtiles_setup(cur) | |
66 | image_format = 'png' | |
67 | count = 0 | |
68 | start_time = time.time() | |
69 | msg = "" | |
70 | ||
71 | #print ('tileid ' + kwargs.get('tileid')) | |
72 | # Need to split tDddsDdzD | |
73 | # note zoom level can be negative hence the '-?' term | |
74 | p = re.compile ('^t'+kwargs.get('tileid')+'s(-?\d+)z\d+$') | |
75 | for ff in os.listdir(directory_path): | |
76 | # Find only dirs related to this tileset | |
77 | m = p.match(ff); | |
78 | if m: | |
79 | s = p.split(ff) | |
80 | if len(s) > 2: | |
81 | #print s[1] | |
82 | # For some reason Viking does '17-zoom level' - so need to reverse that | |
83 | z = 17 - int(s[1]) | |
84 | #print z | |
85 | for r2, xs, ignore in os.walk(os.path.join(directory_path, ff)): | |
86 | for x in xs: | |
87 | #print('x:'+directory_path+'/'+ff+'/'+x) | |
88 | for r3, ignore, ys in os.walk(os.path.join(directory_path, ff, x)): | |
89 | for y in ys: | |
90 | #print('tile:'+directory_path+'/'+ff+'/'+x+'/'+y) | |
91 | # Sometimes have random tmp files left around so skip over these | |
92 | if "tmp" in y.lower(): | |
93 | continue | |
94 | f = open(os.path.join(directory_path, ff, x, y), 'rb') | |
95 | # Viking in xyz so always flip | |
96 | y = flip_y(int(z), int(y)) | |
97 | cur.execute("""insert into tiles (zoom_level, | |
98 | tile_column, tile_row, tile_data) values | |
99 | (?, ?, ?, ?);""", | |
100 | (z, x, y, sqlite3.Binary(f.read()))) | |
101 | f.close() | |
102 | count = count + 1 | |
103 | if (count % 100) == 0: | |
104 | for c in msg: sys.stdout.write(chr(8)) | |
105 | msg = "%s tiles inserted (%d tiles/sec)" % (count, count / (time.time() - start_time)) | |
106 | sys.stdout.write(msg) | |
107 | ||
108 | msg = "\nTotal tiles inserted %s \n" %(count) | |
109 | sys.stdout.write(msg) | |
110 | sys.stdout.write("Optimizing...\n") | |
111 | optimize_database(con) | |
112 | return | |
113 | ||
114 | ## | |
115 | ## Start of code here | |
116 | ## | |
117 | parser = OptionParser(usage="""usage: %prog [options] in-map-cache-directory-root out-file.mbtile | |
118 | ||
119 | Example: | |
120 | ||
121 | Export Viking's cache files of a map type to an mbtiles file: | |
122 | $ viking-cache-mbtile.py -t 17 ~/.viking-maps OSM_Cycle.mbtiles | |
123 | ||
124 | Import from an MB Tiles into Viking's cache file layour is not available [yet] | |
125 | ||
126 | Note you can use the http://github.com/mapbox/mbutil mbutil script to further handle .mbtiles | |
127 | such as converting it into an OSM tile layout and then pointing a new Viking Map at that location with the map type of 'On Disk OSM Layout'""") | |
128 | ||
129 | parser.add_option('-t', dest='tileid', | |
130 | help='''Tile id of Viking map cache to use (19 if not specified as this is Viking's default (MaqQuest))''', | |
131 | type='string', | |
132 | default='19') | |
133 | ||
134 | (options, args) = parser.parse_args() | |
135 | ||
136 | if len(args) != 2: | |
137 | parser.print_help() | |
138 | sys.exit(1) | |
139 | ||
140 | if not os.path.isdir(args[0]): | |
141 | sys.stderr.write('Viking Map Cache directory not specified\n') | |
142 | sys.exit(1) | |
143 | ||
144 | if os.path.isfile(args[1]): | |
145 | sys.stderr.write('Output file already exists!\n') | |
146 | sys.exit(1) | |
147 | ||
148 | # to mbtiles | |
149 | if os.path.isdir(args[0]) and not os.path.isfile(args[0]): | |
150 | directory_path, mbtiles_file = args | |
151 | vikcache_to_mbtiles(directory_path, mbtiles_file, **options.__dict__) |