diff --git a/my_gui/custom_elements/course_view/CourseMap.py b/my_gui/custom_elements/course_view/CourseMap.py index 5fe413b..6859337 100644 --- a/my_gui/custom_elements/course_view/CourseMap.py +++ b/my_gui/custom_elements/course_view/CourseMap.py @@ -5,6 +5,7 @@ import logging from clients.mqtt.listeners import ParamListener from dataholders import DataHolder +import numpy as np CAR_IMG = 0 DIR_SW_IMG = 1 @@ -26,7 +27,7 @@ MANEUVER_TURN_FOLLOW_RIGHT = 6 MANEUVER_EXIT_THROUGH = 7 MANEUVER_LANE_SW_LEFT = 8 -MANEUVER_LANE_SW_RIGHT =9 +MANEUVER_LANE_SW_RIGHT = 9 MANEUVER_STOP = 10 NAVI_EVENT_CROSSING_FRONT = 0 @@ -39,7 +40,8 @@ class CourseMap(tkinter.Frame): - def __init__(self, parent, client: ParamListener, id, dataholder: DataHolder, assets_path='./assets/map', *args, **kwargs): + def __init__(self, parent, client: ParamListener, id, dataholder: DataHolder, assets_path='./assets/map', *args, + **kwargs): tkinter.Frame.__init__(self, parent, *args, **kwargs) self.logger = logging.getLogger('RKID.CourseView') @@ -57,11 +59,11 @@ def __init__(self, parent, client: ParamListener, id, dataholder: DataHolder, as 'maneuver': MANEUVER_STOP } - with open(assets_path+'/course.json') as node_file: + with open(assets_path + '/course.json') as node_file: self.node_info = json.load(node_file) self.ratio = 1 - self.base_img = Image.open(assets_path+'/course.png') + self.base_img = Image.open(assets_path + '/course.png') self.base_width, self.base_height = self.base_img.size self.canvas_img = ImageTk.PhotoImage(self.base_img) self.canvas = tkinter.Canvas(self, width=self.canvas_img.width(), bg='#f0f0f0', height=self.canvas_img.height()) @@ -69,65 +71,73 @@ def __init__(self, parent, client: ParamListener, id, dataholder: DataHolder, as self.is_resized = True self.resized_img = self.canvas_img - figs_paths = ['car_car.png', 'car_dir_sw.png', 'car_exit.png', 'car_lane_left.png', 'car_lane_right.png', 'car_left.png', 'car_right.png', 'car_middle.png', 'car_STOP.png', 'car_line_sensor.png'] + figs_paths = ['car_car.png', 'car_dir_sw.png', 'car_exit.png', 'car_lane_left.png', 'car_lane_right.png', + 'car_left.png', 'car_right.png', 'car_middle.png', 'car_STOP.png', 'car_line_sensor.png'] self.car_ratio = self.node_info['car_rat'] self.fig_imgs = [] self.fig_imgs_resiz = [] for fig_path in figs_paths: - img = Image.open(assets_path+'/figs/'+fig_path).convert('RGBA') - self.fig_imgs.append(img.resize((int(self.car_ratio*img.width), int(self.car_ratio*img.height)), Image.ANTIALIAS)) + img = Image.open(assets_path + '/figs/' + fig_path).convert('RGBA') + self.fig_imgs.append( + img.resize((int(self.car_ratio * img.width), int(self.car_ratio * img.height)), Image.ANTIALIAS)) self.fig_imgs_resiz.append(self.fig_imgs[-1]) self.car_base_width, self.car_base_height = self.fig_imgs[0].size self.car_img = ImageTk.PhotoImage(self.fig_imgs_resiz[CAR_IMG]) self.car_img_id = self.canvas.create_image((100, 50), image=self.car_img) - self.disabled_gui = [] + self.disabled_gui = [{'idx': None, 'tag': None} for i in range(0, 4)] self.goal_gui = {'idx': None, 'tag': None} self.goal_car = {'idx': None, 'tag': None} self.disabled_car = [{'idx': None, 'tag': None} for i in range(0, 4)] self.marker_rad = self.fig_imgs_resiz[0].height * self.car_ratio - self.send_btn = tkinter.Button(self.canvas, text="Send", bg='RoyalBlue1', activebackground='navy', command=self.on_btn_send_click) + self.send_btn = tkinter.Button(self.canvas, text="Send", bg='RoyalBlue1', activebackground='navy', + command=self.on_btn_send_click) # self.send_btn.pack(side=tkinter.RIGHT, anchor=tkinter.SE) self.send_btn.place(x=self.canvas_img.width(), - y=self.canvas_img.height()-10, - width=self.canvas_img.width()/8, height=self.canvas_img.height()/12, anchor=tkinter.SE) + y=self.canvas_img.height(), + width=self.canvas_img.width() / 8, height=self.canvas_img.height() / 12, anchor=tkinter.SE) + self.random_btn = tkinter.Button(self.canvas, text="Randomize", bg='lime green', + activebackground='forest green', + command=self.on_btn_random_click) + self.random_btn.place(x=self.canvas_img.width() - self.canvas_img.width() / 8, + y=self.canvas_img.height(), + width=self.canvas_img.width() / 8, height=self.canvas_img.height() / 12, + anchor=tkinter.SE) self.canvas.pack(side=tkinter.LEFT, expand=True, fill=tkinter.BOTH, anchor=tkinter.NW) self.bind('', self.on_resize) - self.canvas.bind("",self.on_left_click) + self.canvas.bind("", self.on_left_click) self.canvas.bind("", self.on_right_click) self._invalid = True self.continous_update() - def invalidate(self): self._invalid = True def redraw(self): self._invalid = False - self._draw_marker(self.goal_car, 'DarkGoldenrod3', False) - for d in self.disabled_car: - self._draw_marker(d, 'IndianRed1', False) + self._draw_marker(d, 'IndianRed4', False) for d in self.disabled_gui: self._draw_marker(d, 'IndianRed1') - self.disabled_gui = [d for d in self.disabled_gui if d['idx'] is not None] - + self._draw_marker(self.goal_car, 'DarkGoldenrod3', False) self._draw_marker(self.goal_gui, 'gold') self.update_car() self.send_btn.place(x=self.canvas_img.width(), - y=self.canvas_img.height() - 10, + y=self.canvas_img.height(), width=self.canvas_img.width() / 8, height=self.canvas_img.height() / 12, anchor=tkinter.SE) - + self.random_btn.place(x=self.canvas_img.width() - self.canvas_img.width() / 8, + y=self.canvas_img.height(), + width=self.canvas_img.width() / 8, height=self.canvas_img.height() / 12, anchor=tkinter.SE) def _draw_marker(self, marker, color, filled=True): if marker['tag'] is not None: @@ -140,10 +150,10 @@ def _draw_marker(self, marker, color, filled=True): if filled: marker["tag"] = self.canvas.create_oval(self.ratio * (x_c - self.marker_rad), - self.ratio * (y_c - self.marker_rad), - self.ratio * (x_c + self.marker_rad), - self.ratio * (y_c + self.marker_rad), - fill=color) + self.ratio * (y_c - self.marker_rad), + self.ratio * (x_c + self.marker_rad), + self.ratio * (y_c + self.marker_rad), + fill=color) else: self.car_goal_marker = self.canvas.create_oval(self.ratio * (x_c - self.marker_rad), self.ratio * (y_c - self.marker_rad), @@ -171,14 +181,16 @@ def on_resize(self, event): self.canvas_img = self.resized_img for idx, fig_base in enumerate(self.fig_imgs): - self.fig_imgs_resiz[idx] = fig_base.resize((int(self.ratio * self.car_base_width), int(self.ratio * self.car_base_height)), - Image.ANTIALIAS) + self.fig_imgs_resiz[idx] = fig_base.resize( + (int(self.ratio * self.car_base_width), int(self.ratio * self.car_base_height)), + Image.ANTIALIAS) self._invalid = True pass def make_car(self, car_ori, car_dir, maneuver): - img = Image.new('RGBA', ((int(self.ratio * self.car_base_width), int(self.ratio * self.car_base_height))), (0,0,0,0)) + img = Image.new('RGBA', ((int(self.ratio * self.car_base_width), int(self.ratio * self.car_base_height))), + (0, 0, 0, 0)) if car_dir * car_ori > 0: new_img = ImageOps.mirror(self.fig_imgs_resiz[LINE_IMG]) @@ -223,7 +235,8 @@ def make_car(self, car_ori, car_dir, maneuver): if new_img is not None: img.paste(new_img, (0, 0), new_img) - if maneuver in [ MANEUVER_TURN, MANEUVER_TURN_FOLLOW_LEFT, MANEUVER_TURN_FOLLOW_MIDDLE, MANEUVER_TURN_FOLLOW_RIGHT]: + if maneuver in [MANEUVER_TURN, MANEUVER_TURN_FOLLOW_LEFT, MANEUVER_TURN_FOLLOW_MIDDLE, + MANEUVER_TURN_FOLLOW_RIGHT]: new_img = self.fig_imgs_resiz[DIR_SW_IMG] img.paste(new_img, (0, 0), new_img) @@ -236,8 +249,8 @@ def put_car(self, car_img, node_idx, node_dir): angle = math.atan2(self.node_info["dirs"][node_idx][1], self.node_info["dirs"][node_idx][0]) self.car_img = ImageTk.PhotoImage(car_img.rotate(math.degrees(angle), expand=True)) self.canvas.itemconfigure(self.car_img_id, image=self.car_img) - x_basic_offs = self.car_ratio * (350 - 600/2) - y_basic_offs = self.car_ratio * (162 - 324/2) + x_basic_offs = self.car_ratio * (350 - 600 / 2) + y_basic_offs = self.car_ratio * (162 - 324 / 2) car_center = [node_dir * (x_basic_offs * math.cos(angle) - y_basic_offs * math.sin(angle)), node_dir * (x_basic_offs * math.sin(angle) + y_basic_offs * math.cos(angle))] @@ -270,7 +283,9 @@ def update_view(self): for key in data.keys(): self.car_state[key] = data[key][-1] - for i, c_int in enumerate([self.car_state['disabled1'], self.car_state['disabled2'],self.car_state['disabled3'],self.car_state['disabled4']]): + for i, c_int in enumerate( + [self.car_state['disabled1'], self.car_state['disabled2'], self.car_state['disabled3'], + self.car_state['disabled4']]): self.disabled_car[i]['idx'] = self.node_name2idx(c_int) self.goal_car['idx'] = self.node_name2idx(self.car_state['goal node']) @@ -325,7 +340,7 @@ def on_right_click(self, event): self.logger.debug("Why you poke me??") for idx, crd in enumerate(self.node_info["coords"]): - crd = [c*self.ratio for c in crd] + crd = [c * self.ratio for c in crd] if math.dist(crd, [event.x, event.y]) < self.ratio * 40: if not self.node_info['name'][idx].strip(): self.logger.warning(f"Node {idx} has no name, so it can't be disabled!") @@ -343,12 +358,14 @@ def on_right_click(self, event): break if not deleted: - if len(self.disabled_gui) < 4: - self.disabled_gui.append({ - "idx": idx, - "tag": None - }) - else: + added = False + for d in self.disabled_gui: + if d['idx'] is None: + d['idx'] = idx + added = True + break + + if not added: self.logger.warning("Maximum number of disabled nodes reached! Remove before adding new ones!") self.invalidate() @@ -368,7 +385,7 @@ def on_btn_send_click(self): msg = self.node_info['name'][self.goal_gui['idx']] for d in self.disabled_gui: - if self.node_info['name'][d['idx']] is not None: + if d['idx'] is not None and self.node_info['name'][d['idx']] is not None: msg = msg + str(self.node_info['name'][d['idx']]).lower() msg = msg + '\n' @@ -376,3 +393,26 @@ def on_btn_send_click(self): self.client.send_message(self.id, {'msg': msg}) pass + + def on_btn_random_click(self): + disabled_num = np.random.randint(0, 5) + + goal_idx = np.random.randint(1, 16) + + self.goal_gui['idx'] = goal_idx + + disabled_idxs = [] + while len(disabled_idxs) < disabled_num: + next_rnd = np.random.randint(1, 16) + if next_rnd != goal_idx and next_rnd not in disabled_idxs: + disabled_idxs.append(next_rnd) + + for i, idx in enumerate(disabled_idxs): + self.disabled_gui[i]['idx'] = idx + + for i in range(disabled_num, 4): + self.disabled_gui[i]['idx'] = None + + self.logger.info(f"New Random goal: {goal_idx}, disableds: {disabled_idxs}") + self.invalidate() + self.on_btn_send_click()