예제 #1
0
def network_is_connected(network):
    """Verify that the network is connected.

    Returns
    -------
    bool
        True, if the network is connected.
        False, otherwise.

    Notes
    -----
    A network is connected if for every two vertices a path exists connecting them.

    Examples
    --------
    >>> import compas
    >>> from compas.datastructures import Network
    >>> from compas.datastructures import network_is_connected
    >>> network = Network.from_obj(compas.get('lines.obj'))
    >>> network_is_connected(network)
    True
    """
    if network.number_of_nodes() == 0:
        return False
    nodes = breadth_first_traverse(network.adjacency, network.get_any_node())
    return len(nodes) == network.number_of_nodes()
예제 #2
0
def connected_components(adjacency):
    """Identify the vertices of connected components.

    Parameters
    ----------
    adjacency : dict
        An adjacency dictionary mapping vertex identifiers to neighbours.

    Returns
    -------
    list of list of hashable
        A nested list of vertex identifiers.

    Examples
    --------
    >>> adjacency = {0: [1, 2], 1: [0, 2], 2: [0, 1], 3: []}
    >>> connected_components(adjacency)
    [[0, 1, 2], [3]]
    """
    tovisit = set(adjacency)
    components = []
    while tovisit:
        root = tovisit.pop()
        visited = breadth_first_traverse(adjacency, root)
        tovisit -= visited
        components.append(list(visited))
    return components
예제 #3
0
def mesh_is_connected(mesh):
    """Verify that the mesh is connected.

    Parameters
    ----------
    mesh : compas.datastructures.Mesh
        A mesh data structure.

    Returns
    -------
    bool
        True, if the mesh is connected.
        False, otherwise.

    Notes
    -----
    A mesh is connected if for every two vertices a path exists connecting them.

    Examples
    --------
    >>> mesh_is_connected(m1)
    True
    >>> mesh_is_connected(m2)
    True
    >>> mesh_is_connected(m3)
    False
    """
    if not mesh.vertex:
        return False
    nodes = breadth_first_traverse(mesh.adjacency, mesh.get_any_vertex())
    return len(nodes) == mesh.number_of_vertices()
예제 #4
0
def connected_components(adjacency):
    """Identify the vertices of connected components.

    Parameters
    ----------
    adjacency : dict
        An adjacency dictionary mapping vertex identifiers to neighbours.

    Returns
    -------
    list of list of hashable
        A nested list of vertex identifiers.

    Examples
    --------
    .. code-block:: python

        pass

    """
    tovisit = set(adjacency)
    components = []
    while tovisit:
        root = tovisit.pop()
        visited = breadth_first_traverse(adjacency, root)
        tovisit -= visited
        components.append(list(visited))
    return components
예제 #5
0
def connected_components(adjacency):
    """Identify the connected components of a graph.

    Parameters
    ----------
    adjacency : dict[hashable, dict[hashable, None]] | dict[hashable, sequence[hashable]]
        An adjacency dictionary representing the connectivity of the graph
        by mapping nodes identifiers to neighbour identifiers.
        Examples of valid adjacency dicts are

        * ``{0: [1, 2, 3, 4], 1: [0], 2: [0], 3: [0], 4: [0]}``
        * ``{0: {1: None, 2: None, 3: None, 4: None}, 1: {0: None}, 2: {0: None}, 3: {0: None}, 4: {0: None}}``

    Returns
    -------
    list[list[hashable]]
        A list of connected components,
        with each component a list of connected nodes.

    Examples
    --------
    >>> adjacency = {0: [1, 2], 1: [0, 2], 2: [0, 1], 3: []}
    >>> connected_components(adjacency)
    [[0, 1, 2], [3]]

    """
    tovisit = set(adjacency)
    components = []
    while tovisit:
        root = tovisit.pop()
        visited = breadth_first_traverse(adjacency, root)
        tovisit -= visited
        components.append(list(visited))
    return components
