Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/coremodules/landuse/maps.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file maps.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
# size limit at 1280x1280
20
# http://maps.googleapis.com/maps/api/staticmap?size=500x500&path=color:0x000000|weight:10|44.35789,11.3093|44.4378,11.3935&format=GIF&maptype=satellite&scale=2
21
# https://console.cloud.google.com/google/maps-apis
22
import os
23
import sys
24
import numpy as np
25
import wx
26
import urllib
27
from collections import OrderedDict
28
import agilepy.lib_base.classman as cm
29
import agilepy.lib_base.arrayman as am
30
import agilepy.lib_base.xmlman as xm
31
32
import matplotlib.pyplot as plt
33
from coremodules.misc.matplottools import *
34
35
##from agilepy.lib_base.processes import Process
36
from coremodules. network import netconvert
37
from agilepy.lib_base.processes import Process, CmlMixin, P
38
39
import csv
40
41
from matplotlib import cm as cmp
42
from mpl_toolkits.mplot3d import Axes3D
43
try:
44
from scipy import interpolate
45
is_scipy = True
46
except:
47
is_scipy = False
48
49
IS_MAPSUPPORT = True
50
try:
51
from PIL import ImageFilter, Image, ImageChops, ImagePath, ImageDraw
52
except:
53
print "WARNING: Maps requires PIL module."
54
IS_MAPSUPPORT = False
55
56
try:
57
import pyproj
58
59
except:
60
try:
61
from mpl_toolkits.basemap import pyproj
62
63
except:
64
print "WARNING: Maps requires pyproj module."
65
IS_MAPSUPPORT = False
66
# print __doc__
67
# raise
68
69
70
URL_GOOGLEMAP = "https://maps.googleapis.com/maps/api/staticmap?"
71
72
73
def download_googlemap(filepath, bbox, proj, size=640, filetype='gif', maptype='satellite'):
74
print 'download_googlemap', bbox
75
# https://developers.google.com/maps/documentation/static-maps/intro#Paths
76
x_sw, y_sw = bbox[0]
77
x_ne, y_ne = bbox[1]
78
79
# 01 11
80
#
81
#
82
# 00 10
83
lon00, lat00 = proj(x_sw, y_sw, inverse=True)
84
lon10, lat10 = proj(x_ne, y_sw, inverse=True)
85
lon11, lat11 = proj(x_ne, y_ne, inverse=True)
86
lon01, lat01 = proj(x_sw, y_ne, inverse=True)
87
88
size_x = size_y = size/2
89
url = URL_GOOGLEMAP+"size=%dx%d&visible=%.6f,%.6f|%.6f,%.6f&format=%s&maptype=%s&scale=2"\
90
% (size_x, size_y, lat00, lon00, lat11, lon11, filetype.upper(), maptype)
91
print ' url=', url
92
urllib.urlretrieve(url, filepath)
93
94
bbox_lonlat = np.array([[lon00, lat00], [lon11, lat11]])
95
return bbox_lonlat
96
97
98
def download_googlemap_bb(filepath, bbox, proj, apikey, size=640, filetype='gif', maptype='satellite', color="0xff0000ff"):
99
print 'download_googlemap_bb', bbox
100
# https://developers.google.com/maps/documentation/static-maps/intro#Paths
101
x_sw, y_sw = bbox[0]
102
x_ne, y_ne = bbox[1]
103
104
# 01 11
105
#
106
#
107
# 00 10
108
lon00, lat00 = proj(x_sw, y_sw, inverse=True)
109
lon10, lat10 = proj(x_ne, y_sw, inverse=True)
110
lon11, lat11 = proj(x_ne, y_ne, inverse=True)
111
lon01, lat01 = proj(x_sw, y_ne, inverse=True)
112
113
size_x = size_y = size/2
114
115
# 3
116
#
117
# 0 2
118
#
119
# 1
120
dhx = (x_ne-x_sw)/2
121
dhy = (y_ne-y_sw)/2
122
lon0, lat0 = proj(x_sw, y_sw+dhy, inverse=True)
123
lon1, lat1 = proj(x_sw+dhx, y_sw, inverse=True)
124
lon2, lat2 = proj(x_ne, y_sw+dhy, inverse=True)
125
lon3, lat3 = proj(x_sw+dhx, y_ne, inverse=True)
126
127
url = URL_GOOGLEMAP+"key=%s&size=%dx%d&format=%s&maptype=%s&scale=2&path=color:%s|weight:3" % (
128
apikey, size_x, size_y, filetype.upper(), maptype, color)
129
url += "|%.6f,%.6f" % (lat0, lon0)
130
url += "|%.6f,%.6f" % (lat2, lon2)
131
url += "|%.6f,%.6f" % (lat10, lon10)
132
url += "|%.6f,%.6f" % (lat1, lon1)
133
url += "|%.6f,%.6f" % (lat3, lon3)
134
url += "|%.6f,%.6f" % (lat01, lon01)
135
url += "|%.6f,%.6f" % (lat00, lon00)
136
url += "|%.6f,%.6f" % (lat10, lon10)
137
url += "|%.6f,%.6f" % (lat11, lon11)
138
url += "|%.6f,%.6f" % (lat3, lon3)
139
140
#url = URL_GOOGLEMAP+"key=%s&size=%dx%d&format=%s&maptype=%s&scale=2&path=color:%s|weight:5"%(apikey,size_x,size_y,filetype.upper(),maptype,color)
141
#url += "|%.6f,%.6f"%(lat00,lon00)
142
#url += "|%.6f,%.6f"%(lat10,lon10)
143
#url += "|%.6f,%.6f"%(lat11,lon11)
144
#url += "|%.6f,%.6f"%(lat01,lon01)
145
#url += "|%.6f,%.6f"%(lat00,lon00)
146
147
# urllib.urlretrieve (URL_GOOGLEMAP+"size=%dx%d&format=%s&maptype=%s&scale=2&path=color:0xff0000ff|weight:1|%.5f,%.5f|%.5f,%.5f|%.5f,%.5f|%.5f,%.5f"\
148
# %(size_x,size_y,filetype,maptype,lat00,lon00, lat11,lon11, lat01,lon01, lat10,lon10), filepath)
149
print ' url=', url
150
urllib.urlretrieve(url, filepath)
151
bbox_lonlat = np.array([[lon00, lat00], [lon11, lat11]])
152
return bbox_lonlat
153
154
155
def estimate_angle(filepath):
156
157
im = Image.open(filepath).convert("RGB")
158
print 'estimate_angle image', filepath, "%dx%d" % im.size, im.mode, im.getbands()
159
imr, img, imb = im.split()
160
161
# calculate width and height of bbox in pixel from measured rectangle
162
#wr = int(np.sqrt((rect[1][0]-rect[0][0])**2+(rect[1][1]-rect[0][1])**2))
163
#wr_check = int(np.sqrt((rect[2][0]-rect[3][0])**2+(rect[2][1]-rect[3][1])**2))
164
#hr = int(np.sqrt((rect[3][0]-rect[0][0])**2+(rect[3][1]-rect[0][1])**2))
165
#h_check = int(np.sqrt((rect[2][0]-rect[1][0])**2+(rect[2][1]-rect[1][1])**2))
166
167
xcb = im.size[0]/2
168
ycb = im.size[1]/2
169
wx = im.size[0]
170
wy = im.size[1]
171
hx = wx/2
172
hy = wy/2
173
174
# create an image and draw a rectanle with coordinates from bbox
175
#bbox = [(xcb-wr/2,ycb-hr/2), (xcb+wr/2,ycb-hr/2), (xcb+wr/2,ycb+hr/2), (xcb-wr/2,ycb+hr/2),(xcb-wr/2,ycb-hr/2)]
176
im_bbox = ImageChops.constant(im, 0)
177
draw = ImageDraw.Draw(im_bbox)
178
draw.line([(0, hy), (wx, hy)], fill=255)
179
draw.line([(hx, 0), (hx, wy)], fill=255)
180
del draw
181
182
# rotate im_bbox with different angles
183
# and correlate with the red component of the image in filepath
184
# which contains a geo-referenced red rectangle
185
angles = np.arange(-3.0, 3.0, 0.01)
186
matches = np.zeros(len(angles))
187
for i in xrange(len(angles)):
188
im_bbox_rot = im_bbox.rotate(angles[i]) # gimp 1.62
189
im_corr = ImageChops.multiply(imr, im_bbox_rot)
190
# im_corr.show()
191
im_corr_arr = np.asarray(im_corr)
192
matches[i] = np.sum(im_corr_arr)/255
193
# print ' angles[i],matches[i]',angles[i],matches[i]
194
195
angle_opt = angles[np.argmax(matches)]
196
print ' angle_opt', angle_opt
197
198
ys = np.arange(0, int(0.2*wy), 1)
199
matches = np.zeros(len(ys))
200
for y in xrange(len(ys)):
201
im_bbox = ImageChops.constant(im, 0)
202
draw = ImageDraw.Draw(im_bbox)
203
draw.line([(0, y), (wx, y)], fill=255)
204
draw.line([(0, wy-y), (wx, wy-y)], fill=255)
205
del draw
206
im_bbox_rot = im_bbox.rotate(angle_opt)
207
im_corr = ImageChops.multiply(imr, im_bbox_rot)
208
# im_corr.show()
209
im_corr_arr = np.asarray(im_corr)
210
matches[y] = np.sum(im_corr_arr)/255
211
# print ' y,matches[y]',y,matches[y]
212
213
y_opt = ys[np.argmax(matches)]
214
print ' y_opt', y_opt
215
216
if 0:
217
im_bbox = ImageChops.constant(im, 0)
218
draw = ImageDraw.Draw(im_bbox)
219
draw.line([(0, y_opt), (wx, y_opt)], fill=255)
220
draw.line([(0, wy-y_opt), (wx, wy-y_opt)], fill=255)
221
im_bbox_rot = im_bbox.rotate(angle_opt)
222
im_bbox_rot.show()
223
im.show()
224
225
# assuming rectangle:
226
bbox = [(y_opt, y_opt), (wx-y_opt, y_opt), (wx-y_opt, wy-y_opt), (y_opt, wy-y_opt), (y_opt, y_opt)]
227
print ' bbox', bbox
228
return -angle_opt, bbox
229
230
231
class MapsImporter(Process):
232
def __init__(self, maps, logger=None, **kwargs):
233
print 'MapsImporter.__init__', maps, maps.parent.get_ident()
234
self._init_common('mapsimporter', name='Background maps importer',
235
logger=logger,
236
info='Downloads and converts background maps.',
237
)
238
self._maps = maps
239
240
attrsman = self.set_attrsman(cm.Attrsman(self))
241
#self.net = attrsman.add( cm.ObjConf( network.Network(self) ) )
242
# self.status = attrsman.add(cm.AttrConf(
243
# 'status', 'preparation',
244
# groupnames = ['_private','parameters'],
245
# perm='r',
246
# name = 'Status',
247
# info = 'Process status: preparation-> running -> success|error.'
248
# ))
249
250
self.width_tile = attrsman.add(cm.AttrConf('width_tile', kwargs.get('width_tile', 500.0),
251
groupnames=['options'],
252
choices=OrderedDict([("500", 500.0),
253
("1000", 1000.0),
254
("2000", 2000.0),
255
("4000", 4000.0),
256
("8000", 8000.0),
257
]),
258
perm='rw',
259
name='Tile width',
260
unit='m',
261
info='Tile width in meter of quadratic tile. This is the real width of one tile that will be downloaded.',
262
))
263
264
self.size_tile = attrsman.add(cm.AttrConf('size_tile', kwargs.get('size_tile', 1280),
265
groupnames=['options'],
266
perm='r',
267
name='Tile size',
268
info='Tile size in pixel. This is the size of one tile that will be downloaded and determins the map resolution. Maximum is 1280.',
269
))
270
271
self.n_tiles = attrsman.add(cm.FuncConf('n_tiles', 'get_n_tiles', 0,
272
groupnames=['options'],
273
name='Number of tiles',
274
#info = 'Delete a row.',
275
))
276
277
# self.add_option( 'maptype',kwargs.get('maptype','satellite'),
278
# choices = ['satellite',]
279
# perm='rw',
280
# name = 'Map type',
281
# info = 'Type of map to be downloaded.',
282
# )
283
# self.add_option( 'filetype',kwargs.get('filetype','png'),
284
# choices = ['png',]
285
# perm='rw',
286
# name = 'File type',
287
# info = 'Image file format to be downloaded.',
288
# )
289
290
# self.add_option( 'mapserver',kwargs.get('mapserver','google'),
291
# choices = ['google',]
292
# perm='rw',
293
# name = 'Map server',
294
# info = 'Map server from where to download. Some servers require username and password.',
295
# )
296
297
# self.add_option( 'username',kwargs.get('username',''),
298
# perm='rw',
299
# name = 'User',
300
# info = 'User name of map server (if required).',
301
# )
302
303
self.apikey = attrsman.add(cm.AttrConf('apikey', kwargs.get('apikey', ''),
304
groupnames=['options'],
305
perm='rw',
306
name='API key',
307
info='API key for google maps. API key can be obtained from Google at https://cloud.google.com/maps-platform/?refresh=1&pli=1#get-started.',
308
))
309
310
# self.add_option( 'password',kwargs.get('password',''),
311
# perm='rw',
312
# name = 'User',
313
# info = 'User name of map server (if required).',
314
# )
315
316
self.is_remove_orig = attrsman.add(cm.AttrConf('is_remove_orig', kwargs.get('is_remove_orig', True),
317
groupnames=['options'],
318
perm='rw',
319
name='Remove originals',
320
info='Remove original files. Original, untransformed files are not necessary, but can be kept.',
321
))
322
323
def get_n_tiles(self):
324
"""
325
The number of tiles to be downloaded. Please do not download more han 300 tiles, otherwise map server is likely to be offended.
326
"""
327
return self._maps.get_n_tiles(self.width_tile)
328
329
def do(self):
330
self.update_params()
331
332
print 'MapsImporter.do'
333
# self._maps.download(maptype = self.maptype, mapserver = self.mapserver,
334
# filetype = 'png', rootfilepath = None,
335
# width_tile = self.width_tile, size_tile = self.size_tile,
336
# is_remove_orig = True):
337
self._maps.download(maptype='satellite', mapserver='google',
338
filetype='png', rootfilepath=None, apikey=self.apikey,
339
width_tile=self.width_tile, size_tile=self.size_tile,
340
is_remove_orig=self.is_remove_orig)
341
#import_xml(self, rootname, dirname, is_clean_nodes = True)
342
# self.run_cml(cml)
343
# if self.status == 'success':
344
return True
345
346
def update_params(self):
347
"""
348
Make all parameters consistent.
349
example: used by import OSM to calculate/update number of tiles
350
from process dialog
351
"""
352
pass
353
354
355
class Maps(am.ArrayObjman):
356
def __init__(self, landuse, **kwargs):
357
358
self._init_objman(ident='maps',
359
parent=landuse,
360
name='Maps',
361
info='Information on background maps.',
362
**kwargs)
363
self._init_attributes()
364
365
def _init_attributes(self):
366
# print 'maps._init_attributes'
367
368
# self.add(cm.AttrConf( 'width_tile',500,
369
# groupnames = ['state'],
370
# perm='r',
371
# name = 'Tile width',
372
# unit = 'm',
373
# info = 'Tile width in meter of quadratic tile. This is the real wdith of one tile that will be downloaded.',
374
# ))
375
376
# self.add(cm.AttrConf( 'size_tile',1280,
377
# groupnames = ['state'],
378
# perm='r',
379
# name = 'Tile size',
380
# info = 'Tile size in pixel. This is the size of one tile that will be downloaded.',
381
# ))
382
383
if self.has_attrname('width_tile'):
384
# no longer attributes
385
self.delete('width_tile')
386
self.delete('size_tile')
387
# put r/w permissione to older version
388
# self.get_config('width_tile').set_perm('rw')
389
# self.get_config('size_tile').set_perm('rw')
390
391
self.add_col(am.ArrayConf('bboxes', np.zeros((2, 2), dtype=np.float32),
392
groupnames=['state'],
393
perm='r',
394
name='BBox',
395
unit='m',
396
info='Bounding box of map in network coordinate system (lower left coord, upper right coord).',
397
is_plugin=True,
398
))
399
400
self.add_col(am.ArrayConf('filenames', None,
401
dtype=np.object,
402
groupnames=['state'],
403
perm='rw',
404
metatype='filepath',
405
name='File',
406
info='Image file name.',
407
))
408
409
def write_decals(self, fd, indent=4, rootdir=None, delta=np.zeros(3, dtype=np.float32)):
410
print 'write_decals', len(self)
411
net = self.parent.get_net()
412
if rootdir is None:
413
rootdir = os.path.dirname(net.parent.get_rootfilepath())
414
415
#proj = pyproj.Proj(str(net.get_projparams()))
416
#offset = net.get_offset()
417
#width_tile = self.width_tile.value
418
#size_tile = self.size_tile.value
419
420
for filename, bbox in zip(self.filenames.get_value(), self.bboxes.get_value()):
421
#x0, y0 = proj(bbox_lonlat[0][0], bbox_lonlat[0][1])
422
#x1, y1 = proj(bbox_lonlat[1][0],bbox_lonlat[1][1])
423
#bbox = np.array([[x0, y0, 0.0],[x1, y1 ,0.0]],np.float32)
424
425
#bbox_tile = [[x_sw,y_sw ],[x_ne,y_ne]]
426
#x0,y0 = bbox_abs[0]+offset
427
#x1,y1 = bbox_abs[1]+offset
428
429
#bbox = np.array([[x0, y0, 0.0],[x1, y1 ,0.0]],np.float32)
430
# print ' bbox decal',bbox
431
xc, yc = 0.5*(bbox[0]+bbox[1])-delta[:2]
432
zc = 0.0
433
width_tile = bbox[1, 0] - bbox[0, 0]
434
# print ' xc,yc',xc,yc
435
# print ' width_tile',width_tile,bbox
436
if filename == os.path.basename(filename):
437
# filename does not contain path info
438
filepath = filename # os.path.join(rootdir,filename)
439
else:
440
# filename contains path info (can happen if interactively inserted)
441
filepath = filename
442
443
calxml = '<decal filename="%s" centerX="%.2f" centerY="%.2f" centerZ="0.00" width="%.2f" height="%.2f" altitude="0.00" rotation="0.00" tilt="0.00" roll="0.00" layer="0.00"/>\n' % (
444
filepath, xc, yc, width_tile, width_tile)
445
fd.write(indent*' '+calxml)
446
447
def clear_all(self):
448
"""
449
Remove all map information.
450
"""
451
self.clear_rows()
452
# here we could also delete files ??
453
454
def update_netoffset(self, deltaoffset):
455
"""
456
Called when network offset has changed.
457
Children may need to adjust theur coordinates.
458
"""
459
bboxes = self.bboxes.get_value()
460
bboxes[:, :, :2] = bboxes[:, :, :2] + deltaoffset
461
462
def get_n_tiles(self, width_tile):
463
"""
464
Estimates number of necessary tiles.
465
"""
466
net = self.parent.get_net()
467
bbox_sumo, bbox_lonlat = net.get_boundaries()
468
x0 = bbox_sumo[0] # -0.5*width_tile
469
y0 = bbox_sumo[1] # -0.5*width_tile
470
width = bbox_sumo[2]-x0
471
height = bbox_sumo[3]-y0
472
nx = int(width/width_tile+0.5)
473
ny = int(height/width_tile+0.5)
474
return nx*ny
475
476
def download(self, maptype='satellite', mapserver='google', apikey=None,
477
filetype='png', rootfilepath=None,
478
width_tile=1000.0, size_tile=1280,
479
is_remove_orig=True):
480
481
self.clear_rows()
482
net = self.parent.get_net()
483
if rootfilepath is None:
484
rootfilepath = net.parent.get_rootfilepath()
485
486
bbox_sumo, bbox_lonlat = net.get_boundaries()
487
488
offset = net.get_offset()
489
# latlon_sw=np.array([bbox_lonlat[1],bbox_lonlat[0]],np.float32)
490
# latlon_ne=np.array([bbox_lonlat[3],bbox_lonlat[2]],np.float32)
491
492
x0 = bbox_sumo[0] # -0.5*width_tile
493
y0 = bbox_sumo[1] # -0.5*width_tile
494
width = bbox_sumo[2]-x0
495
height = bbox_sumo[3]-y0
496
497
print 'download to', rootfilepath
498
499
# '+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs'
500
#params_proj="+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
501
params_proj = net.get_projparams()
502
proj = pyproj.Proj(str(params_proj))
503
# print ' params_proj',params_proj,IS_MAPSUPPORT
504
# these values are measured manually and are only valid for size_tile = 256/640
505
# width_tile_eff= width_tile#*float(2*size_tile)/238.0#500m 1205.0*width_tile#m 1208
506
# height_tile_eff = width_tile#*float(2*size_tile)/238.0# 500m1144.0*width_tile#m 1140
507
508
nx = int(width/width_tile+0.5)
509
ny = int(height/width_tile+0.5)
510
print ' offset', offset
511
print ' bbox_sumo', bbox_sumo
512
print ' width_tile', width_tile, 'm'
513
print ' Will download %dx%d= %d maps' % (nx, ny, nx*ny)
514
#latlon_tile = np.array([(latlon_ne[0]-latlon_sw[0])/ny, (latlon_ne[1]-latlon_sw[1])/nx])
515
#filepaths = []
516
#centers = []
517
#
518
#
519
# 0 1
520
# 3 2
521
#
522
# 0 1 2 3
523
524
angle = None
525
bbox = None
526
ids_map = []
527
for ix in xrange(nx):
528
for iy in xrange(ny):
529
530
# tile in SUMO network coords. These are the saved coords
531
x_tile = x0+ix*width_tile
532
y_tile = y0+iy*width_tile
533
print ' x_tile,y_tile', x_tile, y_tile
534
bb = np.array([[x_tile, y_tile], [x_tile+width_tile, y_tile+width_tile]], np.float32)
535
536
# tile in absolute coordinates. Coords used for download
537
x_sw = x_tile-offset[0]
538
y_sw = y_tile-offset[1]
539
540
x_ne = x_sw+width_tile
541
y_ne = y_sw+width_tile
542
bbox_tile = [[x_sw, y_sw], [x_ne, y_ne]]
543
544
filepath = rootfilepath+'_map%04dx%04d.%s' % (ix, iy, filetype)
545
# print ' filepath=',filepath
546
547
if angle is None:
548
download_googlemap_bb(filepath, bbox_tile, proj, apikey,
549
size=size_tile,
550
filetype=filetype, maptype=maptype)
551
if os.path.getsize(filepath) > 2000: # download OK
552
angle, bbox = estimate_angle(filepath)
553
# sys.exit(0)
554
else:
555
print 'WARNING in download: no file downloaded from mapserver'
556
return ids_map
557
558
bbox_tile_lonlat = download_googlemap_bb(filepath, bbox_tile, proj, apikey,
559
size=size_tile, filetype=filetype,
560
maptype=maptype, color="0x0000000f")
561
562
if os.path.getsize(filepath) < 2000: # download failed
563
print 'WARNING in download: no file downloaded from mapserver'
564
return ids_map
565
566
print ' bbox_tile', bbox_tile
567
print ' bbox_tile_lonlat', bbox_tile_lonlat
568
569
im = Image.open(filepath).convert("RGB")
570
if 1:
571
print ' downloaded image', filepath, "%dx%d" % im.size, im.mode, im.getbands()
572
print ' x_sw,y_sw', x_sw, y_sw
573
print ' x_ne,y_ne', x_ne, y_ne
574
575
# print ' start rotation'
576
im_rot = im.rotate(angle) # gimp 1.62
577
# im_rot.show()
578
region = im_rot.crop([bbox[0][0], bbox[0][1], bbox[2][0], bbox[2][1]])
579
regsize = region.size
580
print ' regsize', regsize
581
im_crop = Image.new('RGB', (regsize[0], regsize[1]), (0, 0, 0))
582
im_crop.paste(region, (0, 0, regsize[0], regsize[1]))
583
im_tile = im_crop.resize((1024, 1024))
584
# im_crop.show()
585
outfilepath = rootfilepath+'_rot%04dx%04d.%s' % (ix, iy, filetype)
586
587
# print 'save ',outfilepath,"%dx%d" % im_crop.size,im_crop.getbands()
588
im_tile.save(outfilepath, filetype.upper())
589
590
# print ' bb_orig=',bb
591
print ' bb_orig', bb
592
#lon0, lat0 = proj(x_tile-offset[0], y_tile-offset[1])
593
#lon1, lat1 = proj(x_tile+width_tile-offset[0], y_tile+width_tile-offset[1])
594
595
# print ' bb',bb.shape,bb
596
# print ' outfilepath',outfilepath,os.path.basename(outfilepath)
597
# print ' saved bbox',np.array([[x_tile-offset[0], y_tile-offset[1]],[x_tile+width_tile-offset[0], y_tile+width_tile-offset[1]]],np.float32)
598
# print ' saved bbox',bbox_tile_lonlat
599
id_map = self.add_row(filenames=os.path.basename(outfilepath),
600
# bbox_tile,#bbox_tile_lonlat#np.array([[lon0, lat0],[lon1, lat1]],np.float32),
601
bboxes=bb,
602
)
603
ids_map.append(id_map)
604
605
if is_remove_orig:
606
# remove original file
607
os.remove(filepath)
608
609
return ids_map
610
611
612
class CsvElevationsImport(PlotoptionsMixin, CmlMixin, Process):
613
def __init__(self, landuse, rootname=None, rootdirpath=None, netfilepath=None,
614
is_clean_nodes=False, logger=None, **kwargs):
615
616
self._init_common('csvelevationsimporter', name='Elevations csv import',
617
logger=logger,
618
info='Imports the elevations .csv file with 3 colums (Longitudes, Latitudes, Elevations), starting from the first lane',
619
)
620
self._landuse = landuse
621
622
self.init_cml('netconvert')
623
624
attrsman = self.get_attrsman()
625
self.add_option('elevationscsv_filepath', '/home/cristian/scenarios_cri/Elevation/bo_elevations2.csv',
626
groupnames=['options'], # this will make it show up in the dialog
627
cml='--csv-elevation-file',
628
perm='rw',
629
name='Elevations file',
630
wildcards='Elevations CSV file(*.csv)|*.csv*',
631
metatype='filepath',
632
info='Elevations CSV file in',
633
)
634
635
self.interpolation_radius = attrsman.add(cm.AttrConf('interpolation_radius', kwargs.get('interpolation_radius', 150.),
636
groupnames=['options'],
637
name='Interpolation radius',
638
info='In order to find the quote of an unknown ponit, will be interpolated the elevation points around him within this radius.\
639
If it count zero, the point wil have the quote equal to the nearest elevation point. ',
640
))
641
642
# self.method_interp = attrsman.add(cm.AttrConf( 'method_interp', kwargs.get('method_interp', 'cubic'),
643
## groupnames = ['options'],
644
## choices = ['linear', 'cubic', 'quintic'],
645
## name = 'Interpolation method',
646
## info = 'Elevation interpolation method.',
647
# ))
648
649
self.x_offset = attrsman.add(cm.AttrConf('x_offset', kwargs.get('x_offset', -679244.),
650
groupnames=['options'],
651
perm='rw',
652
name='Longitude offset',
653
unit='m',
654
info='Longitude Offset for the importation phase.',
655
))
656
657
self.y_offset = attrsman.add(cm.AttrConf('y_offset', kwargs.get('y_offset', -4924610.),
658
groupnames=['options'],
659
perm='rw',
660
name='Latitude offset',
661
unit='m',
662
info='Latitude Offset for the importation phase.',
663
))
664
665
self.is_plot_elevations = attrsman.add(cm.AttrConf('is_plot_elevations', kwargs.get('is_plot_elevations', False),
666
groupnames=['options'],
667
perm='rw',
668
name='Plot Elevations',
669
info='Plot point elevations.',
670
))
671
672
# Match elevations
673
674
self.is_match_to_nodes = attrsman.add(cm.AttrConf('is_match_to_nodes', kwargs.get('is_match_to_nodes', True),
675
groupnames=['options'],
676
perm='rw',
677
name='Match to node',
678
info='Match the elevations to the network nodes.',
679
))
680
681
# self.is_match_to_nodes_shape = attrsman.add(cm.AttrConf( 'is_match_to_nodes_shape',kwargs.get('is_match_to_nodes_shape',True),
682
## groupnames = ['options'],
683
# perm='rw',
684
## name = 'Match to node shapes',
685
## info = 'Match the elevations to the network nodes shapes.',
686
# ))
687
688
# self.is_match_to_edge = attrsman.add(cm.AttrConf( 'is_match_to_node',kwargs.get('is_match_to_node',True),
689
## groupnames = ['options'],
690
# perm='rw',
691
## name = 'Match to node',
692
## info = 'Matche the elevations to the network nodes.',
693
# ))
694
695
self.is_match_to_edges = attrsman.add(cm.AttrConf('is_match_to_edges', kwargs.get('is_match_to_edges', True),
696
groupnames=['options'],
697
perm='rw',
698
name='Match to edge ',
699
info='Match the elevations to the network edges.',
700
))
701
702
self.is_match_to_zones = attrsman.add(cm.AttrConf('is_match_to_zones', kwargs.get('is_match_to_zones', True),
703
groupnames=['options'],
704
perm='rw',
705
name='Match to zones',
706
info='Match the elevations to the assignment zones.',
707
))
708
709
# self.is_match_to_zones_shape = attrsman.add(cm.AttrConf( 'is_match_to_zones_shape',kwargs.get('is_match_to_zones_shape',True),
710
## groupnames = ['options'],
711
# perm='rw',
712
## name = 'Match to node shapes',
713
## info = 'Match the elevations to the network nodes shapes.',
714
# ))
715
716
self.is_match_to_facilities = attrsman.add(cm.AttrConf('is_match_to_facilities', kwargs.get('is_match_to_facilities', True),
717
groupnames=['options'],
718
perm='rw',
719
name='Match to facilities',
720
info='Match the elevations to the facilities.',
721
))
722
723
# self.is_match_to_facilities_shape = attrsman.add(cm.AttrConf( 'is_match_to_facilities_shape',kwargs.get('is_match_to_facilities_shape',True),
724
## groupnames = ['options'],
725
# perm='rw',
726
## name = 'Match to facility shapes',
727
## info = 'Match the elevations to the facility shapes.',
728
# ))
729
730
self.add_plotoptions(**kwargs)
731
self.add_save_options(**kwargs)
732
attrsman.delete('plottype')
733
attrsman.delete('length_arrowhead')
734
735
def do(self):
736
737
net = self._landuse.parent.net
738
739
with open(self.elevationscsv_filepath, 'r') as csvFile:
740
reader = csv.reader(csvFile)
741
i = 1
742
longitudes = []
743
latitudes = []
744
elevations = []
745
ids_point = []
746
for row in reader:
747
748
longitudes.append(float(row[0]))
749
latitudes.append(float(row[1]))
750
elevations.append(float(row[2]))
751
ids_point.append(i)
752
i += 1
753
754
ids_point = np.array(ids_point)
755
longitudes = np.array(longitudes) + self.x_offset
756
latitudes = np.array(latitudes) + self.y_offset
757
elevations = np.array(elevations)
758
759
csvFile.close()
760
#################################################################################
761
quote = self.evaluate_quote(longitudes, latitudes, elevations, 2000., 10000.)
762
quote = self.evaluate_quote(longitudes, latitudes, elevations, 4000., 7000.)
763
quote = self.evaluate_quote(longitudes, latitudes, elevations, 7000., 11000.)
764
quote = self.evaluate_quote(longitudes, latitudes, elevations, 10000., 3000.)
765
###################################################
766
767
if self.is_match_to_nodes:
768
nodes = net.nodes
769
ids_node = nodes.get_ids()
770
coords = nodes.coords[ids_node]
771
for coord, id_node in zip(coords, ids_node):
772
773
quote = self.evaluate_quote(longitudes, latitudes, elevations, coord[0], coord[1])
774
775
nodes.coords[id_node] = [coord[0], coord[1], quote]
776
# print 'node_coord', nodes.coords[id_node]
777
778
shapes = nodes.shapes[ids_node]
779
for shape, id_node in zip(shapes, ids_node):
780
for coord, i in zip(shape, range(len(shape))):
781
# print coord
782
# print np.stack((longitudes, latitudes), axis = -1)
783
quote = self.evaluate_quote(longitudes, latitudes, elevations, coord[0], coord[1])
784
nodes.shapes[id_node][i] = [coord[0], coord[1], quote]
785
# print 'node_shape', nodes.shapes[id_node]
786
787
# coord[0]
788
# coord[1]
789
790
if self.is_match_to_edges:
791
edges = net.edges
792
ids_edge = edges.get_ids()
793
shapes = edges.shapes[ids_edge]
794
for shape, id_edge in zip(shapes, ids_edge):
795
positive_climb = 0.
796
negative_climb = 0.
797
for coord, i in zip(shape, range(len(shape))):
798
# print coord
799
# print np.stack((longitudes, latitudes), axis = -1)
800
quote = self.evaluate_quote(longitudes, latitudes, elevations, coord[0], coord[1])
801
802
edges.shapes[id_edge][i] = [coord[0], coord[1], quote]
803
print edges.shapes[id_edge][i]
804
if i > 0 and (quote-quote_pre) > 0:
805
positive_climb += (quote-quote_pre)
806
elif i > 0 and (quote-quote_pre) < 0:
807
negative_climb += (-quote + quote_pre)
808
quote_pre = quote
809
# print 'edge_shape', edges.shapes[id_edge][i]
810
slope = (edges.shapes[id_edge][-1][2]-edges.shapes[id_edge][0][2])/edges.lengths[id_edge]
811
edges.average_slopes[id_edge] = slope
812
edges.positive_climbs[id_edge] = positive_climb
813
edges.negative_climbs[id_edge] = negative_climb
814
# print 'slope', slope
815
816
# if self.is_match_to_zones:
817
##
818
# if self.is_match_to_facilities:
819
820
#######################
821
if self.is_plot_elevations:
822
fig = plt.figure()
823
ax = fig.add_subplot(111)
824
## import matplotlib
825
## import matplotlib.pyplot as plt
826
## cm = matplotlib.cm.get_cmap('RdYlBu')
827
# plt.subplot(111)
828
## plt.scatter(longitudes, latitudes, c=elevations, s=20, vmax = 70)
829
# plt.colorbar()
830
# plt.show()
831
plot_point_results_on_map(self, net, ax, longitudes, latitudes, values=elevations,
832
title='Elevations', valuelabel='[m]',
833
)
834
plt.show()
835
############################################
836
837
return True
838
839
def evaluate_quote(self, longitudes, latitudes, elevations, x_point, y_point):
840
841
dists = np.sqrt(np.sum((np.stack((longitudes, latitudes), axis=-1) - [x_point, y_point])**2, 1))
842
843
if is_scipy:
844
print 'use scipy to interpolate'
845
#tck = interpolate.splrep(x, y, s=0)
846
#xnew = np.linspace(np.min(x), np.max(x), 200)
847
#ynew = interpolate.splev(xnew, tck, der=0)
848
# if 1:
849
850
nearest_longitudes = longitudes[(dists < self.interpolation_radius)]
851
nearest_latitudes = latitudes[(dists < self.interpolation_radius)]
852
nearest_elevations = elevations[(dists < self.interpolation_radius)]
853
## nearest_longitudes = longitudes[(longitudes < x_point + self.interpolation_radius)&(longitudes > x_point - self.interpolation_radius)&(latitudes < y_point + self.interpolation_radius)&(latitudes > y_point - self.interpolation_radius)]
854
## nearest_latitudes = latitudes[(longitudes < x_point + self.interpolation_radius)&(longitudes > x_point - self.interpolation_radius)&(latitudes < y_point + self.interpolation_radius)&(latitudes > y_point - self.interpolation_radius)]
855
## nearest_elevations = elevations[(longitudes < x_point + self.interpolation_radius)&(longitudes > x_point - self.interpolation_radius)&(latitudes < y_point + self.interpolation_radius)&(latitudes > y_point - self.interpolation_radius)]
856
print[x_point, y_point], nearest_longitudes, nearest_latitudes, nearest_elevations
857
if len(nearest_longitudes) > 15:
858
859
f_inter = interpolate.SmoothBivariateSpline(
860
nearest_longitudes, nearest_latitudes, nearest_elevations,) # kind = self.method_interp )
861
## #############################################
862
## xnew = np.linspace(x_point-self.interpolation_radius/2, x_point+self.interpolation_radius/2,200)
863
## ynew = np.linspace(y_point-self.interpolation_radius/2, y_point+self.interpolation_radius/2,200)
864
## X, Y = np.meshgrid(xnew, ynew)
865
## Z = f_inter(xnew, ynew)
866
##
867
##
868
## fig = plt.figure()
869
## ax = fig.gca(projection='3d')
870
##
871
##
872
# Plot the surface.
873
# surf = ax.plot_surface(X, Y, Z, cmap=cmp.coolwarm,
874
# linewidth=0, antialiased=False)
875
##
876
## fig.colorbar(surf, shrink=0.5, aspect=5)
877
# plt.savefig('/home/cristian/scenarios_cri/Elevation/interpolation_%d'%(xnew[0]))
878
# plt.show()
879
#############################################
880
quote = f_inter(x_point, y_point)
881
else:
882
quote = elevations[np.argmin(dists)]
883
print 'nearest quote'
884
else:
885
886
nearest_quotes = elevations[(dists < 100)]
887
nearest_dists = dists[(dists < 100)]
888
numerator = 0.0
889
denominator = 0.0
890
for near_quote, near_dist in zip(nearest_quotes, nearest_dists):
891
numerator += near_quote/(10**(near_dist/10))
892
denominator += 1/(10**(near_dist/10))
893
# print numerator, denominator
894
if denominator != 0:
895
quote = numerator/denominator
896
else:
897
quote = elevations[np.argmin(dists)]
898
print 'nearest quote'
899
900
return quote
901
902
903
if __name__ == '__main__':
904
############################################################################
905
###
906
pass
907
908