General code cleanup

This commit is contained in:
Djalim Simaila 2023-04-20 13:57:06 +02:00
parent f55cdae99a
commit 39d68a8037
11 changed files with 640 additions and 431 deletions

View File

@ -1,68 +1,114 @@
"""
This module gives functions to assist tests
"""
import os
import time
import numpy as np
from main import get_discrete_data, get_raw_data
from utils.files import output
from utils.files.input import ScannedObject
def check_discrete_data(expected_file, actual_file, ndigits=7,eps=0.00001) :
def check_discrete_data(expected_file: str, actual_file: str, ndigits=7, eps=0.00001, silent: bool = False) -> dict:
"""
Compares the output of the main process with the reference output for the same file,
This function assume the passed paramters are the discretised one and not the raw,
this function will not test that for the user>
:param expected_file: The reference file, the one we assume is correct
:param actual_file: The output of the main process
:param ndigits: The number of values to keep after the dot
:param eps: the degree of precision we consider two values different
:return: dict containing the average difference for each variable
"""
output_file = "check_discrete_data_full.txt"
minimal_output_file = "check_discrete_data_minimal.txt"
minimal_output_data = ""
output_data = ""
expected = []
x,y,z,r,std = 0,0,0,0,0
list_x_diffs, list_y_diffs, list_z_diffs, list_r_diffs, list_std_diffs = [], [], [], [], []
with open(expected_file, "r") as f:
expected = f.readlines()[1:]
expected = [line.replace(',','.').split('\t') for line in expected]
expected = [line.replace(',', '.').split('\t') for line in expected]
expected = [[float(x) for x in line] for line in expected]
actual = []
with open(actual_file, "r") as f:
actual = f.readlines()[1:]
actual = [line.split('\t') for line in actual]
actual = [[float(x) for x in line if x != '\n'] for line in actual]
for i in range(min(len(expected), len(actual))):
x_diff = round(abs(expected[i][0] - actual[i][0]),ndigits)
y_diff = round(abs(expected[i][1] - actual[i][1]),ndigits)
z_diff = round(abs(expected[i][2] - actual[i][2]),ndigits)
r_diff = round(abs(expected[i][3] - actual[i][3]),ndigits)
std_diff = round(abs(expected[i][4] - actual[i][4]),ndigits)
for point in range(min(len(expected), len(actual))):
# Calculate the difference for each variable
x_diff, y_diff, z_diff, r_diff, std_diff = round(abs(expected[point][0] - actual[point][0]), ndigits), round(abs(expected[point][1] - actual[point][1]), ndigits), round(
abs(expected[point][2] - actual[point][2]), ndigits), round(abs(expected[point][3] - actual[point][3]), ndigits), round(abs(expected[point][4] - actual[point][4]), ndigits)
x += x_diff
y += y_diff
z += z_diff
r += r_diff
std += std_diff
# Add the difference to their respective list
list_x_diffs.append(x_diff)
list_y_diffs.append(y_diff)
list_z_diffs.append(z_diff)
list_r_diffs.append(r_diff)
list_std_diffs.append(std_diff)
line = f"{str(i).rjust(4)}:\t X: {str(x_diff).rjust(8)}\t Y: {str(y_diff).rjust(8)}\t Z: {str(z_diff).rjust(8)}\t R: {str(r_diff).rjust(8)}\t STD: {str(std_diff).rjust(8)}"
# Format the line
line = f"{str(point).rjust(4)}:\t X: {str(x_diff).rjust(8)}\t Y: {str(y_diff).rjust(8)}\t Z: {str(z_diff).rjust(8)}\t R: {str(r_diff).rjust(8)}\t STD: {str(std_diff).rjust(8)}"
output_data += line + "\n"
# If one of the values is greater than epsilon, add the line to the minimal output file
if x_diff > eps or y_diff > eps or z_diff > eps or r_diff > eps or std_diff > eps:
minimal_output_data += line + "\n"
# Save output to file
output.save_output_file(output_file, output_data)
output.save_output_file(minimal_output_file, minimal_output_data)
x = round(x/len(expected),ndigits)
y = round(y/len(expected),ndigits)
z = round(z/len(expected),ndigits)
r = round(r/len(expected),ndigits)
std = round(std/len(expected),ndigits)
print()
print("Analyse données discretisées:")
print(f"difference moyenne X: {x}")
print(f"difference moyenne Y: {y}")
print(f"difference moyenne Z: {z}")
print(f"difference moyenne R: {r}")
print(f"difference moyenne STD: {std}")
print(f"diff globale des fichiers: {(x+y+z+r+std)/5}")
print(f"Voir {output_file} pour plus de détails")
print(f"Voir {minimal_output_file} pour les différences significatives")
print("_"*80)
# Print the results
if not silent:
x = round(sum(list_x_diffs)/len(expected), ndigits)
y = round(sum(list_y_diffs)/len(expected), ndigits)
z = round(sum(list_z_diffs)/len(expected), ndigits)
r = round(sum(list_r_diffs)/len(expected), ndigits)
std = round(sum(list_std_diffs)/len(expected), ndigits)
print()
print("Analyse données discretisées:")
print(f"difference moyenne X: {x}")
print(f"difference moyenne Y: {y}")
print(f"difference moyenne Z: {z}")
print(f"difference moyenne R: {r}")
print(f"difference moyenne STD: {std}")
print(f"diff globale des fichiers: {(x+y+z+r+std)/5}")
print(f"Voir {output_file} pour plus de détails")
print(f"Voir {minimal_output_file} pour les différences significatives")
print("_"*80)
return {
"x": x,
"y": y,
"z": z,
"r": r,
"std": std}
def check_raw_data(expected_file, actual_file, ndigits=7,eps=0.00001) :
def check_raw_data(expected_file, actual_file, ndigits=7, eps=0.00001, silent: bool = False) -> dict:
"""
Compares the output of the main process with the reference output for the same file,
This function assume the passed paramters are the raw one and not the discretised,
this function will not test that for the user.
:param expected_file: The reference file, the one we assume is correct
:param actual_file: The output of the main process
:param ndigits: The number of values to keep after the dot
:param eps: the degree of precision we consider two values different
:return: dict containing the average difference for each variable
"""
output_file = "check_raw_data_full.txt"
minimal_output_file = "check_raw_data_minimal.txt"
minimal_output_data = ""
output_data = ""
expected = []
x,y,z,t,r,xmoy,ymoy = 0,0,0,0,0,0,0
list_x_diffs, list_y_diffs, list_z_diffs, list_teta_diffs, list_radius_diffs, list_xmoy_diffs, list_ymoy_diffs = [], [], [], [], [], [], []
with open(expected_file, "r") as f:
expected = f.readlines()[1:]
expected = [line.replace(',','.').split('\t') for line in expected]
expected = [line.replace(',', '.').split('\t') for line in expected]
expected = [[float(x) for x in line] for line in expected]
actual = []
with open(actual_file, "r") as f:
@ -70,24 +116,24 @@ def check_raw_data(expected_file, actual_file, ndigits=7,eps=0.00001) :
actual = [line.split('\t') for line in actual]
actual = [[float(x) for x in line if x != '\n'] for line in actual]
for i in range(min(len(expected), len(actual))):
x_diff = round(abs(expected[i][0] - actual[i][0]),ndigits)
y_diff = round(abs(expected[i][1] - actual[i][1]),ndigits)
z_diff = round(abs(expected[i][2] - actual[i][2]),ndigits)
t_diff = round(abs(expected[i][3] - actual[i][3]),ndigits)
r_diff = round(abs(expected[i][4] - actual[i][4]),ndigits)
xmoy_diff = round(abs(expected[i][5] - actual[i][5]),ndigits)
ymoy_diff = round(abs(expected[i][6] - actual[i][6]),ndigits)
# Calculate the absolute difference between expected and actual
x_diff, y_diff, z_diff, t_diff, r_diff, xmoy_diff, ymoy_diff = round(abs(expected[i][0] - actual[i][0]), ndigits), round(abs(expected[i][1] - actual[i][1]), ndigits), round(abs(expected[i][2] - actual[i][2]), ndigits), round(
abs(expected[i][3] - actual[i][3]), ndigits), round(abs(expected[i][4] - actual[i][4]), ndigits), round(abs(expected[i][5] - actual[i][5]), ndigits), round(abs(expected[i][6] - actual[i][6]), ndigits)
x += x_diff
y += y_diff
z += z_diff
t += t_diff
r += r_diff
xmoy += xmoy_diff
ymoy += ymoy_diff
# Add each difference to its respctive list
list_x_diffs.append(x_diff)
list_y_diffs.append(y_diff)
list_z_diffs.append(z_diff)
list_teta_diffs.append(t_diff)
list_radius_diffs.append(r_diff)
list_xmoy_diffs.append(xmoy_diff)
list_ymoy_diffs.append(ymoy_diff)
# Format the line
line = f"{str(i).rjust(4)}:\t X: {str(x_diff).rjust(8)}\t Y: {str(y_diff).rjust(8)}\t Z: {str(z_diff).rjust(8)}\t T: {str(t_diff).rjust(8)}\t R: {str(r_diff).rjust(8)}\t Xmoy: {str(xmoy_diff).rjust(8)}\t Ymoy: {str(ymoy_diff).rjust(8)}"
output_data += line + "\n"
# If the diff is greater than epsilon, add it to the minimal output file
if x_diff > eps:
minimal_output_data += f"{i} : X diff {x_diff}\n"
if y_diff > eps:
@ -102,26 +148,116 @@ def check_raw_data(expected_file, actual_file, ndigits=7,eps=0.00001) :
minimal_output_data += f"{i} : Xi-Xmoy diff {xmoy_diff}\n"
if ymoy_diff > eps:
minimal_output_data += f"{i} : Yi-Ymoy diff{ymoy_diff}\n"
# Save output to file
output.save_output_file(output_file, output_data)
output.save_output_file(minimal_output_file, minimal_output_data)
x = round(x/len(expected),ndigits)
y = round(y/len(expected),ndigits)
z = round(z/len(expected),ndigits)
t = round(t/len(expected),ndigits)
r = round(r/len(expected),ndigits)
xmoy = round(xmoy/len(expected),ndigits)
ymoy = round(ymoy/len(expected),ndigits)
# Print the output
if not silent:
sum_x_diff = round(sum(list_x_diffs)/len(expected), ndigits)
sum_y_diff = round(sum(list_y_diffs)/len(expected), ndigits)
sum_z_diff = round(sum(list_z_diffs)/len(expected), ndigits)
sum_teta_diff = round(sum(list_teta_diffs)/len(expected), ndigits)
sum_radius_diff = round(sum(list_radius_diffs)/len(expected), ndigits)
sum_xmoy_diff = round(sum(list_xmoy_diffs)/len(expected), ndigits)
sum_ymoy_diffs = round(sum(list_ymoy_diffs)/len(expected), ndigits)
print()
print("Analyse données brutes :")
print(f"diff moyenne de x : {sum_x_diff}")
print(f"diff moyenne de y : {sum_y_diff}")
print(f"diff moyenne de z : {sum_z_diff}")
print(f"diff moyenne de t : {sum_teta_diff}")
print(f"diff moyenne de r : {sum_radius_diff}")
print(f"diff moyenne de xmoy : {sum_xmoy_diff}")
print(f"diff moyenne de ymoy : {sum_ymoy_diffs}")
print(
f"diff gloabale des fichiers : {(sum_x_diff+sum_y_diff+sum_z_diff+sum_teta_diff+sum_radius_diff+sum_xmoy_diff+sum_ymoy_diffs)/7}")
print(f"Voir {output_file} pour plus de détails")
print(f"Voir {minimal_output_file} pour les différences significatives")
print("_"*80)
return {"x": list_x_diffs,
"y": list_y_diffs,
"z": list_z_diffs,
"teta": list_teta_diffs,
"radius": list_radius_diffs,
"xmoy": list_xmoy_diffs,
"ymoy": list_ymoy_diffs}
def check_consistency(obj: ScannedObject, discretised_file_path: str):
"""
This function takes a obj file, and checks if the discretised result file
respect what should be the correct discritisation
:param obj: The object to check
:param discretised_file_path: The discetised file output
"""
obj.export("verification.txt")
mean_list = []
moyx, moyy, moyz = parse_result_file(discretised_file_path)
moy = moyy
verticies = obj.get_vertices(sort=True)
position = 0
while position < len(verticies) and len(moy) > 0:
xi_value = verticies[position][0]
yi_value = verticies[position][1]
zi_value = verticies[position][2]
mean_list.append(yi_value)
mean = np.mean(mean_list)
print(f"searching for {moy[0]}, currently at {position}", end="\r")
if abs(mean - moy[0]) < 0.000001:
moy.pop(0)
mean_list = []
copyposition = position
if int(verticies[copyposition][2]) >= int(verticies[copyposition+1][2]):
while int(verticies[copyposition][2]) == int(verticies[copyposition-1][2]):
copyposition -= 1
# Position +1 pour l'allignement des indices avec le numero de ligne
# Position - copyposition + 1 car on se deplace seulement si, la condition est fasse aka, on bouge pas si on est aussi de la ou on doit etre
print("line position :", position+1, "|should have stoped :", position - copyposition + 1,
"position higher| Z difference :", verticies[position][2] - verticies[copyposition-1][2])
position += 1
def test_get_raw_data(obj: ScannedObject, expected_file: str, ndigits: int = 6, eps: float = 0.0001):
"""
Test the get_raw_data function, mesure how long it takes to run it then
checks if the values match with the exepected values
:param obj: the object to calculate the data from
:param expected_file: reference output to check data against
:param ndigits: The number of digits to keep after the comma
:param eps: the degree of precision we consider two values different
"""
# Calculate raw data and save it in a file
now = time.time()
data = get_raw_data(obj, ndigits)
print()
print("Analyse données brutes :")
print(f"diff moyenne de x : {x}")
print(f"diff moyenne de y : {y}")
print(f"diff moyenne de z : {z}")
print(f"diff moyenne de t : {t}")
print(f"diff moyenne de r : {r}")
print(f"diff moyenne de xmoy : {xmoy}")
print(f"diff moyenne de ymoy : {ymoy}")
print(f"diff gloabale des fichiers : {(x+y+z+t+r+xmoy+ymoy)/7}")
print(f"Voir {output_file} pour plus de détails")
print(f"Voir {minimal_output_file} pour les différences significatives")
print("_"*80)
print("Time to calculate raw data: ", time.time() - now)
output.save_output_file('tmp_analyse_brute.txt', output.format_data(data, '\t', [
"X (en mm)", "Y (en mm)", "Z (en mm)", "teta (en rad)", "rayon (en mm)", "Xi-Xmoy", "Yi-Ymoy"]))
check_raw_data(expected_file, 'tmp_analyse_brute.txt', ndigits, eps)
os.remove('tmp_analyse_brute.txt')
def test_get_discrete_data(obj: ScannedObject, expected_file: str, ndigits: int = 6, eps: float = 0.0001):
"""
Test the get_discrete_data function mesure how long it takes to run it then
checks if the values match with the exepected values
:param obj: the object to calculate the data from
:param expected_file: reference output to check data against
:param ndigits: The number of digits to keep after the comma
:param eps: the degree of precision we consider two values different
"""
# Calculate discrete data and save it in a file
now = time.time()
data = get_discrete_data(obj, ndigits)
print()
print("Time to calculate discrete data: ", time.time() - now)
output.save_output_file('tmp_analyse_discrete.txt', output.format_data(data, '\t', [
"X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)", "Rayon moyen (en mm)", "Rayon ecart type (en mm)"]))
check_discrete_data(
expected_file, 'tmp_analyse_discrete.txt', ndigits, eps)
os.remove('tmp_analyse_discrete.txt')

