mapper.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. from geoplotlib.layers import BaseLayer
  2. from geoplotlib.core import BatchPainter
  3. import geoplotlib
  4. from geoplotlib.utils import BoundingBox, epoch_to_str
  5. import pyglet
  6. import pandas as pd
  7. import numpy as np
  8. from de2.routing import get_graph, euler_distance, pathfinder, find_percentage_point_in_path as fpp
  9. class PoABLayer(BaseLayer):
  10. """
  11. Renders the map.
  12. """
  13. __colors__ = {
  14. "highlight": [255, 255, 0, 100],
  15. "nodes": [150, 0, 250, 200],
  16. "sailing": [0, 150, 250, 200],
  17. "tugging": [150, 250, 0, 200]
  18. }
  19. def __init__(self, sim=None):
  20. self.sim = sim
  21. self.sim_active = False
  22. self.berths = pd.read_csv("berths.csv")
  23. self.berths["used"] = False
  24. self.paths = pd.read_csv("2022.csv")
  25. self.paths.drop_duplicates(["Locatie van", "Locatie naar"], inplace=True)
  26. for _, traj in self.paths.iterrows():
  27. self.berths.loc[self.berths["lpl_id"] == traj["Locatie van"], "used"] = True
  28. self.berths.loc[self.berths["lpl_id"] == traj["Locatie naar"], "used"] = True
  29. self.berths = self.berths[self.berths["used"]]
  30. self.paths = []
  31. self.painter = BatchPainter()
  32. self.vcache = {} # vessel -> source
  33. self.pcache = {} # vessel -> path, dists
  34. self.graph = get_graph()
  35. def draw_shape(self, x, y):
  36. """
  37. Draws the shape on the layer, at a specific location.
  38. Args:
  39. x (numeric): The x-position to draw this shape at.
  40. y (numeric): The y-position to draw this shape at.
  41. """
  42. self.painter.points(x, y, 5)
  43. def draw_path(self, path, proj):
  44. """
  45. Draws a path on the layer.
  46. Args:
  47. path: The path to draw as (x, y) tuples.
  48. proj: The projector.
  49. """
  50. for ix in range(len(path) - 1):
  51. point1 = path[ix]
  52. point2 = path[ix + 1]
  53. vx1, vy1 = proj.lonlat_to_screen(np.asarray([point1[0]]), np.asarray([point1[1]]))
  54. vx2, vy2 = proj.lonlat_to_screen(np.asarray([point2[0]]), np.asarray([point2[1]]))
  55. self.painter.lines(vx1, vy1, vx2, vy2, width=1.5)
  56. def draw(self, proj, mouse_x, mouse_y, ui_manager):
  57. self.painter = BatchPainter()
  58. tooltips = []
  59. self.painter.set_color(self.__colors__["nodes"])
  60. if not self.sim_active:
  61. ui_manager.status("Press Space to Start Simulation")
  62. else:
  63. model = self.sim.model
  64. time = model.clock.state["time"]
  65. ts = int(time + model.tracer.starting_time / 1000)
  66. ui_manager.info("TIME: %s" % epoch_to_str(ts))
  67. for vessel in model.sailer.state["vessels"]:
  68. if vessel.source is not None or vessel.target is not None:
  69. if vessel.task == "sailing":
  70. self.painter.set_color(self.__colors__["sailing"])
  71. else:
  72. self.painter.set_color(self.__colors__["tugging"])
  73. if vessel.mmsi not in self.vcache or self.vcache[vessel.mmsi] != vessel.source:
  74. self.vcache[vessel.mmsi] = vessel.source
  75. self.pcache[vessel.mmsi] = pathfinder(self.graph, vessel.source, vessel.target)
  76. path, dists = self.pcache[vessel.mmsi]
  77. self.draw_path(path, proj)
  78. tot_distance = vessel.total_distance
  79. traveled_approx = tot_distance - vessel.distance_left
  80. delta = time - model.sailer.state["time"]
  81. traveled_approx += delta * vessel.velocity
  82. percentage = traveled_approx / tot_distance
  83. if sum(dists) == 0:
  84. p1 = p2 = path[0]
  85. percentage = 1.
  86. else:
  87. p1, p2, percentage = fpp(path, dists, percentage)
  88. sx, sy = proj.lonlat_to_screen(np.asarray([p1[0]]), np.asarray([p1[1]]))
  89. tx, ty = proj.lonlat_to_screen(np.asarray([p2[0]]), np.asarray([p2[1]]))
  90. dx = (tx - sx) * percentage
  91. dy = (ty - sy) * percentage
  92. if euler_distance(sx + dx, sy + dy, mouse_x, mouse_y) < 10:
  93. self.painter.set_color(self.__colors__["highlight"])
  94. tooltips.append("%s (MMSI: %s)" % (str(vessel.name), str(vessel.mmsi)))
  95. tooltips.append("%.3f m/s" % vessel.velocity)
  96. self.draw_shape(sx + dx, sy + dy)
  97. ui_manager.tooltip("\n".join(tooltips))
  98. self.painter.batch_draw()
  99. def bbox(self):
  100. box = [max(self.berths["center_lat"]), max(self.berths["center_lon"]), min(self.berths["center_lat"]), min(self.berths["center_lon"])]
  101. return BoundingBox(north=box[0], east=box[1], south=box[2], west=box[3])
  102. def on_key_release(self, key, modifiers):
  103. if key == pyglet.window.key.SPACE:
  104. if self.sim is not None:
  105. self.sim.simulate()
  106. self.sim_active = True
  107. if __name__ == '__main__':
  108. from de2.elements import Port
  109. from pypdevs.simulator import Simulator
  110. port = Port("PoAB", "results-de/IVEF.csv")
  111. sim = Simulator(port)
  112. sim.setClassicDEVS()
  113. sim.setRealTime(scale=0.0002)
  114. sim.setTerminationTime(14 * 24 * 60 * 60) # 14 days
  115. layer = PoABLayer(sim)
  116. geoplotlib.set_window_size(640, 760)
  117. geoplotlib.tiles_provider({
  118. 'url': lambda zoom, xtile, ytile: 'https://tile.openstreetmap.org/%d/%d/%d.png' % (zoom, xtile, ytile),
  119. 'tiles_dir': 'mytiles',
  120. 'attribution': 'Map tiles by Stamen Design, under CC BY 3.0. Data @ OpenStreetMap contributors.'
  121. })
  122. geoplotlib.add_layer(layer)
  123. geoplotlib.show()
  124. sim.model.print_statistics()