Package viewer :: Module sim_viewer
[hide private]
[frames] | no frames]

Source Code for Module viewer.sim_viewer

   1  #!/usr/bin/python 
   2  # -*- coding: utf-8 -*- 
   3   
   4  """A viewer for the MoSP simulator. 
   5   
   6  It uses a socket to receive geometric objects from the simulation and draws these onto a layer of OpenStreetMap-map-tiles. 
   7   
   8  @todo: draw triangles!!! 
   9  @todo: Zoom fit to BBox (Hmm...maybe trial and error is possible...might be tricky...) 
  10  @todo: Zoom to double click position (double clicks should be easy, accurate centering on coordinates is not supportet right now...could be hard) 
  11  """ 
  12   
  13  import time 
  14  import os 
  15  import struct 
  16  import math 
  17   
  18  import socket 
  19   
  20  import pyglet 
  21  # Disable error checking for increased performance 
  22  pyglet.options['debug_gl'] = False 
  23  from pyglet import gl 
  24  from pyglet.window import key, mouse 
  25   
  26  from lib import tilenames as tiles 
  27  from lib.tileloader2 import TileLoader 
  28  from lib.calculations import * 
  29   
  30  __author__ = "P. Tute" 
  31  __maintainer__ = "B. Henne" 
  32  __contact__ = "henne@dcsec.uni-hannover.de" 
  33  __copyright__ = "(c) 2011-2012, DCSec, Leibniz Universitaet Hannover, Germany" 
  34  __license__ = "GPLv3" 
  35   
  36   
  37  TILE_SIZE = 256     #: The size of one OSM-tile in pixels. This is constant as long as OSM does not change. 
  38  KEYBOARD_SCROLL_VALUE = 50 #: Scrolling by keyboard will move the camera by this many pixels. 
  39   
  40   
  41  MESSAGE_TYPES = {'\x00': 'coords', 
  42                   '\x01': 'point', 
  43                   '\x02': 'rectangle', 
  44                   '\x03': 'circle', 
  45                   '\x04': 'triangle', 
  46                   '\x05': 'text', 
  47                   '\x06': 'heatmap', 
  48                   '\x07': 'direct-text', 
  49                   '\xFD': 'delete', 
  50                   '\xFE': 'draw', 
  51                   '\xFF': 'simulation_ended', 
  52                   }  #: Supported message types for lookup after receiving an identifier. 
  53   
  54   
  55  MESSAGE_SIZE = {'\x00': struct.calcsize('!dd'), 
  56                  '\x01': struct.calcsize('!iddi4dd'), 
  57                  '\x02': struct.calcsize('!i4di?4dd'), 
  58                  '\x03': struct.calcsize('!iddi?4dd'), 
  59                  '\x04': struct.calcsize('!i2d2d2d?4dd'), 
  60                  '\x05': struct.calcsize('!iddiii4did'), 
  61                  '\x06': struct.calcsize('!ddi4d'), 
  62                  '\x07': struct.calcsize('!iiii4did'), 
  63                  '\xFD': struct.calcsize('!i'), 
  64                  }   #: The precalculated size of commonly used structs. 
  65   
  66   
  67  ID_TYPE_PREFIX = {'\x00': 0, 
  68                    '\x01': 0, 
  69                    '\x02': 100000, 
  70                    '\x03': 200000, 
  71                    '\x04': 300000, 
  72                    '\x05': 0, 
  73                    } #: These values will be added to the IDs of the respecting object. This is necessary to be able to differentiate between them after they are mixed together for faster calculations. 
  74   
  75   
  76  PIXEL_DISTANCE = {} #: precalculate lat/lon distance when moving one pixel for each zoom-level 
  77  for i in xrange(19): 
  78      left = tiles.xy2latlon(0, 0, i)[1] 
  79      right =  tiles.xy2latlon(1, 0, i)[1] 
  80      PIXEL_DISTANCE[i] = (right - left) / TILE_SIZE 
  81   
