🐛 fix(input.py): handle case where faces is None in ScannedObject constructor
✨ feat(input.py): add support for reading .xyz files and raise InvalidFileFormat exception if file format is not supported 🚸 chore(gui): add warning popup when trying to use Mesh3D graph with .xyz file 🚸 chore(gui): refactor MainWindow.check_input_file method to handle .xyz files 🚸 chore(gui): refactor PreProcessWorker to use ScannedObject.from_file method 🚸 chore(math): add check for faces in verticalise function to avoid errors when faces is None The ScannedObject constructor now handles the case where faces is None. Support for reading .xyz files has been added, and an InvalidFileFormat exception is raised if the file format is not supported. A warning popup has been added to the MainWindow when trying to use the Mesh3D graph with a .xyz file. The MainWindow.check_input_file method
This commit is contained in:
		
							parent
							
								
									4430309b41
								
							
						
					
					
						commit
						d64c8dd333
					
				| @ -6,6 +6,7 @@ Created on Thu Apr 20 2023 | ||||
| @e-mail: djalim.simaila@inrae.fr | ||||
| """ | ||||
| import numpy as np | ||||
| import os | ||||
| from utils.files.output import save_output_file | ||||
| from utils.settings.SettingManager import SettingManager | ||||
| 
 | ||||
| @ -20,6 +21,11 @@ class ResultFileNotGiven(Exception): | ||||
|     Exception raised when no faces was given. | ||||
|     """ | ||||
| 
 | ||||
| class InvalidFileFormat(Exception): | ||||
|     """ | ||||
|     Exception raised when the file format is not supported. | ||||
|     """ | ||||
| 
 | ||||
| class ScannedObject: | ||||
|     """ | ||||
|     This class is used to manage the data of the 3D object. | ||||
| @ -49,7 +55,7 @@ class ScannedObject: | ||||
|     """ | ||||
|     def __init__(self, vertices, faces=None): | ||||
|         self.vertices = np.asarray(vertices) | ||||
|         self.faces = np.asarray(faces) | ||||
|         self.faces = np.asarray(faces) if faces is not None else None | ||||
|         self.old_delta = None | ||||
|         self.old_discrete = None | ||||
|         self.old_discrete_type = None | ||||
| @ -58,6 +64,24 @@ class ScannedObject: | ||||
|         self.z = np.asarray([vertex[2] for vertex in vertices]) | ||||
| 
 | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def from_file(file_path:str, ratio:float = 1,normalised:str = '')->'ScannedObject': | ||||
|         """ | ||||
|         Create an Object from a file. | ||||
| 
 | ||||
|         :param file_path: Path to the file | ||||
|         :param ratio: Ratio to apply to the vertices | ||||
|         :param normalised: the axis to normalise | ||||
|         :return: A ScannedObject | ||||
|         """ | ||||
|         if os.path.splitext(file_path)[1].lower() == ".xyz": | ||||
|             return ScannedObject.from_xyz_file(file_path, ' ',ratio, normalised) | ||||
|         elif os.path.splitext(file_path)[1].lower() == ".obj": | ||||
|             return ScannedObject.from_obj_file(file_path, ratio, normalised) | ||||
|         else: | ||||
|             raise InvalidFileFormat("The file format is not supported.") | ||||
| 
 | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def from_obj_file(file_path:str, ratio:float = 1,normalised:str = '')->'ScannedObject': | ||||
|         """ | ||||
| @ -108,7 +132,7 @@ class ScannedObject: | ||||
|         return ScannedObject(list(zip(x,y,z)), triangles, ) | ||||
|      | ||||
|     @staticmethod | ||||
|     def from_xyz_file(file_path:str, delimiter:str = ' ', normalised:str = '')->'ScannedObject': | ||||
|     def from_xyz_file(file_path:str, delimiter:str = ' ', ratio:float=1, normalised:str = '')->'ScannedObject': | ||||
|         """ | ||||
|         Create an Object from an XYZ file. | ||||
| 
 | ||||
| @ -121,9 +145,10 @@ class ScannedObject: | ||||
|         with open(file_path, 'r',encoding='utf-8') as f: | ||||
|             data = f.readlines() | ||||
|             for line in data: | ||||
|                 x.append(float(line.split(delimiter)[0])) | ||||
|                 y.append(float(line.split(delimiter)[1])) | ||||
|                 z.append(float(line.split(delimiter)[2])) | ||||
|                 print(line) | ||||
|                 x.append(float(line.split(delimiter)[0])* ratio) | ||||
|                 y.append(float(line.split(delimiter)[1])* ratio) | ||||
|                 z.append(float(line.split(delimiter)[2])* ratio) | ||||
| 
 | ||||
