Skip to content
Snippets Groups Projects
MainWindow.py 14.4 KiB
Newer Older
Djalim Simaila's avatar
Djalim Simaila committed
import os
from PyQt5 import QtWidgets
Djalim Simaila's avatar
Djalim Simaila committed
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QFileDialog, QWidget
Djalim Simaila's avatar
Djalim Simaila committed
from utils.files.input import ScannedObject
Djalim Simaila's avatar
Djalim Simaila committed
from utils.gui.pyqt.settings.Settings import Settings
from utils.settings.SettingManager import SettingManager
Djalim Simaila's avatar
Djalim Simaila committed
from utils.graph2D.visplot_render import cross_section, render2D
from utils.graph3D.visplot_render import render3D
Djalim Simaila's avatar
Djalim Simaila committed
from utils.gui.pyqt.main_window.UI_MainWindow import Ui_MainWindow
Djalim Simaila's avatar
Djalim Simaila committed
from utils.gui.pyqt.main_window.Workers.DiscreteDataWorker import DiscreteDataProcessWorker
from utils.gui.pyqt.main_window.Workers.PreProcessWorker import PreProcessWorker
from utils.gui.pyqt.main_window.Workers.RawDataWorker import RawDataProcessWorker
from utils.gui.pyqt.error_popup.ErrorPopup import ErrorPopup
Djalim Simaila's avatar
Djalim Simaila committed
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    """
    Main window of the application
    """

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        # Retrieve the UI
        self.setupUi(self)
        # Setup buttons listeners
Djalim Simaila's avatar
Djalim Simaila committed
        self.start_analyse_button.clicked.connect(self.start_preprocess)
Djalim Simaila's avatar
Djalim Simaila committed
        self.input_file_choose_btn.clicked.connect(self.select_file)
        self.output_folder_choose_btn.clicked.connect(self.select_folder)
Djalim Simaila's avatar
Djalim Simaila committed
        self.show_graph_checkbox.stateChanged.connect(self.toggle_graphs)
        self.actionSauvegarder_le_model_redress.triggered.connect(self.save_model)
Djalim Simaila's avatar
Djalim Simaila committed
        self.actionPr_f_rennces.triggered.connect(self.show_settings)
Djalim Simaila's avatar
Djalim Simaila committed
        

        self.graphType = [
            "Aucun",
            "Mesh3D",
Djalim Simaila's avatar
Djalim Simaila committed
            "Coupe XZ",
            "Coupe YZ",
            "Evolution du rayon moyen",
Djalim Simaila's avatar
Djalim Simaila committed
        ]
        
        self.obj = None
        self.raw_data= None
        self.discrete_data = None

Djalim Simaila's avatar
Djalim Simaila committed
        self.completed = 0
Djalim Simaila's avatar
Djalim Simaila committed
        self.total = 2

        self.comboBoxes = [
            self.slot0ComboBox,
            self.slot1ComboBox,
            self.slot2ComboBox,
            self.slot3ComboBox,
            self.slot4ComboBox,
            self.slot5ComboBox,
            self.slot6ComboBox,
            self.slot7ComboBox,
            self.slot8ComboBox,
            self.slot9ComboBox,
            self.slot10ComboBox
Djalim Simaila's avatar
Djalim Simaila committed
        ]

        for cb in self.comboBoxes:
            cb.addItems(self.graphType)

        self.slots = [
                    [self.slot0,"Aucun"],
                    [self.slot1,"Aucun"],
                    [self.slot2,"Aucun"],
                    [self.slot3,"Aucun"],
                    [self.slot4,"Aucun"],
                    [self.slot5,"Aucun"],
                    [self.slot6,"Aucun"],
                    [self.slot7,"Aucun"],
                    [self.slot8,"Aucun"],
                    [self.slot9,"Aucun"],
                    [self.slot10,"Aucun"]
Djalim Simaila's avatar
Djalim Simaila committed
                    ]
        
        for slot_nb,slot in  enumerate(self.slots):
            slot[1] = SettingManager.get_instance().get_last_graph(slot_nb)
            self.comboBoxes[slot_nb].setCurrentText(slot[1])
Djalim Simaila's avatar
Djalim Simaila committed

        self.settings_window = Settings()

Djalim Simaila's avatar
Djalim Simaila committed
        self.threads = []
Djalim Simaila's avatar
Djalim Simaila committed
###############################################################################
#                                                                             #
#                                                                             #
#                           Input/Setting Management                          #
#                                                                             #
#                                                                             #
###############################################################################
Djalim Simaila's avatar
Djalim Simaila committed
    def select_file(self):
        """
        Open a file dialog to select the input file
        """
        file = QFileDialog.getOpenFileName()[0]
        self.input_file_path.setPlainText(file)
        self.output_file_prefix.setText(os.path.splitext(os.path.basename(file))[0])

    def select_folder(self):
        """
        Open a file dialog to select the output folder
        """
Djalim Simaila's avatar
Djalim Simaila committed
        self.output_folder_path.setPlainText(QFileDialog.getExistingDirectory())
