Finished verticalisation

This commit is contained in:
Djalim Simaila 2023-04-21 17:06:04 +02:00
parent af36b95e09
commit 533077d8b4
5 changed files with 173 additions and 14 deletions

View File

@ -193,7 +193,7 @@ def check_consistency(obj: ScannedObject, discretised_file_path: str):
:param obj: The object to check :param obj: The object to check
:param discretised_file_path: The discetised file output :param discretised_file_path: The discetised file output
""" """
obj.export("verification.txt") obj.export_xyz("verification.txt")
mean_list = [] mean_list = []
moyx, moyy, moyz = parse_result_file(discretised_file_path) moyx, moyy, moyz = parse_result_file(discretised_file_path)
moy = moyy moy = moyy

15
main.py
View File

@ -1,6 +1,8 @@
from utils.math import data_extraction from utils.math import data_extraction
from utils.files import output from utils.files import output
from utils.files.input import ScannedObject from utils.files.input import ScannedObject
from utils.math.position_manipulation import verticalise
from utils.graph3D.visplot_render import render3D
def get_raw_data(obj:ScannedObject, ndigits:int)->dict: def get_raw_data(obj:ScannedObject, ndigits:int)->dict:
""" """
@ -46,7 +48,7 @@ def get_discrete_data(obj:ScannedObject, ndigits:int)->dict:
- Rayon moyen (en mm) : list of mean radius values - Rayon moyen (en mm) : list of mean radius values
- Rayon ecart type (en mm) : list of radius standard deviation 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)","Rayon moyen (en mm)","Rayon ecart type (en mm)"] 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)"]
data = {} data = {}
for colone in colones: for colone in colones:
data[colone] = [] data[colone] = []
@ -55,15 +57,19 @@ def get_discrete_data(obj:ScannedObject, ndigits:int)->dict:
data["X moy (en mm)"].append(round(x, ndigits)) data["X moy (en mm)"].append(round(x, ndigits))
data["Y moy (en mm)"].append(round(y, ndigits)) data["Y moy (en mm)"].append(round(y, ndigits))
data["Z moy (en mm)"].append(round(z, ndigits)) 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["Rayon moyen (en mm)"].append(round(data_extraction.get_mean_radius(discrete_values), 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)) data["Rayon ecart type (en mm)"].append(round(data_extraction.get_radius_std(discrete_values), ndigits))
return data return data
def main(): def main():
# Create an object from the given file # Create an object from the given file
obj = ScannedObject.from_xyz_file("test_cylindre.xyz",normalised='z') obj = ScannedObject.from_obj_file("datasets/Barette/1 - BARETTE.obj")
verticalise(obj)
obj.normalise()
# Calculate raw data and save it in a file # Calculate raw data and save it in a file
data = get_raw_data(obj, 6) data = get_raw_data(obj, 6)
output.save_output_file('analyse_brute.txt', output.save_output_file('analyse_brute.txt',
@ -85,6 +91,7 @@ def main():
["X moy (en mm)", ["X moy (en mm)",
"Y moy (en mm)", "Y moy (en mm)",
"Z moy (en mm)", "Z moy (en mm)",
"Delta z(en mm)",
"Rayon moyen (en mm)", "Rayon moyen (en mm)",
"Rayon ecart type (en mm)"] )) "Rayon ecart type (en mm)"] ))

View File

@ -0,0 +1,3 @@
vispy==0.12.2
PyQt5==5.15.9
numpy==1.24.2

View File