45
main.py
View File

@ -1,9 +1,8 @@
from utils.math import utils
from utils.math import data_extraction
from utils.files import output
from utils.files import parsers
from utils.files.file_data import Object
from utils.files.input import ScannedObject
def get_raw_data(obj:Object, ndigits:int)->dict:
def get_raw_data(obj:ScannedObject, ndigits:int)->dict:
"""
Calculates data from the given object
@ -23,18 +22,18 @@ def get_raw_data(obj:Object, ndigits:int)->dict:
for colone in colones:
data[colone] = []
for discrete_values in obj.get_discrete_vertices():
mean_x ,mean_y, mean_z = utils.get_x_y_z_mean(discrete_values)
mean_x ,mean_y, mean_z = data_extraction.get_x_y_z_mean(discrete_values)
for x,y,z in discrete_values:
data["X (en mm)"].append(round(x, ndigits))
data["Y (en mm)"].append(round(y, ndigits))
data["Z (en mm)"].append(round(z, ndigits))
data["teta (en rad)"].append(round(utils.get_teta_from_x_y(x,y,mean_x,mean_y), ndigits))
data["rayon (en mm)"].append(round(utils.get_radius_from_x_y(x,y,mean_x,mean_y), ndigits))
data["teta (en rad)"].append(round(data_extraction.get_teta_from_x_y(x,y,mean_x,mean_y), ndigits))
data["rayon (en mm)"].append(round(data_extraction.get_radius_from_x_y(x,y,mean_x,mean_y), ndigits))
data["Xi-Xmoy"].append(round(x-mean_x, ndigits))
data["Yi-Ymoy"].append(round(y-mean_y, ndigits))
return data
def get_discrete_data(obj:Object, ndigits:int)->dict:
def get_discrete_data(obj:ScannedObject, ndigits:int)->dict:
"""
Calculates data from the given object
@ -51,29 +50,43 @@ def get_discrete_data(obj:Object, ndigits:int)->dict:
data = {}
for colone in colones:
data[colone] = []
cpt = 0
for discrete_values in obj.get_discrete_vertices():
x,y,z = utils.get_x_y_z_mean(discrete_values)
x,y,z = data_extraction.get_x_y_z_mean(discrete_values)
data["X moy (en mm)"].append(round(x, ndigits))
data["Y moy (en mm)"].append(round(y, ndigits))
data["Z moy (en mm)"].append(round(z, ndigits))
data["Rayon moyen (en mm)"].append(round(utils.get_mean_radius(discrete_values), ndigits))
data["Rayon ecart type (en mm)"].append(round(utils.get_radius_std(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))
return data
def main():
# Create an object from the given file
obj = parsers.parse_xyz_file("test_cylindre.xyz",normalised='z')
obj = ScannedObject.from_xyz_file("test_cylindre.xyz",normalised='z')
# Calculate raw data and save it in a file
data = get_raw_data(obj, 6)
output.save_output_file('analyse_brute.txt', output.format_data(data, '\t', ["X (en mm)", "Y (en mm)", "Z (en mm)", "teta (en rad)", "rayon (en mm)","Xi-Xmoy","Yi-Ymoy"] ))
output.save_output_file('analyse_brute.txt',
output.format_data(data,
'\t',
["X (en mm)",
"Y (en mm)",
"Z (en mm)",
"teta (en rad)",
"rayon (en mm)",
"Xi-Xmoy",
"Yi-Ymoy"] ))
# Calculate discrete data and save it in a file
data = get_discrete_data(obj, 6)
output.save_output_file('analyse_rayon.txt', output.format_data(data, '\t', ["X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)","Rayon moyen (en mm)","Rayon ecart type (en mm)"] ))
output.save_output_file('analyse_rayon.txt',
output.format_data(data,
'\t',
["X moy (en mm)",
"Y moy (en mm)",
"Z moy (en mm)",
"Rayon moyen (en mm)",
"Rayon ecart type (en mm)"] ))
if __name__ == '__main__':
main()

View File

@ -1,53 +0,0 @@
from utils.files.parsers import parse_obj_file, parse_xyz_file
import numpy as np
def parse_result_file(file_path):
lines = []
x,y,z = [],[],[]
with open(file_path, "r") as f:
lines = f.readlines()[1:]
for line in lines:
line = line.replace(",", ".")
values = line.split("\t")
x.append(float(values[0]))
y.append(float(values[1]))
z.append(float(values[2]))
return x,y,z
def verifier_coherance():
obj = parse_obj_file("datasets/Barette/3 - BARETTE v1.obj",normalised='z')
obj.export("verification.txt")
#obj = parse_xyz_file("datasets/Barette/4 - BARETTE v1.xyz",normalised='')
cpt = 0
L = []
moyx, moyy, moyz = parse_result_file("datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt")
print(len(moyx),len(moyy),len(moyz))
moy = moyx
verticies = obj.get_vertices(sort=True)
position = 0
while position < len(verticies) and len(moy) > 0:
x = verticies[position][0]
y = verticies[position][1]
z = verticies[position][2]
L.append(x)
m = np.mean(L)
print(f"searching for {moy[0]}, currently at {position}",end="\r")
if abs(m - moy[0]) < 0.000001:
moy.pop(0)
L = []
copyposition = position
if int(verticies[copyposition][2]) >= int(verticies[copyposition+1][2]):
while int(verticies[copyposition][2]) == int(verticies[copyposition-1][2]):
copyposition -= 1
"""
if verticies[position][2] - verticies[copyposition][2] > 1:
copyposition = position + 1
break
"""
# Position +1 pour l'allignement des indices avec le numero de ligne
# Position - copyposition + 1 car on se deplace seulement si, la condition est fasse aka, on bouge pas si on est aussi de la ou on doit etre
print("index :",position,"|should have stoped :",position - copyposition + 1,"position higher| Z difference :",verticies[position][2] - verticies[copyposition-1][2])
position += 1
if __name__ == "__main__":
verifier_coherance()

72
test.py
View File

@ -1,69 +1,37 @@
import numpy as np
from main import get_raw_data, get_discrete_data
from utils.files.file_data import Object
from utils.files.output import save_output_file, format_data
from utils.files.parsers import parse_obj_file, parse_xyz_file
from utils.files.input import ScannedObject
from integration_tests import data_test
import time
import os
def test_get_raw_data(obj:Object, expected_file:str, ndigits:int = 6, eps:float = 0.0001):
"""
Test the get_raw_data function
"""
# Calculate raw data and save it in a file
now = time.time()
data = get_raw_data(obj, ndigits)
print()
print("Time to calculate raw data: ", time.time() - now)
save_output_file('tmp_analyse_brute.txt', format_data(data, '\t', ["X (en mm)", "Y (en mm)", "Z (en mm)", "teta (en rad)", "rayon (en mm)","Xi-Xmoy","Yi-Ymoy"] ))
data_test.check_raw_data(expected_file, 'tmp_analyse_brute.txt', ndigits, eps)
os.remove('tmp_analyse_brute.txt')
def test_get_discrete_data(obj: Object,expected_file:str, ndigits:int = 6, eps:float = 0.0001):
"""
Test the get_discrete_data function
"""
# Calculate discrete data and save it in a file
now = time.time()
data = get_discrete_data(obj, ndigits)
print()
print("Time to calculate discrete data: ", time.time() - now)
save_output_file('tmp_analyse_discrete.txt', format_data(data, '\t', ["X moy (en mm)", "Y moy (en mm)", "Z moy (en mm)","Rayon moyen (en mm)","Rayon ecart type (en mm)"] ))
data_test.check_discrete_data(expected_file, 'tmp_analyse_discrete.txt', ndigits, eps)
os.remove('tmp_analyse_discrete.txt')
def test():
def test_differences():
eps = 0.000001
obj = ScannedObject.from_xyz_file("datasets/Barette/4 - BARETTE v1.xyz",
"datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt", normalised='z')
#obj = parse_obj_file("datasets/Barette/3 - BARETTE v1.obj",normalised='z')
#obj = parse_xyz_file("datasets/Barette/4 - BARETTE v1.xyz",normalised='z')
obj = parse_xyz_file("datasets/Barette/4 - BARETTE v1.xyz","datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt",normalised='z')
data_test.test_get_raw_data(obj,
"datasets/Barette/BARETTE_Delta 1,0_analyse brute.txt",
eps=eps)
test_get_raw_data(obj,
"datasets/Barette/BARETTE_Delta 1,0_analyse brute.txt",
eps=eps)
test_get_discrete_data(obj,
"datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt",
eps=eps)
data_test.test_get_discrete_data(obj,
"datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt",
eps=eps)
def show_diff_between_obj_and_xyz():
obj1 = parse_obj_file("datasets/Barette/3 - BARETTE v1.obj",normalised='z')
obj2 = parse_xyz_file("datasets/Barette/4 - BARETTE v1.xyz",normalised='z')
def show_diff_two_obj():
obj1 = ScannedObject.from_obj_file(
"datasets/Barette/3 - BARETTE v1.obj", normalised='z')
obj2 = ScannedObject.from_xyz_file(
"datasets/Barette/4 - BARETTE v1.xyz", normalised='z')
obj2verts = obj2.get_vertices(sort=True)
for count, values in enumerate(obj1.get_vertices(sort=True)):
L = [abs(values[i] - obj2verts[count][i]) for i in range(len(values))]
print(*L,sep="\t")
print(*L, sep="\t")
def count_elements_in_discrete_array():
obj = parse_xyz_file("datasets/Barette/4 - BARETTE v1.xyz","datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt",normalised='z')
obj = ScannedObject.from_xyz_file("datasets/Barette/4 - BARETTE v1.xyz",
"datasets/Barette/BARETTE_Delta 1,0_analyse rayon.txt", normalised='z')
cpt = 0
for i in obj.bruteforce_discretization():
print(f"nb of element in z{cpt} to z{cpt+1}:",len(i))
print(f"nb of element in z{cpt} to z{cpt+1}:", len(i))
cpt += 1
if __name__ == "__main__":

View File

@ -1,166 +0,0 @@
"""
This module contains the File class.
"""
import numpy as np
class FaceNotGiven(Exception):
"""
Exception raised when no faces was given.
"""
def parse_result_file(file_path):
lines = []
x,y,z = [],[],[]
with open(file_path, "r") as f:
lines = f.readlines()[1:]
for line in lines:
line = line.replace(",", ".")
values = line.split("\t")
x.append(float(values[0]))
y.append(float(values[1]))
z.append(float(values[2]))
return x,y,z
class Object:
"""
This class is used to manage the data of the 3D object.
"""
def __init__(self, vertices, faces=None, result_file_path=None):
self.vertices = vertices
self.faces = faces
self.result_file_path = result_file_path
self.bruteforce_discretization_result = None
self.x = [vertex[0] for vertex in vertices]
self.y = [vertex[1] for vertex in vertices]
self.z = [vertex[2] for vertex in vertices]
def get_x(self)->list:
"""
Get the x coordinates of the object.
return: x coordinates
"""
return self.x
def get_y(self)->list:
"""
Get the y coordinates of the object.
return: y coordinates
"""
return self.y
def get_z(self)->list:
"""
Get the z coordinates of the object.
return: z coordinates
"""
return self.z
def get_vertices(self, sort:bool = False):
"""
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):
"""
Discretize the vertices of the object.
:param step: Step of the discretization
:return: Discretized vertices
"""
current_interval = int(min(self.get_z()))
splitted_data = [[]]
for line in self.get_vertices(sort=True):
# TODO check distance instead of equality
if line[2] >= current_interval + step:
splitted_data.append([])
current_interval += step
splitted_data[-1].append(line)
if splitted_data[0] == []:
splitted_data = splitted_data[1:]
return splitted_data
def get_discrete_vertices2(self, step:float = 1):
"""
fait un tour de boucle en plus
"""
cpt = 0
L = [[]]
for vertex in self.get_vertices(sort=True):
step = 1
L[-1].append(vertex)
if vertex[2] > cpt + step:
cpt += step
L.append([])
return L
def get_faces(self)->list:
"""
Get the faces of the object.
:return: faces
"""
if self.faces is None:
raise FaceNotGiven('No faces was given')
return self.faces
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}
def bruteforce_discretization(self):
"""
Discretize the object.
:param step: Step of the discretization
:return: Discretized object
"""
if self.bruteforce_discretization_result:
return self.bruteforce_discretization_result
if self.result_file_path is None:
raise Exception("No result file was given")
L = []
splitted_data = [[]]
moyx, moyy, moyz = parse_result_file(self.result_file_path)
moy = moyx
verticies = self.get_vertices(sort=True)
position = 0
while position < len(verticies):
print(position/len(verticies)*100,end="\r")
x = verticies[position][0]
y = verticies[position][1]
z = verticies[position][2]
L.append(x)
splitted_data[-1].append(verticies[position])
m = np.mean(L)
if len(moy) > 0 and abs(m - moy[0]) < 0.000001:
moy.pop(0)
L = []
splitted_data.append([])
copyposition = position
while int(verticies[copyposition][2]) == int(verticies[copyposition-1][2]):
copyposition -= 1
position += 1
print(50*" ")
self.bruteforce_discretization_result = splitted_data
return splitted_data
def export(self, file_path:str):
"""
Export the object in a file.
:param file_path: Path of the file
"""
with open(file_path, "w") as f:
cpt = 0
for vertex in self.get_vertices(sort=True):
x = round(vertex[0], 6)
y = round(vertex[1], 6)
z = round(vertex[2], 6)
#f.write(f"{x}\t{y}\t{z}\n")
f.write(f"{cpt}\n")
f.write(f"{x}\n{y}\n{z}\n")
f.write(f"{15*'-'}\n")

318
utils/files/input.py Normal file
View File

@ -0,0 +1,318 @@
"""
This module contains the functions to parse the input files, and create a ScannedObject.
"""
import numpy as np
from utils.files.output import save_output_file
class FacesNotGiven(Exception):
"""
Exception raised when no faces was given.
"""
class ResultFileNotGiven(Exception):
"""
Exception raised when no faces was given.
"""
class ScannedObject:
"""
This class is used to manage the data of the 3D object.
:param vertices: List of vertices
:param faces: List of faces
:param result_file_path: Path to the result file (deprecated, used for the bruteforce discretization)
:static method from_xyz_file(): Creates a ScannedObject from a .xyz file
:static method from_obj_file(): Creates a ScannedObject from a .obj file
:method get_x(): Returns the x values of the vertices
:method get_y(): Returns the y values of the vertices
:method get_z(): Returns the z values of the vertices
:method get_vertices(): Returns the vertices
:method get_faces(): Returns the faces
:method get_discrete_vertices(): Returns the discrete vertices
:method get_data(): Returns the data
:method export: Exports the data to a file
:raises FacesNotGiven: If no faces was given
:raises ResultFileNotGiven: If no result file was given
:Example:
>>> from utils.files.input import ScannedObject
>>> 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)]
>>> faces = [(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 = ScannedObject(vertices, faces)
>>> obj.get_x()
[0, 1, 1, 0, 0, 1, 1, 0]
>>> obj.get_y()
[0, 0, 1, 1, 0, 0, 1, 1]
>>> obj.get_z()
[0, 0, 0, 0, 1, 1, 1, 1]
>>> obj.get_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)]
>>> obj.get_faces()
[(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 = vertices
self.faces = faces
# Deprecated
self.result_file_path = result_file_path
self.bruteforce_discretization_result = None
#
self.x = [vertex[0] for vertex in vertices]
self.y = [vertex[1] for vertex in vertices]
self.z = [vertex[2] for vertex in vertices]
@staticmethod
def from_obj_file(file_path:str, result_file_path:str = None, ratio:float = 1,normalised:str = '')->'ScannedObject':
"""
Create an Object from an OBJ file.
:param file_path: Path to the OBJ file
:param result_file_path: Path to the result file
:param ratio: Ratio to apply to the vertices
:param normalised: the axis to normalise
:return: A ScannedObject
"""
with open(file_path, 'r') as f:
x, y, z = [], [], []
triangles = []
data = f.readlines()
for line in data :
if line.startswith('f'):
# Face indices start at 1, not 0
triangles.append([int(line.split()[1])-1, int(line.split()[2])-1, int(line.split()[3])-1])
elif line.startswith('v'):
x.append(float(line.split()[1]) * ratio)
y.append(float(line.split()[2]) * ratio)
z.append(float(line.split()[3]) * ratio)
if 'x' in normalised:
xmin = min(x)
for count, value in enumerate(x):
x[count] -= xmin
if 'y' in normalised:
ymin = min(y)
for count, value in enumerate(y):
y[count] -= ymin
if 'z' in normalised:
zmin = min(z)
for count, value in enumerate(z):
z[count] -= zmin
return ScannedObject(list(zip(x,y,z)), triangles, result_file_path)
@staticmethod
def from_xyz_file(file_path: str, result_file_path:str = None, delimiter: str = ' ',normalised:str = '')->'ScannedObject':
"""
Create an Object from an XYZ file.
:param file_path: Path to the XYZ file
:param result_file_path: Path to the result file
:param delimiter: The delimiter used in the xyz file.
:param normalised: the axis to normalise
:return: A ScannedObject
"""
x , y , z = [], [], []
with open(file_path, 'r') 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]))
if 'x' in normalised:
xmin = min(x)
for count, value in enumerate(x):
x[count] -= xmin
if 'y' in normalised:
ymin = min(y)
for count, value in enumerate(y):
y[count] -= ymin
if 'z' in normalised:
zmin = min(z)
for count, value in enumerate(z):
z[count] -= zmin
return ScannedObject(list(zip(x,y,z)), result_file_path=result_file_path)
def get_x(self)->list:
"""
Get the x coordinates of the object.
return: x coordinates
"""
return self.x
def get_y(self)->list:
"""
Get the y coordinates of the object.
return: y coordinates
"""
return self.y
def get_z(self)->list:
"""
Get the z coordinates of the object.
return: z coordinates
"""
return self.z
def get_vertices(self, sort:bool = False):
"""
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):
"""
Discretize the vertices of the object.
:param step: Step of the discretization
:return: Discretized vertices
"""
current_interval = int(min(self.get_z()))
splitted_data = [[]]
for line in self.get_vertices(sort=True):
# TODO check distance instead of equality
if line[2] >= current_interval + step:
splitted_data.append([])
current_interval += step
splitted_data[-1].append(line)
return splitted_data
def get_discrete_vertices2(self, step:float = 1):
"""
Deprecated
"""
cpt = 0
L = [[]]
for vertex in self.get_vertices(sort=True):
step = 1
L[-1].append(vertex)
if vertex[2] > cpt + step:
cpt += step
L.append([])
return L
def get_discrete_vertices3(self, step:float = 1):
"""
Deprecated
"""
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][2]
L.append([])
return L
def get_faces(self)->list:
"""
Get the faces of the object.
:return: faces
"""
if self.faces is None:
raise FacesNotGiven('No faces was given')
return self.faces
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}
def bruteforce_discretization(self):
"""
Deprecated
TODO Remove this when its not needed anymore
"""
if self.bruteforce_discretization_result:
return self.bruteforce_discretization_result
if self.result_file_path is None:
raise ResultFileNotGiven("No result file was given")
L = []
splitted_data = [[]]
moyx, moyy, moyz = parse_result_file(self.result_file_path)
moy = moyx
verticies = self.get_vertices(sort=True)
position = 0
while position < len(verticies):
print(position/len(verticies)*100,end="\r")
x = verticies[position][0]
y = verticies[position][1]
z = verticies[position][2]
L.append(x)
splitted_data[-1].append(verticies[position])
m = np.mean(L)
if len(moy) > 0 and abs(m - moy[0]) < 0.000001:
moy.pop(0)
L = []
splitted_data.append([])
copyposition = position
while int(verticies[copyposition][2]) == int(verticies[copyposition-1][2]):
copyposition -= 1
position += 1
print(50*" ")
self.bruteforce_discretization_result = splitted_data
return splitted_data
def export(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
"""
string = ''
with open(file_path, "w") as f:
for vertex in self.get_vertices(sort=True):
x = round(vertex[0], 6)
y = round(vertex[1], 6)
z = round(vertex[2], 6)
string+=f"{x}{separator}{y}{separator}{z}\n"
save_output_file(file_path,string)
def parse_result_file(file_path: str, separator: str = "\t")-> tuple:
"""
This functions parses the discretised output file to retreive the first
three colunms. It is used to extract the means of x y z for the consistency
check and the bruteforce_discretisation
:param file_path: Path of the file
:param separator: chars used to separate the values
:return: x, y, z
:Example:
>>> parse_result_file("test.txt")
([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [1.0, 2.0, 3.0])
"""
lines = []
x, y, z = [], [], []
with open(file_path, "r") as f:
lines = f.readlines()[1:]
for line in lines:
line = line.replace(",", ".")
values = line.split(separator)
x.append(float(values[0]))
y.append(float(values[1]))
z.append(float(values[2]))
return x, y, z

