From d3136a12b69bb3c3388d638a4879c1999a88047e Mon Sep 17 00:00:00 2001 From: Djalim Simaila Date: Wed, 26 Apr 2023 15:30:37 +0200 Subject: [PATCH] finished graphs --- main.py | 2 +- utils/data_processing/data_processing.py | 4 +- utils/files/input.py | 4 +- utils/graph2D/visplot_render.py | 27 +- utils/graph3D/visplot_render.py | 12 +- .../Canvas/CrossSection2DCanvas.py | 13 - .../pyqt/main_window/Canvas/Mesh3DCanvas.py | 30 -- utils/gui/pyqt/main_window/MainWindow.py | 303 ++++++++++++++---- utils/gui/pyqt/main_window/MainWindow.ui | 189 ++++++++++- utils/gui/pyqt/main_window/UI_MainWindow.py | 135 +++++++- .../pyqt/main_window/Workers/AnalyseWorker.py | 92 ------ .../main_window/Workers/DiscreteDataWorker.py | 41 +++ .../main_window/Workers/PreProcessWorker.py | 35 ++ .../pyqt/main_window/Workers/RawDataWorker.py | 40 +++ utils/gui/pyqt/main_window/Workers/Worker.py | 31 ++ 15 files changed, 707 insertions(+), 251 deletions(-) delete mode 100644 utils/gui/pyqt/main_window/Canvas/CrossSection2DCanvas.py delete mode 100644 utils/gui/pyqt/main_window/Canvas/Mesh3DCanvas.py delete mode 100644 utils/gui/pyqt/main_window/Workers/AnalyseWorker.py create mode 100644 utils/gui/pyqt/main_window/Workers/DiscreteDataWorker.py create mode 100644 utils/gui/pyqt/main_window/Workers/PreProcessWorker.py create mode 100644 utils/gui/pyqt/main_window/Workers/RawDataWorker.py create mode 100644 utils/gui/pyqt/main_window/Workers/Worker.py diff --git a/main.py b/main.py index 0d7a8dd..a01401a 100644 --- a/main.py +++ b/main.py @@ -51,7 +51,7 @@ def main(): ["X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)", - "Delta z(en mm)", + "Discretisation(en mm)", "Rayon moyen (en mm)", "Rayon ecart type (en mm)"] )) print("Data saved in {} seconds".format(time.time()-t)) diff --git a/utils/data_processing/data_processing.py b/utils/data_processing/data_processing.py index 4502f80..8f6c009 100644 --- a/utils/data_processing/data_processing.py +++ b/utils/data_processing/data_processing.py @@ -54,7 +54,7 @@ def get_discrete_data(obj:ScannedObject, ndigits:int, delta_z:float=1, update_pr - Rayon moyen (en mm) : list of mean radius values - Rayon ecart type (en mm) : list of radius standard deviation values """ - colones = ["X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)","Delta z(en mm)","Rayon moyen (en mm)","Rayon ecart type (en mm)"] + colones = ["X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)","Discretisation(en mm)","Rayon moyen (en mm)","Rayon ecart type (en mm)"] data = {} for colone in colones: data[colone] = [] @@ -67,7 +67,7 @@ def get_discrete_data(obj:ScannedObject, ndigits:int, delta_z:float=1, update_pr data["Z moy (en mm)"].append(round(z, ndigits)) first = discrete_values[0] last = discrete_values[-1] - data["Delta z(en mm)"].append(round(last[2]-first[2],ndigits)) + data["Discretisation(en mm)"].append(round(last[2]-first[2],ndigits)) data["Rayon moyen (en mm)"].append(round(data_extraction.get_mean_radius(discrete_values), ndigits)) data["Rayon ecart type (en mm)"].append(round(data_extraction.get_radius_std(discrete_values), ndigits)) update_progress_bar(int(progress/len(discrete_vertices)*100)) diff --git a/utils/files/input.py b/utils/files/input.py index bc6fd24..b29c877 100644 --- a/utils/files/input.py +++ b/utils/files/input.py @@ -97,9 +97,11 @@ class ScannedObject: if line.startswith('f'): if "//" in line: triangles.append([int(line.split()[1].split("//")[0])-1, int(line.split()[2].split("//")[0])-1, int(line.split()[3].split("//")[0])-1]) + elif "/" in line: + triangles.append([int(line.split()[1].split("/")[0])-1, int(line.split()[2].split("/")[0])-1, int(line.split()[3].split("/")[0])-1]) else: triangles.append([int(line.split()[1])-1, int(line.split()[2])-1, int(line.split()[3])-1]) - elif line.startswith('v'): + elif line.startswith('v '): x.append(float(line.split()[1]) * ratio) y.append(float(line.split()[2]) * ratio) z.append(float(line.split()[3]) * ratio) diff --git a/utils/graph2D/visplot_render.py b/utils/graph2D/visplot_render.py index 31925ab..937c6fc 100644 --- a/utils/graph2D/visplot_render.py +++ b/utils/graph2D/visplot_render.py @@ -1,28 +1,33 @@ import vispy.plot as vp import numpy as np -def render2D(values:list): +def render2D(values:list,title:str,show:bool=True): """ Render a 2D plot using vispy :param values: A list with the values """ fig = vp.Fig(size=(600, 500), show=False) plotwidget = fig[0, 0] - fig.title = "bollu" - plotwidget.plot(values) - plotwidget.colorbar(position="top", cmap="autumn") - fig.show(run=True) + fig.title = title + plotwidget.plot(values,marker_size=0, width=2,title=title) + if show: + fig.show(run=True) + else: + return fig -def cross_section(x_values:list, y_values:list): +def cross_section(x_values:list, y_values:list,title:str, show:bool=True ): """ Render a 2D cross section using vispy :param x: A list with the x values :param y: A list with the y values """ - color = (0.3, 0.5, 0.8) + color = (0.3, 0.5, 0.8,.8) fig = vp.Fig(show=False) - line = fig[0:4, 0:4].plot(np.column_stack((x_values,y_values)), symbol='o', width=0, - face_color=color + (0.02,), edge_color=None, - marker_size=8) + line = fig[0:4, 0:4].plot(np.column_stack((x_values,y_values)), symbol='disc', width=0, + face_color=color, edge_color=None, + marker_size=8,title=title) line.set_gl_state(depth_test=False) - fig.show(run=True) \ No newline at end of file + if show: + fig.show(run=True) + else: + return fig \ No newline at end of file diff --git a/utils/graph3D/visplot_render.py b/utils/graph3D/visplot_render.py index 2dccf7f..8c1f0d4 100644 --- a/utils/graph3D/visplot_render.py +++ b/utils/graph3D/visplot_render.py @@ -5,7 +5,7 @@ from vispy.visuals.filters import ShadingFilter, WireframeFilter from utils.files.input import ScannedObject -def render3D(obj:ScannedObject): +def render3D(obj:ScannedObject,show:bool=True): """ Render a 3D model using vispy :param obj: A ScannedObject to be rendered @@ -16,7 +16,8 @@ def render3D(obj:ScannedObject): view = canvas.central_widget.add_view() view.camera = 'arcball' view.camera.depth_value = 1e3 - mesh = Mesh(vertices, faces, color=(.5, .7, .5, 1)) + color = (0.3, 0.5, 0.8) + mesh = Mesh(vertices, faces, color=color) view.add(mesh) wireframe_filter = WireframeFilter(width=0) shading_filter = ShadingFilter(shininess=0) @@ -32,5 +33,8 @@ def render3D(obj:ScannedObject): transform = view.camera.transform shading_filter.light_dir = transform.map(initial_light_dir)[:3] attach_headlight(view) - canvas.show() - app.run() \ No newline at end of file + if show: + canvas.show() + app.run() + else: + return canvas \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/Canvas/CrossSection2DCanvas.py b/utils/gui/pyqt/main_window/Canvas/CrossSection2DCanvas.py deleted file mode 100644 index c3ff198..0000000 --- a/utils/gui/pyqt/main_window/Canvas/CrossSection2DCanvas.py +++ /dev/null @@ -1,13 +0,0 @@ -import vispy.plot as vp -import numpy as np -from utils.files.input import ScannedObject - - -class CrossSection2DCanvas: - def __init__(self,x_values:list, y_values:list,title:str): - color = (0.3, 0.5, 0.8) - self.canvas = vp.Fig(show=False,size=(500, 500)) - line = self.canvas[0,0].plot(np.column_stack((x_values,y_values)), symbol='o', width=0, - face_color=color + (0.02,), edge_color=None, - marker_size=8,title=title) - line.set_gl_state(depth_test=False) \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/Canvas/Mesh3DCanvas.py b/utils/gui/pyqt/main_window/Canvas/Mesh3DCanvas.py deleted file mode 100644 index 8831519..0000000 --- a/utils/gui/pyqt/main_window/Canvas/Mesh3DCanvas.py +++ /dev/null @@ -1,30 +0,0 @@ -from vispy import scene -from vispy.scene.visuals import Mesh -from vispy.visuals.filters import ShadingFilter, WireframeFilter -from vispy.scene import SceneCanvas -from utils.files.input import ScannedObject -import numpy as np - -class Mesh3DCanvas: - def __init__(self,obj:ScannedObject): - vertices = np.asarray(obj.get_vertices()) - faces = np.asarray(obj.get_faces()) - self.canvas = scene.SceneCanvas(keys='interactive', bgcolor='white',size=(400, 400)) - view = self.canvas.central_widget.add_view() - view.camera = 'arcball' - view.camera.depth_value = 1e3 - mesh = Mesh(vertices, faces, color=(.5, .7, .5, 1)) - view.add(mesh) - wireframe_filter = WireframeFilter(width=0) - shading_filter = ShadingFilter(shininess=0) - mesh.attach(wireframe_filter) - mesh.attach(shading_filter) - def attach_headlight(view): - light_dir = (0, 1, 0, 0) - shading_filter.light_dir = light_dir[:3] - initial_light_dir = view.camera.transform.imap(light_dir) - @view.scene.transform.changed.connect - def on_transform_change(event): - transform = view.camera.transform - shading_filter.light_dir = transform.map(initial_light_dir)[:3] - attach_headlight(view) \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/MainWindow.py b/utils/gui/pyqt/main_window/MainWindow.py index a0b189c..7a5ff9c 100644 --- a/utils/gui/pyqt/main_window/MainWindow.py +++ b/utils/gui/pyqt/main_window/MainWindow.py @@ -1,12 +1,14 @@ import os from PyQt5 import QtWidgets -from PyQt5.QtCore import QThread, pyqtSignal, QObject -from PyQt5.QtWidgets import QFileDialog +from PyQt5.QtCore import QThread +from PyQt5.QtWidgets import QFileDialog, QWidget from utils.files.input import ScannedObject +from utils.graph2D.visplot_render import cross_section, render2D +from utils.graph3D.visplot_render import render3D from utils.gui.pyqt.main_window.UI_MainWindow import Ui_MainWindow -from utils.gui.pyqt.main_window.Workers.AnalyseWorker import AnalyseWorker -from utils.gui.pyqt.main_window.Canvas.Mesh3DCanvas import Mesh3DCanvas -from utils.gui.pyqt.main_window.Canvas.CrossSection2DCanvas import CrossSection2DCanvas +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 class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): """ Main window of the application @@ -17,12 +19,61 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # Retrieve the UI self.setupUi(self) # Setup buttons listeners - self.start_analyse_button.clicked.connect(self.start_analyse) + self.start_analyse_button.clicked.connect(self.start_preprocess) self.input_file_choose_btn.clicked.connect(self.select_file) self.output_folder_choose_btn.clicked.connect(self.select_folder) - #CanvasWrapper(ScannedObject.from_obj_file("/Users/djalim/Documents/DevStuff/AnalyseMorphologique/datasets/Barette/1 - BARETTE.obj")).canvas.native - self.completed = 0 + self.show_graph_checkbox.stateChanged.connect(self.toggle_graphs) + + self.graphType = [ + "Aucun", + "Mesh3D", + "CoupeXZ", + "CoupeYZ", + "EvolutionRayon", + ] + + self.obj = None + self.raw_data= None + self.discrete_data = None + + self.completed = 0 + self.total = 2 + + self.comboBoxes = [ + self.slot0ComboBox, + self.slot1ComboBox, + self.slot2ComboBox, + self.slot3ComboBox, + self.slot4ComboBox, + self.slot5ComboBox, + self.slot6ComboBox, + self.slot7ComboBox + ] + + for cb in self.comboBoxes: + cb.addItems(self.graphType) + + self.slots = [ + [self.slot0,None], + [self.slot1,None], + [self.slot2,None], + [self.slot3,None], + [self.slot4,None], + [self.slot5,None], + [self.slot6,None], + [self.slot7,None] + ] + + self.threads = [] + +############################################################################### +# # +# # +# Input/Setting Management # +# # +# # +############################################################################### def select_file(self): """ Open a file dialog to select the input file @@ -35,67 +86,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): """ Open a file dialog to select the output folder """ - self.output_folder_path.setPlainText( - QFileDialog.getExistingDirectory()) - - def start_analyse(self): - """ - Start the analyse - """ - if not self.check_input_file(): - self.input_file_path.setPlainText("Invalid file path") - return - if not self.check_output_folder(): - self.output_folder_path.setPlainText("Invalid folder path") - return - - # Create the thread to run the analyse - self.thread = QThread() - self.worker = AnalyseWorker(self.input_file_path.toPlainText(), - self.output_folder_path.toPlainText(), - self.output_file_prefix.text(), - self.discretisation_value_selector.value()) - self.worker.moveToThread(self.thread) - - # Connect the signals - # Start - self.thread.started.connect(self.worker.run) - # Progress - self.worker.status.connect(self.set_status) - self.worker.progress.connect(self.update_progress_bar) - self.worker.render.connect(self.show_graph) - # Finished - self.worker.finished.connect(self.finish_analyse) - self.worker.finished.connect(self.thread.quit) - self.worker.finished.connect(self.worker.deleteLater) - self.thread.finished.connect(self.thread.deleteLater) - - # Start the thread - self.thread.start() - self.start_analyse_button.setEnabled(False) - - def set_status(self, status:str): - """ - Set the status of the analyse - """ - self.status_text.setText(status) - - def show_graph(self, obj:ScannedObject): - """ - Show the graph - """ - if not self.show_graph_checkbox.checked: - return - self.slot0.addWidget(Mesh3DCanvas(obj).canvas.native) - self.slot1.addWidget(CrossSection2DCanvas(obj.get_x(),obj.get_z(),"Coupe X").canvas.native) - self.slot2.addWidget(CrossSection2DCanvas(obj.get_y(),obj.get_z(),"Coupe Y").canvas.native) - - def finish_analyse(self): - """ - Finish the analyse - """ - self.start_analyse_button.setEnabled(True) - + self.output_folder_path.setPlainText(QFileDialog.getExistingDirectory()) def check_input_file(self): """ @@ -111,8 +102,180 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): if os.path.isdir(self.output_folder_path.toPlainText()): return True +############################################################################### +# # +# # +# Data Processing # +# # +# # +############################################################################### + + def start_preprocess(self): + """ + Start the analyse + """ + if not self.check_input_file(): + self.input_file_path.setPlainText("Invalid file path") + return + if not self.check_output_folder(): + self.output_folder_path.setPlainText("Invalid folder path") + return + + for count,_ in enumerate(self.slots): + self.slots[count][1] = self.comboBoxes[count].currentText() + + self.clear_graphs() + self.completed = 0 + # Create the thread to run the analyse + self.preprocess_thread = QThread() + self.preprocess_worker = PreProcessWorker("PreProcessWorker",self.input_file_path.toPlainText()) + self.preprocess_worker.moveToThread(self.preprocess_thread) + + # Connect the signals + # Start + self.preprocess_thread.started.connect(self.preprocess_worker.run) + # Progress + 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) + # Finished + 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) + + # Start the thread + self.preprocess_thread.start() + self.start_analyse_button.setEnabled(False) + + 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() + + 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 + +############################################################################### +# # +# # +# Graphs management # +# # +# # +############################################################################### + + def toggle_graphs(self): + """ + Show or hide the graphs + """ + 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(): + return + for slot in self.slots: + current_slot = slot[0] + graph_type = slot[1] + if graph_type == "Mesh3D": + current_slot.addWidget(render3D(obj,False).native) + if graph_type == "CoupeX": + current_slot.addWidget(cross_section(obj.get_x(),obj.get_z(),"Coupe X",False).native) + if graph_type == "CoupeY": + current_slot.addWidget(cross_section(obj.get_y(),obj.get_z(),"Coupe Y",False).native) + if graph_type == "EvolutionRayon": + current_slot.addWidget(render2D(list(zip(discrete_data['Z moy (en mm)'],discrete_data['Rayon moyen (en mm)'])),"Evolution du rayon moyen",False).native) + + def clear_graphs(self): + """ + Clear the graphs + """ + 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) + + +############################################################################### +# # +# # +# User interface updates # +# # +# # +############################################################################### + + def finish_analyse(self): + """ + Finish the analyse + """ + 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) + def update_progress_bar(self, value): """ Update the progress bar """ - self.analyse_progress_bar.setValue(value) \ No newline at end of file + self.analyse_progress_bar.setValue(value) + + def set_status(self, status:str): + """ + Set the status of the analyse + """ + self.status_text.setText(status) diff --git a/utils/gui/pyqt/main_window/MainWindow.ui b/utils/gui/pyqt/main_window/MainWindow.ui index 993ea64..c832984 100644 --- a/utils/gui/pyqt/main_window/MainWindow.ui +++ b/utils/gui/pyqt/main_window/MainWindow.ui @@ -122,6 +122,9 @@ afficher les graphes + + true + @@ -145,6 +148,9 @@ + + true + 700 @@ -153,20 +159,175 @@ - - - - - - - - - - - - - - + + + true + + + 0 + + + + true + + + 1 + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + + 2 + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + diff --git a/utils/gui/pyqt/main_window/UI_MainWindow.py b/utils/gui/pyqt/main_window/UI_MainWindow.py index 20ea7f0..69fd36d 100644 --- a/utils/gui/pyqt/main_window/UI_MainWindow.py +++ b/utils/gui/pyqt/main_window/UI_MainWindow.py @@ -76,6 +76,7 @@ class Ui_MainWindow(object): self.analyse_progress_bar.setObjectName("analyse_progress_bar") self.MainSettingsLayout.addWidget(self.analyse_progress_bar) self.show_graph_checkbox = QtWidgets.QCheckBox(self.MainSettings) + self.show_graph_checkbox.setChecked(True) self.show_graph_checkbox.setObjectName("show_graph_checkbox") self.MainSettingsLayout.addWidget(self.show_graph_checkbox, 0, QtCore.Qt.AlignHCenter) self.start_analyse_button = QtWidgets.QPushButton(self.MainSettings) @@ -88,30 +89,136 @@ class Ui_MainWindow(object): self.gridLayout_2.addLayout(self.MainSettingsLayout, 0, 0, 1, 1) self.horizontalLayout_4.addWidget(self.MainSettings) self.Graphs = QtWidgets.QWidget(self.centralwidget) + self.Graphs.setEnabled(True) self.Graphs.setMinimumSize(QtCore.QSize(700, 0)) self.Graphs.setObjectName("Graphs") self.gridLayout_3 = QtWidgets.QGridLayout(self.Graphs) self.gridLayout_3.setObjectName("gridLayout_3") - self.GraphsLayout = QtWidgets.QGridLayout() - self.GraphsLayout.setObjectName("GraphsLayout") - self.slot0 = QtWidgets.QGridLayout() - self.slot0.setObjectName("slot0") - self.GraphsLayout.addLayout(self.slot0, 0, 0, 1, 1) - self.slot2 = QtWidgets.QGridLayout() - self.slot2.setObjectName("slot2") - self.GraphsLayout.addLayout(self.slot2, 2, 0, 1, 1) + self.tabWidget = QtWidgets.QTabWidget(self.Graphs) + self.tabWidget.setEnabled(True) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setEnabled(True) + self.tab.setObjectName("tab") + self.gridLayout_5 = QtWidgets.QGridLayout(self.tab) + self.gridLayout_5.setObjectName("gridLayout_5") + self.slot1_frame = QtWidgets.QFrame(self.tab) + self.slot1_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot1_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot1_frame.setObjectName("slot1_frame") + self.gridLayout_10 = QtWidgets.QGridLayout(self.slot1_frame) + self.gridLayout_10.setObjectName("gridLayout_10") self.slot1 = QtWidgets.QGridLayout() self.slot1.setObjectName("slot1") - self.GraphsLayout.addLayout(self.slot1, 0, 1, 1, 1) - self.solt3 = QtWidgets.QGridLayout() - self.solt3.setObjectName("solt3") - self.GraphsLayout.addLayout(self.solt3, 2, 1, 1, 1) - self.gridLayout_3.addLayout(self.GraphsLayout, 0, 0, 1, 1) + self.gridLayout_10.addLayout(self.slot1, 1, 0, 1, 1) + self.slot1ComboBox = QtWidgets.QComboBox(self.slot1_frame) + self.slot1ComboBox.setObjectName("slot1ComboBox") + self.gridLayout_10.addWidget(self.slot1ComboBox, 0, 0, 1, 1) + self.gridLayout_5.addWidget(self.slot1_frame, 0, 1, 1, 1) + self.slot2_frame = QtWidgets.QFrame(self.tab) + self.slot2_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot2_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot2_frame.setObjectName("slot2_frame") + self.gridLayout_11 = QtWidgets.QGridLayout(self.slot2_frame) + self.gridLayout_11.setObjectName("gridLayout_11") + self.slot2 = QtWidgets.QGridLayout() + self.slot2.setObjectName("slot2") + self.gridLayout_11.addLayout(self.slot2, 1, 0, 1, 1) + self.slot2ComboBox = QtWidgets.QComboBox(self.slot2_frame) + self.slot2ComboBox.setObjectName("slot2ComboBox") + self.gridLayout_11.addWidget(self.slot2ComboBox, 0, 0, 1, 1) + self.gridLayout_5.addWidget(self.slot2_frame, 1, 0, 1, 1) + self.slot3_frame = QtWidgets.QFrame(self.tab) + self.slot3_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot3_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot3_frame.setObjectName("slot3_frame") + self.gridLayout_12 = QtWidgets.QGridLayout(self.slot3_frame) + self.gridLayout_12.setObjectName("gridLayout_12") + self.slot3 = QtWidgets.QGridLayout() + self.slot3.setObjectName("slot3") + self.gridLayout_12.addLayout(self.slot3, 1, 0, 1, 1) + self.slot3ComboBox = QtWidgets.QComboBox(self.slot3_frame) + self.slot3ComboBox.setObjectName("slot3ComboBox") + self.gridLayout_12.addWidget(self.slot3ComboBox, 0, 0, 1, 1) + self.gridLayout_5.addWidget(self.slot3_frame, 1, 1, 1, 1) + self.slot0_frame = QtWidgets.QFrame(self.tab) + self.slot0_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot0_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot0_frame.setObjectName("slot0_frame") + self.gridLayout_8 = QtWidgets.QGridLayout(self.slot0_frame) + self.gridLayout_8.setObjectName("gridLayout_8") + self.slot0 = QtWidgets.QGridLayout() + self.slot0.setObjectName("slot0") + self.gridLayout_8.addLayout(self.slot0, 1, 0, 1, 1) + self.slot0ComboBox = QtWidgets.QComboBox(self.slot0_frame) + self.slot0ComboBox.setObjectName("slot0ComboBox") + self.gridLayout_8.addWidget(self.slot0ComboBox, 0, 0, 1, 1) + self.gridLayout_5.addWidget(self.slot0_frame, 0, 0, 1, 1) + self.tabWidget.addTab(self.tab, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.gridLayout_13 = QtWidgets.QGridLayout(self.tab_2) + self.gridLayout_13.setObjectName("gridLayout_13") + self.slot5_frame = QtWidgets.QFrame(self.tab_2) + self.slot5_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot5_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot5_frame.setObjectName("slot5_frame") + self.gridLayout_18 = QtWidgets.QGridLayout(self.slot5_frame) + self.gridLayout_18.setObjectName("gridLayout_18") + self.slot5 = QtWidgets.QGridLayout() + self.slot5.setObjectName("slot5") + self.gridLayout_18.addLayout(self.slot5, 1, 0, 1, 1) + self.slot5ComboBox = QtWidgets.QComboBox(self.slot5_frame) + self.slot5ComboBox.setObjectName("slot5ComboBox") + self.gridLayout_18.addWidget(self.slot5ComboBox, 0, 0, 1, 1) + self.gridLayout_13.addWidget(self.slot5_frame, 0, 1, 1, 1) + self.slot4_frame = QtWidgets.QFrame(self.tab_2) + self.slot4_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot4_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot4_frame.setObjectName("slot4_frame") + self.gridLayout_17 = QtWidgets.QGridLayout(self.slot4_frame) + self.gridLayout_17.setObjectName("gridLayout_17") + self.slot4 = QtWidgets.QGridLayout() + self.slot4.setObjectName("slot4") + self.gridLayout_17.addLayout(self.slot4, 1, 0, 1, 1) + self.slot4ComboBox = QtWidgets.QComboBox(self.slot4_frame) + self.slot4ComboBox.setObjectName("slot4ComboBox") + self.gridLayout_17.addWidget(self.slot4ComboBox, 0, 0, 1, 1) + self.gridLayout_13.addWidget(self.slot4_frame, 0, 0, 1, 1) + self.slot6_frame = QtWidgets.QFrame(self.tab_2) + self.slot6_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot6_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot6_frame.setObjectName("slot6_frame") + self.gridLayout_19 = QtWidgets.QGridLayout(self.slot6_frame) + self.gridLayout_19.setObjectName("gridLayout_19") + self.slot6 = QtWidgets.QGridLayout() + self.slot6.setObjectName("slot6") + self.gridLayout_19.addLayout(self.slot6, 1, 0, 1, 1) + self.slot6ComboBox = QtWidgets.QComboBox(self.slot6_frame) + self.slot6ComboBox.setObjectName("slot6ComboBox") + self.gridLayout_19.addWidget(self.slot6ComboBox, 0, 0, 1, 1) + self.gridLayout_13.addWidget(self.slot6_frame, 1, 0, 1, 1) + self.slot7_frame = QtWidgets.QFrame(self.tab_2) + self.slot7_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.slot7_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.slot7_frame.setObjectName("slot7_frame") + self.gridLayout_20 = QtWidgets.QGridLayout(self.slot7_frame) + self.gridLayout_20.setObjectName("gridLayout_20") + self.slot7 = QtWidgets.QGridLayout() + self.slot7.setObjectName("slot7") + self.gridLayout_20.addLayout(self.slot7, 1, 0, 1, 1) + self.slot7ComboBox = QtWidgets.QComboBox(self.slot7_frame) + self.slot7ComboBox.setObjectName("slot7ComboBox") + self.gridLayout_20.addWidget(self.slot7ComboBox, 0, 0, 1, 1) + self.gridLayout_13.addWidget(self.slot7_frame, 1, 1, 1, 1) + self.tabWidget.addTab(self.tab_2, "") + self.gridLayout_3.addWidget(self.tabWidget, 0, 0, 1, 1) self.horizontalLayout_4.addWidget(self.Graphs) self.gridLayout.addLayout(self.horizontalLayout_4, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): @@ -125,3 +232,5 @@ class Ui_MainWindow(object): self.discretisation_label.setText(_translate("MainWindow", "Discretisation (en mm)")) self.show_graph_checkbox.setText(_translate("MainWindow", "afficher les graphes")) self.start_analyse_button.setText(_translate("MainWindow", "Analyser le fichier")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "1")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "2")) diff --git a/utils/gui/pyqt/main_window/Workers/AnalyseWorker.py b/utils/gui/pyqt/main_window/Workers/AnalyseWorker.py deleted file mode 100644 index 8a005ae..0000000 --- a/utils/gui/pyqt/main_window/Workers/AnalyseWorker.py +++ /dev/null @@ -1,92 +0,0 @@ -from PyQt5.QtCore import pyqtSignal, QObject -from utils.files.input import ScannedObject -from utils.files.output import save_output_file, format_data -from utils.math.position_manipulation import verticalise -from utils.data_processing.data_processing import get_discrete_data, get_raw_data - -class AnalyseWorker(QObject): - """ - Worker to run the analyse in a thread - """ - finished = pyqtSignal() - render = pyqtSignal(ScannedObject) - progress = pyqtSignal(int) - status = pyqtSignal(str) - - def __init__(self, objpath,output_path,output_file_prefix,delta_z): - super().__init__() - self.objpath = objpath - self.delta_z = delta_z - self.output_path = output_path - self.output_file_prefix = output_file_prefix - self.progress_value = 0 - self.progress_weight = 100 - - def run(self): - """ - Run the analyse - """ - self.set_status("Loading file...") - obj = ScannedObject.from_obj_file(self.objpath) - self.update_progress(5) - - self.set_status("Verticalising object...") - verticalise(obj) - self.update_progress(5) - - self.set_status("Normalising object...") - obj.normalise() - self.update_progress(5) - self.render.emit(obj) - self.set_weight(70) - - self.set_status("Calculating raw data...") - raw_data = get_raw_data(obj, 6,self.delta_z,self.update_progress) - self.set_status("Calculating discrete data...") - discrete_data = get_discrete_data(obj, 6,self.delta_z,self.update_progress) - - self.set_weight(100) - self.set_status("Saving data...") - save_output_file(f'{self.output_path}/{self.output_file_prefix}_delta_{self.delta_z}_analyse_brute.txt', - format_data(raw_data, - '\t', - ["X (en mm)", - "Y (en mm)", - "Z (en mm)", - "teta (en rad)", - "rayon (en mm)", - "Xi-Xmoy", - "Yi-Ymoy"] )) - - self.update_progress(10) - save_output_file(f'{self.output_path}/{self.output_file_prefix}_delta_{self.delta_z}_analyse_rayon.txt', - format_data(discrete_data, - '\t', - ["X moy (en mm)", - "Y moy (en mm)", - "Z moy (en mm)", - "Delta z(en mm)", - "Rayon moyen (en mm)", - "Rayon ecart type (en mm)"] )) - self.update_progress(100) - self.set_status("Done !") - self.finished.emit() - - def set_status(self, status:str): - """ - Set the weight of the progress bar - """ - self.status.emit(status) - - def set_weight(self, weight): - """ - Set the weight of the progress bar - """ - self.progress_weight = weight - - def update_progress(self, percent): - """ - Update the progress bar - """ - self.progress_value += int(percent/100*self.progress_weight) - self.progress.emit(self.progress_value) \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/Workers/DiscreteDataWorker.py b/utils/gui/pyqt/main_window/Workers/DiscreteDataWorker.py new file mode 100644 index 0000000..39ef1ae --- /dev/null +++ b/utils/gui/pyqt/main_window/Workers/DiscreteDataWorker.py @@ -0,0 +1,41 @@ +from PyQt5.QtCore import pyqtSignal +from utils.files.input import ScannedObject +from utils.files.output import save_output_file, format_data +from utils.gui.pyqt.main_window.Workers.Worker import Worker +from utils.data_processing.data_processing import get_discrete_data + +class DiscreteDataProcessWorker(Worker): + """ + Worker to run the analyse in a thread + """ + processedData = pyqtSignal(dict) + + def __init__(self,name:str, obj:ScannedObject,output_path:str,output_file_prefix:str,delta_z:float): + super().__init__(name) + self.obj = obj + self.delta_z = delta_z + self.output_path = output_path + self.output_file_prefix = output_file_prefix + + + def run(self): + """ + Run the analyse + """ + self.set_status("Calculating discrete data...") + discrete_data = get_discrete_data(self.obj, 6,self.delta_z,self.update_progress) + self.processedData.emit(discrete_data) + self.set_weight(100) + self.set_status("Saving data...") + self.update_progress(10) + save_output_file(f'{self.output_path}/{self.output_file_prefix}_delta_{self.delta_z}_analyse_rayon.txt', + format_data(discrete_data, + '\t', + ["X moy (en mm)", + "Y moy (en mm)", + "Z moy (en mm)", + "Discretisation(en mm)", + "Rayon moyen (en mm)", + "Rayon ecart type (en mm)"] )) + self.set_status("Done !") + self.finished.emit() \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py b/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py new file mode 100644 index 0000000..f0abdb5 --- /dev/null +++ b/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py @@ -0,0 +1,35 @@ +from utils.gui.pyqt.main_window.Workers.Worker import Worker +from PyQt5.QtCore import pyqtSignal +from utils.files.input import ScannedObject +from utils.math.position_manipulation import verticalise + +class PreProcessWorker(Worker): + """ + Worker to run the analyse in a thread + """ + processed_obj = pyqtSignal(ScannedObject) + + def __init__(self,name:str, objpath:str): + super().__init__(name) + self.objpath = objpath + self.progress_value = 0 + self.progress_weight = 100 + + def run(self): + """ + Run the analyse + """ + self.set_status("Loading file...") + obj = ScannedObject.from_obj_file(self.objpath) + self.update_progress(5) + + self.set_status("Verticalising object...") + verticalise(obj) + self.update_progress(5) + + self.set_status("Normalising object...") + obj.normalise() + self.update_progress(5) + + self.processed_obj.emit(obj) + self.finished.emit() diff --git a/utils/gui/pyqt/main_window/Workers/RawDataWorker.py b/utils/gui/pyqt/main_window/Workers/RawDataWorker.py new file mode 100644 index 0000000..ecbb40a --- /dev/null +++ b/utils/gui/pyqt/main_window/Workers/RawDataWorker.py @@ -0,0 +1,40 @@ +from PyQt5.QtCore import pyqtSignal +from utils.files.input import ScannedObject +from utils.files.output import save_output_file, format_data +from utils.gui.pyqt.main_window.Workers.Worker import Worker +from utils.data_processing.data_processing import get_raw_data + +class RawDataProcessWorker(Worker): + """ + Worker to run the analyse in a thread + """ + processedData = pyqtSignal(dict) + + def __init__(self,name:str, obj:ScannedObject,output_path:str,output_file_prefix:str,delta_z:float): + super().__init__(name) + self.obj = obj + self.delta_z = delta_z + self.output_path = output_path + self.output_file_prefix = output_file_prefix + + def run(self): + """ + Run the analyse + """ + self.set_status("Calculating raw data...") + raw_data = get_raw_data(self.obj, 6,self.delta_z,self.update_progress) + self.processedData.emit(raw_data) + self.set_weight(100) + self.set_status("Saving data...") + save_output_file(f'{self.output_path}/{self.output_file_prefix}_delta_{self.delta_z}_analyse_brute.txt', + format_data(raw_data, + '\t', + ["X (en mm)", + "Y (en mm)", + "Z (en mm)", + "teta (en rad)", + "rayon (en mm)", + "Xi-Xmoy", + "Yi-Ymoy"] )) + self.set_status("Done !") + self.finished.emit() \ No newline at end of file diff --git a/utils/gui/pyqt/main_window/Workers/Worker.py b/utils/gui/pyqt/main_window/Workers/Worker.py new file mode 100644 index 0000000..3d1b95e --- /dev/null +++ b/utils/gui/pyqt/main_window/Workers/Worker.py @@ -0,0 +1,31 @@ +from PyQt5.QtCore import pyqtSignal, QObject + +class Worker(QObject): + finished = pyqtSignal() + progress = pyqtSignal(int) + status = pyqtSignal(str) + + def __init__(self,name:str): + super().__init__() + self.name = name + self.progress_value = 0 + self.progress_weight = 100 + + def set_status(self, status:str): + """ + Set the weight of the progress bar + """ + self.status.emit(f"[{self.name}]: {status}") + + def set_weight(self, weight): + """ + Set the weight of the progress bar + """ + self.progress_weight = weight + + def update_progress(self, percent): + """ + Update the progress bar + """ + self.progress_value += int(percent/100*self.progress_weight) + self.progress.emit(self.progress_value) \ No newline at end of file