added more docstrings
This commit is contained in:
		
							parent
							
								
									d2e3a43571
								
							
						
					
					
						commit
						d03d6500a0
					
				
							
								
								
									
										7
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								app.py
									
									
									
									
									
								
							| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   app.py | ||||
| @desc:   Main file for the application | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import sys | ||||
| from PyQt5.QtWidgets import QApplication | ||||
| from utils.gui.pyqt.main_window.MainWindow import MainWindow | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Mon Apr 24 2023 | ||||
| @name:   data_processing.py | ||||
| @desc:   A module to process the data | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from utils.math import data_extraction | ||||
| from utils.files.input import ScannedObject | ||||
| from utils.settings.SettingManager import SettingManager | ||||
| @ -13,6 +20,8 @@ def get_raw_data(obj:ScannedObject, ndigits:int,delta_z:float=1,update_progress_ | ||||
| 
 | ||||
|     :param obj: Object to analyse | ||||
|     :param ndigits: Number of digits to keep after the comma | ||||
|     :param delta_z: Delta z to use for the discretisation | ||||
|     :param update_progress_bar: Function to update the progress bar | ||||
|     :return: dict(str:list) with the following keys: | ||||
|         - X (en mm)     : list of x values | ||||
|         - Y (en mm)     : list of y values | ||||
| @ -22,18 +31,24 @@ def get_raw_data(obj:ScannedObject, ndigits:int,delta_z:float=1,update_progress_ | ||||
|         - Xi-Xmoy       : list of Xi-Xmoy values | ||||
|         - Yi-Ymoy       : list of Yi-Ymoy values | ||||
|     """ | ||||
| 
 | ||||
|     # Create the data dict | ||||
|     colones = ["X (en mm)", "Y (en mm)", "Z (en mm)", "teta (en rad)", "rayon (en mm)","Xi-Xmoy","Yi-Ymoy"] | ||||
|     data = {} | ||||
|     for colone in colones: | ||||
|         data[colone] = [] | ||||
| 
 | ||||
|     # Select the discretisation method from the settings | ||||
|     if SettingManager.get_instance().get_setting("discretisation_method") == "Z0-Zi < DeltaZ": | ||||
|         get_discrete_vertices = obj.get_discrete_vertices | ||||
|     else: | ||||
|         get_discrete_vertices = obj.get_discrete_vertices3  | ||||
| 
 | ||||
|     # Get the discrete vertices | ||||
|     discrete_vertices = get_discrete_vertices(delta_z) | ||||
|     progress = 0 | ||||
| 
 | ||||
|     # Calculate the data for each discrete vertex | ||||
|     for discrete_values in discrete_vertices: | ||||
|         mean_x ,mean_y, mean_z = data_extraction.get_x_y_z_mean(discrete_values) | ||||
|         for x,y,z in discrete_values: | ||||
| @ -54,6 +69,8 @@ def get_discrete_data(obj:ScannedObject, ndigits:int, delta_z:float=1, update_pr | ||||
| 
 | ||||
|     :param obj: Object to analyse | ||||
|     :param ndigits: Number of digits to keep after the comma | ||||
|     :param delta_z: Delta z to use for the discretisation | ||||
|     :param update_progress_bar: Function to update the progress bar | ||||
|     :return: dict(str:list) with the following keys: | ||||
|         - X moy (en mm)             : list of x mean values | ||||
|         - Y moy (en mm)             : list of y mean values | ||||
| @ -61,15 +78,19 @@ 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 | ||||
|     """ | ||||
|     # Create the data dict | ||||
|     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] = [] | ||||
| 
 | ||||
|     # Select the discretisation method from the settings | ||||
|     if SettingManager.get_instance().get_setting("discretisation_method") == "Z0-Zi < DeltaZ": | ||||
|         get_discrete_vertices = obj.get_discrete_vertices | ||||
|     else: | ||||
|         get_discrete_vertices = obj.get_discrete_vertices3  | ||||
| 
 | ||||
|     # Get the discrete vertices | ||||
|     discrete_vertices = get_discrete_vertices(delta_z) | ||||
|     progress = 0 | ||||
|     for discrete_values in discrete_vertices: | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| """ | ||||
| This module contains the functions to parse the input files, and create a ScannedObject. | ||||
| Created on Thu Apr 20 2023 | ||||
| @name:   input.py | ||||
| @desc:   This module contains the functions to parse the input files, and create a ScannedObject. | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import numpy as np | ||||
| from utils.files.output import save_output_file | ||||
| @ -64,15 +68,12 @@ class ScannedObject: | ||||
|     [(0, 1, 2), (0, 2, 3), (4, 5, 6), (4, 6, 7), (0, 1, 5), (0, 4, 5), (1, 2, 6), (1, 5, 6), (2, 3, 7), (2, 6, 7), (3, 0, 4), (3, 7, 4)] | ||||
|     >>> obj.get_discrete_vertices() | ||||
|     [[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]],[ (0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)]] | ||||
|     #TODO Add and test exemples | ||||
|     """ | ||||
|     def __init__(self, vertices, faces=None, result_file_path=None): | ||||
|         self.vertices = np.asarray(vertices) | ||||
|         self.faces = np.asarray(faces) | ||||
|         # Deprecated | ||||
|         self.result_file_path = result_file_path | ||||
|         self.bruteforce_discretization_result = None | ||||
|         # | ||||
|         self.result_file_path = result_file_path # Deprecated | ||||
|         self.bruteforce_discretization_result = None # Deprecated | ||||
|         self.x = np.asarray([vertex[0] for vertex in vertices]) | ||||
|         self.y = np.asarray([vertex[1] for vertex in vertices]) | ||||
|         self.z = np.asarray([vertex[2] for vertex in vertices]) | ||||
| @ -95,6 +96,7 @@ class ScannedObject: | ||||
|             data = f.readlines() | ||||
|             for line in data : | ||||
|                 if line.startswith('f'): | ||||
|                     # Ignore the normals and textures | ||||
|                     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: | ||||
| @ -179,19 +181,22 @@ class ScannedObject: | ||||
|         """ | ||||
|         return self.z | ||||
| 
 | ||||
|     def get_vertices(self, sort:bool = False): | ||||
|     def get_vertices(self, sort:bool = False)->list: | ||||
|         """ | ||||
|         Get the vertices of the object. | ||||
|         :param sort: Sort the vertices by z coordinate | ||||
| 
 | ||||
|         :return: vertices | ||||
|         """ | ||||
|          | ||||
|         vertices = self.vertices if not sort else sorted(self.vertices, key=lambda vertex: vertex[2]) | ||||
|         return vertices | ||||
| 
 | ||||
|     def get_discrete_vertices(self, step:float = 1): | ||||
|     def get_discrete_vertices(self, step:float = 1)->list: | ||||
|         """ | ||||
|         Discretize the vertices of the object. | ||||
|         Discretize the vertices of the object using a split method. | ||||
|         This implementation will split the object at every step interval. | ||||
| 
 | ||||
|         :param step: Step of the discretization | ||||
|         :return: Discretized vertices | ||||
|         """ | ||||
| @ -219,24 +224,30 @@ class ScannedObject: | ||||
|                 L.append([]) | ||||
|         return L | ||||
|      | ||||
|     def get_discrete_vertices3(self, step:float = 1): | ||||
|     def get_discrete_vertices3(self, step:float = 1)->list: | ||||
|         """ | ||||
|         Deprecated | ||||
|         Discretize the vertices of the object using a lenght method. | ||||
|         This implementation will split the object when difference between the | ||||
|         first and last point of a slice is greater or equal then the step interval. | ||||
| 
 | ||||
|         :param step: Step of the discretization | ||||
|         :return: Discretized vertices | ||||
|         """ | ||||
|         cpt = 0 | ||||
|         L = [[]] | ||||
|         z = min(self.get_z()) | ||||
|         sorted = self.get_vertices(sort=True) | ||||
|         for index in range(len(sorted)): | ||||
|             L[-1].append(sorted[index]) | ||||
|             if sorted[index][2] - z > step: | ||||
|                 z = sorted[index+1][2] | ||||
|         sorted_vertices = self.get_vertices(sort=True) | ||||
|         for index,_ in enumerate(sorted_vertices): | ||||
|             L[-1].append(sorted_vertices[index]) | ||||
|             if sorted_vertices[index][2] - z > step: | ||||
|                 z = sorted_vertices[index+1][2] | ||||
|                 L.append([]) | ||||
|         return L | ||||
|      | ||||
|     def get_faces(self,resolved:bool = False)->list: | ||||
|         """ | ||||
|         Get the faces of the object. | ||||
| 
 | ||||
|         :return: faces | ||||
|         """ | ||||
|         if self.faces is None: | ||||
| @ -248,6 +259,7 @@ class ScannedObject: | ||||
|     def update_from_faces(self,faces:list): | ||||
|         """ | ||||
|         Update the object from the faces. | ||||
| 
 | ||||
|         :param faces: Faces to update the object from | ||||
|         """ | ||||
|         cpt = 0 | ||||
| @ -274,6 +286,7 @@ class ScannedObject: | ||||
|     def normalise(self, axis:str = 'z'): | ||||
|         """ | ||||
|         Normalise the object. | ||||
| 
 | ||||
|         :param axis: Axis to normalise | ||||
|         """ | ||||
|         if 'x' in axis: | ||||
| @ -287,6 +300,7 @@ class ScannedObject: | ||||
|     def get_data(self)->dict: | ||||
|         """ | ||||
|         Get the data of the object. | ||||
| 
 | ||||
|         :return: Data of the object | ||||
|         """ | ||||
|         return {'verticies': self.vertices, 'faces': self.faces, 'x': self.x, 'y': self.y, 'z': self.z} | ||||
| @ -329,6 +343,7 @@ class ScannedObject: | ||||
|     def export_xyz(self, file_path:str,separator:str="\t"): | ||||
|         """ | ||||
|         Export the object in a file. | ||||
| 
 | ||||
|         :param file_path: Path of the file | ||||
|         :param separator: chars used to separate the values | ||||
|         """ | ||||
| @ -344,6 +359,7 @@ class ScannedObject: | ||||
|     def export_obj(self,file_path): | ||||
|         """ | ||||
|         Export the object in a file. | ||||
| 
 | ||||
|         :param file_path: Path of the file | ||||
|         """ | ||||
|         string = '' | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| """ | ||||
| Deprecated | ||||
| Created on Fri Apr 14 2023 | ||||
| @name:   input.py | ||||
| @desc:   x,y,z input cleaning (Deprecated) | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| 
 | ||||
| def denormalizeXYZ(filePath:str, output:str): | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| """ | ||||
| This module is used to manage the output files of the program. | ||||
| Created on Mon Apr 17 2023 | ||||
| @name:   output.py | ||||
| @desc:   Output file formatting and saving | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| 
 | ||||
| from utils.settings.SettingManager import SettingManager | ||||
| @ -10,7 +14,7 @@ def format_data(data:dict, separator:str, selected_columns:list = None) -> str: | ||||
|     Format the data to be saved in the output file. | ||||
| 
 | ||||
|     :param data: Data to be formatted | ||||
|     :param selected_columns: Columns to be saved | ||||
|     :param selected_columns: Columns to be saved (in the specified order) | ||||
|     :param separator: Separator of the columns | ||||
|     :return: Formatted data | ||||
| 
 | ||||
| @ -27,19 +31,24 @@ def format_data(data:dict, separator:str, selected_columns:list = None) -> str: | ||||
|          3   ;6   ;9 | ||||
|         ' | ||||
|     """ | ||||
|     isPrettier = SettingManager.get_instance().get_setting('pretiffy_output_file') | ||||
|     # Get the setting for the output file | ||||
|     is_prettier = SettingManager.get_instance().get_setting('pretiffy_output_file') | ||||
|     output = '' | ||||
|     # If the columns are not specified, we take all the columns from dict | ||||
|     if selected_columns is None: | ||||
|         selected_columns = list(data.keys()) | ||||
|      | ||||
|     # Write the columns headers | ||||
|     for column_name in selected_columns: | ||||
|         if isPrettier: | ||||
|         if is_prettier: | ||||
|             output += column_name.ljust(len(column_name) if len(column_name) > 8 else 9 )  + separator | ||||
|         else: | ||||
|             output += column_name + separator | ||||
|     output += '\n' | ||||
|     # Write the columns values | ||||
|     for i in range(len(data[selected_columns[0]])): | ||||
|         for column in selected_columns: | ||||
|             if isPrettier: | ||||
|             if is_prettier: | ||||
|                 output += str(data[column][i]).ljust(len(column) if len(column) > 8 else 9 ) + separator | ||||
|             else: | ||||
|                 output += str(data[column][i]) + separator | ||||
|  | ||||
| @ -1,8 +1,17 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   mpl_render.py | ||||
| @desc:   A module to render a 2D data using matplotlib | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| 
 | ||||
| import matplotlib.pyplot as plt | ||||
| 
 | ||||
| def render2D(values:list): | ||||
|     """ | ||||
|     Render a 2D model using matplotlib | ||||
| 
 | ||||
|     :param values: A list with the values | ||||
|     """ | ||||
|     fig = plt.figure() | ||||
| @ -13,6 +22,7 @@ def render2D(values:list): | ||||
| def cross_section(x_values:list, y_values:list): | ||||
|     """ | ||||
|     Render a 2D cross section using matplotlib | ||||
|      | ||||
|     :param x: A list with the x values | ||||
|     :param y: A list with the y values | ||||
|     """ | ||||
|  | ||||
| @ -1,10 +1,22 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   visplot_render.py | ||||
| @desc:   A module to render a 2D data using vispy | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import vispy.plot as vp | ||||
| import numpy as np | ||||
| 
 | ||||
| def render2D(values:list,title:str,xlabel="",ylabel="",show:bool=True): | ||||
| def render2D(values:list,title:str,xlabel="",ylabel="",show:bool=True)->vp.Fig|None: | ||||
|     """ | ||||
|     Render a 2D plot using vispy | ||||
| 
 | ||||
|     :param values: A list with the values | ||||
|     :param title: Title of the plot | ||||
|     :param xlabel: Label of the x axis | ||||
|     :param ylabel: Label of the y axis | ||||
|     :param show: If True, show the plot, else return the canvas | ||||
|     """ | ||||
|     fig = vp.Fig(size=(600, 500), show=False) | ||||
|     plotwidget = fig[0, 0] | ||||
| @ -20,11 +32,16 @@ def render2D(values:list,title:str,xlabel="",ylabel="",show:bool=True): | ||||
|     else: | ||||
|         return fig | ||||
| 
 | ||||
| def cross_section(x_values:list, y_values:list,title:str,xlabel="",ylabel="",show:bool=True  ): | ||||
| def cross_section(x_values:list, y_values:list,title:str,xlabel="",ylabel="",show:bool=True)->vp.Fig|None: | ||||
|     """ | ||||
|     Render a 2D cross section using vispy | ||||
| 
 | ||||
|     :param x: A list with the x values | ||||
|     :param y: A list with the y values | ||||
|     :param title: Title of the plot | ||||
|     :param xlabel: Label of the x axis | ||||
|     :param ylabel: Label of the y axis | ||||
|     :param show: If True, show the plot, else return the canvas | ||||
|     """ | ||||
|     color = (0.3, 0.5, 0.8,.8) | ||||
|     fig = vp.Fig(show=False) | ||||
|  | ||||
| @ -1,3 +1,11 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   mpl_render.py | ||||
| @desc:   A module to render a 3D data using matplotlib | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| 
 | ||||
| from mpl_toolkits.mplot3d.art3d import Poly3DCollection | ||||
| import matplotlib.pyplot as plt | ||||
| import numpy as np | ||||
| @ -6,6 +14,7 @@ from utils.files.input import ScannedObject | ||||
| def render3D(obj:ScannedObject): | ||||
|     """ | ||||
|     Render a 3D model using matplotlib's Poly3dcollection | ||||
|      | ||||
|     :param obj: A ScannedObject to be rendered | ||||
|     """ | ||||
|     fig = plt.figure() | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   visplot_render.py | ||||
| @desc:   A module to render a 3D data using vispy | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import numpy as np | ||||
| from vispy import app, scene | ||||
| from vispy.scene.visuals import Mesh | ||||
| @ -5,20 +12,27 @@ from vispy.visuals.filters import ShadingFilter, WireframeFilter | ||||
| from utils.files.input import ScannedObject | ||||
| 
 | ||||
| 
 | ||||
| def render3D(obj:ScannedObject,show:bool=True): | ||||
| def render3D(obj:ScannedObject,show:bool=True)->scene.SceneCanvas|None: | ||||
|     """ | ||||
|     Render a 3D model using vispy | ||||
|     Render a 3D model mesh using vispy | ||||
| 
 | ||||
|     :param obj: A ScannedObject to be rendered | ||||
|     :param show: If True, show the plot, else return the canvas | ||||
|     :return: A canvas with the rendered object | ||||
|     """ | ||||
|     # Extract the vertices and faces from the object | ||||
|     vertices = np.asarray(obj.get_vertices()) | ||||
|     faces = np.asarray(obj.get_faces()) | ||||
|     # Create the canvas | ||||
|     canvas = scene.SceneCanvas(keys='interactive', bgcolor='white') | ||||
|     # Create a viewbox to display the mesh in | ||||
|     view = canvas.central_widget.add_view() | ||||
|     view.camera = 'arcball' | ||||
|     view.camera.depth_value = 1e3 | ||||
|     color = (0.3, 0.5, 0.8) | ||||
|     mesh = Mesh(vertices, faces, color=color) | ||||
|     view.add(mesh) | ||||
|     # Add filters to the mesh | ||||
|     wireframe_filter = WireframeFilter(width=0) | ||||
|     shading_filter = ShadingFilter(shininess=0) | ||||
|     mesh.attach(wireframe_filter) | ||||
|  | ||||
| @ -1,7 +1,28 @@ | ||||
| from PyQt5 import QtCore, QtGui, QtWidgets | ||||
| """ | ||||
| Created on Wed Apr 28 2023 | ||||
| @name:   ErrorPopup.py | ||||
| @desc:   A class to show a popup with an error message | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from PyQt5.QtWidgets import QMessageBox | ||||
| 
 | ||||
| class ErrorPopup(object): | ||||
|     """ | ||||
|     A class to show a popup with an error message | ||||
| 
 | ||||
|     :param error_text: The error message | ||||
|     :param details: The details of the error | ||||
|     :param button_label: The label of the button | ||||
|     :param button_callback: The callback of the button | ||||
| 
 | ||||
|     :ivar error_text: The error message | ||||
|     :ivar details: The details of the error | ||||
|     :ivar button_label: The label of the button | ||||
|     :ivar button_callback: The callback of the button | ||||
| 
 | ||||
|     :method show_popup: Show the popup | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self,error_text,details = None,button_label = None,button_callback=None): | ||||
|         self.error_text = error_text | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Mon Apr 24 2023 | ||||
| @name:   MainWindow.py | ||||
| @desc:   Main window of the application | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import os | ||||
| from PyQt5 import QtWidgets | ||||
| from PyQt5.QtCore import QThread | ||||
| @ -14,7 +21,8 @@ from utils.gui.pyqt.main_window.Workers.RawDataWorker import RawDataProcessWorke | ||||
| from utils.gui.pyqt.error_popup.ErrorPopup import ErrorPopup | ||||
| class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|     """ | ||||
|     Main window of the application | ||||
|     Main window of the application, it contains all the UI elements | ||||
| 
 | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, parent=None): | ||||
| @ -133,7 +141,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
| 
 | ||||
|     def start_preprocess(self): | ||||
|         """ | ||||
|         Start the analyse | ||||
|         Start the analyse, create the thread and connect the signals. | ||||
|         """ | ||||
|         if not self.check_input_file(): | ||||
|             return | ||||
| @ -171,6 +179,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|         self.start_analyse_button.setEnabled(False) | ||||
| 
 | ||||
|     def process_raw_data(self, obj:ScannedObject): | ||||
|         """ | ||||
|         Start the analyse, create the thread and connect the signals. | ||||
|         """ | ||||
|         self.processrawdata_thread = QThread() | ||||
|         self.processraw_worker = RawDataProcessWorker("RawDataProcessWorker", | ||||
|                                                       obj, | ||||
| @ -195,6 +206,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|         self.processrawdata_thread.start() | ||||
| 
 | ||||
|     def process_discrete_data(self, obj:ScannedObject): | ||||
|         """ | ||||
|         Start the analyse, create the thread and connect the signals. | ||||
|         """ | ||||
|         self.processdiscrete_thread = QThread() | ||||
|         self.processdiscrete_worker = DiscreteDataProcessWorker("DiscreteDataProcessWorker", | ||||
|                                                                 obj, | ||||
| @ -219,15 +233,27 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|         self.processdiscrete_thread.start() | ||||
| 
 | ||||
|     def set_obj(self,obj:ScannedObject): | ||||
|         """ | ||||
|         Set the obj to the main window | ||||
|         """ | ||||
|         self.obj = obj | ||||
| 
 | ||||
|     def set_discrete_data(self,discrete_data:dict): | ||||
|         """ | ||||
|         Set the discrete data to the main window | ||||
|         """ | ||||
|         self.discrete_data = discrete_data | ||||
| 
 | ||||
|     def set_raw_data(self,raw_data:dict): | ||||
|         """ | ||||
|         Set the raw data to the main window | ||||
|         """ | ||||
|         self.raw_data = raw_data  | ||||
| 
 | ||||
|     def save_model(self): | ||||
|         """ | ||||
|         Save the model to a file | ||||
|         """ | ||||
|         if self.obj is None: | ||||
|             ErrorPopup("Aucune analyse effectuée. Aucun modèle à sauvegarder").show_popup() | ||||
|             return | ||||
| @ -255,6 +281,13 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|             self.Graphs.hide() | ||||
| 
 | ||||
|     def renderGraphs(self,obj:ScannedObject,raw_data:dict,discrete_data:dict): | ||||
|         """ | ||||
|         Render the graphs | ||||
| 
 | ||||