|         if 'x' in normalised: | ||||
|             xmin = min(x) | ||||
| @ -238,6 +263,14 @@ class ScannedObject: | ||||
|         self.old_discrete = splitted_data | ||||
|         return splitted_data | ||||
|      | ||||
|     def has_faces(self)->bool: | ||||
|         """ | ||||
|         Check if the object has faces. | ||||
| 
 | ||||
|         :return: True if the object has faces, False otherwise | ||||
|         """ | ||||
|         return self.faces is not None | ||||
| 
 | ||||
|     def get_faces(self,resolved:bool = False)->list: | ||||
|         """ | ||||
|         Get the faces of the object. | ||||
|  | ||||
| @ -163,16 +163,20 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|             - if it exists | ||||
|             - if its extension is .obj | ||||
|         """ | ||||
|         authorised_extensions = [".obj",".xyz"] | ||||
|         if not os.path.isfile(self.input_file_path.toPlainText()) : | ||||
|             ErrorPopup("Fichier d'entrée invalide: Aucun fichier selectionné, ou le fichier n'existe pas", | ||||
|                         button_label="Choisir un fichier d'entrée", | ||||
|                         button_callback=self.select_file).show_popup() | ||||
|             return False | ||||
|         if os.path.splitext(self.input_file_path.toPlainText())[1].lower() != ".obj": | ||||
|         if os.path.splitext(self.input_file_path.toPlainText())[1].lower() not in authorised_extensions: | ||||
|             ErrorPopup("Fichier d'entrée invalide: l'extension du fichier est incorrecte ", | ||||
|                         button_label="Choisir un fichier d'entrée", | ||||
|                         button_callback=self.select_file).show_popup() | ||||
|             return False | ||||
|         if os.path.splitext(self.input_file_path.toPlainText())[1].lower() == ".xyz": | ||||
|             print("test") | ||||
|             ErrorPopup("Attention!, Ce programme ne peut pas redresser les fichiers .xyz, assurez vous que l'objet est deja droit. Il sera aussi impossible d'utiliser le graphe 'Mesh3D'").show_popup() | ||||
|         return True | ||||
| 
 | ||||
|     def check_output_folder(self): | ||||
| @ -430,7 +434,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): | ||||
|             current_slot = slot[0] | ||||
|             graph_type = slot[1] | ||||
|             if graph_type == "Mesh3D": | ||||
|                 current_slot.addWidget(render3D(obj,False).native) | ||||
|                 if obj.has_faces(): | ||||
|                     current_slot.addWidget(render3D(obj,False).native) | ||||
|             if graph_type == "Coupe XZ": | ||||
|                 current_slot.addWidget(cross_section(obj.get_x(), | ||||
|                                                      obj.get_z(), | ||||
|  | ||||
| @ -43,7 +43,7 @@ class PreProcessWorker(Worker): | ||||
|         """ | ||||
|         # Read the file | ||||
|         self.set_status("Loading file...") | ||||
|         obj = ScannedObject.from_obj_file(self.objpath) | ||||
|         obj = ScannedObject.from_file(self.objpath) | ||||
|         self.update_progress(5) | ||||
| 
 | ||||
|         # Verticalise the object | ||||
|  | ||||
| @ -75,12 +75,13 @@ def get_mass_properties(obj:ScannedObject)->tuple: | ||||
|     inertia[1, 2] = inertia[2, 1] = -(intg[8] - volume * cog[1] * cog[2]) | ||||
|     inertia[0, 2] = inertia[2, 0] = -(intg[9] - volume * cog[2] * cog[0]) | ||||
|     return volume, cog, inertia | ||||
| 
 | ||||
| def verticalise(obj:ScannedObject): | ||||
|     """ | ||||
|     Rotate the object so that the principal axis of inertia is vertical | ||||
|     :param obj: Object to analyse | ||||
|     """ | ||||
|     if not obj.has_faces(): | ||||
|         return | ||||
|     cog, inertia = get_mass_properties(obj)[1:] | ||||
|     [val,vect] = np.linalg.eig(inertia) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user