def create_box(f): mesh = lib_msh.Mesh(f) cube = lib_msh.Mesh(cube=[mesh.xmin, mesh.xmax, mesh.ymin, mesh.ymax, mesh.zmin, mesh.zmax]) cube.verts[:,:3] -= mesh.center cube.verts[:,:3] *= 1.25 cube.verts[:,:3] += mesh.center cube.write("box.mesh") lib_exe.execute( lib_exe.tetgen + "-pgANEF box.mesh > /dev/null 2>&1" ) hausd = 0.02 * np.max(mesh.dims) lib_exe.execute( lib_exe.mmg3d + "box.1.mesh -hausd %f -hmax %f > /dev/null 2>&1" % (hausd, hausd) )
def adapt_box_to(f, box, maxNb=20000): shutil.copyfile(box,"box.mesh") cube = lib_msh.Mesh("box.mesh") mesh = lib_msh.Mesh(f) step = 1 if len(mesh.verts)<maxNb else int(len(mesh.verts)/maxNb)+1 dists, _ = nearest_neighbor(cube.verts[:,:3], mesh.verts[::step,:3]) cube.scalars = np.array(dists) ABS = np.absolute(cube.scalars) mini, maxi = 0.005*np.max(cube.dims), 0.5*np.max(cube.dims) cube.scalars = mini + (maxi-mini) * (ABS - np.min(ABS)) / (np.max(ABS) - np.min(ABS)) cube.write("box.1.mesh") cube.writeSol("box.1.sol") lib_exe.execute(lib_exe.mmg3d + "box.1.mesh -hgrad 1.5 > /dev/null 2>&1")
def import_mesh(filepath): MESH = lib_msh.Mesh(filepath) if os.path.exists(filepath[:-5] + ".sol"): MESH.readSol() MESH.tets = lib_msh.np.array([]) MESH.discardUnused() meshes = [] rTris = MESH.tris[:, -1].tolist() if len(MESH.tris) > 0 else [] rQuads = MESH.quads[:, -1].tolist() if len(MESH.quads) > 0 else [] tris = [t.tolist() for t in MESH.tris] quads = [q.tolist() for q in MESH.quads] verts = [v.tolist()[:-1] for v in MESH.verts] REFS = set(rTris + rQuads) for i, r in enumerate(REFS): refFaces = [t[:-1] for t in tris + quads if t[-1] == r] mesh_name = bpy.path.display_name_from_filepath(filepath) mesh = bpy.data.meshes.new(name=mesh_name) meshes.append(mesh) mesh.from_pydata(verts, [], refFaces) mesh.validate() mesh.update() scene = bpy.context.scene objects = [] for i, m in enumerate(meshes): obj = bpy.data.objects.new(m.name, m) bpy.ops.object.select_all(action='DESELECT') scene.objects.link(obj) scene.objects.active = obj objects.append(obj) del meshes scene.update() bpy.ops.object.select_all(action='DESELECT') for o in objects: o.select = True bpy.ops.object.join() bpy.ops.object.editmode_toggle() bpy.ops.mesh.remove_doubles() bpy.ops.object.editmode_toggle()
def to_mesh(f, output): #Convert a stl to mesh with meshlabserver meshlabScript = os.path.join(os.path.dirname(os.path.abspath(__file__)), "meshlab_scripts", "cleanSTL.mlx") tmp = f.replace(".stl", ".obj") lib_exe.execute(lib_exe.meshlabserver + "-i %s -o %s -s %s > /dev/null 2>&1" % (f, tmp, meshlabScript)) f = tmp #Convert a .obj to .mesh with open(f, "r") as _f: LINES = _f.readlines() mesh = lib_msh.Mesh() mesh.verts = np.array([[float(x) for x in l.split()[1:]] for l in LINES if l[0] == "v"]) mesh.tris = np.array([[int(x) - 1 for x in l.split()[1:]] for l in LINES if l[0] == "f"]) mesh.verts = np.insert(mesh.verts, 3, 0, axis=1) mesh.tris = np.insert(mesh.tris, 3, 0, axis=1) mesh.computeBBox() mesh.write(output)
def export_mesh(filepath): #Get the selected object APPLY_MODIFIERS = True scene = bpy.context.scene bpy.ops.object.duplicate() obj = scene.objects.active bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_face_by_sides(number=4, type='GREATER') bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY') bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_face_by_sides(number=3, type='GREATER') bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY') bpy.ops.object.editmode_toggle() mesh = obj.to_mesh(scene, APPLY_MODIFIERS, 'PREVIEW') mesh.transform(obj.matrix_world) #Get the info verts = [[v.co[0], v.co[1], v.co[2], 0] for v in mesh.vertices[:]] triangles = [[v for v in f.vertices] + [f.material_index + 1] for f in mesh.polygons if len(f.vertices) == 3] quads = [[v for v in f.vertices] + [f.material_index + 1] for f in mesh.polygons if len(f.vertices) == 4] edges = [[e.vertices[0], e.vertices[1], 0] for e in mesh.edges if e.use_edge_sharp] exportMesh = lib_msh.Mesh() exportMesh.verts = lib_msh.np.array(verts) exportMesh.tris = lib_msh.np.array(triangles) exportMesh.quads = lib_msh.np.array(quads) exportMesh.edges = lib_msh.np.array(edges) exportMesh.write(filepath)
import os import argparse import lib_msh if __name__ == "__main__": #arguments parser = argparse.ArgumentParser( description="Merges multiple .mesh together") parser.add_argument("-i", "--input", type=str, nargs="+", help="Input .mesh files", required=True) parser.add_argument("-o", "--output", type=str, help="Output .mesh file", required=True) args = parser.parse_args() original = lib_msh.Mesh(args.input[0]) for other in args.input[1:]: original.fondre(lib_msh.Mesh(other)) original.write(args.output)
lib_exe.python_cmd("carve.py") + "-i %s -o %s -r %d" % (IN, OUT, 31)) if args.medit: lib_exe.execute(lib_exe.medit + "%s" % (OUT)) os.remove(OUT) # 2 - convert .obj and .stl objects to .mesh print("Testing convert.py") IN1 = os.path.join(args.directory, "buddha.obj") OUT1 = os.path.join(args.directory, "buddha1.mesh") lib_exe.execute( lib_exe.python_cmd("convert.py") + "-i %s -o %s" % (IN1, OUT1)) IN2 = os.path.join(args.directory, "buddha.stl") OUT2 = os.path.join(args.directory, "buddha2.mesh") lib_exe.execute( lib_exe.python_cmd("convert.py") + "-i %s -o %s" % (IN2, OUT2)) if args.medit: lib_exe.execute(lib_exe.medit + "%s %s" % (OUT1, OUT2)) buddha1 = lib_msh.Mesh(OUT1) buddha2 = lib_msh.Mesh(OUT2) #print(len(buddha1.verts), len(buddha2.verts)) #assert( len(buddha1.verts) == len(buddha2.verts) ) assert (buddha1.verts[0][1] == buddha2.verts[0][1]) assert (buddha1.tris[10][2] == buddha2.tris[10][2]) os.remove(OUT1) os.remove(OUT2) # 3 - compute the distance between two meshes print("Testing distance.py") IN1 = os.path.join(args.directory, "buddha.mesh") IN2 = os.path.join(args.directory, "buddha.displaced.mesh") OUT = os.path.join(args.directory, "buddha.distance.mesh") lib_exe.execute( lib_exe.python_cmd("distance.py") + "-i1 %s -i2 %s -o %s" %
args.template = os.path.abspath(args.template) if args.template else None args.input = os.path.abspath(args.input) args.output = os.path.abspath(args.output) #Copy the template to warp shutil.copyfile(args.template, "sphere.mesh") #Warp lib_exe.execute(lib_paths.wrapping + " %s -p -nit %d -load %f > /dev/null 2>&1" % (args.input, 150, 40) ) #Clean the mesh and extract the surface final = None try: number_max=-1 for f in [x for x in os.listdir(".") if "sphere.d." in x and ".mesh" in x]: number = int(f.split(".")[2]) if number>number_max: final = f except: final = "sphere.d.mesh" warped = lib_msh.Mesh(final) warped.tris = warped.tris[warped.tris[:,-1] != 2] warped.tets = np.array([]) warped.discardUnused() warped.write(args.output) #Remove the unused files #os.remove("sphere.mesh") #os.remove("sphere.d.mesh")
print(args.source + " is not a valid file") sys.exit() if not os.path.splitext(args.source)[1] == ".mesh": print(args.source + " is not a .mesh file") sys.exit() if not os.path.isfile(args.target): print(args.target + " is not a valid file") sys.exit() if not os.path.splitext(args.target)[1] == ".mesh": print(args.target + " is not a .mesh file") sys.exit() if not os.path.splitext(args.matrix)[1] == ".txt": print("Output file must be in the .txt format") sys.exit() sourceMesh = lib_msh.Mesh(args.source) targetMesh = lib_msh.Mesh(args.target) sourceStep = int(len(sourceMesh.verts) / args.maxPoints) + 1 targetStep = int(len(targetMesh.verts) / args.maxPoints) + 1 sourceVerts = sourceMesh.verts[::sourceStep, :-1] targetVerts = targetMesh.verts[::targetStep, :-1] MAT, dist = icp(sourceVerts, targetVerts, max_iterations=args.maxIterations, tolerance=args.tolerance) writeMatrixToFile(MAT, args.matrix)
args = parser.parse_args() #check args.input = os.path.abspath(args.input) if not os.path.exists(args.input): print("No input file") sys.exit(1) if args.matrix: for i, m in enumerate(args.matrix): args.matrix[i] = os.path.abspath(m) if not os.path.exists(m): print("No matrix file", m) sys.exit(1) #apply mesh = lib_msh.Mesh(args.input) if args.matrix: for matrix in args.matrix: mesh.applyMatrix(matFile=matrix) else: """ if args.center: mesh.verts[:,:3] -= mesh.center if args.scale: mesh.verts[:,:3] *= args.scale else: mesh.verts[:,:3] *= 1. / np.max(mesh.dims) mesh.verts[:,:3] += [0.5,0.5,0.5] """ #else: #Scale relative to the appropriate center
if not os.path.splitext(args.input1)[1] == ".mesh": print(args.input1 + " is not a .mesh file") sys.exit() if not os.path.isfile(args.input2): print(args.input2 + " is not a valid file") sys.exit() if not os.path.splitext(args.input2)[1] == ".mesh": print(args.input2 + " is not a .mesh file") sys.exit() if not os.path.splitext( args.output)[1] == ".mesh" and not os.path.splitext( args.output)[1] == ".sol": print("Output file must be in the .mesh format") sys.exit() if __name__ == "__main__": args = parse() checkArgs(args) mesh1 = lib_msh.Mesh(args.input1) mesh2 = lib_msh.Mesh(args.input2) if len(mesh1.verts) != len(mesh2.verts): print("Different number of verts for the two meshes") sys.exit() mesh1.vectors = mesh1.verts[:, :3] - mesh2.verts[:, :3] if os.path.splitext(args.output)[1] == ".mesh": mesh1.write(args.output) mesh1.writeSol(args.output.replace(".mesh", ".sol")) else: mesh1.writeSol(args.output)
parser.add_argument("-d", "--icotris", type=int, help="Icosphere triangles reference", required=True) parser.add_argument("-e", "--icotets", type=int, help="Icosphere tetrahedra reference", required=True) parser.add_argument("-b", "--fixtris", type=int, help="Fixed triangles reference", required=True) args = parser.parse_args(sys.argv[1:]) #checks args.template = os.path.abspath(args.template) args.signed = os.path.abspath(args.signed) args.output = os.path.abspath(args.output) # dref: Fixed surface inside the template (number + ref) # elref: Elements inside the fixed surface # bref: Follower elements shutil.copyfile(args.template, "template.mesh") cmd = lib_exe.morphing + " %s %s -nit %d -dref 1 %d -elref 1 %d -bref 1 %d > /dev/null 2>&1" % (args.signed, "template.mesh", args.iterations, args.icotris, args.icotets, args.fixtris) lib_exe.execute(cmd) #Clean the mesh mesh = lib_msh.Mesh(args.signed[:-5] + ".1.mesh") mesh.readSol( args.signed[:-5] + ".1.depl.sol") mesh.tets = np.array([]) mesh.tris = mesh.tris[mesh.tris[:,-1]!=10] mesh.discardUnused() mesh.write(args.output) mesh.writeSol(args.output.replace("mesh", "sol")) #Remove the temporary files os.remove(args.signed[:-5] + ".1.mesh") os.remove(args.signed[:-5] + ".1.depl.sol")
help="Hausdorff distance", default=0.01) parser.add_argument("-r", "--reference", type=int, help="New surface reference", default=0) parser.add_argument("-l", "--levelset", type=float, help="Levelset value", default=0) args = parser.parse_args(sys.argv[1:]) #checks args.input = os.path.abspath(args.input) args.output = os.path.abspath(args.output) lib_exe.execute(lib_exe.mmg3d + "%s -ls %f -hausd %f -o tmp.mesh" % (args.input, args.levelset, args.distance)) mesh = lib_msh.Mesh("tmp.mesh") mesh.tets = np.array([]) mesh.tris = mesh.tris[mesh.tris[:, -1] == 10] mesh.discardUnused() mesh.tris[:, -1] = args.reference mesh.write(args.output) os.remove("tmp.mesh") os.remove("tmp.sol")
if not os.path.isfile(args.input): print(args.input + " is not a valid file") sys.exit() if not os.path.splitext(args.input)[1] == ".mesh": print(args.input + " is not a .mesh file") sys.exit() if not os.path.splitext(args.output)[1] == ".mesh": print("Output file must be in the .mesh format") sys.exit() if args.resolution < 11 or args.resolution > 301: print("The resolution must be in [11, 301]") sys.exit() print("1 - Converting .mesh to binary .xyz") print("- 1.1 - Opening the mesh file") mesh = lib_msh.Mesh(args.input) print("- 1.2 - Converting to binary point data") binaryData, totalScale = ptsToXYZCubes(mesh.verts, args.resolution) print("2 - Creating the filled volume") print("- 2.1 - Space carving") newData = spaceCarve(binaryData) newData = nd.binary_closing(newData, structure=nd.generate_binary_structure(3, 3), iterations=3) print("- 2.2 - Marching cubes") verts, faces, _, _ = mea.marching_cubes_lewiner(volume=newData, level=0.5) recon = lib_msh.Mesh() recon.verts = np.insert(np.array(verts), 3, 0, axis=1) recon.tris = np.insert(np.array(faces), 3, 0, axis=1) recon.computeBBox()
args.interior = os.path.abspath(args.interior) args.exterior = os.path.abspath(args.exterior) args.output = os.path.abspath(args.output) if args.template: args.template = os.path.abspath(args.template) #check for intersections if intersects(args.interior): print("interior surface is self-intersecting") sys.exit(1) if intersects(args.exterior): print("exterior surface is self-intersecting") sys.exit(2) #Merge the meshes and run tetgen exterior, interior = lib_msh.Mesh(args.exterior), lib_msh.Mesh( args.interior) #exterior.tris = exterior.tris[exterior.tris[:,-1]!=2] exterior.tris[:, -1] = 2 exterior.discardUnused() interior.tris[:, -1] = 1 interior.fondre(exterior) interior.write("mask.mesh") if intersects("mask.mesh"): print("mask is self-intersecting") sys.exit(3) #Run tetgen lib_exe.execute(lib_exe.tetgen + "-pgaANEFY mask.mesh") for f in os.listdir("."):
if f.endswith(".obj") or f.endswith(".stl"): lib_exe.execute( lib_exe.python_cmd("convert.py") + "-i %s -o %s" % (f, f.replace(f[-3:], "mesh"))) args.input[i] = f.replace(f[-3:], "mesh") # 2 - If needed, merge everything together if len(args.input) > 1: lib_exe.execute( lib_exe.python_cmd("merge.py") + "-i %s -o %s" % (" ".join(args.input), NAME + ".mesh")) else: shutil.copyfile(args.input[0], NAME + ".mesh") # 3 - Transform to an object between 0.1 and 0.9 mesh = lib_msh.Mesh(NAME + ".mesh") S = 0.8 / np.max(mesh.dims) C = mesh.center lib_exe.execute( lib_exe.python_cmd("transform.py") + "-i %s -o %s -t %f %f %f" % (NAME + ".mesh", "tmp.mesh", -C[0], -C[1], -C[2])) lib_exe.execute( lib_exe.python_cmd("transform.py") + "-i %s -o %s -s %f %f %f" % ("tmp.mesh", "tmp.mesh", S, S, S)) lib_exe.execute( lib_exe.python_cmd("transform.py") + "-i %s -o %s -t %f %f %f" % ("tmp.mesh", NAME + ".scaled.mesh", 0.5, 0.5, 0.5)) os.remove("tmp.mesh") # 4 - Remesh HAUSD = 0.0025
args = parser.parse_args() if not os.path.isfile(args.input): print(args.input + " is not a valid file") sys.exit() if not os.path.splitext(args.input)[1] == ".mesh": print(args.input + " is not a .mesh file") sys.exit() if not os.path.splitext(args.output)[1] == ".mesh": print("Output file must be in the .mesh format") sys.exit() if intersects(args.input): print(args.input + " has intersecting facets") sys.exit() mesh = lib_msh.Mesh(args.input) ico = lib_msh.Mesh(ico=[args.center, args.radius]) ico.tris[:, -1] = 10 mesh.fondre(ico) mesh.write("out.mesh") lib_exe.execute(lib_exe.tetgen + "-pgANEYF out.mesh") lib_exe.execute(lib_exe.mmg3d + "out.1.mesh -nosurf -o " + args.output) os.remove(args.output.replace(".mesh", ".sol")) #Make the same references in args.output than in out.mesh def distance(a, b): return ((a[0] - b[0])**2 + (a[1] - b[1])**2 + (a[2] - b[2])**2)**0.5 final = lib_msh.Mesh(args.output) for i, t in enumerate(final.tris): vert1 = final.verts[t[0]]
if args.interiorIsovalue < args.exteriorIsovalue: print("The inner shell must be closer than the outer shell") sys.exit() if args.interiorIsovalue < 5 or args.exteriorIsovalue < 5: print("The shell must be closer than maxDim/5") sys.exit() args.input = os.path.abspath(args.input) args.output = os.path.abspath(args.output) #Carve the input mesh lib_exe.execute( lib_exe.python_cmd("carve.py") + "-i %s -o %s -r %d" % (args.input, args.output.replace(".mesh", ".carved.mesh"), 31)) #Create a box and mesh it to compute the signed distance on mesh = lib_msh.Mesh(args.input) c = np.max(mesh.dims) / 8 cube = lib_msh.Mesh(cube=[ mesh.xmin - c, mesh.xmax + c, mesh.ymin - c, mesh.ymax + c, mesh.zmin - c, mesh.zmax + c ]) cube.write("box.mesh") lib_exe.execute(lib_exe.tetgen + "-pgANEF %s" % ("box.mesh")) lib_exe.execute( lib_exe.mmg3d + "%s -hausd %f -hmax %f" % ("box.1.mesh", np.max(mesh.dims) / 50, np.max(mesh.dims) / 25)) #Compute the signed distance to the carved object lib_exe.execute( lib_exe.mshdist + "-ncpu 16 -noscale %s %s" % ("box.1.o.mesh", args.output.replace(".mesh", ".carved.mesh")))