View File

@ -1,3 +1,7 @@
"""
Deprecated
"""
def denormalizeXYZ(filePath:str, output:str):
"""
Denormalize an XYZ file

View File

@ -10,6 +10,19 @@ def format_data(data:dict, separator:str, selected_columns:list = None) -> str:
:param selected_columns: Columns to be saved
:param separator: Separator of the columns
:return: Formatted data
Example:
>>> data = {
... 'col1': [1, 2, 3],
... 'col2': [4, 5, 6],
... 'col3': [7, 8, 9]
... }
>>> format_data(data, separator=';')
'col1;col2;col3
1 ;4 ;7
2 ;5 ;8
3 ;6 ;9
'
"""
output = ''
if selected_columns is None:

View File

@ -1,75 +0,0 @@
"""
This module contains functions to parse files.
"""
from utils.files.file_data import Object
def parse_obj_file(file_path:str, result_file_path:str = None, ratio:float = 1,normalised:str = '')->Object:
"""
Parse an OBJ file and return a dict with the vertices and faces
:param filePath: Path to the OBJ file
:param ratio: Ratio to apply to the vertices
:param cornered: If True, the vertices will be cornered
:return: A dict with the vertices and faces
"""
with open(file_path, 'r') as f:
x, y, z = [], [], []
triangles = []
data = f.readlines()
for line in data :
if line.startswith('f'):
# Face indices start at 1, not 0
triangles.append([int(line.split()[1])-1, int(line.split()[2])-1, int(line.split()[3])-1])
elif line.startswith('v'):
x.append(float(line.split()[1]) * ratio)
y.append(float(line.split()[2]) * ratio)
z.append(float(line.split()[3]) * ratio)
if 'x' in normalised:
xmin = min(x)
for count, value in enumerate(x):
x[count] -= xmin
if 'y' in normalised:
ymin = min(y)
for count, value in enumerate(y):
y[count] -= ymin
if 'z' in normalised:
zmin = min(z)
for count, value in enumerate(z):
z[count] -= zmin
return Object(list(zip(x,y,z)), triangles, result_file_path)
def parse_xyz_file(file_path: str, result_file_path:str = None, delimiter: str = ' ',normalised:str = '') -> Object:
"""
Parses an xyz file and returns a dict containing the coordinates.
:param file: The xyz file to be parsed.
:param delimiter: The delimiter used in the xyz file.
:return: A dictionary containing the coordinates.
"""
x , y , z = [], [], []
with open(file_path, 'r') 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]))
if 'x' in normalised:
xmin = min(x)
for count, value in enumerate(x):
x[count] -= xmin
if 'y' in normalised:
ymin = min(y)
for count, value in enumerate(y):
y[count] -= ymin
if 'z' in normalised:
zmin = min(z)
for count, value in enumerate(z):
z[count] -= zmin
return Object(list(zip(x,y,z)), result_file_path=result_file_path)

