| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- from geoplotlib.layers import BaseLayer
- from geoplotlib.core import BatchPainter
- import geoplotlib
- from geoplotlib.colors import create_set_cmap
- from geoplotlib.utils import BoundingBox, epoch_to_str
- import time as ptime
- import pandas as pd
- import numpy as np
- from de2.routing import get_graph, euler_distance, pathfinder, find_percentage_point_in_path as fpp
- from twin.elements import Vessel
- class PoABLayer(BaseLayer):
- """
- Renders the map.
- """
- __colors__ = {
- "highlight": [150, 0, 250, 200], # yellow
- "nodes": [150, 0, 250, 200], # purple
- "ecological": [0, 255, 0, 200] # green
- }
- FPS = 30
- def __init__(self, client):
- self.client = client
- self.berths = pd.read_csv("berths.csv")
- self.painter = BatchPainter()
- self.ticks = 0
- self.time = 0
- self.initial_time = 0
- self.last_rt_time = ptime.time()
- self.time_factor = 1.0
- self.vessels = []
- self.graph = get_graph()
- def update_vessels(self):
- self.client.spin()
- if len(self.client.received["initial_time"]) > 0:
- self.initial_time, self.time_factor = eval(self.client.received["initial_time"].pop(0))
- while len(self.client.received["vessels"]) > 0:
- vessel = eval(self.client.received["vessels"].pop(0))
- # self.time_factor = (vessel[0] - self.time) / (ptime.time() - self.last_rt_time)
- self.time = vessel[0]
- self.ticks = 0
- vdict = {
- "mmsi": vessel[1],
- "name": vessel[2],
- "task": vessel[3],
- "velocity": vessel[4],
- "source": vessel[5],
- "target": vessel[6],
- "start": vessel[7],
- "ETA": vessel[8],
- }
- self.vessels.append(vdict)
- self.last_rt_time = ptime.time()
- def draw_shape(self, x, y):
- """
- Draws the shape on the layer, at a specific location.
- Args:
- x (numeric): The x-position to draw this shape at.
- y (numeric): The y-position to draw this shape at.
- """
- self.painter.points(x, y, 5)
- def draw_path(self, path, proj):
- """
- Draws a WSG84 path on the layer.
- Args:
- path: The path to draw as (x, y) tuples.
- proj: The projector.
- """
- x = []
- y = []
- for ix in range(len(path) - 1):
- point1 = path[ix]
- point2 = path[ix + 1]
- x.append(point1[0])
- x.append(point2[0])
- y.append(point1[1])
- y.append(point2[1])
- px, py = proj.lonlat_to_screen(np.asarray(x), np.asarray(y))
- vx1 = [e for ei, e in enumerate(px) if ei % 2 == 0]
- vx2 = [e for ei, e in enumerate(px) if ei % 2 == 1]
- vy1 = [e for ei, e in enumerate(py) if ei % 2 == 0]
- vy2 = [e for ei, e in enumerate(py) if ei % 2 == 1]
- self.painter.lines(vx1, vy1, vx2, vy2, width=1.5)
- def draw(self, proj, mouse_x, mouse_y, ui_manager):
- self.ticks += 1
- self.update_vessels()
- if len(self.client.received["error"]) > 0:
- print('\n'.join(self.client.received["error"]))
- ui_manager.status('\n'.join(self.client.received["error"]))
- self.client.received["error"].clear()
- self.painter = BatchPainter()
- tooltips = []
- # Show the simulation time in top right
- ts = self.time + (self.ticks / self.FPS) * self.time_factor
- ui_manager.info("TIME: %s (x %.1f)" % (epoch_to_str(self.initial_time + ts), self.time_factor))
- # Get all sailing vessels
- rem = []
- for vix, vessel in enumerate(self.vessels):
- col = self.__colors__["ecological"]
- eco = Vessel.ecological()
- dist = 0
- if vessel["velocity"] < eco[0]:
- dist = eco[0] - vessel["velocity"]
- elif vessel["velocity"] > eco[1]:
- dist = vessel["velocity"] - eco[1]
- col[0] = min(255, int(dist) * 50)
- col[1] = 255 - col[0]
- self.painter.set_color(col)
- # Obtain (and draw) vessel trajectory
- if "trajectory" not in vessel:
- vessel["trajectory"] = pathfinder(self.graph, vessel["source"], vessel["target"])
- path, dists = vessel["trajectory"]
- # Compute distance traveled and draw a vessel there
- # TODO: use distance_left when it should be updated
- tot_distance = sum(dists)
- traveled = (ts - vessel["start"]) * vessel["velocity"]
- distance_left = tot_distance - traveled
- if tot_distance == 0:
- p1 = p2 = path[0]
- percentage = 1.
- else:
- percentage = traveled / tot_distance
- p1, p2, percentage = fpp(path, dists, percentage)
- if percentage < 1:
- self.draw_path(path, proj)
- sx, sy = proj.lonlat_to_screen(np.asarray([p1[0]]), np.asarray([p1[1]]))
- tx, ty = proj.lonlat_to_screen(np.asarray([p2[0]]), np.asarray([p2[1]]))
- dx = (tx - sx) * percentage
- dy = (ty - sy) * percentage
- if euler_distance(sx + dx, sy + dy, mouse_x, mouse_y) < 10:
- self.painter.set_color(self.__colors__["highlight"])
- tooltips.append("%s (MMSI: %s)" % (str(vessel["name"]), str(vessel["mmsi"])))
- tooltips.append("task: %s | ETA: %s" % (vessel["task"], epoch_to_str(vessel["ETA"])))
- tooltips.append("velocity: %.3f m/s" % vessel["velocity"])
- tooltips.append("dist left/total: %.3f/%.3f m" % (distance_left, tot_distance))
- # self.draw_path(path, proj)
- self.draw_shape(sx + dx, sy + dy)
- else:
- rem.append(vix)
- for vix in reversed(rem):
- self.vessels.pop(vix)
- ui_manager.tooltip("\n".join(tooltips))
- self.painter.batch_draw()
- def bbox(self):
- box = [max(self.berths["center_lat"]), max(self.berths["center_lon"]), min(self.berths["center_lat"]), min(self.berths["center_lon"])]
- return BoundingBox(north=box[0], east=box[1], south=box[2], west=box[3])
- if __name__ == '__main__':
- from networking.mqtt import MQTTClient
- client = MQTTClient("Dashboard")
- client.subscribe("initial_time")
- client.subscribe("vessels")
- client.subscribe("error")
- layer = PoABLayer(client)
- geoplotlib.set_window_size(640, 760)
- geoplotlib.tiles_provider({
- 'url': lambda zoom, xtile, ytile: 'https://tile.openstreetmap.org/%d/%d/%d.png' % (zoom, xtile, ytile),
- 'tiles_dir': 'mytiles',
- 'attribution': 'Map tiles by OpenStreetMap Carto, under CC BY 3.0. Data @ OpenStreetMap contributors.'
- })
- geoplotlib.add_layer(layer)
- geoplotlib.show()
|