예제 #6
0
def connected_components(adjacency):
    tovisit = set(adjacency)
    components = []
    while tovisit:
        root = tovisit.pop()
        visited = breadth_first_traverse(adjacency, root)
        tovisit -= visited
        components.append(list(visited))
    return components
예제 #7
0
def unify_cycles_rhino(vertices, faces, root=0):
    """Unify the cycle directions of the given faces such that adjacent faces share opposite halfedges.

    Parameters
    ----------
    vertices : sequence[[float, float, float] | :class:`compas.geometry.Point`]
        A list of vertex coordinates.
    faces : sequence[sequence[int]]
        A list of faces with each face defined by a list of indices into the list of vertices.
    root : int, optional
        The starting face.

    Returns
    -------
    list[list[int]]
        A list of faces with the same orientation as the root face.

    Raises
    ------
    AssertionError
        If not all faces were visited.

    Notes
    -----
    The algorithm works by first building an adjacency dict of the faces, which can be traversed efficiently to unify all face cycles.
    Although this process technically only requires the connectivity information contained in the faces,
    the locations of the vertices can be used to speed up execution for very large collections of faces.

    Examples
    --------
    >>> vertices = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 1.0]]
    >>> faces = [[0, 1, 2], [0, 3, 2]]
    >>> unify_cycles_rhino(vertices, faces)  # doctest: +SKIP
    [[0, 1, 2], [2, 3, 0]]

    """
    def unify(node, nbr):
        # find the common edge
        for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
            if u in faces[node] and v in faces[node]:
                # node and nbr have edge u-v in common
                i = faces[node].index(u)
                j = faces[node].index(v)
                if i == j - 1 or (j == 0 and u == faces[node][-1]):
                    # if the traversal of a neighboring halfedge
                    # is in the same direction
                    # flip the neighbor
                    faces[nbr][:] = faces[nbr][::-1]
                    return

    adj = face_adjacency_rhino(vertices, faces)
    visited = breadth_first_traverse(adj, root, unify)
    assert len(list(visited)) == len(faces), 'Not all faces were visited'
    return faces
예제 #8
0
def unify_cycles_rhino(vertices, faces, root=0):
    """Unify the cycle directions of the given faces such that adjacent faces share opposite halfedges.

    Parameters
    ----------
    vertices : list
        A list of vertex coordinates.
    faces : list
        A list of lists of face vertex indices.
    root : int, optional
        The starting face.

    Returns
    -------
    list
        A list of faces with the same orientation as the root face.

    Raises
    ------
    AssertionError
        If not all faces were visited.

    Examples
    --------
    >>> vertices = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 1.0]]
    >>> faces = [[0, 1, 2], [0, 3, 2]]
    >>> unify_cycles_rhino(vertices, faces)  # doctest: +SKIP
    [[0, 1, 2], [2, 3, 0]]

    Notes
    -----
    This function uses Rhino's RTree for constructing a face adjacency dict.
    """
    def unify(node, nbr):
        # find the common edge
        for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
            if u in faces[node] and v in faces[node]:
                # node and nbr have edge u-v in common
                i = faces[node].index(u)
                j = faces[node].index(v)
                if i == j - 1 or (j == 0 and u == faces[node][-1]):
                    # if the traversal of a neighboring halfedge
                    # is in the same direction
                    # flip the neighbor
                    faces[nbr][:] = faces[nbr][::-1]
                    return

    adj = face_adjacency_rhino(vertices, faces)
    visited = breadth_first_traverse(adj, root, unify)
    assert len(list(visited)) == len(faces), 'Not all faces were visited'
    return faces