@ -60,15 +60,15 @@ class ScannedObject:
#TODO Add and test exemples #TODO Add and test exemples
""" """
def __init__(self, vertices, faces=None, result_file_path=None): def __init__(self, vertices, faces=None, result_file_path=None):
self.vertices = vertices self.vertices = np.asarray(vertices)
self.faces = faces self.faces = np.asarray(faces)
# Deprecated # Deprecated
self.result_file_path = result_file_path self.result_file_path = result_file_path
self.bruteforce_discretization_result = None self.bruteforce_discretization_result = None
# #
self.x = [vertex[0] for vertex in vertices] self.x = np.asarray([vertex[0] for vertex in vertices])
self.y = [vertex[1] for vertex in vertices] self.y = np.asarray([vertex[1] for vertex in vertices])
self.z = [vertex[2] for vertex in vertices] self.z = np.asarray([vertex[2] for vertex in vertices])
@staticmethod @staticmethod
@ -225,16 +225,56 @@ class ScannedObject:
L.append([]) L.append([])
return L return L
def get_faces(self,resolved:bool = False)->list:
def get_faces(self)->list:
""" """
Get the faces of the object. Get the faces of the object.
:return: faces :return: faces
""" """
if self.faces is None: if self.faces is None:
raise FacesNotGiven('No faces was given') raise FacesNotGiven('No faces was given')
if resolved:
return self.vertices[self.faces]
return self.faces return self.faces
def update_from_faces(self,faces:list):
"""
Update the object from the faces.
:param faces: Faces to update the object from
"""
cpt = 0
vertex_dict = {}
new_vertices = []
new_faces = []
for face in faces:
new_faces.append([])
for vertex in face:
vertex = tuple(vertex)
if vertex not in vertex_dict:
vertex_dict[vertex] = cpt
cpt += 1
new_vertices.append(vertex)
new_faces[-1].append(vertex_dict[vertex])
self.vertices = np.asarray(new_vertices)
self.faces = np.asarray(new_faces)
self.x = self.vertices[:,0]
self.y = self.vertices[:,1]
self.z = self.vertices[:,2]
self.normalise()
def normalise(self, axis:str = 'z'):
"""
Normalise the object.
:param axis: Axis to normalise
"""
if 'x' in axis:
self.x -= min(self.x)
if 'y' in axis:
self.y -= min(self.y)
if 'z' in axis:
self.z -= min(self.z)
self.vertices = np.asarray(list(zip(self.x,self.y,self.z)))
def get_data(self)->dict: def get_data(self)->dict:
""" """
Get the data of the object. Get the data of the object.
@ -258,7 +298,7 @@ class ScannedObject:
verticies = self.get_vertices(sort=True) verticies = self.get_vertices(sort=True)
position = 0 position = 0
while position < len(verticies): while position < len(verticies):
print(position/len(verticies)*100,end="\r") print('progression :',position/len(verticies)*100,end="\r")
x = verticies[position][0] x = verticies[position][0]
y = verticies[position][1] y = verticies[position][1]
z = verticies[position][2] z = verticies[position][2]
@ -277,7 +317,7 @@ class ScannedObject:
self.bruteforce_discretization_result = splitted_data self.bruteforce_discretization_result = splitted_data
return splitted_data return splitted_data
def export(self, file_path:str,separator:str="\t"): def export_xyz(self, file_path:str,separator:str="\t"):
""" """
Export the object in a file. Export the object in a file.
:param file_path: Path of the file :param file_path: Path of the file
@ -292,6 +332,25 @@ class ScannedObject:
string+=f"{x}{separator}{y}{separator}{z}\n" string+=f"{x}{separator}{y}{separator}{z}\n"
save_output_file(file_path,string) save_output_file(file_path,string)
def export_obj(self,file_path):
"""
Export the object in a file.
:param file_path: Path of the file
"""
string = ''
with open(file_path, "w") as f:
for vertex in self.get_vertices():
x = round(vertex[0], 6)
y = round(vertex[1], 6)
z = round(vertex[2], 6)
string+=f"v {x} {y} {z}\n"
for face in self.get_faces():
string+="f "
for vertex in face:
string+=f"{vertex+1} "
string+="\n"
save_output_file(file_path,string)
def parse_result_file(file_path: str, separator: str = "\t")-> tuple: def parse_result_file(file_path: str, separator: str = "\t")-> tuple:
""" """

View File

