def main(): args = parse_args() mesh = pymesh.load_mesh(args.mesh_file) if not args.dual: vertices, edges = pymesh.mesh_to_graph(mesh) else: vertices, edges = pymesh.mesh_to_dual_graph(mesh) wire_network = pymesh.wires.WireNetwork.create_from_data(vertices, edges) wire_network.write_to_file(args.wire_file)
def main(): args = parse_args(); mesh = pymesh.load_mesh(args.mesh_file); if not args.dual: vertices, edges = pymesh.mesh_to_graph(mesh); else: vertices, edges = pymesh.mesh_to_dual_graph(mesh); wire_network = pymesh.wires.WireNetwork.create_from_data(vertices, edges); wire_network.write_to_file(args.wire_file);
def slide_verts(input_mesh, prct, mesh_name): dihedral_angle_list = [] mesh_nodes, mesh_edges = pymesh.mesh_to_graph(input_mesh) mesh_faces = input_mesh.faces input_mesh.add_attribute("face_normal") face_normal = input_mesh.get_attribute("face_normal").reshape((mesh_faces.shape[0], 3)) all_edges_has_two_faces = True vertices = input_mesh.vertices.copy() for edge_idx in range(len(mesh_edges)): n_0 = mesh_edges[edge_idx, 0] n_1 = mesh_edges[edge_idx, 1] n_0_adjacent_face_indices = set(input_mesh.get_vertex_adjacent_faces(n_0)) n_1_adjacent_faces_indices = set(input_mesh.get_vertex_adjacent_faces(n_1)) edge_adjacent_faces_indices = np.sort(list(n_0_adjacent_face_indices & n_1_adjacent_faces_indices)) if len(edge_adjacent_faces_indices) == 2: face_idx_0 = edge_adjacent_faces_indices[0] face_idx_1 = edge_adjacent_faces_indices[1] if len(edge_adjacent_faces_indices) != 2: print( f"message generated in slide function. mesh {mesh_name} : edge {edge_idx} has {len(edge_adjacent_faces_indices)} adjacent face.") all_edges_has_two_faces = False break face_0_normal = face_normal[face_idx_0] face_1_normal = face_normal[face_idx_1] cos_theta = min(np.dot(face_0_normal, face_1_normal), 1) cos_theta = max(-1, cos_theta) dihedral_angle = np.expand_dims(np.pi - np.arccos(cos_theta), axis=0) dihedral_angle_list.append(dihedral_angle) if all_edges_has_two_faces: dihedral_angle_array = np.array(dihedral_angle_list) vids = np.random.permutation(len(vertices)) target = int(prct * len(vids)) shifted = 0 for vi in vids: if shifted < target: edges = np.where((mesh_edges[:, 0] == vi) | (mesh_edges[:, 1] == vi))[0] if min(dihedral_angle_array[edges]) > 2.65: edge = mesh_edges[np.random.choice(edges)] vi_t = edge[1] if vi == edge[0] else edge[0] nv = vertices[vi] + np.random.uniform(0.2, 0.5) * (vertices[vi_t] - vertices[vi]) vertices[vi] = nv shifted += 1 else: break shifted = shifted / len(vertices) slided_mesh = pymesh.form_mesh(vertices, input_mesh.faces) return all_edges_has_two_faces, slided_mesh
def extract_frontier_from_mesh(mesh_filepath): filename = os.path.splitext(os.path.basename(mesh_filepath))[0] mesh = pymesh.load_mesh(mesh_filepath) mesh.enable_connectivity() # enables connectivity on mesh mesh.add_attribute( "face_centroid") # adds the face centroids to be accessed mesh.add_attribute("face_normal") # adds the face normals to be accessed mesh.add_attribute("vertex_valance") faces = mesh.faces centroids = mesh.get_face_attribute("face_centroid") normals = mesh.get_face_attribute("face_normal") vertex_valance = mesh.get_vertex_attribute("vertex_valance") #print vertex_valance frontiers = set() for face_id in range(0, mesh.num_faces): adj_faces = mesh.get_face_adjacent_faces(face_id) if len(adj_faces) <= 2: #print centroids[face_id] p = centroids[face_id] p = (p[0], p[1], p[2]) frontiers.add(p) pts, _ = pymesh.mesh_to_graph(mesh) x, y, z = zip(*pts) x = np.array(x) y = np.array(y) z = np.array(z) fig = plt.figure() # figsize=(800 / 72, 800 / 72) ax = plt.axes(projection='3d') ax.set_title(filename) # ax.scatter3D(x, y, z, c=z, cmap='Greens'); ax.scatter3D(x, y, z, s=[1.0 for n in range(len(x))], c="blue") set_axes_equal(ax) # print(frontiers) x, y, z = zip(*frontiers) x = np.array(x) y = np.array(y) z = np.array(z) ax.scatter3D(x, y, z, s=[3.0 for n in range(len(x))], c="red") plt.show()
def __init__(self, input_mesh, mesh_name, data_edges, edge_area, edges_seg_labels, edges_soft_seg_labels, faces_seg_labels, nodes_seg_labels, filename_to_save, graph_label): self.__graph = None self.__input_mesh = input_mesh self.__mesh_name = mesh_name self.__input_mesh.enable_connectivity() self.__mesh_nodes, self.__mesh_edges = pymesh.mesh_to_graph( self.__input_mesh) self.__mesh_faces = self.__input_mesh.faces self.__filename_to_save = filename_to_save self.__graph_label = graph_label self.__data_edges = data_edges self.__edges_seg_labels = edges_seg_labels self.__edges_soft_seg_labels = edges_soft_seg_labels self.__faces_seg_labels = faces_seg_labels self.__nodes_seg_labels = nodes_seg_labels self.__edge_area = edge_area self.two_face_neighbor = True
def generate_primitives(self): if self.mesh.num_faces <= 0: return; self.primitives = []; d = norm(self.bmax - self.bmin) / math.sqrt(self.mesh.dim); radius = d * self.line_width; assert(radius > 0); vertices, edges = pymesh.mesh_to_graph(self.mesh); lengths = norm(vertices[edges[:,0],:] - vertices[edges[:,1],:], axis=1); color = color_table["dark_gray"]; for v in vertices: ball = Sphere(v, radius); ball.color = color; self.primitives.append(ball); for e,l in zip(edges, lengths): if l <= 0.5 * radius : continue; cylinder = Cylinder(vertices[e[0]], vertices[e[1]], radius); cylinder.color = color; self.primitives.append(cylinder);
def generate_primitives(self): if self.mesh.num_faces <= 0: return self.primitives = [] d = norm(self.bmax - self.bmin) / math.sqrt(self.mesh.dim) radius = d * self.line_width assert (radius > 0) vertices, edges = pymesh.mesh_to_graph(self.mesh) lengths = norm(vertices[edges[:, 0], :] - vertices[edges[:, 1], :], axis=1) color = get_color(self.line_color) for v in vertices: ball = Sphere(v, radius) ball.color = color self.primitives.append(ball) for e, l in zip(edges, lengths): if l <= 0.5 * radius: continue cylinder = Cylinder(vertices[e[0]], vertices[e[1]], radius) cylinder.color = color self.primitives.append(cylinder)
def get_vertices_and_edges(obj_mesh): vertices, edges = pymesh.mesh_to_graph(obj_mesh) return vertices, edges
def get_border_edge(mesh): vertices, edges = pymesh.mesh_to_graph(mesh) print(np.all(vertices == mesh.vertices))
from utils import create_weighted_graph, add_connectivity # NB: THE FULL VERSION OF PYMESH MUST BE INSTALLED TO RUN THIS SCRIPT # AS THE PIP INSTALLATION DOES NOT INCLUDE THE FUNCTION load_mesh() # THE FULL VERSION OF PYMESH CAN BE INSTALLED VIA git clone .. for i in np.arange(4, 12, 2): mesh_name = "poly_" + str(i) + ".off" mesh_boundary = "poly_boundary_" + str(i) + ".txt" mesh_connectivity = "poly_connectivity_" + str(i) + ".txt" # load and visualize mesh mesh = pymesh.load_mesh(mesh_name) #plt.triplot(mesh.vertices[:,0], mesh.vertices[:,1], mesh.faces, 'ko-', lw = 0.5, alpha=0.5, ms = 0.7) # convert mesh to graph graph = pymesh.mesh_to_graph(mesh) # add weights to account for irregularity of mesh weighted_graph = create_weighted_graph(graph) # add connectivity start_c = time.time() connect = np.loadtxt(mesh_connectivity) weighted_graph_with_connectivity = add_connectivity( np.copy(graph[0]), weighted_graph.copy(), connect) # create networkx graph G = nx.from_edgelist(weighted_graph) G_prime = nx.from_edgelist(weighted_graph_with_connectivity) # load boundary vertices and find their indices in the graph sources = np.loadtxt(mesh_boundary)
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 get_bounding_box_center(mesh): vertices, edges = pymesh.mesh_to_graph(mesh) wire_network = pymesh.WireNetwork.create_from_data(vertices=vertices, edges=edges) return wire_network.bbox_center