|         :param obj: The scanned object | ||||
|         :param raw_data: The raw data | ||||
|         :param discrete_data: The discrete data | ||||
|         """ | ||||
|         if not self.show_graph_checkbox.isChecked(): | ||||
|             return | ||||
|         for slot in self.slots: | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Wed Apr 26 2023 | ||||
| @name:   DiscreteDataWorker.py | ||||
| @desc:   A module to process discrete data in a thread | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from PyQt5.QtCore import pyqtSignal | ||||
| from utils.files.input import ScannedObject | ||||
| from utils.files.output import save_output_file, format_data | ||||
| @ -7,7 +14,19 @@ from utils.settings.SettingManager import SettingManager | ||||
| 
 | ||||
| class DiscreteDataProcessWorker(Worker): | ||||
|     """ | ||||
|     Worker to run the analyse in a thread | ||||
|     Worker to calculate the discrete data in a thread | ||||
| 
 | ||||
|     :param name: The name of the worker | ||||
|     :param obj: The scanned object | ||||
|     :param output_path: The path to save the output file | ||||
|     :param output_file_prefix: The prefix of the output file | ||||
|     :param delta_z: The delta z | ||||
| 
 | ||||
|     :ivar obj: The scanned object | ||||
|     :ivar delta_z: The delta z | ||||
|     :ivar output_path: The path to save the output file | ||||
|     :ivar output_file_prefix: The prefix of the output file | ||||
|     :ivar processedData: The signal to emit the result | ||||
|     """ | ||||
|     processedData = pyqtSignal(dict) | ||||
| 
 | ||||
| @ -24,11 +43,14 @@ class DiscreteDataProcessWorker(Worker): | ||||
|         Run the analyse | ||||
|         """ | ||||
|         self.set_status("Calculating discrete data...") | ||||
|         # Execute the analyse | ||||
|         discrete_data = get_discrete_data(self.obj, 6,self.delta_z,self.update_progress) | ||||
|         # Emit the result | ||||
|         self.processedData.emit(discrete_data) | ||||
|         self.set_weight(100) | ||||
|         self.set_status("Saving data...") | ||||
|         self.update_progress(10) | ||||
|         # Save the result | ||||
|         suffix = SettingManager.get_instance().get_setting('discrete_data_suffix').replace('{delta_z}',str(self.delta_z)) | ||||
|         extension = SettingManager.get_instance().get_setting('output_file_extension') | ||||
|         separator = SettingManager.get_instance().get_setting('output_file_separator') | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Wed Apr 26 2023 | ||||
| @name:   PreProcessWorker.py | ||||
| @desc:   A module to pre process the 3d object in a thread | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from utils.gui.pyqt.main_window.Workers.Worker import Worker | ||||
| from PyQt5.QtCore import pyqtSignal | ||||
| from utils.files.input import ScannedObject | ||||
| @ -5,7 +12,17 @@ from utils.math.position_manipulation import verticalise | ||||
| 
 | ||||