Djalim Simaila's avatar
Djalim Simaila committed
    def check_input_file(self):
        """
        Check if the input file is valid
        """
        if not os.path.isfile(self.input_file_path.toPlainText()):
            ErrorPopup("Fichier d'entrée invalide",button_label="Choisir un fichier d'entrée",button_callback=self.select_file).show_popup()
            return False
        return True
Djalim Simaila's avatar
Djalim Simaila committed

    def check_output_folder(self):
        """
        Check if the output folder is valid
        """
        if not os.path.isdir(self.output_folder_path.toPlainText()):
            ErrorPopup("Dossier de sortie invalide",button_label="Choisir un dossier de sortie",button_callback=self.select_folder).show_popup()
            return False
        return True
Djalim Simaila's avatar
Djalim Simaila committed

###############################################################################
#                                                                             #
#                                                                             #
#                              Data Processing                                #
#                                                                             #
#                                                                             #
###############################################################################

    def start_preprocess(self):
Djalim Simaila's avatar
Djalim Simaila committed
        """
        Start the analyse
        """
        if not self.check_input_file():
            return
        if not self.check_output_folder():
            return
Djalim Simaila's avatar
Djalim Simaila committed
        
        settings = SettingManager.get_instance()
Djalim Simaila's avatar
Djalim Simaila committed
        for count,_ in enumerate(self.slots):
            self.slots[count][1] = self.comboBoxes[count].currentText()
            settings.set_last_graph(count,self.slots[count][1])
Djalim Simaila's avatar
Djalim Simaila committed
            
        self.clear_graphs()
        self.completed = 0
Djalim Simaila's avatar
Djalim Simaila committed
        # Create the thread to run the analyse
Djalim Simaila's avatar
Djalim Simaila committed
        self.preprocess_thread = QThread()
        self.preprocess_worker = PreProcessWorker("PreProcessWorker",self.input_file_path.toPlainText())
        self.preprocess_worker.moveToThread(self.preprocess_thread)
Djalim Simaila's avatar
Djalim Simaila committed

        # Connect the signals
        # Start
Djalim Simaila's avatar
Djalim Simaila committed
        self.preprocess_thread.started.connect(self.preprocess_worker.run)
Djalim Simaila's avatar
Djalim Simaila committed
        # Progress
Djalim Simaila's avatar
Djalim Simaila committed
        self.preprocess_worker.status.connect(self.set_status)
        self.preprocess_worker.progress.connect(self.update_progress_bar)
        self.preprocess_worker.processed_obj.connect(self.set_obj)
        self.preprocess_worker.processed_obj.connect(self.process_raw_data)
        self.preprocess_worker.processed_obj.connect(self.process_discrete_data)
Djalim Simaila's avatar
Djalim Simaila committed
        # Finished
Djalim Simaila's avatar
Djalim Simaila committed
        self.preprocess_worker.finished.connect(self.preprocess_thread.quit)
        self.preprocess_worker.finished.connect(self.preprocess_worker.deleteLater)
        self.preprocess_thread.finished.connect(self.preprocess_thread.deleteLater)
Djalim Simaila's avatar
Djalim Simaila committed

        # Start the thread
Djalim Simaila's avatar
Djalim Simaila committed
        self.preprocess_thread.start()
Djalim Simaila's avatar
Djalim Simaila committed
        self.start_analyse_button.setEnabled(False)

Djalim Simaila's avatar
Djalim Simaila committed
    def process_raw_data(self, obj:ScannedObject):
        self.processrawdata_thread = QThread()
        self.processraw_worker = RawDataProcessWorker("RawDataProcessWorker",
                                                      obj,
                                                      self.output_folder_path.toPlainText(),
                                                      self.output_file_prefix.text(),
                                                      self.discretisation_value_selector.value())
        self.processraw_worker.moveToThread(self.processrawdata_thread)
        # Connect the signals
        # Start
        self.processrawdata_thread.started.connect(self.processraw_worker.run)
        # Progress
        self.processraw_worker.status.connect(self.set_status)
        self.processraw_worker.progress.connect(self.update_progress_bar)
        self.processraw_worker.processedData.connect(self.set_raw_data)
        # Finished
        self.processraw_worker.finished.connect(self.finish_analyse)
        self.processraw_worker.finished.connect(self.processrawdata_thread.quit)
        self.processraw_worker.finished.connect(self.processraw_worker.deleteLater)
        self.processrawdata_thread.finished.connect(self.processrawdata_thread.deleteLater)

        # Start the thread
        self.processrawdata_thread.start()