82 -class SimViewer(pyglet.window.Window):
83 84 """A tool for displaying mosp-simulations. 85 86 @author: P. Tute 87 88 """ 89
90 - def __init__(self, lat=0, lon=0, zoom=15, host='localhost', port=60001, ugly_drag=False, **kwargs):
91 """Initialize the viewer. 92 93 @param lat: Latitude to center view on (default 0). 94 @type lat: float 95 @param lon: Longitude to center view on (default 0). 96 @type lon: float 97 @param zoom: OSM-zomm-level to start with (default 16). 98 @type zoom: int in range [0, 18] 99 @param host: The host running the simulation (default 'localhost'). 100 @type host: string 101 @param port: The port used by the simulation (default 60001). 102 @type port: int 103 @param ugly_drag: If set to True, dragging the map with the mouse will look uglier, but run faster (default False). 104 @param kwargs: @see http://pyglet.org/doc/api/pyglet.window.Window-class.html#__init__ 105 106 """ 107 108 super(SimViewer, self).__init__(**kwargs) 109 110 # defines, how many tiles must be drawn on each side of the center one 111 self.number_of_tiles = -1 112 # drawing offset to not start drawing tiles at (0, 0) but somewhat out of the visible area 113 # this should improve the feeling of scrolling and zooming... 114 self.drawing_offset = 0 115 self.zoom = zoom 116 self.center_x, self.center_y = tiles.latlon2xy(lat, lon, self.zoom) 117 # set new center_lat and center_lon to middle of center tile to avoid complications 118 self.center_lat, self.center_lon = tiles.xy2latlon(self.center_x, self.center_y, self.zoom) 119 self.default_lat, self.default_lon = self.center_lat, self.center_lon 120 self.offset_x , self.offset_y = 0, 0 121 self.ugly_drag = ugly_drag 122 123 self.cache_dir = '.cache' 124 self.data_dir = 'data' 125 self.screenshot_dir = 'screenshots' 126 self.not_found_image = os.path.join(self.data_dir, 'image_not_found.png') 127 try: 128 os.mkdir(self.cache_dir) 129 print 'No cache folder found. Creating it.' 130 except OSError: 131 print 'Found cache folder.' 132 133 try: 134 os.mkdir(self.screenshot_dir) 135 except OSError: 136 pass 137 timestamp = time.localtime() 138 self.current_sc_dir = str(timestamp.tm_year) + '.' + str(timestamp.tm_mon) + '.' + str(timestamp.tm_mday) 139 try: 140 os.mkdir(os.path.join(self.screenshot_dir, self.current_sc_dir)) 141 except OSError: 142 pass 143 144 # color used as background. Here a light grey is used 145 pyglet.gl.glClearColor(0.8,0.8,0.8,1.0) 146 # indicates if mouse-dragging happened, so on_mouse_release() can react 147 self.mouse_drag = False 148 self.draw_fps = True 149 # indicators to signal if the simulation has ended and if the end-screen should be shown 150 self.ended = False 151 self.draw_end_overlay = False 152 self.end_text1 = 'End of simulation.' 153 self.end_label1 = pyglet.text.Label(self.end_text1, 154 font_name='Times New Roman', 155 font_size=36, 156 color=(255, 255, 255, 255), 157 x=self.width/2, y=self.height/2, 158 anchor_x='center', anchor_y='center') 159 self.end_text2 = '(C)onnect to a new one? Show (l)ast screen? (Q)uit?' 160 self.end_label2 = pyglet.text.Label(self.end_text2, 161 font_name='Times New Roman', 162 font_size=18, 163 color=(255, 255, 255, 255), 164 x=self.width/2, y=self.height/2-80, 165 anchor_x='center', anchor_y='center') 166 167 self.copyright_text = u'Maps \xa9 OpenStreetMap contributors, CC-BY-SA' 168 self.copyright_label = pyglet.text.Label(self.copyright_text, 169 font_name='Times New Roman', 170 font_size=10, 171 color=(0, 0, 0, 255), 172 x=0, y=0, 173 anchor_x='right', anchor_y='bottom') 174 self.fps = 0 175 self.last_draw = 0 176 self.fps_label = pyglet.text.Label(str(int(self.fps)), 177 font_name='Times New Roman', 178 font_size=14, 179 color=(0, 0, 0, 255), 180 x=20, y=20, 181 anchor_x='center', anchor_y='center') 182 183 self.tiles = {} 184 self.tiles_used = {} 185 self.tileloader = TileLoader(tile_list=self.tiles, cache_dir=self.cache_dir) 186 187 # batched drawing to increase performance 188 self.drawing_batch = pyglet.graphics.Batch() 189 self.points = {} 190 self.rectangles = {} 191 self.circles = {} 192 self.triangles = {} 193 self.text_data = {} 194 self.text_objects = {} 195 self.direct_text_objects = {} 196 self.point_coords = {} 197 self.point_coords_offset = [] 198 self.point_colors = {} 199 self.point_colors_all = [] 200 self.point_vertex_list = self.drawing_batch.add(1, gl.GL_POINTS, None, 201 ('v2i/stream', (0, 0)), 202 ('c4d/stream', (0, 0, 0, 0))) 203 self.quad_coords = {} 204 self.quad_coords_offset = [] 205 self.quad_colors = {} 206 self.quad_colors_all = [] 207 self.quad_vertex_list = self.drawing_batch.add(1, gl.GL_QUADS, None, 208 ('v2i/stream', (0, 0)), 209 ('c4d/stream', (0, 0, 0, 0))) 210 self.triangle_coords = {} 211 self.triangle_coords_offset = [] 212 self.triangle_colors = {} 213 self.triangle_colors_all = [] 214 self.triangle_vertex_list = self.drawing_batch.add(1, gl.GL_TRIANGLES, None, 215 ('v2i/stream', (0, 0)), 216 ('c4d/stream', (0, 0, 0, 0))) 217 self.line_loop_coords = {} 218 self.line_loop_colors = {} 219 self.line_loop_vertex_lists = {} 220 self.polygon_coords = {} 221 self.polygon_colors = {} 222 self.polygon_vertex_lists = {} 223 self.heatmap_batch = pyglet.graphics.Batch() 224 self.heatmap_data = [] 225 self.heatmap_point_coords = [] 226 self.heatmap_point_coords_offset = [] 227 self.heatmap_point_colors = [] 228 self.heatmap_point_list = self.heatmap_batch.add(1, gl.GL_POINTS, None, 229 ('v2i/stream', (0, 0)), 230 ('c4d/stream', (0, 0, 0, 0))) 231 self.heatmap_quad_coords = [] 232 self.heatmap_quad_coords_offset = [] 233 self.heatmap_quad_colors = [] 234 self.heatmap_quad_list = self.heatmap_batch.add(1, gl.GL_QUADS, None, 235 ('v2i/stream', (0, 0)), 236 ('c4d/stream', (0, 0, 0, 0))) 237 238 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 239 self.socket.setblocking(0) 240 self.host = host 241 self.port = port 242 try: 243 print 'connecting' 244 self.socket.connect((self.host, self.port)) 245 print 'connected' 246 except socket.error as (errno, message): 247 if errno == 115: # Linux 248 # [Errno 115] Operation now in progress 249 # ... since we use non-blocking sockets 250 # this exception is not needed 251 pass 252 elif errno == 36: # same for OS X 253 pass 254 else: 255 print 'error while connecting' 256 print '\t', errno, message 257 raise 258 259 pyglet.clock.schedule_interval(self.receive, 1/30.0) 260 pyglet.clock.schedule_interval(self.on_draw, 1/60.0) 261 pyglet.clock.schedule_interval(self.reload_tiles, 0.5)
262
263 - def receive(self, dt):
264 """Receive data from a given port and parse it to create drawable objects. 265 266 @param dt: Time since last call. Necessary for pyglet-scheduling, ignored here. 267 @author: P. Tute 268 269 """ 270 271 new_points = {} 272 new_rects = {} 273 new_circles = {} 274 new_triangles = {} 275 new_texts = {} 276 new_heatmap = [] 277 while True: 278 try: 279 message_type = self.socket.recv(1) 280 if message_type == '': 281 # no data to be read...try again later 282 break 283 if MESSAGE_TYPES[message_type] == 'delete': 284 type = self.socket.recv(1) 285 id = struct.unpack('!i', self.socket.recv(MESSAGE_SIZE[message_type]))[0] 286 self.remove_drawing(0, type, id) 287 elif MESSAGE_TYPES[message_type] == 'coords': 288 lat, lon = struct.unpack('!dd', self.socket.recv(MESSAGE_SIZE[message_type])) 289 self.default_lat, self.default_lon = lat, lon 290 self.center_x, self.center_y = tiles.latlon2xy(lat, lon, self.zoom) 291 self.center_x -= 1 292 self.center_lat, self.center_lon = tiles.xy2latlon(self.center_x, self.center_y, self.zoom) 293 self.offset_x , self.offset_y = 0, 0 294 self.update_tiles() 295 elif MESSAGE_TYPES[message_type] == 'point': 296 # pid, lat, lon, rad, r, g, b, a, ttl 297 data = self.socket.recv(MESSAGE_SIZE[message_type]) 298 point = struct.unpack('!iddi4dd', data) 299 new_points[point[0] + ID_TYPE_PREFIX[message_type]] = point[1:] 300 if point[8] > 0: 301 pyglet.clock.schedule_once(self.remove_drawing, point[8], message_type, point[0]) 302 elif MESSAGE_TYPES[message_type] == 'rectangle': 303 # rid, minlat, minlon, maxlat, maxlon, line-width, filled?, r, g, b, a, ttl 304 data = self.socket.recv(MESSAGE_SIZE[message_type]) 305 rect = struct.unpack('!i4di?4dd', data) 306 new_rects[rect[0] + ID_TYPE_PREFIX[message_type]] = rect[1:] 307 if rect[11] > 0: 308 pyglet.clock.schedule_once(self.remove_drawing, rect[11], message_type, rect[0]) 309 elif MESSAGE_TYPES[message_type] == 'circle': 310 # cid, lat, lon, radius, filled?, r, g, b, a, ttl 311 data = self.socket.recv(MESSAGE_SIZE[message_type]) 312 circle = struct.unpack('!iddi?4dd', data) 313 new_circles[circle[0] + ID_TYPE_PREFIX[message_type]] = circle[1:] 314 if circle[9] > 0: 315 pyglet.clock.schedule_once(self.remove_drawing, circle[9], message_type, circle[0]) 316 elif MESSAGE_TYPES[message_type] == 'triangle': 317 # trid, lat/lon1, lat/lon2, lat/lon3, filled?, r, g, b, a, ttl 318 data = self.socket.recv(MESSAGE_SIZE[message_type]) 319 triangle = struct.unpack('!i2d2d2d?4dd', data) 320 new_triangles[triangle[0] + ID_TYPE_PREFIX[message_type]] = triangle[1:] 321 print triangle[12] 322 if triangle[12] > 0: 323 pyglet.clock.schedule_once(self.remove_drawing, triangle[12], message_type, triangle[0]) 324 elif MESSAGE_TYPES[message_type] =='text': 325 # tid, lat, lon, x-off, y-off, fsize, r, g, b, a, tsize, ttl 326 data = self.socket.recv(MESSAGE_SIZE[message_type]) 327 text_data = struct.unpack('!iddiii4did', data) 328 text_content = struct.unpack('!' + 'c' * text_data[10], self.socket.recv(struct.calcsize('!' + 'c' * text_data[10]))) 329 text_data_list = list(text_data[1:]) 330 text_data_list.append(text_content) 331 new_texts[text_data[0]] = text_data_list 332 if text_data[11] > 0: 333 pyglet.clock.schedule_once(self.remove_drawing, text_data[11], message_type, text_data[0]) 334 elif MESSAGE_TYPES[message_type] == 'heatmap': 335 # lat, lon, rad, r, g, b, a 336 data = self.socket.recv(MESSAGE_SIZE[message_type]) 337 hm = struct.unpack('!ddi4d', data) 338 self.heatmap_data.append(hm) 339 new_heatmap.append(hm) 340 elif MESSAGE_TYPES[message_type] == 'direct-text': 341 # x, y, fsize, r, g, b, a, tsize, ttl 342 data = self.socket.recv(MESSAGE_SIZE[message_type]) 343 id, x, y, fsize, r, g, b, a, tsize, ttl = struct.unpack('!iiii4did', data) 344 if x < 0: 345 x = self.width + x #draw text from right side 346 if y < 0: 347 y = self.height + y #draw text from top 348 text_content = struct.unpack('!' + 'c' * tsize, self.socket.recv(struct.calcsize('!' + 'c' * tsize))) 349 self.direct_text_objects[id] = pyglet.text.Label("".join(text_content), 350 font_name='Times New Roman', 351 font_size=fsize, 352 color = tuple([int(i * 255) for i in (r, g, b, a)]), 353 x=x, y=y, 354 anchor_x='left', anchor_y='bottom') 355 elif MESSAGE_TYPES[message_type] == 'draw': 356 self.update_coordinates(new_points, new_rects, new_circles, new_triangles, new_texts, new_heatmap) 357 self.update_vertex_lists() 358 break 359 elif MESSAGE_TYPES[message_type] == 'simulation_ended': 360 self.ended = True 361 self.draw_end_overlay = True 362 else: 363 #should not happen 364 print '\twtf', repr(message_type) 365 break 366 except socket.error as (errno, msg): 367 if errno != 11: 368 raise 369 else: 370 # [Errno 11] Resource temporarily unavailable 371 # might happen, if no data is available from the simulation, try again later 372 break
373
374 - def update_coordinates(self, points=None, rects=None, circles=None, triangles=None, texts=None, hms=None, all=False):
375 """Calculate all coordinates necessary for drawing received points, rectangles and circles. 376 377 @param points: Points whose coordinates need to be calculated 378 @type points: dict 379 @param rects: Rectangles whose coordinates need to be calculated 380 @type rects: dict 381 @param circles: Circles whose coordinates need to be calculated 382 @type circles: dict 383 @param texts: Texts whose coordinates need to be calculated 384 @type texts: dict 385 @param hms: Heatmap-blips whose coordinates need to be calculated 386 @type hms: list 387 @param all: If all is True, all known coordinates will be redrawn. Other passed arguments will be ignored. 388 @type all: boolean 389 @author: P. Tute 390 391 """ 392 393 # calculate coords for points 394 if not points: 395 # prevent errors if points is None 396 points = {} 397 if all: 398 # recalculate all known coordinates 399 points = self.points 400 for point in points: 401 self.points[point] = points[point] 402 (lat, lon, rad, r, g, b, a, ttl) = points[point] 403 x, y = latlon_to_xy(lat, lon, self.zoom, self) 404 if rad > 0: 405 # using GL_QUADS should be faster when drawing points with more than one pixel 406 coords = [] 407 coords.append(x - rad) 408 coords.append(y - rad) 409 coords.append(x + rad) 410 coords.append(y - rad) 411 coords.append(x + rad) 412 coords.append(y + rad) 413 coords.append(x - rad) 414 coords.append(y + rad) 415 self.quad_coords[point] = coords 416 self.quad_colors[point] = [r, g, b, a] * 4 417 else: 418 self.point_coords[point] = [x, y] 419 self.point_colors[point] = [r, g, b, a] 420 421 # calculate coords for rectangles 422 if not rects: 423 rects = {} 424 if all: 425 rects = self.rectangles 426 for rect in rects: 427 self.rectangles[rect] = rects[rect] 428 (minlat, minlon, maxlat, maxlon, line_width, filled, r, g, b, a, ttl) = rects[rect] 429 x_left, y_bottom = latlon_to_xy(minlat, minlon, self.zoom, self) 430 x_right, y_top = latlon_to_xy(maxlat, maxlon, self.zoom, self) 431 coords = [] 432 if filled: 433 # use GL_QUADS to draw filled rectangle 434 coords.append(x_left) 435 coords.append(y_bottom) 436 coords.append(x_right) 437 coords.append(y_bottom) 438 coords.append(x_right) 439 coords.append(y_top) 440 coords.append(x_left) 441 coords.append(y_top) 442 self.quad_coords[rect] = coords 443 self.quad_colors[rect] = [r, g, b, a] * 4 444 else: 445 # each shape with GL_LINE_LOOP must be drawn seperately 446 # otherwise all shapes will be connected 447 # because of this the usage of Batch is not possible here 448 449 # draw with width of at least one pixel 450 rad = 1 if line_width < 1 else line_width 451 self.line_loop_colors[rect] = [] 452 for i in xrange(rad): 453 coords.extend((x_left + i, 454 y_bottom + i, 455 x_right - i, 456 y_bottom + i, 457 x_right - i, 458 y_top - i, 459 x_left + i, 460 y_top - i)) 461 self.line_loop_colors[rect].extend((r, b, g, a) * 4) 462 self.line_loop_coords[rect] = coords 463 if not rect in self.line_loop_vertex_lists: 464 self.line_loop_vertex_lists[rect] = pyglet.graphics.vertex_list(len(coords) / 2, 465 'v2i', 'c4d') 466 if not circles: 467 circles = {} 468 if all: 469 circles = self.circles 470 for circle in circles: 471 self.circles[circle] = circles[circle] 472 (lat, lon, rad, filled, r, g, b, a, ttl) = circles[circle] 473 rad = self.meters_to_pixels(rad) 474 x, y = latlon_to_xy(lat, lon, self.zoom, self) 475 coords = bresenham_circle(x, y, rad) 476 colors = [r, g, b, a] * (len(coords) / 2) 477 478 if filled: 479 self.polygon_coords[circle] = coords 480 self.polygon_colors[circle] = colors 481 if not circle in self.polygon_vertex_lists: 482 self.polygon_vertex_lists[circle] = pyglet.graphics.vertex_list(len(coords) / 2, 483 'v2i', 'c4d') 484 else: 485 self.point_coords[circle] = coords 486 self.point_colors[circle] = colors 487 488 if not triangles: 489 triangles = {} 490 if all: 491 triangles = self.triangles 492 for tri in triangles: 493 self.triangles[tri] = triangles[tri] 494 (lat1, lon1, lat2, lon2, lat3, lon3, filled, r, g, b, a, ttl) = triangles[tri] 495 x_1, y_1 = latlon_to_xy(lat1, lon1, self.zoom, self) 496 x_2, y_2 = latlon_to_xy(lat2, lon2, self.zoom, self) 497 x_3, y_3 = latlon_to_xy(lat3, lon3, self.zoom, self) 498 coords = [x_1, y_1, x_2, y_2, x_3, y_3] 499 if filled: 500 # use GL_TRIANGLES for filled triangle 501 self.triangle_coords[tri] = coords 502 self.triangle_colors[tri] = [r, g, b, a] * 3 503 else: 504 # use GL_LINE_LOOP for hollow triangle 505 self.line_loop_colors[tri] = [r, g, b, a] * 3 506 self.line_loop_coords[tri] = coords 507 if not tri in self.line_loop_vertex_lists: 508 self.line_loop_vertex_lists[tri] = pyglet.graphics.vertex_list(len(coords) / 2, 509 'v2i', 'c4d') 510 511 if not texts: 512 texts = {} 513 if all: 514 texts = self.text_data 515 for text in texts: 516 self.text_data[text] = texts[text] 517 (lat, lon, x_off, y_off, fsize, r, g, b, a, tsize, ttl, content) = texts[text] 518 x, y = latlon_to_xy(lat, lon, self.zoom, self) 519 x += self.meters_to_pixels(x_off) + self.offset_x + self.drawing_offset 520 y += self.meters_to_pixels(y_off) + self.offset_y + self.drawing_offset 521 self.text_objects[text] = pyglet.text.Label("".join(content), 522 font_name='Times New Roman', 523 font_size=fsize, 524 color = tuple([int(i * 255) for i in (r, g, b, a)]), 525 x=x, y=y, 526 anchor_x='left', anchor_y='bottom') 527 528 # calculate heatmap coords 529 if not hms: 530 hms = [] 531 if all: 532 hms = self.heatmap_data 533 self.heatmap_point_coords = [] 534 self.heatmap_point_colors = [] 535 self.heatmap_quad_coords = [] 536 self.heatmap_quad_colors = [] 537 for hm in hms: 538 x, y = latlon_to_xy(hm[0], hm[1], self.zoom, self) 539 rad = hm[2] 540 color = hm[3:] 541 if rad > 0: 542 self.heatmap_quad_coords.append(x - rad) 543 self.heatmap_quad_coords.append(y - rad) 544 self.heatmap_quad_coords.append(x + rad) 545 self.heatmap_quad_coords.append(y - rad) 546 self.heatmap_quad_coords.append(x + rad) 547 self.heatmap_quad_coords.append(y + rad) 548 self.heatmap_quad_coords.append(x - rad) 549 self.heatmap_quad_coords.append(y + rad) 550 self.heatmap_quad_colors.extend(color * 4) 551 else: 552 self.heatmap_point_coords.append(x) 553 self.heatmap_point_coords.append(y) 554 self.heatmap_point_colors.extend(color)
555
556 - def update_vertex_lists(self):
557 """Add offsets to coordinates and update the used VertexLists.""" 558 559 # update points 560 if len(self.point_coords) > 0: 561 coords = [] 562 self.point_colors_all = [] 563 for point in self.point_coords: 564 coords.extend(self.point_coords[point]) 565 self.point_colors_all.extend(self.point_colors[point]) 566 self.point_coords_offset = [] 567 for i, coord in enumerate(coords): 568 if not i%2: 569 # x-values 570 self.point_coords_offset.append(coord + self.offset_x + self.drawing_offset) 571 else: 572 self.point_coords_offset.append(coord + self.offset_y + self.drawing_offset) 573 574 # update quads 575 if len(self.quad_coords) > 0: 576 coords = [] 577 self.quad_colors_all = [] 578 for quad in self.quad_coords: 579 coords.extend(self.quad_coords[quad]) 580 self.quad_colors_all.extend(self.quad_colors[quad]) 581 self.quad_coords_offset = [] 582 for i, coord in enumerate(coords): 583 if not i%2: 584 # x-values 585 self.quad_coords_offset.append(coord + self.offset_x + self.drawing_offset) 586 else: 587 self.quad_coords_offset.append(coord + self.offset_y + self.drawing_offset) 588 589 # update triangles 590 if len(self.triangle_coords) > 0: 591 coords = [] 592 self.triangle_colors_all = [] 593 for triangle in self.triangle_coords: 594 coords.extend(self.triangle_coords[triangle]) 595 self.triangle_colors_all.extend(self.triangle_colors[triangle]) 596 self.triangle_coords_offset = [] 597 for i, coord in enumerate(coords): 598 if not i%2: 599 # x-values 600 self.triangle_coords_offset.append(coord + self.offset_x + self.drawing_offset) 601 else: 602 self.triangle_coords_offset.append(coord + self.offset_y + self.drawing_offset) 603 604 # update line_loops 605 if len(self.line_loop_coords) > 0: 606 for line in self.line_loop_coords: 607 coords = self.line_loop_coords[line] 608 colors = self.line_loop_colors[line] 609 coords_updated = [] 610 for i, coord in enumerate(coords): 611 if not i%2: 612 # x-values 613 coords_updated.append(coord + self.offset_x + self.drawing_offset) 614 else: 615 coords_updated.append(coord + self.offset_y + self.drawing_offset) 616 if self.line_loop_vertex_lists[line].get_size() != len(coords_updated) / 2: 617 self.line_loop_vertex_lists[line].resize(len(coords_updated) / 2) 618 self.line_loop_vertex_lists[line].vertices = coords_updated 619 self.line_loop_vertex_lists[line].colors = colors 620 621 # update polygons 622 if len(self.polygon_coords) > 0: 623 for tri in self.polygon_coords: 624 coords = self.polygon_coords[tri] 625 colors = self.polygon_colors[tri] 626 coords_updated = [] 627 for i, coord in enumerate(coords): 628 if not i%2: 629 # x-values 630 coords_updated.append(coord + self.offset_x + self.drawing_offset) 631 else: 632 coords_updated.append(coord + self.offset_y + self.drawing_offset) 633 if self.polygon_vertex_lists[tri].get_size() != len(coords_updated) / 2: 634 self.polygon_vertex_lists[tri].resize(len(coords_updated) / 2) 635 self.polygon_vertex_lists[tri].vertices = coords_updated 636 self.polygon_vertex_lists[tri].colors = colors 637 638 # update heatmap 639 if len(self.heatmap_point_coords) > 0: 640 self.heatmap_point_coords_offset = [] 641 for i, coord in enumerate(self.heatmap_point_coords): 642 if not i%2: 643 # x-values 644 self.heatmap_point_coords_offset.append(coord + self.offset_x + self.drawing_offset) 645 else: 646 self.heatmap_point_coords_offset.append(coord + self.offset_y + self.drawing_offset) 647 if len(self.heatmap_quad_coords) > 0: 648 self.heatmap_quad_coords_offset = [] 649 for i, coord in enumerate(self.heatmap_quad_coords): 650 if not i%2: 651 # x-values 652 self.heatmap_quad_coords_offset.append(coord + self.offset_x + self.drawing_offset) 653 else: 654 self.heatmap_quad_coords_offset.append(coord + self.offset_y + self.drawing_offset)
655
656 - def reload_tiles(self, dt):
657 """Loads newly downloaded tiles from file""" 658 659 self.tileloader.load_images()
660
661 - def get_image(self, x, y, z, layer='mapnik'):
662 """Load an image from the cache folder or download it. 663 664 Try to load from cache-folder first, download and cache if no image was found. 665 The image is placed in self.tiles by this method or by the TileLoader.load_images() after downloading. 666 667 @param x: OSM-tile number in x-direction 668 @type x: int 669 @param y: OSM-tile number in y-direction 670 @type y: int 671 @param z: OSM-zoom 672 @type z: int in range [0, 18] 673 @param layer: The used map layer (default 'mapnik') 674 @type layer: string (one of 'tah', 'oam' and 'mapnik') 675 676 """ 677 678 url = tiles.tileURL(x, y, z, layer) 679 parts = url.split('/')[-4:] 680 681 if not os.path.exists(os.path.join(self.cache_dir, *parts)): 682 # Image is not cached yet. Create necessary folders and download image." 683 self.tileloader.enqueue_tile(x, y, z, layer) 684 return 685 # Image is cached. Try to load it. 686 try: 687 image = pyglet.image.load(os.path.join(self.cache_dir, *parts)) 688 except: 689 image = pyglet.resource.image(self.not_found_image) 690 image.anchor_x = image.width / 2 691 image.anchor_y = image.height / 2 692 self.tiles[(x, y, z)] = image
693
694 - def on_resize(self, width, height):
695 """Recalculate drawing_offset and number_of_tiles if necessary, update tiles. 696 697 This is called by pyglet when the viewer is started or resized. 698 699 @see: http://pyglet.org/doc/api/pyglet.window.Window-class.html#on_resize 700 701 """ 702 703 super(SimViewer, self).on_resize(width, height) 704 number_of_tiles = ((max(self.width, self.height) / TILE_SIZE) / 2) + 2 705 if number_of_tiles != self.number_of_tiles: 706 size_of_combined_map = (2 * number_of_tiles + 1) * TILE_SIZE 707 self.drawing_offset = (max(self.width, self.height) - size_of_combined_map) / 2 708 self.number_of_tiles = number_of_tiles 709 self.update_tiles()
710
711 - def update_tiles(self):
712 """Update the self.tiles and self.tiles_used dicts after changes. 713 714 When necessary load new images and delete old ones. 715 This should not be called to often since it causes all coordinates of all drawings to be recalculated. 716 717 """ 718 719 for y in xrange(-self.number_of_tiles, self.number_of_tiles + 1): 720 for x in xrange(-self.number_of_tiles, self.number_of_tiles + 1): 721 # absolute osm-values 722 absolute_x = self.center_x + x 723 absolute_y = self.center_y - y 724 if (absolute_x, absolute_y, self.zoom) not in self.tiles: 725 # image is not in memory...load it 726 self.get_image(absolute_x, absolute_y, self.zoom) 727 # add tile to the tiles that will be drawn... 728 # add number_of_tiles so coordinates start at (0, 0) to make drawing simpler 729 self.tiles_used[(x + self.number_of_tiles, y + self.number_of_tiles)] = (absolute_x, absolute_y, self.zoom) 730 731 # cleanup to save memory 732 for coord in self.tiles.keys(): 733 # tile is to far out of vision 734 if (not (self.center_x - 2 * self.number_of_tiles < coord[0] < self.center_x + 2 * self.number_of_tiles 735 and self.center_y - 2 * self.number_of_tiles < coord[1] < self.center_y + 2 * self.number_of_tiles) 736 and coord[2] == self.zoom): 737 del self.tiles[coord] 738 # tile is too many zoom-levels away 739 if not (self.zoom - 4 < coord[2] < self.zoom + 4): 740 del self.tiles[coord] 741 742 self.update_coordinates(all=True) 743 self.update_vertex_lists() 744 self.on_draw()
745
746 - def meters_to_pixels(self, m):
747 """Calculate the number of pixels that equal the given distance in. 748 749 @see: http://wiki.openstreetmap.org/wiki/Zoom_levels 750 751 @param m: Distance in meter 752 @type m: int 753 @returns: Distance in pixels 754 @rtype: int 755 756 """ 757 758 earth_cirumference_meters = 637813.70 759 lat = math.radians(self.center_lat) 760 distance_per_pixel = earth_cirumference_meters*math.degrees(math.cos(lat))/2**(self.zoom+8) 761 numer_of_pixels = m / distance_per_pixel 762 return int(numer_of_pixels)
763
764 - def on_draw(self, dt=0):
765 """Draw the screen. 766 767 This is periodically called by pyglet. 768 769 @param dt: Time since last call. Necessary for scheduling but ignored here. 770 771 """ 772 773 self.tileloader.load_images() 774 self.clear() 775 # draw tiles 776 for coord in self.tiles_used: 777 image = self.tiles[self.tiles_used[coord]] 778 x = coord[0] 779 y = coord[1] 780 image.blit(x * TILE_SIZE + self.offset_x + self.drawing_offset, 781 y * TILE_SIZE + self.offset_y + self.drawing_offset, 782 0) 783 784 # enable alpha blending 785 gl.glEnable(gl.GL_BLEND) 786 787 # draw all the things! 788 if len(self.point_coords_offset) > 0: 789 if self.point_vertex_list.get_size() != len(self.point_coords_offset) / 2: 790 self.point_vertex_list.resize(len(self.point_coords_offset) / 2) 791 self.point_vertex_list.vertices = self.point_coords_offset 792 self.point_vertex_list.colors = self.point_colors_all 793 if len(self.quad_coords_offset) > 0: 794 if self.quad_vertex_list.get_size() != len(self.quad_coords_offset) / 2: 795 self.quad_vertex_list.resize(len(self.quad_coords_offset) / 2) 796 self.quad_vertex_list.vertices = self.quad_coords_offset 797 self.quad_vertex_list.colors = self.quad_colors_all 798 if len(self.triangle_coords_offset) > 0: 799 if self.triangle_vertex_list.get_size() != len(self.triangle_coords_offset) / 2: 800 self.triangle_vertex_list.resize(len(self.triangle_coords_offset) / 2) 801 self.triangle_vertex_list.vertices = self.triangle_coords_offset 802 self.triangle_vertex_list.colors = self.triangle_colors_all 803 self.drawing_batch.draw() 804 if len(self.heatmap_point_coords_offset) > 0: 805 if self.heatmap_point_list.get_size() != len(self.heatmap_point_coords_offset) / 2: 806 self.heatmap_point_list.resize(len(self.heatmap_point_coords_offset) / 2) 807 self.heatmap_point_list.vertices = self.heatmap_point_coords_offset 808 self.heatmap_point_list.colors = self.heatmap_point_colors 809 if len(self.heatmap_quad_coords_offset) > 0: 810 if self.heatmap_quad_list.get_size() != len(self.heatmap_quad_coords_offset) / 2: 811 self.heatmap_quad_list.resize(len(self.heatmap_quad_coords_offset) / 2) 812 self.heatmap_quad_list.vertices = self.heatmap_quad_coords_offset 813 self.heatmap_quad_list.colors = self.heatmap_quad_colors 814 self.heatmap_batch.draw() 815 for line in self.line_loop_vertex_lists.values(): 816 line.draw(gl.GL_LINE_LOOP) 817 for poly in self.polygon_vertex_lists.values(): 818 poly.draw(gl.GL_POLYGON) 819 for text in self.text_objects.values(): 820 text.draw() 821 for text in self.direct_text_objects.values(): 822 text.draw() 823 824 # draw copyright text 825 self.copyright_label.x = self.width# - 10 826 pyglet.graphics.draw(4, gl.GL_QUADS, 827 ('v2i', (self.copyright_label.x+2, self.copyright_label.y-2, 828 self.copyright_label.x-self.copyright_label.content_width-2, self.copyright_label.y-2, 829 self.copyright_label.x-self.copyright_label.content_width-2, self.copyright_label.y+self.copyright_label.content_height-1, 830 self.copyright_label.x+2, self.copyright_label.y+self.copyright_label.content_height-1)), 831 ('c4d', (1, 1, 1, 0.7) * 4)) 832 self.copyright_label.draw() 833 834 # draw fps 835 if self.draw_fps: 836 now = time.time() 837 self.fps = self.fps*0.8 + 0.2 / (now - self.last_draw) 838 self.last_draw = now 839 self.fps_label.text = str(int(self.fps)) 840 self.fps_label.draw() 841 842 if self.draw_end_overlay: 843 pyglet.graphics.draw(4, gl.GL_QUADS, 844 ('v2i', (0, 0, 0, self.height, self.width, self.height, self.width, 0)), 845 ('c4d', (0, 0, 0, 0.5) * 4)) 846 self.end_label1.x = self.width / 2 847 self.end_label1.y = self.height / 2 848 self.end_label1.draw() 849 self.end_label2.x = self.width / 2 850 self.end_label2.y = self.height / 2 - 80 851 self.end_label2.draw()
852
853 - def change_zoom(self, factor):
854 """Zooms in or out of map by given factor. 855 856 @param factor: The factor to zoom by in OSM-zoom levels. 857 @type factor: int 858 859 """ 860 861 if factor > 0 and self.zoom + factor <= 18 or factor < 0 and self.zoom - factor >= 0: 862 self.zoom += factor 863 self.center_x, self.center_y = tiles.latlon2xy(self.center_lat, self.center_lon, self.zoom) 864 self.center_lat, self.center_lon = tiles.xy2latlon(self.center_x, self.center_y, self.zoom) 865 self.update_tiles()
866
867 - def on_key_press(self, symbol, modifiers):
868 """This is called by pyglet whenever a key is pressed. 869 870 @see: http://pyglet.org/doc/api/pyglet.window.Window-class.html#on_key_press 871 872 """ 873 874 super(SimViewer, self).on_key_press(symbol, modifiers) 875 if modifiers & key.MOD_CTRL: 876 if symbol == key.UP: 877 self.change_zoom(1) 878 elif symbol == key.DOWN: 879 self.change_zoom(-1) 880 elif symbol == key.F: 881 self.set_fullscreen(not self.fullscreen) 882 elif symbol == key.S: 883 self.take_screenshot() 884 elif symbol == key.UP: 885 self.offset_y -= KEYBOARD_SCROLL_VALUE 886 self.handle_offset() 887 elif symbol == key.DOWN: 888 self.offset_y += KEYBOARD_SCROLL_VALUE 889 self.handle_offset() 890 elif symbol == key.LEFT: 891 self.offset_x += KEYBOARD_SCROLL_VALUE 892 self.handle_offset() 893 elif symbol == key.RIGHT: 894 self.offset_x -= KEYBOARD_SCROLL_VALUE 895 self.handle_offset() 896 elif symbol == key.PLUS: 897 self.change_zoom(1) 898 elif symbol == key.MINUS: 899 self.change_zoom(-1) 900 elif symbol == key.F: 901 self.draw_fps = not self.draw_fps 902 elif symbol == key.Q: 903 self.close() 904 elif symbol == key.L: 905 if self.ended: 906 self.draw_end_overlay = not self.draw_end_overlay 907 elif symbol == key.C: 908 if self.ended: 909 self.ended = False 910 self.draw_end_overlay = False 911 self.reset_drawings() 912 self.reconnect() 913 elif symbol == key.SPACE: 914 self.center_x, self.center_y = tiles.latlon2xy(self.default_lat, self.default_lon, self.zoom) 915 self.center_x -= 1 916 self.center_lat, self.center_lon = tiles.xy2latlon(self.center_x, self.center_y, self.zoom) 917 self.offset_x , self.offset_y = 0, 0 918 self.update_tiles()
919
920 - def take_screenshot(self):
921 """Take a screenshot of the current simulation and save it with the current timestamp as it's name.""" 922 shot = pyglet.image.get_buffer_manager().get_color_buffer() 923 time_of_shot = str(int(time.time())) 924 path = os.path.join(self.screenshot_dir, self.current_sc_dir) 925 tries = 0 926 filename = time_of_shot + '_' + str(tries) + '.png' 927 while os.path.exists(os.path.join(path, filename)): 928 tries += 1 929 filename = time_of_shot + '_' + str(tries) + '.png' 930 shot.save(os.path.join(path, filename))
931
932 - def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
933 """Called, when mouse-dragging is recognized. 934 935 @see: http://pyglet.org/doc/api/pyglet.window.Window-class.html#on_mouse_drag 936 937 """ 938 939 if buttons & mouse.LEFT: 940 self.mouse_drag = True 941 self.offset_x = self.offset_x + dx 942 self.offset_y = self.offset_y + dy 943 if not self.ugly_drag: 944 self.update_vertex_lists()
945
946 - def on_mouse_release(self, x, y, buttons, modifiers):
947 """This is called by pyglet when a mouse button is released. 948 949 @see: http://pyglet.org/doc/api/pyglet.window.Window-class.html#on_mouse_release 950 951 """ 952 953 if buttons & mouse.LEFT and self.mouse_drag: 954 self.mouse_drag = False 955 self.handle_offset(update_tiles=self.ugly_drag)
956
957 - def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
958 """This is called by pyglet when the mouse-wheel is scrolled. 959 960 @see: http://pyglet.org/doc/api/pyglet.window.Window-class.html#on_mouse_scroll 961 962 """ 963 964 self.change_zoom(scroll_y)
965
966 - def handle_offset(self, update_tiles=True):
967 """Check, if new tiles need to be loaded because of the current offset. 968 969 If the offset is bigger than one tile, the appropriate tile 970 will become the new center and the offset is changed accordingly. 971 972 @param update_tiles: If True, self.update_tiles() will be called after adjusting for offset (default). 973 974 """ 975 #Casts to float and back to int while calculating center are necessary 976 #because python floors the results for integer division: 977 #8.0 / (-7.0) = -1.143 --> rounded down to -2 978 self.center_x -= int(self.offset_x / float(TILE_SIZE)) 979 self.offset_x = (self.offset_x % TILE_SIZE if self.offset_x >= 0 980 else -(-self.offset_x % TILE_SIZE)) 981 self.center_y += int(self.offset_y / float(TILE_SIZE)) 982 self.offset_y = (self.offset_y % TILE_SIZE if self.offset_y >= 0 983 else -(-self.offset_y % TILE_SIZE)) 984 self.center_lat, self.center_lon = tiles.xy2latlon(self.center_x, self.center_y, self.zoom) 985 if update_tiles: 986 self.update_tiles()
987
988 - def remove_drawing(self, dt, type, id):
989 """Remove a drawing-object from the viewer. 990 991 The object is specified by it's type (in hexadecimal, see MESSAGE_TYPES) and it's unique id. 992 993 @param dt: Necessary for scheduling, ignored here 994 @type dt: int 995 @param type: Specifies which kind of object should be removed. Must be one of the types in MESSAGE_TYPES (in hexadecimal). 996 @type type: string 997 @param id: ID of the removed object 998 @type id: int 999 1000 """ 1001 1002 id = id + ID_TYPE_PREFIX[type] 1003 type = MESSAGE_TYPES[type] 1004 1005 if type == 'point' and id in self.points: 1006 (lat, lon, rad, r, g, b, a, ttl) = self.points[id] 1007 del self.points[id] 1008 if rad > 0: 1009 del self.quad_coords[id] 1010 del self.quad_colors[id] 1011 else: 1012 del self.point_coords[id] 1013 del self.point_colors[id] 1014 # this needs to be done because pyglet batches seem to not update correctly when removing stuff 1015 # maybe there is another way that I just have not found yet... 1016 self.point_vertex_list.delete() 1017 self.point_vertex_list = self.drawing_batch.add(1, gl.GL_POINTS, None, 1018 ('v2i', (0, 0)), 1019 ('c4d', (0, 0, 0, 0))) 1020 elif type == 'rectangle' and id in self.rectangles: 1021 (minlat, minlon, maxlat, maxlon, line_width, filled, r, g, b, a, ttl) = self.rectangles[id] 1022 del self.rectangles[id] 1023 if filled: 1024 del self.quad_coords[id] 1025 del self.quad_colors[id] 1026 else: 1027 del self.line_loop_coords[id] 1028 del self.line_loop_colors[id] 1029 del self.line_loop_vertex_lists[id] 1030 elif type == 'circle' and id in self.circles: 1031 (lat, lon, rad, filled, r, g, b, a, ttl) = self.circles[id] 1032 del self.circles[id] 1033 if filled: 1034 del self.polygon_coords[id] 1035 del self.polygon_colors[id] 1036 del self.polygon_vertex_lists[id] 1037 else: 1038 del self.point_coords[id] 1039 del self.point_colors[id] 1040 self.point_coords_offset = [] 1041 self.point_colors_all = [] 1042 # this needs to be done because pyglet batches seem to not update correctly when removing stuff 1043 # maybe there is another way that I just have not found yet... 1044 self.point_vertex_list.delete() 1045 self.point_vertex_list = self.drawing_batch.add(1, gl.GL_POINTS, None, 1046 ('v2i', (0, 0)), 1047 ('c4d', (0, 0, 0, 0))) 1048 if type == 'triangle' and id in self.triangles: 1049 (lat1, lon1, lat2, lon2, lat3, lon3, filled, r, g, b, a, ttl) = self.triangles[id] 1050 del self.triangles[id] 1051 if filled: 1052 del self.triangle_coords[id] 1053 del self.triangle_colors[id] 1054 self.triangle_vertex_list.delete() 1055 self.triangle_vertex_list = self.drawing_batch.add(1, gl.GL_POINTS, None, 1056 ('v2i', (0, 0)), 1057 ('c4d', (0, 0, 0, 0))) 1058 else: 1059 del self.line_loop_coords[id] 1060 del self.line_loop_colors[id] 1061 del self.line_loop_vertex_lists[id] 1062 elif type == 'text' and id in self.text_objects: 1063 del self.text_data[id] 1064 del self.text_objects[id] 1065 # no need to update vertex lists...return here 1066 return 1067 elif type == 'direct-text' and id in self.direct_text_objects: 1068 del self.direct_text_objects[id] 1069 return 1070 1071 self.update_vertex_lists()
1072
1073 - def reset_drawings(self):
1074 """Empty all vertex lists and set up new ones.""" 1075 self.points = {} 1076 self.rectangles = {} 1077 self.circles = {} 1078 1079 self.point_coords = {} 1080 self.point_coords_offset = [] 1081 self.point_colors = {} 1082 self.point_colors_all = [] 1083 self.point_vertex_list.delete() 1084 self.point_vertex_list = self.drawing_batch.add(1, gl.GL_POINTS, None, 1085 ('v2i/stream', (0, 0)), 1086 ('c4d/stream', (0, 0, 0, 0))) 1087 1088 self.quad_coords = {} 1089 self.quad_coords_offset = [] 1090 self.quad_colors = {} 1091 self.quad_colors_all = [] 1092 self.quad_vertex_list.delete() 1093 self.quad_vertex_list = self.drawing_batch.add(1, gl.GL_QUADS, None, 1094 ('v2i/stream', (0, 0)), 1095 ('c4d/stream', (0, 0, 0, 0))) 1096 self.line_loop_coords = {} 1097 self.line_loop_colors = {} 1098 self.line_loop_vertex_lists = {} 1099 self.polygon_coords = {} 1100 self.polygon_colors = {} 1101 self.polygon_vertex_lists = {} 1102 1103 self.heatmap_data = [] 1104 self.heatmap_point_coords = [] 1105 self.heatmap_point_coords_offset = [] 1106 self.heatmap_point_colors = [] 1107 self.heatmap_point_list.delete() 1108 self.heatmap_point_list = self.heatmap_batch.add(1, gl.GL_POINTS, None, 1109 ('v2i/stream', (0, 0)), 1110 ('c4d/stream', (0, 0, 0, 0))) 1111 self.heatmap_quad_coords = [] 1112 self.heatmap_quad_coords_offset = [] 1113 self.heatmap_quad_colors = [] 1114 self.heatmap_quad_list.delete() 1115 self.heatmap_quad_list = self.heatmap_batch.add(1, gl.GL_QUADS, None, 1116 ('v2i/stream', (0, 0)), 1117 ('c4d/stream', (0, 0, 0, 0)))
1118
1119 - def reconnect(self):
1120 """Try to establish a new connection to the host and ports used when initialising. 1121 1122 This is mainly used when a new simulation was started and the viewer is supposed to be restarted. 1123 1124 """ 1125 1126 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1127 self.socket.setblocking(0) 1128 try: 1129 print 'connecting' 1130 self.socket.connect((self.host, self.port)) 1131 print 'connected' 1132 except socket.error as (errno, message): 1133 if errno == 115: 1134 # Operation now in progress 1135 # ... since we use non-blocking sockets 1136 # this exception is not needed 1137 pass 1138 else: 1139 print 'error while connecting' 1140 print '\t', errno, message 1141 raise socket.error, (errno, message)
1142
1143 - def close(self):
1144 """This is called by pyglet when the viewer is closed. 1145 1146 The screenshot folder is deleted, if no screenshots were taken. 1147 1148 """ 1149 1150 super(SimViewer, self).close() 1151 try: 1152 os.rmdir(os.path.join(self.screenshot_dir, self.current_sc_dir)) 1153 except OSError: 1154 # directory contains screenshots...keep it 1155 pass 1156 try: 1157 os.rmdir(self.screenshot_dir) 1158 except OSError: 1159 # directory contains screenshots...keep it 1160 pass
1161 1162 1163 if __name__ == '__main__': 1164 viewer = SimViewer(52.382463, 9.717836, width=800, height=600, resizable=True, caption='MoSP-Simulation Viewer') 1165 pyglet.app.run() 1166