| class PreProcessWorker(Worker): | ||||
|     """ | ||||
|     Worker to run the analyse in a thread | ||||
|     Worker to pre process the 3d object in a thread | ||||
| 
 | ||||
|     :param name: The name of the worker | ||||
|     :param objpath: The path to the 3d object | ||||
| 
 | ||||
|     :ivar objpath: The path to the 3d object | ||||
|     :ivar progress_value: The current progress value | ||||
|     :ivar progress_weight: The weight of the progress bar | ||||
|     :ivar processed_obj: The signal to emit the processed object | ||||
| 
 | ||||
|     :method run: Pre process the object, read the file, verticalise it and normalise it | ||||
|     """ | ||||
|     processed_obj = pyqtSignal(ScannedObject) | ||||
| 
 | ||||
| @ -17,19 +34,24 @@ class PreProcessWorker(Worker): | ||||
| 
 | ||||
|     def run(self): | ||||
|         """ | ||||
|         Run the analyse | ||||
|         Pre process the object, read the file, verticalise it and normalise it | ||||
|         Emit the processed object in the processed_obj signal | ||||
|         """ | ||||
|         # Read the file | ||||
|         self.set_status("Loading file...") | ||||
|         obj = ScannedObject.from_obj_file(self.objpath) | ||||
|         self.update_progress(5) | ||||
| 
 | ||||