Djalim Simaila's avatar
Djalim Simaila committed
    def process_discrete_data(self, obj:ScannedObject):
        self.processdiscrete_thread = QThread()
        self.processdiscrete_worker = DiscreteDataProcessWorker("DiscreteDataProcessWorker",
                                                                obj,
                                                                self.output_folder_path.toPlainText(),
                                                                self.output_file_prefix.text(),
                                                                self.discretisation_value_selector.value())
        self.processdiscrete_worker.moveToThread(self.processdiscrete_thread)
        # Connect the signals
        # Start
        self.processdiscrete_thread.started.connect(self.processdiscrete_worker.run)
        # Progress
        self.processdiscrete_worker.status.connect(self.set_status)
        self.processdiscrete_worker.progress.connect(self.update_progress_bar)
        self.processdiscrete_worker.processedData.connect(self.set_discrete_data)
        # Finished
        self.processdiscrete_worker.finished.connect(self.finish_analyse)
        self.processdiscrete_worker.finished.connect(self.processdiscrete_thread.quit)
        self.processdiscrete_worker.finished.connect(self.processdiscrete_worker.deleteLater)
        self.processdiscrete_thread.finished.connect(self.processdiscrete_thread.deleteLater)
        
        # Start the thread
        self.processdiscrete_thread.start()

    def set_obj(self,obj:ScannedObject):
        self.obj = obj

    def set_discrete_data(self,discrete_data:dict):
        self.discrete_data = discrete_data

    def set_raw_data(self,raw_data:dict):
        self.raw_data = raw_data 

    def save_model(self):
        if self.obj is None:
            ErrorPopup("Aucune analyse effectuée. Aucun modèle à sauvegarder").show_popup()
            return
        file_path = QFileDialog.getSaveFileName(self,
                                                "Sauvegarder le modèle",
                                                "./",
                                                "Fichier OBJ (*.obj)")
        self.obj.export_obj(file_path[0])
        
Djalim Simaila's avatar
Djalim Simaila committed
###############################################################################
#                                                                             #
#                                                                             #
#                              Graphs management                              #
#                                                                             #
#                                                                             #
###############################################################################

    def toggle_graphs(self):
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        Show or hide the graphs
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        if self.show_graph_checkbox.isChecked():
            self.Graphs.show()
        else:
            self.Graphs.hide()

    def renderGraphs(self,obj:ScannedObject,raw_data:dict,discrete_data:dict):
        if not self.show_graph_checkbox.isChecked():
Djalim Simaila's avatar
Djalim Simaila committed
            return
Djalim Simaila's avatar
Djalim Simaila committed
        for slot in self.slots:
            current_slot = slot[0]
            graph_type = slot[1]
            if graph_type == "Mesh3D":
                current_slot.addWidget(render3D(obj,False).native)
Djalim Simaila's avatar
Djalim Simaila committed
            if graph_type == "Coupe XZ":
                current_slot.addWidget(cross_section(obj.get_x(),
                                                     obj.get_z(),
                                                     "Coupe XZ",
                                                     "X (en mm)",
                                                     "Z (en mm)",
                                                     False).native)
Djalim Simaila's avatar
Djalim Simaila committed
            if graph_type == "Coupe YZ":
                current_slot.addWidget(cross_section(obj.get_y(),
                                                     obj.get_z(),
                                                     "Coupe YZ",
                                                     "Y (en mm)",
                                                     "Z (en mm)",
                                                     False).native)
Djalim Simaila's avatar
Djalim Simaila committed
            if graph_type == "Evolution du rayon moyen":
                current_slot.addWidget(render2D(list(zip(discrete_data['Z moy (en mm)'],discrete_data['Rayon moyen (en mm)'])),
                                                "Evolution du rayon moyen en fonction de Z",
                                                "Z (en mm)",
                                                "Rayon moyen (en mm)\n",
                                                False).native)
Djalim Simaila's avatar
Djalim Simaila committed

Djalim Simaila's avatar
Djalim Simaila committed
    def clear_graphs(self):
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        Clear the graphs
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        if not self.show_graph_checkbox.isChecked():
            return
        for slot,_ in self.slots:
            for i in reversed(range(slot.count())):
                slot.itemAt(i).widget().setParent(None)
Djalim Simaila's avatar
Djalim Simaila committed
###############################################################################
#                                                                             #
#                                                                             #
#                            User interface updates                           #
#                                                                             #
#                                                                             #
###############################################################################
Djalim Simaila's avatar
Djalim Simaila committed
    def finish_analyse(self):
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        Finish the analyse
Djalim Simaila's avatar
Djalim Simaila committed
        """
Djalim Simaila's avatar
Djalim Simaila committed
        self.completed += 1
        if self.completed == self.total:
            self.status_text.setText("Done")
            self.analyse_progress_bar.setValue(100)
            self.renderGraphs(self.obj,self.raw_data,self.discrete_data)
            self.start_analyse_button.setEnabled(True)
Djalim Simaila's avatar
Djalim Simaila committed

    def update_progress_bar(self, value):
        """
        Update the progress bar
        """
Djalim Simaila's avatar
Djalim Simaila committed
        self.analyse_progress_bar.setValue(value)

    def set_status(self, status:str):
        """
        Set the status of the analyse
        """
        self.status_text.setText(status)
Djalim Simaila's avatar
Djalim Simaila committed

    def show_settings(self):
        """
        Show the settings window
        """
        self.settings_window.show()