예제 #9
0
def mesh_unify_cycles(mesh, root=None):
    """Unify the cycle directions of all faces.

    Unified cycle directions is a necessary condition for the data structure to
    work properly. When in doubt, run this function on your mesh.

    Parameters
    ----------
    mesh : Mesh
        A mesh object.
    root : str, optional [None]
        The key of the root face.

    """
    def unify(node, nbr):
        # find the common edge
        for u, v in mesh.face_halfedges(nbr):
            if u in mesh.face[node] and v in mesh.face[node]:
                # node and nbr have edge u-v in common
                i = mesh.face[node].index(u)
                j = mesh.face[node].index(v)
                if i == j - 1:
                    # if the traversal of a neighbouring halfedge
                    # is in the same direction
                    # flip the neighbour
                    mesh.face[nbr][:] = mesh.face[nbr][::-1]
                    return

    if root is None:
        root = mesh.get_any_face()

    adj = face_adjacency(mesh)

    visited = breadth_first_traverse(adj, root, unify)

    assert len(
        list(visited)) == mesh.number_of_faces(), 'Not all faces were visited'

    mesh.halfedge = {key: {} for key in mesh.vertices()}
    for fkey in mesh.faces():
        for u, v in mesh.face_halfedges(fkey):
            mesh.halfedge[u][v] = fkey
            if u not in mesh.halfedge[v]:
                mesh.halfedge[v][u] = None
예제 #10
0
def network_is_connected(network):
    """Verify that the network is connected.

    Returns
    -------
    bool
        True, if the network is connected.
        False, otherwise.

    Notes
    -----
    A network is connected if for every two vertices a path exists connecting them.

    """
    if not network.vertex:
        return False

    nodes = breadth_first_traverse(network.adjacency, network.get_any_vertex())

    return len(nodes) == network.number_of_vertices()
예제 #11
0
def network_is_connected(network):
    """Verify that the mesh is connected.

    A mesh is connected if the following conditions are fulfilled:

    * For every two vertices a path exists connecting them.

    Returns
    -------
    bool
        True, if the mesh is connected.
        False, otherwise.

    """
    if not network.vertex:
        return False

    nodes = breadth_first_traverse(network.adjacency, network.get_any_vertex())

    return len(nodes) == network.number_of_vertices()
예제 #12
0
def unify_cycles(vertices, faces, root=0):
    """"""
    def unify(node, nbr):
        # find the common edge
        for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
            if u in faces[node] and v in faces[node]:
                # node and nbr have edge u-v in common
                i = faces[node].index(u)
                j = faces[node].index(v)
                if i == j - 1 or (j == 0 and u == faces[node][-1]):
                    # if the traversal of a neighboring halfedge
                    # is in the same direction
                    # flip the neighbor
                    faces[nbr][:] = faces[nbr][::-1]
                    return

    adj = face_adjacency(vertices, faces)

    visited = breadth_first_traverse(adj, root, unify)

    assert len(list(visited)) == len(faces), 'Not all faces were visited'
    return faces
예제 #13
0
def mesh_is_connected(mesh):
    """Verify that the mesh is connected.

    Parameters
    ----------
    mesh : :class:`compas.datastructures.Mesh`
        A mesh data structure.

    Returns
    -------
    bool
        True, if the mesh is connected.
        False, otherwise.

    Notes
    -----
    A mesh is connected if for every two vertices a path exists connecting them.

    Examples
    --------
    >>> from compas.datastructures import Mesh
    >>> mesh = Mesh()
    >>> mesh_is_connected(mesh)
    False
    >>> a = mesh.add_vertex(x=0, y=0, z=0)
    >>> b = mesh.add_vertex(x=1, y=0, z=0)
    >>> c = mesh.add_vertex(x=1, y=1, z=0)
    >>> mesh_is_connected(mesh)
    False
    >>> abc = mesh.add_face([a, b, c])
    >>> mesh_is_connected(mesh)
    True

    """
    if not mesh.vertex:
        return False
    nodes = breadth_first_traverse(mesh.adjacency, mesh.get_any_vertex())
    return len(nodes) == mesh.number_of_vertices()