11
utils/graph2D/plots.py Normal file
View File

@ -0,0 +1,11 @@
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()
ax = fig.add_subplot()
ax.plot(values)
plt.show()

View File

@ -7,6 +7,13 @@ import math
def get_mean(values:list):
"""
Get the mean of the values.
:param values: values
:return: mean of the values
:Example:
>>> get_mean([1,2,3,4,5])
3.0
"""
return np.mean(values)
@ -16,6 +23,10 @@ def get_standard_deviation(values:list):
:param values: values
:return: standard deviation of the values
:Example:
>>> get_standard_deviation([1,2,3,4,5])
1.4142135623730951
"""
return np.std(values)
@ -26,6 +37,10 @@ def get_x_y_z_mean(discrete_values:list):
:param x: x coordinates
:param y: y coordinates
:return: mean of x and y coordinates in the discrete range
:Example:
>>> get_x_y_z_mean([(1,2,3),(4,5,6),(7,8,9)])
(4.0, 5.0, 6.0)
"""
x = [vertex[0] for vertex in discrete_values]
y = [vertex[1] for vertex in discrete_values]
@ -41,6 +56,10 @@ def get_radius_from_x_y(xi:float, yi:float, x_mean:float, y_mean:float):
:param x_mean: mean of x coordinates in the discrete range
:param y_mean: mean of y coordinates in the discrete range
:return: radius for this point
:Example:
>>> get_radius_from_x_y(1,2,3,4)
2.8284271247461903
"""
return np.sqrt(np.power((xi - x_mean), 2) + np.power((yi - y_mean), 2))
@ -50,6 +69,10 @@ def get_mean_radius(discrete_values:list):
:param discrete_values: discrete values
:return: mean of the radius in the discrete range
:Example:
>>> get_mean_radius([(1,2,3),(4,5,6),(7,8,9)])
2.82842712474619
"""
x_mean, y_mean, z_mean = get_x_y_z_mean(discrete_values)
radius = []
@ -63,6 +86,10 @@ def get_radius_std(discrete_values:list):
:param discrete_values: discrete values
:return: standard deviation of the radius in the discrete range
:Example:
>>> get_radius_std([(1,2,3),(4,5,6),(7,8,9)])
2.8284271247461903
"""
x_mean, y_mean, z_mean = get_x_y_z_mean(discrete_values)
radius = []
@ -76,6 +103,10 @@ def get_mean_teta(discrete_values:list):
:param discrete_values: discrete values
:return: mean of the teta in the discrete range
:Example:
>>> get_mean_teta([(1,2,3),(4,5,6),(7,8,9)])
0.7853981633974483
"""
x_mean, y_mean, z_mean = get_x_y_z_mean(discrete_values)
teta = []
@ -92,5 +123,14 @@ def get_teta_from_x_y(xi:float, yi:float, x_mean:float, y_mean:float):
:param x_mean: mean of x coordinates in the discrete range
:param y_mean: mean of y coordinates in the discrete range
:return: teta for this point
:Example:
>>> get_teta_from_x_y(1,2,3,4)
0.7853981633974483
"""
return math.atan((xi - x_mean)/(yi - y_mean))
return math.atan((xi - x_mean)/(yi - y_mean))
#todo fix examples
if __name__ == "__main__":
import doctest
doctest.testmod()