def create_from_setting(cls, setting): """ Syntax: { "type": "boundary", "mesh": mesh_file, "color": color_name, "radius": radius } """ mesh = pymesh.load_mesh(setting["mesh"]) vertices = mesh.vertices bd_edges = mesh.boundary_edges vertices, bd_edges, __ = pymesh.remove_isolated_vertices_raw( vertices, bd_edges) wires = pymesh.wires.WireNetwork() if len(bd_edges) > 0: wires.load(vertices, bd_edges) else: logger = logging.getLogger(__name__) logger.warning("Mesh ({}) contains no boundary.".format( setting["mesh"])) tmp_dir = tempfile.gettempdir() stamp = datetime.datetime.now().isoformat() wire_file = os.path.join(tmp_dir, "{}.wire".format(stamp)) wires.write_to_file(wire_file) wire_setting = { "type": "wire_network", "wire_network": wire_file, "color": setting.get("color", None), "radius": setting.get("radius", 0.1), "bbox": mesh.bbox, } return WireView.create_from_setting(wire_setting)
def slice_mesh(mesh, N): bbox_min, bbox_max = mesh.bbox; min_corner = [bbox_min[0] -1.0, bbox_min[1] - 1.0, bbox_min[2] - 1.0]; output_wires = []; for i in range(N): ratio = float(i) / float(N); slice_val = bbox_min[0] * ratio + bbox_max[0] * (1-ratio); max_corner = [slice_val, bbox_max[1] + 1.0, bbox_max[2] + 1.0]; box = pymesh.generate_box_mesh(min_corner, max_corner); diff = pymesh.boolean(box, mesh, "difference"); #pymesh.save_mesh("tmp_{}.msh".format(i), diff); vertices = diff.vertices; y_out_range = np.logical_or( vertices[:,1] < bbox_min[1], vertices[:,1] > bbox_max[1]); z_out_range = np.logical_or( vertices[:,2] < bbox_min[2], vertices[:,2] > bbox_max[2]); on_outside = np.logical_or(y_out_range, z_out_range); if not np.any(on_outside): continue; edges = []; for f in diff.faces: if np.sum(on_outside[f]) == 1: if on_outside[f[0]]: edges.append([f[1], f[2]]); if on_outside[f[1]]: edges.append([f[2], f[0]]); if on_outside[f[2]]: edges.append([f[0], f[1]]); if len(edges) == 0: continue; edges = np.array(edges, dtype=int); below_ground = vertices[:,1] < 0.5*(bbox_min[1]+bbox_max[1]); edges_below_ground = np.any(below_ground[edges], axis=1); edges = edges[np.logical_not(edges_below_ground)]; vertices, edges, __ = \ pymesh.remove_isolated_vertices_raw(vertices, edges); wires = pymesh.wires.WireNetwork.create_from_data(vertices, edges); output_wires.append(wires); print('.',end="",flush=True) print("done"); return output_wires;
def extract_submesh(mesh, face_indices, n_ring): vertices = mesh.vertices selected_faces = np.zeros(mesh.num_faces, dtype=bool) selected_faces[face_indices] = True ring_index = np.zeros(mesh.num_faces, dtype=int) ring_index[selected_faces] += 1 for i in range(n_ring): selected_faces = expand_by_one_ring(mesh, selected_faces) ring_index[selected_faces] += 1 selected_face_indices = np.arange(mesh.num_faces)[selected_faces] faces = mesh.faces[selected_faces] ring_index = (ring_index[selected_faces] - n_ring - 1) * (-1) vertices, faces, __ = pymesh.remove_isolated_vertices_raw(vertices, faces) mesh = pymesh.form_mesh(vertices, faces) mesh.add_attribute("ori_face_index") mesh.set_attribute("ori_face_index", selected_face_indices) mesh.add_attribute("ring") mesh.set_attribute("ring", ring_index) return mesh
def extract_submesh(mesh, face_indices, n_ring): vertices = mesh.vertices; selected_faces = np.zeros(mesh.num_faces, dtype=bool); selected_faces[face_indices] = True; ring_index = np.zeros(mesh.num_faces, dtype=int); ring_index[selected_faces] += 1; for i in range(n_ring): selected_faces = expand_by_one_ring(mesh, selected_faces); ring_index[selected_faces] += 1; selected_face_indices = np.arange(mesh.num_faces)[selected_faces]; faces = mesh.faces[selected_faces]; ring_index = (ring_index[selected_faces] - n_ring - 1) * (-1); vertices, faces, __ = pymesh.remove_isolated_vertices_raw(vertices, faces); mesh = pymesh.form_mesh(vertices, faces); mesh.add_attribute("ori_face_index"); mesh.set_attribute("ori_face_index", selected_face_indices); mesh.add_attribute("ring"); mesh.set_attribute("ring", ring_index); return mesh;
def makeMesh(self, path2file, do_clean=False): path, file_name = os.path.split(path2file) fname, fext = os.path.splitext(file_name) # read image stack_tif = io.imread(path2file, plugin='tifffile') print('tif shape: {}'.format(stack_tif.shape), flush=True) bin_stack_tif = stack_tif.astype(bool).astype(np.int16) # clean from isolated and small pixels (optional) if do_clean: bin_stack_tif = self.erode_converge(bin_stack_tif) bin_stack_tif = self.clean_not_attached(bin_stack_tif) print('Saving image after cleaning', flush=True) io.imsave("aux.tif", (255*bin_stack_tif).astype(np.uint8), plugin='tifffile') bin_stack_tif = binary_erosion(bin_stack_tif, iterations=1) # create 1 pixel layer to make close meshes NZ = bin_stack_tif.shape[0] NY = bin_stack_tif.shape[1] NX = bin_stack_tif.shape[2] aux = np.zeros((NZ + 10, NY + 10, NX + 10)) aux[5:NZ + 5, 5:NY + 5, 5:NX + 5] = bin_stack_tif print('Triangulation of a set of points ...', flush=True) aux = aux.astype(np.float32) aux = filters.gaussian_filter(aux, 2.0, truncate=1.0) maxA = np.max(aux) aux = aux / maxA * 4.0 - 1.0 # aux = aux * 4.0 - 1.0 minA = np.min(aux) maxA = np.max(aux) print('Cleaning memory', flush=True) del stack_tif del bin_stack_tif gc.collect() print("min aux: {} max aux: {}".format(minA, maxA), flush=True) verts, faces, normals, values = measure.marching_cubes_lewiner(aux, 0) print('Cleaning memory', flush=True) del aux gc.collect() print("Mesh data 0:",flush=True) print("Verts: {} Faces: {}".format(verts.shape, faces.shape)) print('Remove isolated vertices', flush=True) verts, faces, info = pymesh.remove_isolated_vertices_raw(verts, faces) print(info, flush=True) print("Mesh data 1:",flush=True) print("Verts: {} Faces: {}".format(verts.shape, faces.shape)) print('Remove duplicated vertices', flush=True) verts, faces, info = pymesh.remove_duplicated_vertices_raw(verts, faces) print(info, flush=True) print("Mesh data 2:",flush=True) print("Verts: {} Faces: {}".format(verts.shape, faces.shape)) verts = verts - 5.0 print('Set the mesh ...', flush=True) final_mesh = pymesh.form_mesh(verts, faces) savefilename = "{}.obj".format(fname) savefilepath = os.path.join('./', savefilename) print("saving file {}".format(savefilename), flush=True) pymesh.save_mesh(savefilepath, final_mesh) print('done.', flush=True)
def bevel(wires, logger, remove_holes, dist): bbox_min, bbox_max = wires.bbox #wires = uniform_sampling(wires); mesh = constrained_triangulate(wires, logger, remove_holes) cell_ids = mesh.get_attribute("cell").ravel().astype(int) num_cells = np.amax(cell_ids) + 1 comps = [] for i in range(num_cells): to_keep = np.arange(mesh.num_faces, dtype=int)[cell_ids == i] if not np.any(to_keep): continue cut_mesh = pymesh.submesh(mesh, to_keep, 0) bd_edges = cut_mesh.boundary_edges vertices, edges, __ = pymesh.remove_isolated_vertices_raw( cut_mesh.vertices, bd_edges) bd_wires = pymesh.wires.WireNetwork.create_from_data(vertices, edges) offset_dir = np.zeros((bd_wires.num_vertices, 2)) for ei in edges: v0 = ei[0] v1 = ei[1] adj_vts = bd_wires.get_vertex_neighbors(v0) if len(adj_vts) == 2: if adj_vts[0] == v1: vp = adj_vts[1] else: vp = adj_vts[0] e0 = vertices[v1] - vertices[v0] e1 = vertices[vp] - vertices[v0] e0 /= norm(e0) e1 /= norm(e1) theta = math.atan2(e0[0] * e1[1] - e0[1] * e1[0], e0.dot(e1)) if abs(theta) > 0.99 * math.pi: offset = np.array([-e0[1], e0[0]]) scale = 1.0 else: if theta > 0: offset = e0 + e1 scale = math.sin(theta / 2) else: offset = -e0 - e1 scale = math.cos(math.pi / 2 + theta / 2) offset /= norm(offset) offset_dir[v0] = offset * dist / scale offset_vertices = vertices + offset_dir vertices = np.vstack((vertices, offset_vertices)) edges = np.vstack((edges, edges + bd_wires.num_vertices)) vertices, edges, __ = pymesh.remove_duplicated_vertices_raw( vertices, edges, dist / 2) comp_wires = pymesh.wires.WireNetwork.create_from_data( vertices, edges) comp = constrained_triangulate(comp_wires, logger, True) comps.append(comp) mesh = pymesh.merge_meshes(comps) bd_vertices = mesh.boundary_vertices is_inside = np.ones(mesh.num_vertices, dtype=bool) is_inside[bd_vertices] = False vertices = np.hstack((mesh.vertices, np.zeros((mesh.num_vertices, 1)))) vertices[is_inside, 2] = dist mesh = pymesh.form_mesh(vertices, mesh.faces) return mesh
def bevel(wires, logger, remove_holes, dist): bbox_min, bbox_max = wires.bbox; #wires = uniform_sampling(wires); mesh = constrained_triangulate(wires, logger, remove_holes); cell_ids = mesh.get_attribute("cell").ravel().astype(int); num_cells = np.amax(cell_ids) + 1; comps = []; for i in range(num_cells): to_keep = np.arange(mesh.num_faces, dtype=int)[cell_ids == i]; if not np.any(to_keep): continue; cut_mesh = pymesh.submesh(mesh, to_keep, 0); bd_edges = cut_mesh.boundary_edges; vertices, edges, __ = pymesh.remove_isolated_vertices_raw( cut_mesh.vertices, bd_edges); bd_wires = pymesh.wires.WireNetwork.create_from_data(vertices, edges); offset_dir = np.zeros((bd_wires.num_vertices, 2)); for ei in edges: v0 = ei[0]; v1 = ei[1]; adj_vts = bd_wires.get_vertex_neighbors(v0); if len(adj_vts) == 2: if adj_vts[0] == v1: vp = adj_vts[1]; else: vp = adj_vts[0]; e0 = vertices[v1] - vertices[v0]; e1 = vertices[vp] - vertices[v0]; e0 /= norm(e0); e1 /= norm(e1); theta = math.atan2(e0[0]*e1[1] - e0[1]*e1[0], e0.dot(e1)); if abs(theta) > 0.99 * math.pi: offset = np.array([-e0[1], e0[0]]); scale = 1.0; else: if theta > 0: offset = e0 + e1; scale = math.sin(theta/2); else: offset = -e0 - e1 scale = math.cos(math.pi/2 + theta/2); offset /= norm(offset); offset_dir[v0] = offset * dist / scale; offset_vertices = vertices + offset_dir; vertices = np.vstack((vertices, offset_vertices)); edges = np.vstack((edges, edges + bd_wires.num_vertices)); vertices, edges, __ = pymesh.remove_duplicated_vertices_raw( vertices, edges, dist/2); comp_wires = pymesh.wires.WireNetwork.create_from_data(vertices, edges); comp = constrained_triangulate(comp_wires, logger, True); comps.append(comp); mesh = pymesh.merge_meshes(comps); bd_vertices = mesh.boundary_vertices; is_inside = np.ones(mesh.num_vertices, dtype=bool); is_inside[bd_vertices] = False; vertices = np.hstack((mesh.vertices, np.zeros((mesh.num_vertices, 1)))); vertices[is_inside, 2] = dist; mesh = pymesh.form_mesh(vertices, mesh.faces); return mesh;