| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- 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], # yellow
- "nodes": [150, 0, 250, 200], # purple
- "sailing": [0, 150, 250, 200], # blue
- "tugging": [150, 250, 0, 200] # green
- }
- def __init__(self, sim=None, streamer=None):
- self.sim = sim
- self.streamer = streamer
- self.sim_active = False
- self.berths = pd.read_csv("berths.csv")
- # Uncomment the following lines if the berths list should only look at berths used
- # 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.tcache = {} # mmsi -> start time
- 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 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.painter = BatchPainter()
- tooltips = []
- # self.draw_path([[4.295200916909143, 51.33976669811829], [4.295765234634749, 51.33948916458878], [4.293551595412932, 51.33772327775724], [4.292987285902909, 51.338000801857774], [4.294133417960714, 51.33891513667706], [4.295200916909143, 51.33976669811829]], proj)
- # pts = [(4.29508,51.3404), (4.29472,51.33883), (4.29646,51.33891), (4.297,51.33805), (4.29754,51.33719), (4.29533,51.33968), (4.29813,51.33624), (4.29533,51.33968), (4.29867,51.33538), (4.29893,51.33495), (4.2992,51.33452), (4.29947,51.33409), (4.2953,51.33949), (4.29509,51.33908), (4.29518,51.33883), (4.29475,51.33873), (4.30082,51.33193), (4.29465,51.3387), (4.29473,51.33879), (4.2947,51.33877), (4.29469,51.33877), (4.29468,51.33877), (4.29468,51.33876), (4.29467,51.33876), (4.29467,51.33876), (4.29475,51.33879), (4.29474,51.33879), (4.29474,51.33879), (4.29467,51.33873), (4.29467,51.33872), (4.29467,51.33871), (4.2947,51.33874), (4.2947,51.33874), (4.2947,51.33874), (4.29469,51.33874), (4.29469,51.33874), (4.29469,51.33874), (4.29616,51.33904)]
- # self.draw_path(pts, proj)
- # self.painter.set_color([255, 0, 0, 200])
- #
- # # DRAW THE PoAB GRAPH
- # for v in self.graph.vs:
- # x, y = proj.lonlat_to_screen(np.asarray([v["x"]]), np.asarray([v["y"]]))
- # self.draw_shape(x, y)
- # for e in self.graph.es:
- # src = e.source_vertex
- # tgt = e.target_vertex
- # cx1, cy1 = proj.lonlat_to_screen(np.asarray([src["x"]]), np.asarray([src["y"]]))
- # cx2, cy2 = proj.lonlat_to_screen(np.asarray([tgt["x"]]), np.asarray([tgt["y"]]))
- # self.painter.lines(cx1, cy1, cx2, cy2, width=2)
- if not self.sim_active:
- ui_manager.status("Press Space to Start Simulation")
- else:
- # Show the simulation time in top right
- # model = self.sim.model
- time = self.streamer.time
- ts = int(time + self.streamer.starting_time)
- # time = model.clock.state["time"]
- # ts = int(time + model.scheduler.starting_time / 1000)
- ui_manager.info("TIME: %s" % epoch_to_str(ts))
- # Get all sailing vessels
- for vessel in self.streamer.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"])
- # Obtain (and draw) vessel trajectory
- 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)
- self.tcache[vessel.mmsi] = time
- path, dists = self.pcache[vessel.mmsi]
- self.draw_path(path, proj)
- # Compute distance traveled and draw a vessel there
- tot_distance = vessel.total_distance
- traveled_approx = tot_distance - vessel.distance_left
- delta = time - self.tcache[vessel.mmsi]
- 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
- from de2.tracer import Streamer
- port = Port("PoAB", "results-de2/plan.csv")
- streamer = Streamer()
- sim = Simulator(port)
- # sim.setClassicDEVS()
- # sim.setVerbose(None)
- sim.setRealTime(scale=0.0002)
- sim.setCustomTracer("de2.tracer", "TracerPort", [streamer])
- # sim.setTerminationTime(31 * 24 * 60 * 60) # 14 days
- sim.setTerminationCondition(lambda _, m: m.scheduler.state["index"] >= len(m.scheduler.ivef))
- # sim.simulate()
- layer = PoABLayer(sim, streamer)
- 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()
- sim.model.print_statistics()
|