diff --git a/utils/files/input.py b/utils/files/input.py index 80f13c9..274ce2d 100644 --- a/utils/files/input.py +++ b/utils/files/input.py @@ -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. diff --git a/utils/gui/pyqt/main_window/MainWindow.py b/utils/gui/pyqt/main_window/MainWindow.py index 90b9280..e8c8cf5 100644 --- a/utils/gui/pyqt/main_window/MainWindow.py +++ b/utils/gui/pyqt/main_window/MainWindow.py @@ -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(), diff --git a/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py b/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py index 389d7e9..010bf68 100644 --- a/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py +++ b/utils/gui/pyqt/main_window/Workers/PreProcessWorker.py @@ -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 diff --git a/utils/math/position_manipulation.py b/utils/math/position_manipulation.py index 778f85a..cb65d9f 100644 --- a/utils/math/position_manipulation.py +++ b/utils/math/position_manipulation.py @@ -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)