-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsaveEntireCity.py
255 lines (211 loc) · 9.62 KB
/
saveEntireCity.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
"""
_____/\\\\\\\\\\__________/\\\____________
___/\\\///////\\\________\/\\\____________
__\///______/\\\_________\/\\\____________
_________/\\\//__________\/\\\____________
________\////\\\____/\\\\\\\\\____________
___________\//\\\__/\\\////\\\____________
__/\\\______/\\\__\/\\\__\/\\\____________
_\///\\\\\\\\\/___\//\\\\\\\/\\___________
___\/////////______\///////\//____________
_______________________________________________________________
_______________________________________________________________
______________________________________/\\\\\\\\\_______________
____/\\\\\__/\\\\\____/\\\\\\\\\_____/\\\/////\\\__/\\\\\\\\\\_
__/\\\///\\\\\///\\\_\////////\\\___\/\\\\\\\\\\__\/\\\//////__
_\/\\\_\//\\\__\/\\\___/\\\\\\\\\\__\/\\\//////___\/\\\\\\\\\\_
_\/\\\__\/\\\__\/\\\__/\\\/////\\\__\/\\\_________\////////\\\_
_\/\\\__\/\\\__\/\\\_\//\\\\\\\\/\\_\/\\\__________/\\\\\\\\\\_
_\///___\///___\///___\////////\//__\///__________\//////////__
______________________________________________________________________________
______________________________________________________________________________
______________________/\\\____________________________________________________
____/\\\\\__/\\\\\___\///___/\\/\\\\\\____/\\\____/\\\__/\\\\\\\\\\___________
__/\\\///\\\\\///\\\__/\\\_\/\\\////\\\__\/\\\___\/\\\_\/\\\//////____________
_\/\\\_\//\\\__\/\\\_\/\\\_\/\\\__\//\\\_\/\\\___\/\\\_\/\\\\\\\\\\___________
_\/\\\__\/\\\__\/\\\_\/\\\_\/\\\___\/\\\_\/\\\___\/\\\_\////////\\\___________
_\/\\\__\/\\\__\/\\\_\/\\\_\/\\\___\/\\\_\//\\\\\\\\\___/\\\\\\\\\\___________
_\///___\///___\///__\///__\///____\///___\/////////___\//////////____________
_____/\\\\\\\\\\__________/\\\__
___/\\\///////\\\________\/\\\__
__\///______/\\\_________\/\\\__
_________/\\\//__________\/\\\__
________\////\\\____/\\\\\\\\\__
___________\//\\\__/\\\////\\\__
__/\\\______/\\\__\/\\\__\/\\\__
_\///\\\\\\\\\/___\//\\\\\\\/\\_
___\/////////______\///////\//__
http://www.3d-maps-minus-3d.com/
This script attempts to save whole city from here.com's 3d mode
Since only cities are modeled in 3d so far (2014), they are a little bit like 'islands' - surrounded by tiles with no data
This script finds those edhes, and proceeds to download all the tiles.
- IT TAKES FOREVER, AND DOWNLOADS LOTS OF IMAGES so proceed with care
The core code is all by Michal Migurski
he wrote about it here: http://mike.teczno.com/notes/webgl-nokia-maps-II.html
and his original code is here: https://github.com/migurski/NokiaWebGL
"""
from sys import argv, stderr
from math import log, pow, pi, ceil
from urlparse import urljoin
from urllib import urlopen
from struct import unpack
import os
import os.path
from ModestMaps.Geo import Location, MercatorProjection, deriveTransformation
from ModestMaps.Providers import IMapProvider
from ModestMaps.Core import Coordinate
def fromNokia(x, y, zoom):
""" Return column, row, zoom for Nokia x, y, z.
"""
row = int(pow(2, zoom) - y - 1)
col = x
return col, row, zoom
def toNokia(col, row, zoom):
""" Return x, y, z for Nokia tile column, row, zoom.
"""
x = col
y = int(pow(2, zoom) - row - 1)
return x, y, zoom
def coordinatePath(coord):
"""
"""
x, y, z = toNokia(int(coord.column), int(coord.row), int(coord.zoom))
#
# maximum number of digits in row or column at this zoom
# and a zero-padded string format for integers.
#
len = ceil(log(2 ** z) / log(10))
fmt = '%%0%dd' % len
row, col = fmt % y, fmt % x
if len == 4:
dir = '%s%s/%s%s' % (row[0:2], col[0:2], row[2:3], col[2:3])
elif len == 5:
dir = '%s%s/%s%s' % (row[0:2], col[0:2], row[2:4], col[2:4])
elif len == 6:
dir = '%s%s/%s%s/%s%s' % (row[0:2], col[0:2], row[2:4], col[2:4], row[4:5], col[4:5])
else:
raise BadZoom('len = %d unsupported' % len)
return '%(z)d/%(dir)s/map_%(z)d_%(y)d_%(x)d' % locals()
class BadZoom (Exception):
pass
class Provider (IMapProvider):
def __init__(self):
t = deriveTransformation(-pi, pi, 0, 0, pi, pi, 1, 0, -pi, -pi, 0, 1)
self.projection = MercatorProjection(0, t)
def getTileData(self, coord):
"""
"""
server = 'bcde'[int(coord.row + coord.column + coord.zoom) % 4]
path = coordinatePath(coord)
url = 'http://%(server)s.maps3d.svc.nokia.com/data4/%(path)s.n3m' % locals()
#
# Open the data and count the textures.
#
try:
data = urlopen(url).read()
(textures, ) = unpack('<i', data[4:8])
print >> stderr, 'url:', url
#print >> stderr, 'textures:', textures
#
# Pick out the filenames of the JPEG textures,
# stored as ASCII strings deeper in the file.
#
off = 12 + textures * 8
bitmap_blocks = [unpack('<ii', data[off + 8:off + 16]) for off in range(off, off + textures * 16, 16)]
imagename_blocks = [(start + 1, unpack('<B', data[start:start + 1])[0]) for (index, start) in bitmap_blocks]
image_names = [data[start:start + length] for (start, length) in imagename_blocks]
image_urls = [urljoin(url, name) for name in image_names]
#print >> stderr, 'bitmap blocks:', bitmap_blocks
#print >> stderr, 'image urls:', image_urls
#
# Output JPEGs locally.
#
name = path.split('/')
count = 0
for texture in range(textures):
if image_urls[count].endswith('.jpg'):
#jpg = open('tile_sets/out_%s_%d.jpg' % (name[4], texture), 'w')
#recreate the original folder structure
directory_ar = path.split('/');
directory = 'data/'
for index in range(len(directory_ar)-1):
directory = directory + directory_ar[index] + '/';
if not os.path.exists(directory):
os.makedirs(directory)
jpg = open('data/%(path)s_%(count)s.jpg'% locals(), 'w')
jpg.write(urlopen(image_urls[texture]).read())
count += 1
return True;
except:
print >> stderr, ' 404'
return False;
if __name__ == '__main__':
p = Provider()
if len(argv) == 1:
lat, lon = 33.997956, -118.486562
zoom = 19
elif len(argv) == 4:
lat, lon = map(float, argv[1:3])
zoom = int(argv[3])
else:
raise Exception('oops')
#
#SET THE INITIAL TILE HERE
#it can be any tile within a city... the script will iterate through until it finds the edges
#
#tile urls look like this:
#http://c.maps3d.svc.nokia.com/data4//13/5124/11/map_d_b_a_0.jpg
#http://c.maps3d.svc.nokia.com/data4//13/5124/11/map_13_5119_2411_0.jpg
#http://d.maps3d .svc.nokia.com/data4//13/5124/11/map_13_5110_2410_0.jpg
#
a = 77197
b = 163624
d = 18
#this is all stuff to make the script 'walk' around the tiles until it finds the edges
grid = 10
i = 38
j = -121
diri = 1
dirj = -1
maxi = 8
mini = -8
foundrow = False
reachedEnd = False
while (not reachedEnd):
y, x, z = fromNokia(a+i, b+j, d)
c = Coordinate(x, y, z)
loc = Location(lat, lon)
coord = p.locationCoordinate(loc).zoomTo(c.zoom)
print >> stderr, 'i:', i,'->',a+i,' j:', j,'->',b+j,
if p.getTileData(c):
i += diri
maxi = max(maxi,i)
mini = min(mini,i)
foundrow = True
else:
if (i<maxi and i>mini):
i += diri
#if you get to the end of a row
elif(i==maxi or i==mini):
#if no tiles were found in row
print >> stderr, 'foundrow:',foundrow
if (foundrow == False):
#restart and switch direction
if (diri == 1):
diri = -1
i = -1
if (dirj == 1):
j = 0
else:
j = -1
elif (dirj == 1):
dirj = -1
j = -1
diri = 1
i = 0
else:
reachedEnd = True
else:
foundrow = False
i = 0
j += dirj