Пример #1
0
    def __init__(self) -> None:
        super().__init__()
        self.bg_color = "#000000"
        self.line_color = "#FFFFFF"
        self.image = None
        self.clear_path()
        self.lsystem = Lsystem("lsystem", "", {})

        # Creating l-system image object
        self.limage = LsystemImage(self.lsystem)
        self.image_drawer = LsystemImageDrawer(self.limage)
        self.image_drawer.finishSignal.connect(self.update_label)
        # Creating drawer for image into thread for multithreading
        self.draw_thread = QThread()
        self.draw_thread.started.connect(self.image_drawer.work)
        self.image_drawer.moveToThread(self.draw_thread)
        self.image_drawer.finishSignal.connect(self.draw_thread.quit)

        # Creating scaled l-ystem image object
        self.scaled_limage = LsystemImage(self.lsystem)
        self.scaled_image_drawer = LsystemImageDrawer(self.scaled_limage)
        self.scaled_image_drawer.finishSignal.connect(self.save_image)
        # Creating drawer for scaled image into thread
        self.scaled_draw_thread = QThread()
        self.scaled_draw_thread.started.connect(self.scaled_image_drawer.work)
        self.scaled_image_drawer.moveToThread(self.scaled_draw_thread)
        self.scaled_image_drawer.finishSignal.connect(
            self.scaled_draw_thread.quit)

        # Creatign database manager window
        self.db_manager = Window_db(self)

        # Loading ui
        self.initUi()
Пример #2
0
 def _update_step_length(self, limage: LsystemImage, scale: int) -> None:
     limage.set_step_length(self.spinBox_step_length.value() * scale)
Пример #3
0
 def _update_rot_angle_div(self, limage: LsystemImage) -> None:
     rad_angle = angle_part_of_circle(self.spinBox_plane_div.value())
     limage.set_rot_angle(rad_angle)
Пример #4
0
 def _update_rot_angle_angle(self, limage: LsystemImage) -> None:
     rad_angle = deg_to_rad(self.spinBox_angle.value())
     limage.set_rot_angle(rad_angle)
Пример #5
0
 def _update_start_coords(self, limage: LsystemImage, scale: int) -> None:
     image_x, image_y = decart_to_image_coords(
         (self.spinBox_start_x.value() * scale,
          self.spinBox_start_y.value() * scale),
         limage.get_size())
     limage.set_start_coords(image_x, image_y)
Пример #6
0
 def _update_size(self, limage: LsystemImage, scale: int) -> None:
     limage.set_size(self.spinBox_size_x.value() * scale,
                     self.spinBox_size_y.value() * scale)