@ -0,0 +1,90 @@
import numpy as np
from utils.files.input import ScannedObject
from utils.math.data_extraction import get_mean
def get_mass_properties(obj:ScannedObject):
'''
Evaluate and return a tuple with the following elements:
- the volume
- the position of the center of gravity (COG)
- the inertia matrix expressed at the COG
Documentation can be found here:
http://www.geometrictools.com/Documentation/PolyhedralMassProperties.pdf
'''
verts = np.asarray(obj.get_vertices())
faces = np.asarray(obj.get_faces())
faces = verts[faces]
x = np.asarray([[point[0] for point in faces] for faces in faces])
y = np.asarray([[point[1] for point in faces] for faces in faces])
z = np.asarray([[point[2] for point in faces] for faces in faces])
def subexpression(x):
w0, w1, w2 = x[:, 0], x[:, 1], x[:, 2]
temp0 = w0 + w1
f1 = temp0 + w2
temp1 = w0 * w0
temp2 = temp1 + w1 * temp0
f2 = temp2 + w2 * f1
f3 = w0 * temp1 + w1 * temp2 + w2 * f2
g0 = f2 + w0 * (f1 + w0)
g1 = f2 + w1 * (f1 + w1)
g2 = f2 + w2 * (f1 + w2)
return f1, f2, f3, g0, g1, g2
x0, x1, x2 = x[:, 0], x[:, 1], x[:, 2]
y0, y1, y2 = y[:, 0], y[:, 1], y[:, 2]
z0, z1, z2 = z[:, 0], z[:, 1], z[:, 2]
a1, b1, c1 = x1 - x0, y1 - y0, z1 - z0
a2, b2, c2 = x2 - x0, y2 - y0, z2 - z0
d0, d1, d2 = b1 * c2 - b2 * c1, a2 * c1 - a1 * c2, a1 * b2 - a2 * b1
f1x, f2x, f3x, g0x, g1x, g2x = subexpression(x)
f1y, f2y, f3y, g0y, g1y, g2y = subexpression(y)
f1z, f2z, f3z, g0z, g1z, g2z = subexpression(z)
intg = np.zeros((10))
intg[0] = sum(d0 * f1x)
intg[1:4] = sum(d0 * f2x), sum(d1 * f2y), sum(d2 * f2z)
intg[4:7] = sum(d0 * f3x), sum(d1 * f3y), sum(d2 * f3z)
intg[7] = sum(d0 * (y0 * g0x + y1 * g1x + y2 * g2x))
intg[8] = sum(d1 * (z0 * g0y + z1 * g1y + z2 * g2y))
intg[9] = sum(d2 * (x0 * g0z + x1 * g1z + x2 * g2z))
intg /= np.array([6, 24, 24, 24, 60, 60, 60, 120, 120, 120])
volume = intg[0]
cog = intg[1:4] / volume
cogsq = cog ** 2
inertia = np.zeros((3, 3))
inertia[0, 0] = intg[5] + intg[6] - volume * (cogsq[1] + cogsq[2])
inertia[1, 1] = intg[4] + intg[6] - volume * (cogsq[2] + cogsq[0])
inertia[2, 2] = intg[4] + intg[5] - volume * (cogsq[0] + cogsq[1])
inertia[0, 1] = inertia[1, 0] = -(intg[7] - volume * cog[0] * cog[1])
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):
cog = get_mass_properties(obj)
cog, inertia = get_mass_properties(obj)[1:]
[val,vect] = np.linalg.eig(inertia)
if np.linalg.det(vect) < 0:
vect[:,2] = - vect[:,2]
rot = vect.T
faces = obj.get_faces(True)
theta = -np.pi/2
R_y = np.array([[np.cos(theta), 0, np.sin(theta)],
[0, 1, 0],
[-np.sin(theta), 0, np.cos(theta)]])
for face,_ in enumerate(faces):
for vertex in range(3):
faces[face][vertex] = rot@(faces[face][vertex] - cog)
faces[face][vertex] = R_y@(faces[face][vertex])
obj.update_from_faces(faces)