|         # Verticalise the object | ||||
|         self.set_status("Verticalising object...") | ||||
|         verticalise(obj) | ||||
|         self.update_progress(5) | ||||
| 
 | ||||
|         # Normalise the object | ||||
|         self.set_status("Normalising object...") | ||||
|         obj.normalise() | ||||
|         self.update_progress(5) | ||||
| 
 | ||||
|         # Emit the processed object | ||||
|         self.processed_obj.emit(obj) | ||||
|         self.finished.emit() | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Wed Apr 26 2023 | ||||
| @name:   RawDataWorker.py | ||||
| @desc:   A module to process the raw data in a thread | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from PyQt5.QtCore import pyqtSignal | ||||
| from utils.files.input import ScannedObject | ||||
| from utils.files.output import save_output_file, format_data | ||||
| @ -7,7 +14,19 @@ from utils.settings.SettingManager import SettingManager | ||||
| 
 | ||||
| class RawDataProcessWorker(Worker): | ||||
|     """ | ||||
|     Worker to run the analyse in a thread | ||||
|     Worker to calculate the raw data in a thread | ||||
| 
 | ||||
|     :param name: The name of the worker | ||||
|     :param obj: The scanned object | ||||
|     :param output_path: The path to save the output file | ||||
|     :param output_file_prefix: The prefix of the output file | ||||
|     :param delta_z: The delta z | ||||
| 
 | ||||
|     :ivar obj: The scanned object | ||||
|     :ivar delta_z: The delta z | ||||
|     :ivar output_path: The path to save the output file | ||||
|     :ivar output_file_prefix: The prefix of the output file | ||||
|     :ivar processedData: The signal to emit the result | ||||
|     """ | ||||
|     processedData = pyqtSignal(dict) | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,25 @@ | ||||
| """ | ||||
| Created on Wed Apr 26 2023 | ||||
| @name:   Worker.py | ||||
| @desc:   Base class for the workers | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from PyQt5.QtCore import pyqtSignal, QObject | ||||
| 
 | ||||
| class Worker(QObject): | ||||
|     """ | ||||
|     Base class for the workers | ||||
| 
 | ||||
