예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
 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())
예제 #5
0
    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)
예제 #6
0
 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)
예제 #7
0
    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")
예제 #8
0
    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)
예제 #9
0
    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()
예제 #10
0
        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)
예제 #11
0
 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())