def mesh_unweld_edges(mesh, edges): """Unwelds a mesh along edges. Parameters ---------- mesh : Mesh A mesh. edges: list List of edges as tuples of vertex keys. """ # set of vertices in edges to unweld vertices = set([i for edge in edges for i in edge]) # to store changes to do all at once vertex_changes = {} for vkey in vertices: # maps between old mesh face index and new network vertex index old_to_new = {nbr: i for i, nbr in enumerate(mesh.vertex_faces(vkey))} new_to_old = {i: nbr for i, nbr in enumerate(mesh.vertex_faces(vkey))} # get adjacency network of faces around the vertex excluding adjacency # through the edges to unweld network_vertices = [ mesh.face_centroid(fkey) for fkey in mesh.vertex_faces(vkey) ] network_edges = [] for nbr in mesh.vertex_neighbors(vkey): if not mesh.is_edge_on_boundary(vkey, nbr) and ( vkey, nbr) not in edges and (nbr, vkey) not in edges: network_edges.append((old_to_new[mesh.halfedge[vkey][nbr]], old_to_new[mesh.halfedge[nbr][vkey]])) adjacency = adjacency_from_edges(network_edges) for key, values in adjacency.items(): adjacency[key] = {value: None for value in values} # include non connected vertices edge_vertices = list(set([i for edge in network_edges for i in edge])) for i in range(len(mesh.vertex_faces(vkey))): if i not in edge_vertices: adjacency[i] = {} # collect the disconnected parts around the vertex due to unwelding vertex_changes[vkey] = [[new_to_old[key] for key in part] for part in connected_components(adjacency)] for vkey, changes in vertex_changes.items(): # for each disconnected part replace the vertex by a new vertex in the # faces of the part for change in changes: mesh_substitute_vertex_in_faces( mesh, vkey, mesh.add_vertex(attr_dict=mesh.vertex[vkey]), change) # delete old vertices mesh.delete_vertex(vkey)
def mesh_disconnected_vertices(mesh): """Get the disconnected vertex groups in a mesh. Parameters ---------- mesh : Mesh A mesh. Returns ------- parts : list The list of disconnected vertex groups. """ return connected_components(mesh.adjacency)
def network_disconnected_nodes(network): """Get the disconnected node groups in a network. Parameters ---------- network : Network A network. Returns ------- list The list of disconnected node groups. """ return connected_components(network.adjacency)
def mesh_disconnected_vertices(mesh): """Get the disconnected vertex groups in a mesh. Parameters ---------- mesh : :class:`compas.datastructures.Mesh` A mesh. Returns ------- list[list[int]] The disconnected parts of the mesh as a list of lists of vertex identifiers. """ return connected_components(mesh.adjacency)
def network_disconnected_nodes(network): """Get the disconnected node groups in a network. Parameters ---------- network : :class:`compas.datastructures.Network` A network. Returns ------- list[list[hashable]] The list of disconnected node groups. """ return connected_components(network.adjacency)
def mesh_connected_components(mesh): """Find the connected components of the mesh. Parameters ---------- mesh : :class:`compas.datastructures.Mesh` A mesh data structure. Returns ------- list[list[int]] Groups of connected vertices. """ return connected_components(mesh.adjacency)
def mesh_connected_components(mesh): return connected_components(mesh.adjacency)
from compas.datastructures import Mesh from compas.viewers import MeshViewer from compas.utilities import download_file_from_remote from compas.topology import connected_components source = 'https://raw.githubusercontent.com/ros-industrial/abb/kinetic-devel/abb_irb6600_support/meshes/irb6640/visual/link_1.stl' filepath = os.path.join(compas.APPDATA, 'data', 'meshes', 'ros', 'link_1.stl') download_file_from_remote(source, filepath, overwrite=False) stl = STL(filepath, precision='6f') mesh = Mesh.from_vertices_and_faces(stl.parser.vertices, stl.parser.faces) vertexgroups = connected_components(mesh.halfedge) facegroups = [[] for _ in range(len(vertexgroups))] vertexsets = list(map(set, vertexgroups)) for fkey in mesh.faces(): vertices = set(mesh.face_vertices(fkey)) for i, vertexset in enumerate(vertexsets): if vertices.issubset(vertexset): facegroups[i].append(fkey) break meshes = [] for vertexgroup, facegroup in zip(vertexgroups, facegroups):
def from_quad_mesh(cls, quad_mesh, collect_strips=True, collect_polyedges=True, attribute_density=True): """Build coarse quad mesh from quad mesh with density and child-parent element data. Parameters ---------- quad_mesh : QuadMesh A quad mesh. attribute_density : bool, optional Keep density data of dense quad mesh and inherit it as aatribute. Returns ---------- coarse_quad_mesh : CoarseQuadMesh A coarse quad mesh with density data. """ polyedges = quad_mesh.singularity_polyedge_decomposition() # vertex data vertices = { vkey: quad_mesh.vertex_coordinates(vkey) for vkey in quad_mesh.vertices() } coarse_vertices_children = { vkey: vkey for polyedge in polyedges for vkey in [polyedge[0], polyedge[-1]] } coarse_vertices = { vkey: quad_mesh.vertex_coordinates(vkey) for vkey in coarse_vertices_children } # edge data coarse_edges_children = {(polyedge[0], polyedge[-1]): polyedge for polyedge in polyedges} singularity_edges = [(x, y) for polyedge in polyedges for u, v in pairwise(polyedge) for x, y in [(u, v), (v, u)]] # face data faces = { fkey: quad_mesh.face_vertices(fkey) for fkey in quad_mesh.faces() } adj_edges = {(f1, f2) for f1 in quad_mesh.faces() for f2 in quad_mesh.face_neighbors(f1) if f1 < f2 and quad_mesh.face_adjacency_halfedge(f1, f2) not in singularity_edges} coarse_faces_children = {} for i, connected_faces in enumerate( connected_components(adjacency_from_edges(adj_edges))): mesh = Mesh.from_vertices_and_faces( vertices, [faces[face] for face in connected_faces]) coarse_faces_children[i] = [ vkey for vkey in reversed(mesh.boundaries()[0]) if mesh.vertex_degree(vkey) == 2 ] coarse_quad_mesh = cls.from_vertices_and_faces(coarse_vertices, coarse_faces_children) # attribute relation child-parent element between coarse and dense quad meshes coarse_quad_mesh.data['attributes'][ 'vertex_coarse_to_dense'] = coarse_vertices_children coarse_quad_mesh.data['attributes']['edge_coarse_to_dense'] = { u: {} for u in coarse_quad_mesh.vertices() } for (u, v), polyedge in coarse_edges_children.items(): coarse_quad_mesh.data['attributes']['edge_coarse_to_dense'][u][ v] = polyedge coarse_quad_mesh.data['attributes']['edge_coarse_to_dense'][v][ u] = list(reversed(polyedge)) # collect strip and polyedge attributes if collect_strips: coarse_quad_mesh.collect_strips() if collect_polyedges: coarse_quad_mesh.collect_polyedges() # store density attribute from input dense quad mesh if attribute_density: coarse_quad_mesh.set_strips_density(1) for skey in coarse_quad_mesh.strips(): u, v = coarse_quad_mesh.strip_edges(skey)[0] d = len( coarse_edges_children.get((u, v), coarse_edges_children.get((v, u), []))) coarse_quad_mesh.set_strip_density(skey, d) # store quad mesh and use as polygonal mesh coarse_quad_mesh.set_quad_mesh(quad_mesh) coarse_quad_mesh.set_polygonal_mesh(quad_mesh.copy()) return coarse_quad_mesh