|     :param name: The name of the worker | ||||
| 
 | ||||
|     :ivar name: The name of the worker | ||||
|     :ivar progress_value: The current progress value | ||||
|     :ivar progress_weight: The weight of the progress bar | ||||
|     :ivar finished: The signal to emit when the worker is finished | ||||
|     :ivar progress: The signal to emit the progress value | ||||
|     :ivar status: The signal to emit the status of the worker | ||||
|     """ | ||||
|     finished = pyqtSignal() | ||||
|     progress = pyqtSignal(int) | ||||
|     status = pyqtSignal(str) | ||||
|  | ||||
| @ -1,11 +1,19 @@ | ||||
| """ | ||||
| Created on Thu Apr 27 2023 | ||||
| @name:   Settings.py | ||||
| @desc:   Settings window | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import os | ||||
| from PyQt5 import QtWidgets | ||||
| from PyQt5.QtWidgets import QWidget | ||||
| from utils.files.input import ScannedObject | ||||
| from utils.gui.pyqt.settings.UI_Settings import Ui_Settings | ||||
| from utils.settings.SettingManager import SettingManager | ||||
| 
 | ||||
| class Settings(QtWidgets.QMainWindow,Ui_Settings): | ||||
|     """ | ||||
|     Settings window | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, parent=None): | ||||
|         super().__init__(parent) | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| """ | ||||
| This module contains some utility functions for math operations. | ||||
| Created on Mon Apr 17 2023 | ||||
| @name:   data_extraction.py | ||||
| @desc:   This module contains some utility functions for math operations. | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import numpy as np | ||||
| import math | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   position_manipulation.py | ||||
| @desc:   This module contains some utility functions for position manipulation. | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import numpy as np | ||||
| from utils.files.input import ScannedObject | ||||
| from utils.math.data_extraction import get_mean | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| """ | ||||
| Created on Fri Apr 21 2023 | ||||
| @name:   SettingManager.py | ||||
| @desc:   A module to manage the settings | ||||
| @auth:   Djalim Simaila | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| from yaml import load, dump | ||||
| try: | ||||
|     from yaml import CLoader as Loader, CDumper as Dumper | ||||
| @ -5,6 +12,12 @@ except ImportError: | ||||
|     from yaml import Loader, Dumper | ||||
| 
 | ||||
| class SettingManager: | ||||
|     """ | ||||
|     A class to manage the settings | ||||
| 
 | ||||
