main.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. import matplotlib
  2. matplotlib.use("TkAgg")
  3. from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
  4. from matplotlib.figure import Figure
  5. from Tkinter import *
  6. from PIL import Image, ImageTk
  7. import tkSimpleDialog
  8. import urllib
  9. import urllib2
  10. import json
  11. import time
  12. JUMP = 25
  13. MAX_WIDTH = 20 * JUMP
  14. MAX_HEIGHT = 20 * JUMP
  15. CLICK_TOLERANCE = 5
  16. address = "http://127.0.0.1:8001"
  17. username = "test"
  18. root = Tk()
  19. names = {}
  20. event_entry = StringVar()
  21. canvas = Canvas(root, width=MAX_WIDTH, height=MAX_HEIGHT, bg="white")
  22. name = 0
  23. class FakeLayer():
  24. def __init__(self, address):
  25. self.types = {}
  26. self.sources = {}
  27. self.targets = {}
  28. self.attrs = {}
  29. def send_event(self, event):
  30. pass
  31. def read_available_attributes(self, name):
  32. if self.types[name] == "const":
  33. return ["value"]
  34. else:
  35. return []
  36. def read_attribute(self, name, attr):
  37. return self.attr.get(name, {}).get(attr, None)
  38. def set_attribute(self, name, attr, value):
  39. self.attrs[name][attr] = value
  40. def instantiate_block(self, name, block_type):
  41. self.types[name] = block_type
  42. def instantiate_link(self, name, link_type, source, target):
  43. self.types[name] = link_type
  44. self.sources[name] = source
  45. self.targets[name] = target
  46. self.attrs[name] = {}
  47. def simulate(self):
  48. pass
  49. def pause(self):
  50. pass
  51. attribute = []
  52. available_attrs = []
  53. simulation = []
  54. def poll(address):
  55. working_available_attrs = []
  56. working_simulation = None
  57. while 1:
  58. returnvalue = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username}))).read())
  59. print("Process " + str(returnvalue))
  60. if (returnvalue.startswith("AVAILABLE_ATTR_VALUE")):
  61. working_available_attrs.append([json.loads(returnvalue.split(" ", 1)[1]), None])
  62. elif (returnvalue.startswith("AVAILABLE_ATTR_TYPE")):
  63. working_available_attrs[-1][1] = json.loads(returnvalue.split(" ", 1)[1])
  64. elif (returnvalue.startswith("AVAILABLE_ATTR_END")):
  65. available_attrs.append(working_available_attrs)
  66. working_available_attrs = []
  67. elif (returnvalue.startswith("ATTR_VALUE")):
  68. v = returnvalue.split(" ", 1)[1]
  69. if v == "None":
  70. v = None
  71. else:
  72. v = json.loads(v)
  73. attribute.append(v)
  74. elif (returnvalue.startswith("SIM_TIME")):
  75. working_simulation = (json.loads(returnvalue.split(" ", 1)[1]), {})
  76. elif (returnvalue.startswith("SIM_PROBE")):
  77. blockname, blockvalue = returnvalue.split(" ", 1)[1].rsplit(" ", 1)
  78. working_simulation[1][json.loads(blockname)] = json.loads(blockvalue)
  79. elif (returnvalue.startswith("SIM_END")):
  80. simulation.append(working_simulation)
  81. working_simulation = None
  82. elif (returnvalue.startswith("CONFORMANCE_OK")):
  83. root.configure(background="grey")
  84. elif (returnvalue.startswith("CONFORMANCE_FAIL")):
  85. root.configure(background="red")
  86. elif (returnvalue.startswith("ALGEBRAIC_LOOP")):
  87. root.configure(background="blue")
  88. else:
  89. print("Error: got unknown result: " + returnvalue)
  90. class MvLayer():
  91. def __init__(self, address):
  92. import threading
  93. self.address = address
  94. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % username, "username": "user_manager"}))).read()
  95. thrd = threading.Thread(target=poll, args=[address])
  96. thrd.daemon = True
  97. thrd.start()
  98. def read_available_attributes(self, name):
  99. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"read_available_attributes"', "username": username}))).read()
  100. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  101. while not available_attrs:
  102. time.sleep(0.1)
  103. return available_attrs.pop(0)
  104. def read_attribute(self, name, attr):
  105. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"read_attribute"', "username": username}))).read()
  106. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  107. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % attr, "username": username}))).read()
  108. while not attribute:
  109. time.sleep(0.1)
  110. return attribute.pop(0)
  111. def set_attribute(self, name, attr, value):
  112. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"set_attribute"', "username": username}))).read()
  113. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  114. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % attr, "username": username}))).read()
  115. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": json.dumps(value), "username": username}))).read()
  116. def instantiate_block(self, name, block_type):
  117. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"instantiate_node"', "username": username}))).read()
  118. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (block_type), "username": username}))).read()
  119. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (name), "username": username}))).read()
  120. def instantiate_link(self, name, link_type, source, target):
  121. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"instantiate_association"', "username": username}))).read()
  122. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (link_type), "username": username}))).read()
  123. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (name), "username": username}))).read()
  124. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (source), "username": username}))).read()
  125. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (target), "username": username}))).read()
  126. def simulate(self):
  127. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"simulate"', "username": username}))).read()
  128. def pause(self):
  129. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"pause"', "username": username}))).read()
  130. def send_event(self, event):
  131. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"event"', "username": username}))).read()
  132. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (event), "username": username}))).read()
  133. def delete(self, block):
  134. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"delete_element"', "username": username}))).read()
  135. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (block), "username": username}))).read()
  136. def lower(value):
  137. return value / JUMP * JUMP
  138. def upper(value):
  139. return (value / JUMP + 1) * JUMP
  140. def avg(a, b):
  141. return float(a + b) / 2
  142. class InterfaceCore():
  143. drawn = set()
  144. refs = dict()
  145. #mv = MvLayer(address)
  146. mv = FakeLayer(address)
  147. def delete(self, x, y):
  148. lname = self.find((x, y))
  149. self.mv.delete(lname)
  150. for i in self.refs[lname]:
  151. canvas.delete(i)
  152. del self.refs[lname]
  153. if lname in names:
  154. self.canvas.delete(names[lname])
  155. del names[lname]
  156. self.drawn = set([e for e in self.drawn if e[4] != lname])
  157. def clicked(self, event):
  158. if self.find((event.x, event.y)):
  159. # Something already there, so don't add, but modify
  160. lname = self.find((event.x, event.y))
  161. attrs = self.mv.read_available_attributes(lname)
  162. for attr, t in attrs:
  163. old_value = self.mv.read_attribute(lname, attr)
  164. if old_value == "None":
  165. old_value = None
  166. new_value = tkSimpleDialog.askstring("Attribute modification", attr, initialvalue=old_value)
  167. if t == "Float":
  168. new_value = float(new_value)
  169. elif t == "String":
  170. new_value = str(new_value)
  171. elif t == "Natural":
  172. new_value = int(new_value)
  173. else:
  174. print("Got unknown type: " + str(t))
  175. self.mv.set_attribute(lname, attr, new_value)
  176. if attr == "name":
  177. if lname in names:
  178. self.canvas.delete(names[lname])
  179. del names[lname]
  180. entry = [x for x in self.drawn if x[4] == lname]
  181. xc, xy = avg(entry[0], entry[2]), avg(entry[1], entry[3])
  182. names[lname] = self.canvas.create_text(xc, xy, text=new_value)
  183. else:
  184. global name
  185. x = event.x
  186. y = event.y
  187. self.mv.instantiate_block(str(name), "State")
  188. r = canvas.create_oval(lower(x), lower(y), upper(x), upper(y), fill="white")
  189. b = (lower(x), lower(y), upper(x), upper(y), str(name), "NODE")
  190. self.drawn.add(b)
  191. self.refs[str(name)] = [r]
  192. name += 1
  193. def find(self, location):
  194. def sqrt(a):
  195. return a**0.5
  196. x, y = location
  197. matches = []
  198. for e in self.drawn:
  199. x1, y1, x2, y2, x0, y0 = e[0], e[1], e[2], e[3], x, y
  200. if e[5] == "LINK":
  201. distance = abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2) - CLICK_TOLERANCE
  202. elif e[5] == "NODE":
  203. if x0 <= x2 and x0 > x1 and y0 <= y2 and y0 > y1:
  204. distance = -float("inf")
  205. else:
  206. distance = float("inf")
  207. matches.append((distance, e[4]))
  208. if matches:
  209. minimal_distance, name = sorted(matches)[0]
  210. if minimal_distance <= 0:
  211. return name
  212. return None
  213. def draw(self, start, end):
  214. source = self.find(start)
  215. target = self.find(end)
  216. if source and target:
  217. global name
  218. self.mv.instantiate_link(str(name), "Transition", source, target)
  219. self.refs[str(name)] = [canvas.create_line(start[0], start[1], end[0], end[1], fill="black", arrow=LAST)]
  220. self.drawn.add((start[0], start[1], end[0], end[1], str(name), "LINK"))
  221. name += 1
  222. def add_event(self, event):
  223. self.mv.send_event(event)
  224. core = InterfaceCore()
  225. def clicked(event):
  226. core.clicked(event)
  227. def draw(event):
  228. global start_location
  229. start_location = (event.x, event.y)
  230. def release(event):
  231. core.draw(start_location, (event.x, event.y))
  232. def simulate():
  233. core.mv.simulate()
  234. def pause():
  235. core.mv.pause()
  236. def delete(event):
  237. core.delete(event.x, event.y)
  238. def add_event():
  239. core.add_event(event_entry.get())
  240. buttons = [
  241. Button(root, text="START", command=simulate),
  242. Button(root, text="PAUSE", command=pause),
  243. Entry(root, textvariable=event_entry),
  244. Button(root, text="EVENT", command=add_event),
  245. ]
  246. for i, b in enumerate(buttons):
  247. b.grid(row=0, column=i)
  248. canvas.grid(row=1,column=0,columnspan=len(buttons))
  249. core.canvas = canvas
  250. for i in range(JUMP, MAX_HEIGHT, JUMP):
  251. canvas.create_line(0, i, MAX_HEIGHT, i, fill="grey")
  252. for i in range(JUMP, MAX_WIDTH, JUMP):
  253. canvas.create_line(i, 0, i, MAX_WIDTH, fill="grey")
  254. canvas.bind("<Button-1>", clicked)
  255. canvas.bind("<Button-2>", delete)
  256. canvas.bind("<Button-3>", draw)
  257. canvas.bind("<ButtonRelease-3>", release)
  258. visual = Toplevel(root)
  259. # Example:
  260. # simulation = [(1, "A"), (3, "B"), (4, "A")]
  261. simulation = [(1, "A"), (3, "B"), (4, "A")]
  262. frame = Frame(visual)
  263. frame.pack(fill=BOTH,expand=True)
  264. f = Figure()
  265. a = f.add_subplot(111)
  266. a.plot([], [])
  267. f.suptitle("Events")
  268. fcanvas = FigureCanvasTkAgg(f, frame)
  269. fcanvas.show()
  270. fcanvas.get_tk_widget().pack()
  271. reverse_lookup = {}
  272. def update_graphs():
  273. times = [x[0] for x in simulation]
  274. events = [reverse_lookup.setdefault(x[1], len(reverse_lookup)) for x in simulation]
  275. lookup = [None] * len(reverse_lookup)
  276. for k, v in reverse_lookup.items():
  277. lookup[v] = k
  278. a.clear()
  279. a.plot(times, events, linestyle="none", marker="o")
  280. f.get_axes()[0].set_yticks(range(-2, len(lookup) + 2))
  281. f.get_axes()[0].set_yticklabels(["", ""] + lookup + ["", ""])
  282. fcanvas.draw()
  283. root.after(500, update_graphs)
  284. root.after(500, update_graphs)
  285. root.mainloop()