def take_vector_screenshot(self): if self._world.grid.__class__.__name__ == "TriangularGrid": if not os.path.exists("outputs/screenshots") or not os.path.isdir( "outputs/screenshots"): os.mkdir("outputs/screenshots") directory = "." if os.path.exists("outputs/screenshots") and os.path.isdir( "outputs/screenshots"): directory = "outputs/screenshots" path = TopQFileDialog(self._splitter).getSaveFileName( options=(TopQFileDialog.Options()), filter="*.svg", directory=directory) if path[0] == '': return if path[0].endswith(".svg"): create_svg(self._world, path[0]) else: create_svg(self._world, path[0] + ".svg") else: show_msg( "Not implemented yet.\nWorks only with Triangular Grid for now!\nSorry!", Level.WARNING, self._splitter)
def init_scenario(self, scenario_module): if self.config_data.visualization: # if visualization is on, run the scenario in a separate thread and show that the program runs.. x = threading.Thread(target=load_scenario, args=( scenario_module, self, )) self.vis.wait_for_thread(x, "loading scenario... please wait.", "Loading Scenario") else: # if no vis, just run the scenario on the main thread load_scenario(scenario_module, self) if self._scenario_load_error is not None: show_msg( "Error while loading Scenario:\n%s" % self._scenario_load_error.msg, Level.CRITICAL, self.vis.get_main_window()) exit(1) if self.vis is not None: self.vis.update_visualization_data() if self.config_data.agent_random_order: random.shuffle(self.agents)
def export_recording(self): if len(self.recorder.records) == 0: show_msg("No rounds recorded. Nothing to export.", Level.INFO, self._splitter) return if self._running: self.start_stop() self._viewer.set_show_info_frame(False) self._viewer.set_enable_cursor(False) if "set_disable_sim" in dir(self._gui_module): self._gui_module.set_disable_sim(True) else: show_msg( "No 'set_disable_sim(disable_flag)' function in gui module found." "\nRunning simulation within recording mode may result in undefined behavior!", Level.WARNING, self._splitter) self.recorder.show(self.do_export) # loop while self.recorder.is_open(): self._process_events() # go back to the main window if "set_disable_sim" in dir(self._gui_module): self._gui_module.set_disable_sim(False) self._viewer.agent_update_flag = True self._viewer.item_update_flag = True self._viewer.location_update_flag = True self._viewer.update_data() self._viewer.set_show_info_frame(True) self._viewer.set_enable_cursor(True)
def save_scenario(fn): try: f = open(fn, "w+") f.write("def scenario(world):\n") for prtc in self.agent_map_coordinates.values(): f.write("\tworld.add_agent(%s, color=%s)\n" % (str(prtc.coordinates), str(prtc.get_color()))) for tl in self.item_map_coordinates.values(): f.write("\tworld.add_item(%s, color=%s)\n" % (str(tl.coordinates), str(tl.get_color()))) for lctn in self.location_map_coordinates.values(): f.write("\tworld.add_location(%s, color=%s)\n" % (str(lctn.coordinates), str(lctn.get_color()))) f.flush() f.close() except IOError as e: show_msg("Couldn't save scenario.\n%s" % e, Level.WARNING, self.vis.get_main_window())
def wait_for_thread(self, thread: Thread, window_message, window_title): """ executes a thread and shows a loading window till the thread stops. blocks the gui, while thread runs. :param thread: the thread :param window_message: the displayed message :param window_title: the title of the loading window :return: """ loading_window = LoadingWindow(window_message, window_title) if self._gui is not None and issubclass(self._gui.__class__, QWidget): self._gui.setDisabled(True) thread.start() while thread.is_alive(): try: self._process_events() except VisualizationError as ve: show_msg(ve, Level.CRITICAL, self._splitter) exit(1) thread.join() loading_window.close() self._gui.setDisabled(False)
def run(self, round_start_timestamp): """ main function for running the simulation with the visualization. At this time, its just error handling here.. the simulation and drawing stuff starts in the run_iteration method :param round_start_timestamp: timestamp of the start of the round. :return: """ try: self._run_iteration(round_start_timestamp) except VisualizationError as ve: if ve.level == Level.INFO: show_msg(ve.msg, ve.level, self.get_main_window()) if ve.level == Level.CRITICAL: show_msg(ve.msg, ve.level, self.get_main_window()) exit(1) if ve.level == Level.WARNING: try: self._run_iteration(round_start_timestamp) show_msg(ve.msg, ve.level, self.get_main_window()) except VisualizationError as ve: show_msg(ve.msg, ve.level, self.get_main_window()) if ve.level != Level.INFO: exit(1)
def save_scenario(self, quick): def save_scenario(fn): try: f = open(fn, "w+") f.write("def scenario(world):\n") for prtc in self.agent_map_coordinates.values(): f.write("\tworld.add_agent(%s, color=%s)\n" % (str(prtc.coordinates), str(prtc.get_color()))) for tl in self.item_map_coordinates.values(): f.write("\tworld.add_item(%s, color=%s)\n" % (str(tl.coordinates), str(tl.get_color()))) for lctn in self.location_map_coordinates.values(): f.write("\tworld.add_location(%s, color=%s)\n" % (str(lctn.coordinates), str(lctn.get_color()))) f.flush() f.close() except IOError as e: show_msg("Couldn't save scenario.\n%s" % e, Level.WARNING, self.vis.get_main_window()) # create scenario folder, if it doesn't already exist. if not os.path.exists("components/scenario") or not os.path.isdir( "components/scenario"): os.mkdir("components/scenario") if quick: # if the scenario folder exists, try to create and save the new scenario file, if it fails print the error. if os.path.exists("components/scenario") and os.path.isdir( "components/scenario"): now = datetime.datetime.now() filename = str( "components/scenario/%d-%d-%d_%d-%d-%d_scenario.py" % (now.year, now.month, now.day, now.hour, now.minute, now.second)) save_scenario(filename) # checks if the file exists. If not, some unknown error occured while saving. if not os.path.exists(filename) or not os.path.isfile( filename): show_msg( "Error: scenario couldn't be saved due to an unknown reason.", Level.WARNING, self.vis.get_main_window()) else: show_msg("\"scenario\" folder couldn't be created.", Level.WARNING, self.vis.get_main_window()) else: directory = "." if os.path.exists("components/scenario") and os.path.isdir( "components/scenario"): directory = "components/scenario" path = TopQFileDialog(self.vis.get_main_window()).getSaveFileName( options=TopQFileDialog.Options(), filter="*.py", directory=directory) if path[0] == '': return if path[0].endswith(".py"): save_scenario(path[0]) else: save_scenario(path[0] + ".py")
def do_export(self, rps, width, height, codec, first_frame_idx, last_frame_idx, animation): if not os.path.exists("outputs/videos") or not os.path.isdir( "outputs/videos"): os.mkdir("outputs/videos") directory = "." if os.path.exists("outputs/videos") and os.path.isdir( "outputs/videos"): directory = "outputs/videos" path = TopQFileDialog(self._splitter).getSaveFileName( options=(TopQFileDialog.Options()), filter="*.mp4;;*.avi;;*.mkv", directory=directory) if path[0] == '': return if path[0].endswith("mp4") or path[0].endswith( ".avi") or path[0].endswith(".mkv"): fullpath = path[0] else: fullpath = path[0] + path[1].replace('*', '') if animation: animation_steps = int(30 / rps) if animation_steps < 1: animation_steps = 1 else: animation_steps = 1 writer = cv2.VideoWriter(fullpath, cv2.VideoWriter_fourcc(*codec), rps * animation_steps, (width, height)) self._viewer.setDisabled(True) # creating and opening loading window lw = LoadingWindow("", "Exporting Video...") lw.show() out_of = (last_frame_idx - first_frame_idx + 1) * animation_steps for i in range(first_frame_idx - 1, last_frame_idx): # render and write frame self._viewer.inject_record_data(self.recorder.records[i]) # animate for j in range(1, animation_steps + 1): # process events so the gui thread does respond to interactions.. self._process_events() # update loading windows text and progress bar processing = (i - first_frame_idx + 1) * animation_steps + j lw.set_message("Please wait!\nExporting frame %d/%d..." % (processing, out_of)) lw.set_progress(processing, out_of) self._viewer.set_animation_percentage(j / animation_steps) self._viewer.glDraw() img = self._viewer.get_frame_cv(width, height) writer.write(img) self._viewer.inject_record_data(self.recorder.records[last_frame_idx - 1]) writer.release() lw.close() self._viewer.setDisabled(False) self._viewer.resizeGL(self._viewer.width(), self._viewer.height()) self._viewer.update_scene() show_msg("Video exported successfully!", Level.INFO, self._splitter)
def __init__(self, world): """ Main Interface between the OpenGL stuff and the simulator. Initializes the camera, and the opengl-widget. controlls the speed of the simulation. :param world: the world class """ self._world = world self._last_light_rotation = 0 self._rounds_per_second = 10 self._reset_flag = False self._running = False self._app = None self._viewer = None self._gui = None self._splitter = None self._recording = False self._animation = world.config_data.animation self._auto_animation = world.config_data.auto_animation self._manual_animation_speed = world.config_data.manual_animation_speed self.light_rotation = False self.grid_size = world.grid.size # create the QApplication self._app = QApplication([]) # create camera for the visualization # if grid is 2D, set to orthographic projection (it is better for 2D) if self._world.grid.get_dimension_count() == 2: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "ortho", self._world.grid.get_scaling()) else: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "perspective", self._world.grid.get_scaling()) # create the opengl widget self._viewer = OGLWidget(self._world, self._camera) self._viewer.glInit() self.recorder = Recorder(self._world, self._viewer) # create and show the main Window self._splitter = QSplitter() self._splitter.closeEvent = close self._splitter.setMinimumWidth(self._world.config_data.window_size_x) self._splitter.setMinimumHeight(self._world.config_data.window_size_y) self._splitter.setWindowTitle("Simulator") self._splitter.show() # create gui # creating the gui has to happen after showing the window, so the gui can access # opengl variables and programs during creation self._gui_module = importlib.import_module('components.gui.' + self._world.config_data.gui) # the key press handler def key_press_event(event): self._gui_module.key_handler(event.key(), self._world, self) # loading key handler from gui module if "key_handler" in dir(self._gui_module): self._viewer.keyPressEventHandler = key_press_event self._splitter.keyPressEvent = key_press_event else: show_msg("No key_handler(key, vis) function found in gui module!", Level.WARNING, self._splitter) # loading gui from gui module if "create_gui" in dir(self._gui_module): self._gui = self._gui_module.create_gui(self._world, self) if self._gui is not None and issubclass(self._gui.__class__, QWidget): self._splitter.addWidget(self._gui) self._splitter.keyPressEvent = self._viewer.keyPressEvent self._splitter.keyReleaseEvent = self._viewer.keyReleaseEvent self._splitter.addWidget(self._viewer) self._splitter.setSizes([ self._world.config_data.window_size_x * 0.25, self._world.config_data.window_size_x * 0.75 ]) else: # noinspection PyUnresolvedReferences show_msg( "The create_gui(world, vis) function in gui module didn't return a QWidget." + "Expected a QWidget or a subclass, but got %s." % self._gui.__class__.__name__, Level.WARNING, self._splitter) self._splitter.addWidget(self._viewer) else: show_msg( "No create_gui(world, vis) function found in gui module. GUI not created", Level.INFO, self._splitter) self._splitter.addWidget(self._viewer) # waiting for the simulation window to be fully active while not self._splitter.windowHandle().isExposed(): self._process_events() # first update and draw call. self._viewer.update_scene()
def export_call(): try: input_rps = float(fps_edit.text()) if input_rps <= 0: show_msg("Rounds per second has to be greater than 0!", Level.WARNING, window) return except ValueError: show_msg("Rounds per second has to be a number!", Level.WARNING, window) return try: input_width = int(width_edit.text()) if input_width <= 0: show_msg("Width has to be greater than 0!", Level.WARNING, window) return except ValueError: show_msg("Width has to be an integer!", Level.WARNING, window) return try: input_height = int(height_edit.text()) if input_height <= 0: show_msg("Height has to be greater than 0!", Level.WARNING, window) return except ValueError: show_msg("Height has to be an integer!", Level.WARNING, window) return try: ff = int(start_frame.text()) ef = int(end_frame.text()) if ff < 1 or ef < 1: show_msg("frame index cannot be lower than 1", Level.WARNING, window) return if ff > len(self.records) or ef > len(self.records): show_msg( "frame index cannot be higher than the index of last frame (%d)" % len(self.records), Level.WARNING, window) return if ff > ef: show_msg( "index of first frame cannot be higher than index of last frame", Level.WARNING, window) return except ValueError: show_msg("frame index has to be an integer!", Level.WARNING, window) return window.setDisabled(True) export_callback(input_rps, input_width, input_height, codec_combo.itemData(codec_combo.currentIndex()), ff, ef, anim_checkbox.isChecked()) window.setDisabled(False)
def on_click(): if size_edit.text().isnumeric(): vis.recalculate_grid(int(size_edit.text())) else: show_msg("Grid size has to be a number.", Level.WARNING, vis.get_main_window())