|     :ivar settings: The settings | ||||
|     :ivar instance: The instance of the class | ||||
|     """ | ||||
|     instance = None | ||||
| 
 | ||||
|     def __init__(self): | ||||
| @ -16,13 +29,21 @@ class SettingManager: | ||||
|             self.createInitialSettings() | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def get_instance(): | ||||
|     def get_instance()->'SettingManager': | ||||
|         """ | ||||
|         Get the instance of the class | ||||
| 
 | ||||
|         :return: The instance of the class | ||||
|         """ | ||||
|         if SettingManager.instance is None: | ||||
|             SettingManager.instance = SettingManager() | ||||
|         return SettingManager.instance | ||||
| 
 | ||||
| 
 | ||||
|     def save(self): | ||||
|         """ | ||||
|         Save the settings to the config file | ||||
|         """ | ||||
|         with open('config.yml', 'w') as f: | ||||
|             f.write(dump(self.settings, Dumper=Dumper)) | ||||
| 
 | ||||
| @ -42,19 +63,45 @@ class SettingManager: | ||||
|         self.settings['pretiffy_output_file'] = True | ||||
|         self.save() | ||||
| 
 | ||||
|     def get_last_graph(self, graph_number): | ||||
|     def get_last_graph(self, graph_number)->str: | ||||
|         """ | ||||
|         Get the last graph name for the specified slot | ||||
|         """ | ||||
|         return self.settings['lastGraph'][graph_number] | ||||
| 
 | ||||
|     def set_last_graph(self, graph_number, graph_name): | ||||
|         """ | ||||
|         Set the last graph name for the specified slot | ||||
|          | ||||
|         :param graph_number: The slot number | ||||
|         :param graph_name: The graph name | ||||
|         """ | ||||
|         self.settings['lastGraph'][graph_number] = graph_name | ||||
|         self.save() | ||||
| 
 | ||||
|     def get_setting(self, setting_name): | ||||
|     def get_setting(self, setting_name)->any: | ||||
|         """ | ||||
|         Get the value of the specified setting | ||||
| 
 | ||||
|         :param setting_name: The name of the setting | ||||
|         :return: The value of the setting | ||||
|         """ | ||||
|         return self.settings[setting_name] | ||||
|      | ||||
|     def get_settings(self): | ||||
|     def get_settings(self)->dict: | ||||
|         """ | ||||
|         Get the settings | ||||
| 
 | ||||
|         :return: The settings | ||||
|         """ | ||||
|         return self.settings | ||||
|      | ||||
|     def set_setting(self, setting_name, setting_value): | ||||
|         """ | ||||
|         Set the value of the specified setting | ||||
| 
 | ||||
|         :param setting_name: The name of the setting | ||||
|         :param setting_value: The value of the setting | ||||
|         """ | ||||
|         self.settings[setting_name] = setting_value | ||||
|         self.save() | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user