def main(): args = parse_args() mesh = pymesh.load_mesh(args.input_mesh) f_indices = pymesh.get_degenerated_faces(mesh) if (len(f_indices) == 0): print("mesh does not have any degenerated faces") return v_indices = mesh.faces[f_indices].ravel() degenerated_faces = np.zeros(mesh.num_faces) degenerated_faces[f_indices] = 1.0 degenerated = np.zeros(mesh.num_vertices) degenerated[v_indices] = 1.0 mesh.add_attribute("degenerated_faces") mesh.set_attribute("degenerated_faces", degenerated_faces) mesh.add_attribute("degenerated") mesh.set_attribute("degenerated", degenerated) print("{} degenerated faces, consisting of {} vertices.".format( len(f_indices), np.count_nonzero(degenerated))) if args.verbose: print("Degenerated faces indices: {}".format(f_indices)) pymesh.save_mesh(args.output_mesh, mesh, "degenerated", "degenerated_faces") if args.extract_region is not None: region = pymesh.submesh(mesh, f_indices, 0) pymesh.save_mesh(args.extract_region, region, *region.get_attribute_names())
def main(): args = parse_args(); mesh = pymesh.load_mesh(args.input_mesh); f_indices = pymesh.get_degenerated_faces(mesh); if (len(f_indices) == 0): print("mesh does not have any degenerated faces"); return; v_indices = mesh.faces[f_indices].ravel(); degenerated_faces = np.zeros(mesh.num_faces); degenerated_faces[f_indices] = 1.0; degenerated = np.zeros(mesh.num_vertices); degenerated[v_indices] = 1.0; mesh.add_attribute("degenerated_faces"); mesh.set_attribute("degenerated_faces", degenerated_faces); mesh.add_attribute("degenerated"); mesh.set_attribute("degenerated", degenerated); print("{} degenerated faces, consisting of {} vertices.".format( len(f_indices), np.count_nonzero(degenerated))); if args.verbose: print("Degenerated faces indices: {}".format(f_indices)); pymesh.save_mesh(args.output_mesh, mesh, "degenerated", "degenerated_faces"); if args.extract_region is not None: region = pymesh.submesh(mesh, f_indices, 0); pymesh.save_mesh(args.extract_region, region, *region.get_attribute_names());
def repousse(mesh, logger): cell_ids = mesh.get_attribute("cell").ravel().astype(int); mesh.add_attribute("edge_length"); tol = np.amax(mesh.get_attribute("edge_length")) * 0.1; bbox_min, bbox_max = mesh.bbox; scaling = 2.0 / norm(bbox_max - bbox_min); start_time = time(); num_cells = np.amax(cell_ids)+1; results = []; 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); pymesh.save_mesh("debug.msh", cut_mesh); cut_mesh, __ = pymesh.remove_degenerated_triangles(cut_mesh, 100); cut_mesh, __ = pymesh.split_long_edges(cut_mesh, tol); dof = cut_mesh.num_vertices; assembler = pymesh.Assembler(cut_mesh); L = assembler.assemble("laplacian"); M = assembler.assemble("mass"); L_rhs = M * np.ones(dof) * -0.5; bd_indices = cut_mesh.boundary_vertices; n = len(bd_indices); C = scipy.sparse.coo_matrix((np.ones(n), (np.arange(n, dtype=int), bd_indices)), shape=(n, dof)); C_rhs = np.zeros(n); A = scipy.sparse.bmat([ [-L, C.T], [C, None] ]); rhs = np.concatenate((L_rhs.ravel(), C_rhs)); solver = pymesh.SparseSolver.create("SparseLU"); solver.compute(A); x = solver.solve(rhs); z = x[:dof].reshape((-1, 1)); vertices = np.hstack((cut_mesh.vertices, z)); out_mesh = pymesh.form_mesh(vertices, cut_mesh.faces); results.append(out_mesh); finish_time = time(); t = finish_time - start_time; logger.info("Repousse running time: {}".format(t)); mesh = pymesh.merge_meshes(results); vertices = mesh.vertices[:,:2]; mesh_2d = pymesh.form_mesh(vertices, mesh.faces); pymesh.save_mesh("out_2d.msh", mesh_2d) return mesh;
def repousse(mesh, logger): cell_ids = mesh.get_attribute("cell").ravel().astype(int) mesh.add_attribute("edge_length") tol = np.amax(mesh.get_attribute("edge_length")) * 0.1 bbox_min, bbox_max = mesh.bbox scaling = 2.0 / norm(bbox_max - bbox_min) start_time = time() num_cells = np.amax(cell_ids) + 1 results = [] 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) pymesh.save_mesh("debug.msh", cut_mesh) cut_mesh, __ = pymesh.remove_degenerated_triangles(cut_mesh, 100) cut_mesh, __ = pymesh.split_long_edges(cut_mesh, tol) dof = cut_mesh.num_vertices assembler = pymesh.Assembler(cut_mesh) L = assembler.assemble("laplacian") M = assembler.assemble("mass") L_rhs = M * np.ones(dof) * -0.5 bd_indices = cut_mesh.boundary_vertices n = len(bd_indices) C = scipy.sparse.coo_matrix( (np.ones(n), (np.arange(n, dtype=int), bd_indices)), shape=(n, dof)) C_rhs = np.zeros(n) A = scipy.sparse.bmat([[-L, C.T], [C, None]]) rhs = np.concatenate((L_rhs.ravel(), C_rhs)) solver = pymesh.SparseSolver.create("SparseLU") solver.compute(A) x = solver.solve(rhs) z = x[:dof].reshape((-1, 1)) vertices = np.hstack((cut_mesh.vertices, z)) out_mesh = pymesh.form_mesh(vertices, cut_mesh.faces) results.append(out_mesh) finish_time = time() t = finish_time - start_time logger.info("Repousse running time: {}".format(t)) mesh = pymesh.merge_meshes(results) vertices = mesh.vertices[:, :2] mesh_2d = pymesh.form_mesh(vertices, mesh.faces) pymesh.save_mesh("out_2d.msh", mesh_2d) 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
def main(): args = parse_args(); mesh = pymesh.load_mesh(args.input_mesh); mesh = pymesh.submesh(mesh, args.face_indices, args.n_ring) pymesh.save_mesh(args.output_mesh, mesh, *mesh.get_attribute_names());
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 create_graph(mesh, centroids, normals, robot_pos, traversal_tresh=35, bumpiness_tresh=0.37, dbscan_eps=3, dbscan_min_samples=2): """ :param mesh: :param centroids: :param normals: :param closer_centroid_idx: :param traversal_tresh: :param dbscan_eps: :param dbscan_min_samples: :return: """ print("Creating Graph... num faces:", mesh.num_faces) frontiers = extract_frontiers(mesh) print("Found ", frontiers, "frontiers") G = nx.Graph() for face_idx in xrange(mesh.num_faces): face = mesh.faces[face_idx] face_inclination = graph_search.MeshGraphSearch.calculate_traversal_angle( normals[face_idx]) # if 0 <= face_inclination <= traversal_tresh or 180 - traversal_tresh <= face_inclination <= 180: if traversal_tresh < face_inclination < 180 - traversal_tresh: continue G.add_node(face_idx) for face_idx in list(G.nodes()): face_vertexes = mesh.faces[face_idx] for v in face_vertexes: vertex_adj_faces = mesh.get_vertex_adjacent_faces(v) for face_adjacent in vertex_adj_faces: if face_adjacent != face_idx and G.has_node(face_adjacent): G.add_edge(face_idx, face_adjacent, weight=1) #print "G edge_list:", len(list(G.edges())), sorted(list(G.edges())) # remove small connected components for component in list(nx.connected_components(G)): if len(component) < 3: for node in component: G.remove_node(node) g_centroids = [(centroids[v][0], centroids[v][1], centroids[v][2]) for v in sorted(G.nodes())] centroid_g_dict = {i: v for i, v in enumerate(sorted(G.nodes()))} closer_centroid_idx = mesh_planner.mesh_helper.find_closer_centroid( g_centroids, robot_pos, force_return_closer=True) conn_nodes = nx.node_connected_component( G, centroid_g_dict[closer_centroid_idx]) Gconn = G.subgraph(conn_nodes).copy() kdtree = spatial.KDTree(g_centroids) pairs = kdtree.query_pairs(bumpiness_tresh) print "pairs:", len(pairs), pairs joined_by_bumpiness_nodes = set() for pair in pairs: p1_conn = centroid_g_dict[ pair[0]] # node inside the biggest connected component p2_out = centroid_g_dict[ pair[1]] # node outside of the biggest connected component # if edge is already mapped, then drop it if Gconn.has_edge(p1_conn, p2_out) or Gconn.has_edge(p2_out, p1_conn): continue # if edge is only connecting inside the Gconn drop it if Gconn.has_node(p1_conn) and Gconn.has_node(p2_out): continue # if edge is not connecting Gconn with other connected elements drop it if not Gconn.has_node(p1_conn) and not Gconn.has_node(p2_out): continue if p1_conn not in Gconn.nodes(): p1_conn, p2_out = p2_out, p1_conn # if there is already a connection between the outside element and Gconn intersecting_gconn_nodes = list( set(G.neighbors(p2_out)).intersection(Gconn.nodes())) if len(intersecting_gconn_nodes) > 1: continue # this node is an another connected subgraph # add this node and the other ones of the subgraph # if not Gconn.has_node(p2_out): # small_component = nx.node_connected_component(G, p2_out) # for n in small_component: # if not Gconn.has_node(n): # Gconn.add_node(n) small_comp_nodes = nx.node_connected_component(G, p2_out) Gsmall = G.subgraph(small_comp_nodes).copy() GconnTemp = Gconn.copy() Gconn = nx.compose(Gconn, Gsmall) for pair2 in pairs: pair2_1 = centroid_g_dict[pair2[0]] pair2_2 = centroid_g_dict[pair2[1]] if (Gsmall.has_node(pair2_1) and GconnTemp.has_node(pair2_2)) or \ (GconnTemp.has_node(pair2_1) and Gsmall.has_node(pair2_2)): gconn_node = pair2_1 outside_node = pair2_2 if not GconnTemp.has_node(gconn_node): outside_node, gconn_node = gconn_node, outside_node # intersecting_gconn_nodes = list(set(Gconn.neighbors(gconn_node)).intersection(Gsmall.nodes())) # if len(intersecting_gconn_nodes) > 0: # continue Gconn.add_edge(pair2_1, pair2_2, weight=1) joined_by_bumpiness_nodes.add(pair2_1) joined_by_bumpiness_nodes.add(pair2_2) # a = np.asarray(centroids[pair2_1]) # b = np.asarray(centroids[pair2_2]) # # print("dist:", np.linalg.norm(a - b)) # add remaining edges of the new component from the original graph for e in G.edges(): p1_conn = e[0] p2_out = e[1] # if edge is already mapped, then drop it if Gconn.has_edge(p1_conn, p2_out) or Gconn.has_edge(p2_out, p1_conn): continue # if edge is only connecting inside the Gconn drop it if not p1_conn in Gconn.nodes() and not p2_out in Gconn.nodes(): continue Gconn.add_edge(p1_conn, p2_out, weight=1) print "Gconn node_list:", list(Gconn.nodes()) # numpy array of x,y,z positions in sorted node order gcon_centroids = [(centroids[v][0], centroids[v][1], centroids[v][2]) for v in sorted(Gconn.nodes())] xyz = np.array(gcon_centroids) # scalar colors scalars = xyz[:, 2] #np.array(list(Gconn.nodes())) #xyz[:, 2] #+ 5 mlab.figure(1, bgcolor=(0, 0, 0)) mlab.clf() # centroid_gcon_dict = {v: int(i) for i, v in enumerate(gcon_centroids)} # print "centroid_gcon_dict:", centroid_gcon_dict.keys() # edge_list = [] # for e in Gconn.edges(): # e1 = (centroids[e[0]][0], centroids[e[0]][1], centroids[e[0]][2]) # e2 = (centroids[e[1]][0], centroids[e[1]][1], centroids[e[1]][2]) # edge_list.append([centroid_gcon_dict[e1], centroid_gcon_dict[e2]]) # # edge_list = np.array(edge_list) # #edge_list = np.array(list(Gconn.edges())) # print "edge_list:", edge_list # pts.mlab_source.dataset.lines = np.array(edge_list) # #pts.update() # lines = mlab.pipeline.stripper(pts) # mlab.pipeline.surface(lines, color=(0.2, 0.4, 0.5), line_width=1.5, opacity=.9) #colormap='Accent', # tube = mlab.pipeline.tube(pts, tube_radius=0.1) # mlab.pipeline.surface(tube, color=(0.8, 0.8, 0.8)) # final_mesh_pts = [] # for e in Gconn.nodes(): # final_mesh_pts.append((centroids[e][0], centroids[e][1], centroids[e][2])) # # final_mesh_faces = [] # for e in Gconn.nodes(): # final_mesh_faces.append(mesh.faces[e]) # # x, y, z = zip(*final_mesh_pts) # x = np.array(x) # y = np.array(y) # z = np.array(z) # # print "mesh.faces:", mesh.faces # # mlab.triangular_mesh(x, y, z, final_mesh_faces) filtered_mesh = pymesh.submesh(mesh, Gconn.nodes(), 1) pymesh.save_mesh("/tmp/tmp.stl", filtered_mesh) pts, _ = pymesh.mesh_to_graph(filtered_mesh) x, y, z = zip(*pts) x = np.array(x) y = np.array(y) z = np.array(z) mlab.triangular_mesh(x, y, z, filtered_mesh.faces) mlab.show()
def main(): args = parse_args() mesh = pymesh.load_mesh(args.input_mesh) mesh = pymesh.submesh(mesh, args.face_indices, args.n_ring) pymesh.save_mesh(args.output_mesh, mesh, *mesh.get_attribute_names())
def main(): args = parse_args() mesh = pymesh.load_mesh(args.input_mesh) if not mesh.has_attribute("corner_texture"): raise RuntimeError("Mesh contains no uv!") mesh.add_attribute("face_area") uv = mesh.get_attribute("corner_texture").reshape((-1, 2)) if len(uv) == 0: raise RuntimeError("Invalid uv size.") faces = np.arange(mesh.num_faces * mesh.vertex_per_face).reshape( (-1, mesh.vertex_per_face)) uv_mesh = pymesh.form_mesh(uv, faces) uv_mesh.add_attribute("face_area") ori_area = mesh.get_face_attribute("face_area") uv_area = uv_mesh.get_face_attribute("face_area") area_ratio = np.divide(uv_area, ori_area) uv_mesh.add_attribute("area_ratio") uv_mesh.set_attribute("area_ratio", area_ratio) mesh.add_attribute("area_ratio") mesh.set_attribute("area_ratio", area_ratio) mesh.add_attribute("u") mesh.set_attribute("u", uv[:, 0]) if (args.separate): uv_mesh, info = pymesh.remove_duplicated_vertices(uv_mesh) comps = pymesh.separate_mesh(uv_mesh) segments = [] uv = uv.reshape((-1, 6), order="C") vertices = mesh.vertices combined_uv = [] for comp in comps: ori_vertex_indices = comp.get_attribute( "ori_vertex_index").ravel() ori_elem_indices = comp.get_attribute( "ori_elem_index").ravel().astype(int) segment = pymesh.submesh(mesh, ori_elem_indices, 0) ori_face_indices = segment.get_attribute( "ori_face_index").ravel().astype(int) ori_uv = uv[ori_face_indices] combined_uv.append(ori_uv) segment.add_attribute("corner_texture") segment.set_attribute("corner_texture", ori_uv.ravel()) segments.append(segment) combined_uv = np.vstack(combined_uv) mesh = pymesh.merge_meshes(segments) mesh.add_attribute("corner_texture") mesh.set_attribute("corner_texture", combined_uv.ravel(order="C")) elif args.cut: uv_mesh, info = pymesh.remove_duplicated_vertices(uv_mesh) index_map = info["index_map"] vertices = mesh.vertices faces = mesh.faces vertices = vertices[faces.ravel(order="C")] new_vertices = np.zeros((uv_mesh.num_vertices, 3)) new_vertices[index_map] = vertices mesh = pymesh.form_mesh(new_vertices, uv_mesh.faces) mesh.add_attribute("corner_texture") mesh.set_attribute("corner_texture", uv) if args.save_uv: pymesh.save_mesh(args.output_mesh, uv_mesh, *uv_mesh.attribute_names) else: pymesh.save_mesh(args.output_mesh, mesh, *mesh.attribute_names)