from geoplotlib.layers import BaseLayer from geoplotlib.core import BatchPainter import geoplotlib from geoplotlib.utils import BoundingBox, epoch_to_str import pyglet import pandas as pd import numpy as np from de2.routing import get_graph, euler_distance, pathfinder, find_percentage_point_in_path as fpp class PoABLayer(BaseLayer): """ Renders the map. """ __colors__ = { "highlight": [255, 255, 0, 100], "nodes": [150, 0, 250, 200], "sailing": [0, 150, 250, 200], "tugging": [150, 250, 0, 200] } def __init__(self, sim=None): self.sim = sim self.sim_active = False self.berths = pd.read_csv("berths.csv") self.berths["used"] = False self.paths = pd.read_csv("2022.csv") self.paths.drop_duplicates(["Locatie van", "Locatie naar"], inplace=True) for _, traj in self.paths.iterrows(): self.berths.loc[self.berths["lpl_id"] == traj["Locatie van"], "used"] = True self.berths.loc[self.berths["lpl_id"] == traj["Locatie naar"], "used"] = True self.berths = self.berths[self.berths["used"]] self.paths = [] self.painter = BatchPainter() self.vcache = {} # vessel -> source self.pcache = {} # vessel -> path, dists self.graph = get_graph() 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 path on the layer. Args: path: The path to draw as (x, y) tuples. proj: The projector. """ for ix in range(len(path) - 1): point1 = path[ix] point2 = path[ix + 1] vx1, vy1 = proj.lonlat_to_screen(np.asarray([point1[0]]), np.asarray([point1[1]])) vx2, vy2 = proj.lonlat_to_screen(np.asarray([point2[0]]), np.asarray([point2[1]])) self.painter.lines(vx1, vy1, vx2, vy2, width=1.5) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter = BatchPainter() tooltips = [] self.painter.set_color(self.__colors__["nodes"]) if not self.sim_active: ui_manager.status("Press Space to Start Simulation") else: model = self.sim.model time = model.clock.state["time"] ts = int(time + model.tracer.starting_time / 1000) ui_manager.info("TIME: %s" % epoch_to_str(ts)) for vessel in model.sailer.state["vessels"]: if vessel.source is not None or vessel.target is not None: if vessel.task == "sailing": self.painter.set_color(self.__colors__["sailing"]) else: self.painter.set_color(self.__colors__["tugging"]) if vessel.mmsi not in self.vcache or self.vcache[vessel.mmsi] != vessel.source: self.vcache[vessel.mmsi] = vessel.source self.pcache[vessel.mmsi] = pathfinder(self.graph, vessel.source, vessel.target) path, dists = self.pcache[vessel.mmsi] self.draw_path(path, proj) tot_distance = vessel.total_distance traveled_approx = tot_distance - vessel.distance_left delta = time - model.sailer.state["time"] traveled_approx += delta * vessel.velocity percentage = traveled_approx / tot_distance if sum(dists) == 0: p1 = p2 = path[0] percentage = 1. else: p1, p2, percentage = fpp(path, dists, percentage) 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("%.3f m/s" % vessel.velocity) self.draw_shape(sx + dx, sy + dy) 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]) def on_key_release(self, key, modifiers): if key == pyglet.window.key.SPACE: if self.sim is not None: self.sim.simulate() self.sim_active = True if __name__ == '__main__': from de2.elements import Port from pypdevs.simulator import Simulator port = Port("PoAB", "results-de/IVEF.csv") sim = Simulator(port) sim.setClassicDEVS() sim.setRealTime(scale=0.0002) sim.setTerminationTime(14 * 24 * 60 * 60) # 14 days layer = PoABLayer(sim) 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 Stamen Design, under CC BY 3.0. Data @ OpenStreetMap contributors.' }) geoplotlib.add_layer(layer) geoplotlib.show() sim.model.print_statistics()