renderer.py 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from api.od import ODAPI
  2. from concrete_syntax.graphviz.renderer import render_object_diagram, make_graphviz_id
  3. from concrete_syntax.graphviz.make_url import show_graphviz
  4. from examples.petrinet.renderer import render_petri_net_to_dot
  5. from examples.semantics.operational.port.renderer import render_port_to_dot
  6. from examples.semantics.operational.port import helpers
  7. # COLORS
  8. PLACE_BG = "#DAE8FC" # fill color
  9. PLACE_FG = "#6C8EBF" # font, line, arrow
  10. BERTH_BG = "#FFF2CC"
  11. BERTH_FG = "#D6B656"
  12. CAPACITY_BG = "#F5F5F5"
  13. CAPACITY_FG = "#666666"
  14. WORKER_BG = "#D5E8D4"
  15. WORKER_FG = "#82B366"
  16. GENERATOR_BG = "#FFE6CC"
  17. GENERATOR_FG = "#D79B00"
  18. CLOCK_BG = "black"
  19. CLOCK_FG = "white"
  20. def graphviz_style_fg_bg(fg, bg):
  21. return f"style=filled,fillcolor=\"{bg}\",color=\"{fg}\",fontcolor=\"{fg}\""
  22. def render_port(state, m, mm):
  23. dot = render_object_diagram(state, m, mm,
  24. reify=True,
  25. only_render=[
  26. # Only render these types
  27. "Place", "Berth", "CapacityConstraint", "WorkerSet", "Generator", "Clock",
  28. "connection", "capacityOf", "canOperate", "generic_link",
  29. # Petri Net types not included (they are already rendered by other function)
  30. # Port-State-types not included to avoid cluttering the diagram, but if you need them, feel free to add them.
  31. ],
  32. # We can style nodes/edges according to their type:
  33. type_to_style={
  34. "Place": graphviz_style_fg_bg(PLACE_FG, PLACE_BG),
  35. "Berth": graphviz_style_fg_bg(BERTH_FG, BERTH_BG),
  36. "CapacityConstraint": graphviz_style_fg_bg(CAPACITY_FG, CAPACITY_BG),
  37. "WorkerSet": "shape=oval,"+graphviz_style_fg_bg(WORKER_FG, WORKER_BG),
  38. "Generator": "shape=parallelogram,"+graphviz_style_fg_bg(GENERATOR_FG, GENERATOR_BG),
  39. "Clock": graphviz_style_fg_bg(CLOCK_FG, CLOCK_BG),
  40. # same blue as Place, thick line:
  41. "connection": f"color=\"{PLACE_FG}\",fontcolor=\"{PLACE_FG}\",penwidth=2.0",
  42. # same grey as CapacityConstraint
  43. "capacityOf": f"color=\"{CAPACITY_FG}\",fontcolor=\"{CAPACITY_FG}\"",
  44. # same green as WorkerSet
  45. "canOperate": f"color=\"{WORKER_FG}\",fontcolor=\"{WORKER_FG}\"",
  46. # purple line
  47. "generic_link": "color=purple,fontcolor=purple,arrowhead=onormal",
  48. },
  49. # We have control over the node/edge labels that are rendered:
  50. type_to_label={
  51. "CapacityConstraint": lambda capconstr_name, capconstr, odapi: f"{capconstr_name}\\nshipCapacity={odapi.get_slot_value(capconstr, "shipCapacity")}",
  52. "Place": lambda place_name, place, odapi: f"{place_name}\\nnumShips={helpers.get_num_ships(odapi, place)}",
  53. "Berth": lambda berth_name, berth, odapi: f"{berth_name}\\nnumShips={helpers.get_num_ships(odapi, berth)}\\nstatus={odapi.get_slot_value(helpers.design_to_state(odapi, berth), "status")}",
  54. "Clock": lambda _, clock, odapi: f"Clock\\ntime={odapi.get_slot_value(clock, "time")}",
  55. "connection": lambda conn_name, conn, odapi: f"{conn_name}\\nmoved={odapi.get_slot_value(helpers.design_to_state(odapi, conn), "moved")}",
  56. # hide generic link labels
  57. "generic_link": lambda lnk_name, lnk, odapi: "",
  58. "WorkerSet": lambda ws_name, ws, odapi: f"{ws_name}\\nnumWorkers={odapi.get_slot_value(ws, "numWorkers")}",
  59. # hide the type (it's already clear enough)
  60. "Generator": lambda gen_name, gen, odapi: gen_name,
  61. },
  62. )
  63. return dot
  64. def render_port_and_petri_net(state, m, mm):
  65. od = ODAPI(state, m, mm)
  66. dot = ""
  67. dot += "// petri net:\n"
  68. dot += render_petri_net_to_dot(od)
  69. dot += "\n// the rest:\n"
  70. dot += render_port(state, m, mm)
  71. return dot
  72. def show_port_and_petri_net(state, m, mm, engine="dot"):
  73. show_graphviz(render_port_and_petri_net(state, m, mm), engine=engine)