Пример #7
0
class MainWindow(QMainWindow, BasicUiUtils, Ui_MainWindow):
    def __init__(self) -> None:
        super().__init__()
        self.bg_color = "#000000"
        self.line_color = "#FFFFFF"
        self.image = None
        self.clear_path()
        self.lsystem = Lsystem("lsystem", "", {})

        # Creating l-system image object
        self.limage = LsystemImage(self.lsystem)
        self.image_drawer = LsystemImageDrawer(self.limage)
        self.image_drawer.finishSignal.connect(self.update_label)
        # Creating drawer for image into thread for multithreading
        self.draw_thread = QThread()
        self.draw_thread.started.connect(self.image_drawer.work)
        self.image_drawer.moveToThread(self.draw_thread)
        self.image_drawer.finishSignal.connect(self.draw_thread.quit)

        # Creating scaled l-ystem image object
        self.scaled_limage = LsystemImage(self.lsystem)
        self.scaled_image_drawer = LsystemImageDrawer(self.scaled_limage)
        self.scaled_image_drawer.finishSignal.connect(self.save_image)
        # Creating drawer for scaled image into thread
        self.scaled_draw_thread = QThread()
        self.scaled_draw_thread.started.connect(self.scaled_image_drawer.work)
        self.scaled_image_drawer.moveToThread(self.scaled_draw_thread)
        self.scaled_image_drawer.finishSignal.connect(
            self.scaled_draw_thread.quit)

        # Creatign database manager window
        self.db_manager = Window_db(self)

        # Loading ui
        self.initUi()

    def initUi(self) -> None:
        # Loading ui from converted file
        self.setupUi(self)
        self.retranslateUi(self)

        # Connectiong signals
        self.spinBox_step.valueChanged.connect(self.update_step_slider)
        self.horizontalSlider_step.valueChanged.connect(
            self.update_step_spinbox)
        self.pushButton_update.clicked.connect(self.generate_result)
        self.pushButton_ch_bg_color.clicked.connect(self.request_bg_color)
        self.pushButton_ch_line_color.clicked.connect(self.request_line_color)
        self.pushButton_clear.clicked.connect(self.clear_label)
        self.radioButton_angle_mode.clicked.connect(self.set_angle_mode)
        self.radioButton_div_mode.clicked.connect(self.set_plane_div_mode)
        self.pushButton_save_image.clicked.connect(self.generate_scaled_result)
        self.action_open.triggered.connect(self.open)
        self.action_new.triggered.connect(self.new)
        self.action_save.triggered.connect(self.save)
        self.action_saveas.triggered.connect(self.saveas)
        self.action_exit.triggered.connect(exit)
        self.action_open_db_manager.triggered.connect(self.db_manager.show)
        self.action_save_to_db.triggered.connect(self.save_to_db)

    # Wrapper function for updating params
    def update_lsystem_params(self) -> None:
        self._update_name()
        self._update_inititator()
        self._update_rules()

    def update_limage_params(self, limage: LsystemImage, scale: int = 1) -> None:
        self._update_size(limage, scale)
        self._update_start_coords(limage, scale)
        self._update_start_angle(limage)
        if self.radioButton_angle_mode.isChecked():
            self._update_rot_angle_angle(limage)
        else:
            self._update_rot_angle_div(limage)
        self._update_step_length(limage, scale)

    def update_drawer_params(self, drawer: LsystemImageDrawer) -> None:
        self._update_iteration(drawer)

    def _update_name(self) -> None:
        self.lsystem.set_name(self.lineEdit_name.text())

    def _update_inititator(self) -> None:
        self.lsystem.set_inititator(self.lineEdit_initiator.text())

    def _update_rules(self) -> None:
        # Checking if rules is not empty
        try:
            rules_dict = strings_to_dict(
                self.plainTextEdit_rules.toPlainText().split("\n"), " ")
        except IndexError:
            # On empty rules dont change anything
            return
        self.lsystem.set_rules(rules_dict)

    def _update_size(self, limage: LsystemImage, scale: int) -> None:
        limage.set_size(self.spinBox_size_x.value() * scale,
                        self.spinBox_size_y.value() * scale)

    def _update_start_coords(self, limage: LsystemImage, scale: int) -> None:
        image_x, image_y = decart_to_image_coords(
            (self.spinBox_start_x.value() * scale,
             self.spinBox_start_y.value() * scale),
            limage.get_size())
        limage.set_start_coords(image_x, image_y)

    def _update_start_angle(self, limage: LsystemImage) -> None:
        rad_angle = deg_to_rad(self.spinBox_start_angle.value())
        limage.set_start_angle(rad_angle)

    def _update_rot_angle_angle(self, limage: LsystemImage) -> None:
        rad_angle = deg_to_rad(self.spinBox_angle.value())
        limage.set_rot_angle(rad_angle)

    def _update_rot_angle_div(self, limage: LsystemImage) -> None:
        rad_angle = angle_part_of_circle(self.spinBox_plane_div.value())
        limage.set_rot_angle(rad_angle)

    def _update_step_length(self, limage: LsystemImage, scale: int) -> None:
        limage.set_step_length(self.spinBox_step_length.value() * scale)

    def _update_iteration(self, drawer: LsystemImageDrawer) -> None:
        drawer.set_iteration(self.spinBox_step.value())

    def new(self) -> None:
        self.clear_path()
        self.spinBox_angle.setValue(0)
        self.spinBox_plane_div.setValue(2)
        self.spinBox_start_angle.setValue(0)
        self.spinBox_step.setValue(1)
        self.horizontalSlider_step.setValue(1)
        self.lineEdit_name.clear()
        self.lineEdit_initiator.clear()
        self.plainTextEdit_rules.clear()
        self.clear_label()

    def save_data(self) -> None:
        name = self.lineEdit_name.text()
        if not name:
            name = "lsystem"
        if self.radioButton_angle_mode.isChecked():
            angle_div = self.spinBox_angle.value()
        else:
            angle_div = self.spinBox_plane_div.value()
        initiator = self.lineEdit_initiator.text()
        rules_text = self.plainTextEdit_rules.toPlainText()
        with open(self.path, "w") as f:
            f.write(name + "\n")
            f.write(str(angle_div) + "\n")
            f.write(initiator + "\n")
            f.write(rules_text + "\n")

    def save(self) -> None:
        if self.path is not None:
            self.save_data()
        else:
            self.saveas()

    def saveas(self) -> None:
        # Checking if file selected
        try:
            self.path = self.requset_save_path(
                "Сохранить l-систему", "l-system files (*.ls)")
            self.save_data()
        except FileNotFoundError:
            # Doing nothing if no file selected
            return

    def open(self) -> None:
        # Checking if file selected
        try:
            self.path = self.request_open_path(
                "Открыть l-систему", "l-system files (*.ls)")
        except FileNotFoundError:
            # Doing nothing if no file selected
            return
        # Loading data if file selected
        self.load_data()

    def load_data(self) -> None:
        with open(self.path, "r") as f:
            text = f.read()
        lines = text.strip().split("\n")
        lines = tuple(line.strip() for line in lines)
        # Checking for file format
        if not (lines[1].isdecimal() and
                all(map(lambda line: " " in line, lines[3:]))):
            self.clear_path()
            self.show_messagebox("Неверный формат файла!")
            return
        try:
            # Asking for loading mode
            mode = self.request_choice(
                "Как загрузить данные", "Выберите режим поворотов", ("Деление плоскости", "Угол"))
        except InterruptedError:
            # Clearing path and exiting if mode not selected
            self.clear_path()
            return
        name = lines[0]
        angle_div = int(lines[1])
        initiator = lines[2]
        rules_text = "\n".join(lines[3:])
        if mode == "Угол":
            self.set_angle_mode()
            self.spinBox_angle.setValue(angle_div)
        else:
            self.set_plane_div_mode()
            self.spinBox_plane_div.setValue(angle_div)
        self.lineEdit_name.setText(name)
        self.lineEdit_initiator.setText(initiator)
        self.plainTextEdit_rules.setPlainText(rules_text)

    def clear_path(self) -> None:
        self.path = None

    def request_line_color(self) -> None:
        try:
            color = self.request_color()
        except ValueError:
            return
        self.limage.set_line_color(color)
        self.scaled_limage.set_line_color(color)

    def request_bg_color(self) -> None:
        try:
            color = self.request_color()
        except ValueError:
            return
        self.limage.set_bg_color(color)
        self.scaled_limage.set_bg_color(color)

    def generate_result(self) -> None:
        self.update_lsystem_params()
        self.update_limage_params(self.limage)
        self.update_drawer_params(self.image_drawer)
        self.draw_thread.start()

    def check_values(self) -> bool:
        return self.lineEdit_initiator.text() and self.plainTextEdit_rules.toPlainText()

    def get_rule_strings(self) -> list:
        text = self.plainTextEdit_rules.toPlainText()
        return text.split("\n")

    def update_step_slider(self) -> None:
        self.horizontalSlider_step.setValue(self.spinBox_step.value())

    def update_step_spinbox(self) -> None:
        self.spinBox_step.setValue(self.horizontalSlider_step.value())

    def update_label(self) -> None:
        image = self.limage.get_image()
        pixmap = image_to_pixmap(image)
        self.label_result.setPixmap(pixmap)

    def clear_label(self) -> None:
        self.label_result.clear()

    def set_angle_mode(self) -> None:
        self.radioButton_angle_mode.setChecked(True)
        self.spinBox_angle.setEnabled(True)
        self.spinBox_plane_div.setEnabled(False)

    def set_plane_div_mode(self) -> None:
        self.radioButton_div_mode.setChecked(True)
        self.spinBox_angle.setEnabled(False)
        self.spinBox_plane_div.setEnabled(True)

    def save_image(self) -> None:
        try:
            path = self.requset_save_path("Сохранить", "All files (*.*)")
        except FileNotFoundError:
            return
        img = self.scaled_limage.get_image()
        img = img.convert("RGBA")
        img.save(path)

    def generate_scaled_result(self) -> None:
        scale = self.spinBox_scale.value()
        self.update_lsystem_params()
        self.update_limage_params(self.scaled_limage, scale)
        self.update_drawer_params(self.scaled_image_drawer)
        self.scaled_draw_thread.start()

    def save_to_db(self):
        name = self.lineEdit_name.text()

        # Checking name
        if not name:
            name = "lsystem"
        if self.radioButton_angle_mode.isChecked():
            angle_div = self.spinBox_angle.value()
        else:
            angle_div = self.spinBox_plane_div.value()

        # Loading params
        initiator = self.lineEdit_initiator.text()
        rules_text = self.plainTextEdit_rules.toPlainText()
        if self.radioButton_angle_mode.isChecked():
            rot_angle = self.spinBox_angle.value()
            plane_div = ""
        else:
            rot_angle = ""
            plane_div = self.spinBox_plane_div.value()

        self.db_manager.create_cursor()

        # Checking is same system exists
        id_with_name = self.db_manager.execute_query_fetchone(
            f"SELECT id FROM lsystems WHERE name = '{name}'")
        if id_with_name:
            # Asking for overwrite
            ans = QMessageBox.question(self, "Перезапись",
                                       "Такая система уже сохранена в БД, перезаписать?",
                                       QMessageBox.Yes, QMessageBox.No)
            if ans == QMessageBox.Yes:
                self.db_manager.execute_query(f"""UPDATE lsystems
                SET initiator = '{initiator}', rules = '{rules_text}', \
                    rot_angle = '{rot_angle}', plane_div = '{plane_div}'
                WHERE id = {id_with_name[0]}""")
            else:
                return
        else:
            self.db_manager.execute_query(f"""INSERT INTO lsystems(name, initiator, rules, rot_angle, plane_div) \
                VALUES('{name}', '{initiator}', '{rules_text}', '{rot_angle}', '{plane_div}')""")
        self.db_manager.close_cursor()
        self.db_manager.commit_changes()

    # Close app on closing main form
    def closeEvent(self, event):
        exit()