diff --git a/integration_tests/data_test.py b/integration_tests/data_test.py
index ef2889d362a8d9a2cc0d736c2c7677989a737c8d..0e3db873d53cf9943a8d3b4b1aae5eb4759d7f7b 100644
--- a/integration_tests/data_test.py
+++ b/integration_tests/data_test.py
@@ -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)
-
-        x += x_diff
-        y += y_diff
-        z += z_diff
-        r += r_diff
-        std += 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)}"
+    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)
+
+        # 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)
+
+        # 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)
-
-def check_raw_data(expected_file, actual_file, ndigits=7,eps=0.00001) :
+    # 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, 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)
-
-        x += x_diff
-        y += y_diff
-        z += z_diff     
-        t += t_diff
-        r += r_diff
-        xmoy += xmoy_diff
-        ymoy += ymoy_diff
+        # 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)
+
+        # 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("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("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 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')
diff --git a/main.py b/main.py
index 37eb7b1914aad01a38c6d0e993ac873c8d63b7f7..3eec56a1bc3b74cc86bba793908ee097cb1f94c8 100644
--- a/main.py
+++ b/main.py
@@ -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()
\ No newline at end of file
diff --git a/outputchecker.py b/outputchecker.py
deleted file mode 100644
index 717819bb87776dd01faede50c15c34f3168bd371..0000000000000000000000000000000000000000
--- a/outputchecker.py
+++ /dev/null
@@ -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()
\ No newline at end of file
diff --git a/test.py b/test.py
index ec276e376decc98178e7ad0fccc209bf6787f46f..2eac71a56c113f7177182a9973cf566ae0a9aba3 100644
--- a/test.py
+++ b/test.py
@@ -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')
+
+    data_test.test_get_raw_data(obj,
+                                "datasets/Barette/BARETTE_Delta 1,0_analyse brute.txt",
+                                eps=eps)
 
-    #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_discrete_data(obj,
+                                     "datasets/Barette/BARETTE_Delta 1,0_analyse rayon.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)
 
-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__":
diff --git a/utils/files/file_data.py b/utils/files/file_data.py
deleted file mode 100644
index 087effa45607527f3d4ddaf9e3d16603e80c75f7..0000000000000000000000000000000000000000
--- a/utils/files/file_data.py
+++ /dev/null
@@ -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")
-            
\ No newline at end of file
diff --git a/utils/files/input.py b/utils/files/input.py
new file mode 100644
index 0000000000000000000000000000000000000000..0da7d3759c172c8ca6ed25f71421b8acc8deaa0b
--- /dev/null
+++ b/utils/files/input.py
@@ -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
diff --git a/utils/files/norm.py b/utils/files/norm.py
index e4531d1834a9398e35de9b23972c324a8d4c1c23..61c1d615099610a76928f23af4ccc357d03b7236 100644
--- a/utils/files/norm.py
+++ b/utils/files/norm.py
@@ -1,3 +1,7 @@
+"""
+Deprecated
+"""
+
 def denormalizeXYZ(filePath:str, output:str):
     """
     Denormalize an XYZ file
diff --git a/utils/files/output.py b/utils/files/output.py
index 185cc3aabb417b196ace8bbf2dbb453874ec69ef..3eca9abca6b4a4369bd4aca75c198f6a4b7dfc1e 100644
--- a/utils/files/output.py
+++ b/utils/files/output.py
@@ -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:
diff --git a/utils/files/parsers.py b/utils/files/parsers.py
deleted file mode 100644
index 8633ebb1b69ef3306554272f1489ab514594deb7..0000000000000000000000000000000000000000
--- a/utils/files/parsers.py
+++ /dev/null
@@ -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)
\ No newline at end of file
diff --git a/utils/graph2D/plots.py b/utils/graph2D/plots.py
new file mode 100644
index 0000000000000000000000000000000000000000..be38083482b48ce714174a23a1ad771180fbaf07
--- /dev/null
+++ b/utils/graph2D/plots.py
@@ -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()
\ No newline at end of file
diff --git a/utils/math/utils.py b/utils/math/data_extraction.py
similarity index 77%
rename from utils/math/utils.py
rename to utils/math/data_extraction.py
index e30a74d5f93fbb80e75980afc31c177e98f9bdf1..4e82b7db5b846b4816793e681fca44645c69ff85 100644
--- a/utils/math/utils.py
+++ b/utils/math/data_extraction.py
@@ -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))
\ No newline at end of file
+    return math.atan((xi - x_mean)/(yi - y_mean))
+
+#todo fix examples
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()
\ No newline at end of file