diff --git a/utils/files/input.py b/utils/files/input.py index 4cca4caa76cfbd9dbe6c23b8b9f92207dbc2c776..9f59ac8aec5c58d56805c7f6a9bda1e649b0e131 100644 --- a/utils/files/input.py +++ b/utils/files/input.py @@ -5,6 +5,7 @@ Created on Thu Apr 20 2023 @auth: Djalim Simaila @e-mail: djalim.simaila@inrae.fr """ +import struct import numpy as np import os from utils.files.output import save_output_file @@ -53,6 +54,9 @@ class ScannedObject: :raises FacesNotGiven: If no faces was given :raises ResultFileNotGiven: If no result file was given """ + + authorised_extensions = [".obj",".stl",".xyz"] + def __init__(self, vertices, faces=None): self.vertices = np.asarray(vertices) self.faces = np.asarray(faces) if faces is not None else None @@ -78,9 +82,27 @@ class ScannedObject: 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) + elif os.path.splitext(file_path)[1].lower() == ".stl": + if open(file_path, 'rb').read(5) == b'solid': + return ScannedObject.from_ascii_stl_file(file_path, ratio, normalised) + else: + return ScannedObject.from_binary_stl_file(file_path, ratio, normalised) else: raise InvalidFileFormat("The file format is not supported.") + @staticmethod + def from_triangles(triangles:list, normalised:str = '')->'ScannedObject': + """ + Create an Object from a list of triangles. + + :param triangles: List of triangles + :param vertices: List of vertices + :return: A ScannedObject + """ + obj = ScannedObject([], None) + obj.update_from_faces(triangles) + obj.normalise(normalised) + return obj @staticmethod def from_obj_file(file_path:str, ratio:float = 1,normalised:str = '')->'ScannedObject': @@ -165,6 +187,60 @@ class ScannedObject: z[count] -= zmin return ScannedObject(list(zip(x,y,z))) + @staticmethod + def from_binary_stl_file(file_path:str, ratio:float = 1, normalised:str = '')->'ScannedObject': + """ + Create an Object from a binary STL file. + + :param file_path: Path to the STL file + :param ratio: Ratio to apply to the vertices + :param normalised: the axis to normalise + :return: A ScannedObject + """ + with open(file_path, 'rb') as f: + data = f.read(84) + n_triangles = int.from_bytes(data[80:84], byteorder='little') + triangles = [] + + for numero_triangles in range(n_triangles): + f.read(12) + current_triangle = [] + for i in range(3): + vertex = list(struct.unpack('fff', f.read(12))) + for point in vertex: + point *= ratio + current_triangle.append(vertex) + triangles.append(current_triangle) + f.read(2) + + return ScannedObject.from_triangles(triangles, normalised) + + @staticmethod + def from_ascii_stl_file(file_path:str, ratio:float = 1, normalised:str = '')->'ScannedObject': + """ + Create an Object from an STL file. + + :param file_path: Path to the STL file + :param ratio: Ratio to apply to the vertices + :param normalised: the axis to normalise + :return: A ScannedObject + """ + with open(file_path, 'r', encoding='utf-8') as f: + triangles = [] + vertex_buffer = [] + data = f.readlines() + for line in data : + if line.startswith('vertex'): + x = float(line.split()[1]) * ratio + y = float(line.split()[2]) * ratio + z = float(line.split()[3]) * ratio + vertex_buffer.append([x,y,z]) + if len(vertex_buffer) == 3: + triangles.append(vertex_buffer) + vertex_buffer = [] + + return ScannedObject.from_triangles(triangles, normalised) + def get_x(self)->list: """ Get the x coordinates of the object. @@ -257,8 +333,10 @@ class ScannedObject: for index,_ in enumerate(sorted_vertices): splitted_data[-1].append(sorted_vertices[index]) if sorted_vertices[index][2] - z > step: - z = sorted_vertices[index+1][2] - splitted_data.append([]) + # if you split on the very last point, dont create an empty slice + if index + 1 < len(sorted_vertices): + z = sorted_vertices[index+1][2] + splitted_data.append([]) self.old_discrete = splitted_data return splitted_data @@ -313,7 +391,6 @@ class ScannedObject: self.x = self.vertices[:,0] self.y = self.vertices[:,1] self.z = self.vertices[:,2] - self.normalise() def normalise(self, axis:str = 'z'): """ diff --git a/utils/gui/pyqt/main_window/MainWindow.py b/utils/gui/pyqt/main_window/MainWindow.py index 6ed857897aa4897875a196246aa1fefb63122502..202612d5e107205a7ce4f9ace45091d4d622a183 100644 --- a/utils/gui/pyqt/main_window/MainWindow.py +++ b/utils/gui/pyqt/main_window/MainWindow.py @@ -163,7 +163,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): - if it exists - if its extension is .obj """ - authorised_extensions = [".obj",".xyz"] + authorised_extensions = ScannedObject.authorised_extensions + 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",