Source code for Py3DViewer.utils.IO

import numpy as np
from .ObservableArray import *
import copy


[docs]def read_mesh(filename): """ Imports the data from the given .mesh file Parameters: filename (string): The name of the .mesh file Return: (Array, Array, Array): The mesh vertices, the mesh simplices and the mesh labels """ assert filename.split(".")[-1] == "mesh" # Maybe throw exception? with open(filename) as f: reading_vertices = False tmp_vtx = [] tmp_polygons = [] tmp_polyhedra = [] tmp_labels_polygons = [] tmp_labels_polyhedra = [] num_vtx = 0 num_simplices = 0 line = f.readline() while line != "" and "Vertices" not in line: line = f.readline() assert line != "" num_vtx = int(f.readline()) for i in range(num_vtx): line = f.readline() x, y, z = list(map(lambda x: float(x), line.split()[:-1])) tmp_vtx += [(x, y, z)] line = f.readline() while line != "": while "Tetrahedra" not in line and "Hexahedra" not in line and "Quadrilaterals" not in line and "Triangles" not in line and line != "": line = f.readline() if(line == ""): continue num_simplices = int(f.readline()) if "Tetrahedra" in line: for i in range(num_simplices): line = f.readline() a, b, c, d = list(map(lambda x: int(x) - 1, line.split()[:-1])) label = float(line.split()[-1]) tmp_polyhedra += [(a, b, c, d)] tmp_labels_polyhedra += [label] elif "Hexahedra" in line: for i in range(num_simplices): line = f.readline() a, b, c, d, e, f_, g, h = list(map(lambda x: int(x) - 1, line.split()[:-1])) label = float(line.split()[-1]) tmp_polyhedra += [(a, b, c, d, e, f_, g, h)] tmp_labels_polyhedra += [label] elif "Quadrilaterals" in line: for i in range(num_simplices): line = f.readline() a, b, c, d = list(map(lambda x: int(x) - 1, line.split()[:-1])) label = float(line.split()[-1]) tmp_polygons += [(a, b, c, d)] tmp_labels_polygons += [label] elif "Triangles" in line: for i in range(num_simplices): line = f.readline() a, b, c = list(map(lambda x: int(x) - 1, line.split()[:-1])) label = float(line.split()[-1]) tmp_polygons += [(a, b, c)] tmp_labels_polygons += [label] else: assert False, "File is not valid." tmp_vtx = np.array(tmp_vtx) tmp_simplices = tmp_polyhedra if len(tmp_polyhedra) > 0 else tmp_polygons tmp_simplices = np.array(tmp_simplices) tmp_labels = tmp_labels_polyhedra if len(tmp_labels_polyhedra) > 0 else tmp_labels_polygons tmp_labels = np.array(tmp_labels, dtype=np.int64) vtx = ObservableArray(tmp_vtx.shape) vtx[:] = tmp_vtx simplices = ObservableArray(tmp_simplices.shape, dtype=np.int64) simplices[:] = tmp_simplices labels = ObservableArray(tmp_labels.shape, dtype=np.int64) labels[:] = tmp_labels return vtx, simplices, labels
[docs]def save_mesh(mesh, filename): """ Writes the data from the given mesh object to a .mesh file Parameters : mesh (Tetmesh / Hexmesh): The mesh to serialize to the file filename (string): The name of the .mesh file """ with open(filename, 'w') as f: f.write('MeshVersionFormatted 1\nDimension 3\n') f.write('Vertices\n') f.write(f'{mesh.num_vertices}\n') for v in np.asarray(mesh.vertices): f.write(f'{float(v[0])} {float(v[1])} {float(v[2])} 0\n') if mesh.mesh_is_volumetric: if mesh.polys.shape[1] == 4: f.write('Tetrahedra\n') f.write(f'{mesh.num_polys}\n') for idx, t in enumerate(np.asarray(mesh.polys)): f.write(f'{int(t[0]) + 1} {t[1] + 1} {int(t[2]) + 1} {int(t[3]) + 1} {np.asarray(mesh.labels)[idx]}\n') else: f.write('Hexahedra\n') f.write(f'{mesh.num_polys}\n') for idx, h in enumerate(np.asarray(mesh.polys)): f.write( f'{int(h[0]) + 1} {int(h[1]) + 1} {int(h[2]) + 1} {int(h[3]) + 1} {int(h[4]) + 1} {int(h[5]) + 1} {int(h[6]) + 1} {int(h[7]) + 1} {np.asarray(mesh.labels)[idx]}\n') else: if mesh.polys.shape[1] == 4: f.write('Quadrilaterals\n') f.write(f'{mesh.num_polys}\n') for idx, t in enumerate(np.asarray(mesh.polys)): f.write(f'{int(t[0]) + 1} {t[1] + 1} {int(t[2]) + 1} {int(t[3]) + 1} {np.asarray(mesh.labels)[idx]}\n') else: f.write('Trianglese\n') f.write(f'{mesh.num_polys}\n') for idx, h in enumerate(np.asarray(mesh.polys)): f.write( f'{int(h[0]) + 1} {int(h[1]) + 1} {int(h[2]) + 1} {np.asarray(mesh.labels)[idx]}\n') f.write('End')
[docs]def read_mtl(filename): with open(filename) as f: material_aux = { "kd": [], "ks": [], "ke": 1, "ns": 0.0, "transparence": False, "opacity": 0.0, "map_kd": None, "map_ke": None, "map_d": None, "map_ks": None, "bump": None, "norm": None, "illum": 0.0, "ni": 0.98 } material_queue = {} s = "" flag = False for line in f.readlines(): if line[0:6] == 'newmtl': # The first time in this branch we don't want to copy the material aux because it's empty if flag: material_queue[s] = copy.copy(material_aux) flag = True s = line.split()[1] aux = line.split() if line[0:2] == 'Kd': material_aux["kd"] = [float(aux[1]), float(aux[2]), float(aux[3])] if line[0:2] == 'Ks': material_aux["ks"] = [float(aux[1]), float(aux[2]), float(aux[3])] if line[0:2] == 'Ke': material_aux["ke"] = float(aux[1]) if line[0:2] == 'Ns': material_aux["ns"] = float(aux[1]) if line[0:5] == 'illum': material_aux["illum"] = float(aux[1]) if line[0] == 'd': material_aux['transparence'] = True material_aux["opacity"] = float(aux[1]) if line[0:2] == 'tr': material_aux['transparence'] = True material_aux["opacity"] = 1 - float(aux[1]) if line[0:6] == 'map_Kd': texture = line.split()[1] material_aux["map_kd"] = texture if line[0:6] == 'map_Ke': texture = line.split()[1] material_aux["map_ke"] = texture if line[0:6] == 'map_d': texture = line.split()[1] material_aux["map_d"] = texture if line[0:6] == 'map_Ks': texture = line.split()[1] material_aux["map_ks"] = texture if line[0:4] == 'bump' or line[0:8] == 'map_Bump': texture = line.split()[1] material_aux["bump"] = texture if line[0:4] == 'norm': texture = line.split()[1] material_aux["norm"] = texture if line[0:4] == 'Ni': texture = line.split()[1] material_aux["ni"] = texture # This represents the last material material_queue[s] = copy.copy(material_aux) return material_queue
[docs]def read_obj(filename): """ Imports the data from the given .obj file Parameters: filename (string): The name of the .obj file Return: (Array, Array, Array): The mesh vertices, the mesh simplices and the mesh labels""" with open(filename) as f: tmp_vtx = [] tmp_faces = [] tmp_normals = [] tmp_uvcoords = [] tmp_coor = [] coor_row = [] groups = {} normals_row = [] tmp_polytex = [] tmp_polypos = [] cont = 0 s = "" sgroup = False for line in f.readlines(): if line[0:6] == 'usemtl': if sgroup: groups[s] = copy.copy(cont) s = line.split()[1] sgroup = True if line[0:2] == 'v ': if (line[0:2]): vtx = line.split() tmp_vtx.append([float(vtx[1]), float(vtx[2]), float(vtx[3])]) # The slashes after the split up here are temporary, we need to improve this parser if line[0:2] == 'vt': uvcoords = line.split() if (len(uvcoords) == 3): tmp_uvcoords.append([float(uvcoords[1]), float(uvcoords[2]), 0]) else: tmp_uvcoords.append([float(uvcoords[1]), float(uvcoords[2]), float(uvcoords[3])]) if line[0:2] == 'vn': if (line[0:2]): normals = line.split() tmp_normals.append([float(normals[1]), float(normals[2]), float(normals[3])]) if line[0:2] == 'f ': # count is cont = cont + 1 faces = line.split() format = len(faces[1].split("/")) faces = faces[1:] tmp_faces.append([int(f.split("/")[0]) - 1 for f in faces]) if format == 2: # v/vt for c in faces: coor_row.append(int(c.split("/")[1])) tmp_coor.append(coor_row) coor_row = [] elif format == 3: # v/vt/vn for c in faces: coor_row.append(int(c.split("/")[1])) normals_row.append((int(c.split("/")[2]))) tmp_coor.append(coor_row) tmp_normals.append(normals_row) coor_row = [] normals_row = [] groups[s] = copy.copy(cont) tmp_vtx = np.array(tmp_vtx) tmp_faces = np.array(tmp_faces) tmp_normals = np.array(tmp_normals, dtype=object) # Uv coords tmp_uvcoords = np.array(tmp_uvcoords) # Correspondences between uv coords and faces tmp_coor = np.array(tmp_coor) vtx = ObservableArray(tmp_vtx.shape) vtx[:] = tmp_vtx faces = ObservableArray(tmp_faces.shape, dtype=np.int64) faces[:] = tmp_faces normals = ObservableArray(tmp_normals.shape) normals[:] = normals uvcoords = ObservableArray(tmp_uvcoords.shape) uvcoords[:] = tmp_uvcoords coor = ObservableArray(tmp_coor.shape, dtype=np.int64) coor[:] = tmp_coor return vtx, faces, normals, uvcoords, coor, groups
[docs]def save_obj(mesh, filename): """ Writes the data from the given mesh object to a .obj file Parameters : mesh (Trimesh / Quadmesh): The mesh to serialize to the file filename (string): the name of the .obj file """ with open(filename, 'w') as f: for vtx in mesh.vertices: f.write(f"v {float(vtx[0])} {float(vtx[1])} {float(vtx[2])}\n") for face in mesh.polys: if 'Trimesh' in str(type(mesh)): f.write(f"f {int(face[0]) + 1} {int(face[1]) + 1} {int(face[2]) + 1}\n") if 'Quadmesh' in str(type(mesh)): f.write(f"f {int(face[0]) + 1} {int(face[1]) + 1} {int(face[2]) + 1} {int(face[3]) + 1}\n")
[docs]def read_skeleton(filename): """ Imports the data from the given .skel file Parameters: filename (string): The name of the .skel file Return: (Array, Array, Array): The skeleton joints, the joints radius and the skeleton bones """ with open(filename) as file: joint_list = [] bones = [] radius = [] for line in file.readlines(): try: splitted_line = line.split() idx = int(splitted_line[0]) x = float(splitted_line[1]) y = float(splitted_line[2]) z = float(splitted_line[3]) rad = float(splitted_line[4]) num_neighbors = int(splitted_line[5]) joint_list.append([x, y, z]) radius.append(rad) for i in range(num_neighbors): neighbor = int(splitted_line[6 + i]) bones.append([idx, neighbor]) except Exception: continue return np.array(joint_list), np.array(radius), np.array(bones, dtype=np.int64)
[docs]def read_off(filename): with open(filename) as file: vtx_list = [] face_list = [] edge_list = [] num_vertices = 0 num_faces = 0 num_edges = 0 lines = file.readlines() idx = 0 for line in lines: idx += 1 if line[0] == '#': continue if len(line.split()) == 3: head = line.split() num_vertices = int(head[0]) num_faces = int(head[1]) num_edges = int(head[2]) break for line in lines[idx:idx + num_vertices]: vtx = line.split() vtx_list += [[float(vtx[0]), float(vtx[1]), float(vtx[2])]] if num_faces > 0: for line in lines[idx + num_vertices:]: face = line.split() face_list += [[int(f) for f in face[1:int(face[0]) + 1]]] vtx_list = np.array(vtx_list) face_list = np.array(face_list) vtx = ObservableArray(vtx_list.shape) vtx[:] = vtx_list faces = ObservableArray(face_list.shape, dtype=np.int64) faces[:] = face_list return vtx, faces
[docs]def save_off(mesh, filename): with open(filename, 'w') as f: f.write('OFF\n') f.write('#Created with Py3DViewer\n\n') f.write(f'{mesh.num_vertices} {mesh.num_polys} 0\n') for vtx in mesh.vertices: f.write(f'{float(vtx[0])} {float(vtx[1])} {float(vtx[2])}\n') for face in mesh.polys: if face.size == 3: f.write(f'3 {int(face[0])} {int(face[1])} {int(face[2])}\n') elif face.size == 4: f.write(f'4 {int(face[0])} {int(face[1])} {int(face[2])} {int(face[3])}\n')