Exemple #1
0
def assembly_hull(assembly, keys=None, unify=True):
    """Construct the convex hull of an assembly.

    Parameters
    ----------
    assembly : Assembly
        The assembly data structure.
    keys: list, optional
        The identifiers of the blocks to include in the hull calculation.
        Defaults to all blocks.
    unify : bool, optional
        Unify the face cycles of the hull.
        Default is ``True``.

    Returns
    -------
    tuple
        The vertices and faces of the hull.

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

        import compas_assembly
        from compas.datastructures import Mesh
        from compas.viewers import MeshViewer
        from compas_assembly.datastructures import Assembly

        assembly = Assembly.from_json(compas_assembly.get('assembly.json'))

        vertices, faces = assembly_hull(assembly)
        hull = Mesh.from_vertices_and_faces(vertices, faces)

        viewer = MeshViewer()
        viewer.mesh = hull
        viewer.show()

    """
    keys = keys or list(assembly.vertices())

    points = []
    for key in keys:
        block = assembly.blocks[key]
        points.extend(block.get_vertices_attributes('xyz'))

    faces = convex_hull(points)
    vertices = list(set(flatten(faces)))

    i_index = {i: index for index, i in enumerate(vertices)}

    vertices = [points[index] for index in vertices]
    faces = [[i_index[i] for i in face] for face in faces]

    if unify:
        faces = unify_cycles(vertices, faces)

    return vertices, faces
Exemple #2
0
def get_convex_hull_mesh(points):
    faces = convex_hull(points)
    vertices = list(set(flatten(faces)))

    i_index = {i: index for index, i in enumerate(vertices)}
    vertices = [points[index] for index in vertices]
    faces = [[i_index[i] for i in face] for face in faces]
    faces = unify_cycles(vertices, faces)

    mesh = Mesh.from_vertices_and_faces(vertices, faces)

    return mesh
def volmesh_merge_adjacent_halffaces(volmesh, hfkeys):

    # check halffaces ----------------------------------------------------------
    for hfkey in hfkeys:
        if not volmesh.is_halfface_on_boundary(hfkey):
            raise ValueError('Halfface {} is interior.'.format(hfkey))
    if not _are_halffaces_chained(volmesh, hfkeys):
        raise ValueError('These halffaces are not chained.')
    # --------------------------------------------------------------------------
    halffaces = [volmesh.halfface[hfkey] for hfkey in hfkeys]
    # --------------------------------------------------------------------------
    vkeys = set()
    for hfkey in hfkeys:
        for key in volmesh.halfface_vertices(hfkey):
            vkeys.add(key)

    vkeys = list(vkeys)
    points = [volmesh.vertex_coordinates(vkey) for vkey in vkeys]

    faces_by_index = convex_hull(points)
    faces_by_vkeys = []
    for face in faces_by_index:
        faces_by_vkeys.append([vkeys[index] for index in face])

    # make temp cell mesh ------------------------------------------------------
    cell = Mesh()
    for i in range(len(vkeys)):
        key = vkeys[i]
        x, y, z = points[i]
        cell.add_vertex(key=key, x=x, y=y, z=z)
    for face in faces_by_vkeys:
        cell.add_face(face)

    # merge coplanar faces -----------------------------------------------------
    cell_merge_coplanar_adjacent_faces(cell)

    # get correct direction of faces -------------------------------------------
    faces = [cell.face[fkey] for fkey in cell.face]
    if halffaces[0] in faces:
        new_faces = [face[::-1] for face in faces]
    else:
        new_faces = faces

    volmesh.add_cell(new_faces)

    return volmesh
def assembly_hull(assembly, keys=None, unify=True):
    """Construct the convex hull of an assembly.

    Parameters
    ----------
    assembly : Assembly
        The assembly data structure.
    keys: list, optional
        The identifiers of the blocks to include in the hull calculation.
        Defaults to all blocks.
    unify : bool, optional
        Unify the face cycles of the hull.
        Default is ``True``.

    Returns
    -------
    tuple
        The vertices and faces of the hull.

    Examples
    --------
    >>>

    """
    keys = keys or list(assembly.nodes())

    points = []
    for key in keys:
        block = assembly.blocks[key]
        points.extend(block.vertices_attributes('xyz'))

    faces = convex_hull(points)
    vertices = list(set(flatten(faces)))

    i_index = {i: index for index, i in enumerate(vertices)}

    vertices = [points[index] for index in vertices]
    faces = [[i_index[i] for i in face] for face in faces]

    if unify:
        faces = unify_cycles(vertices, faces)

    return vertices, faces
Exemple #5
0
    def from_skeleton(cls, lines, radius=1):

        network = Network.from_lines(lines)

        tube_extremities = {}

        nodes = []
        for vkey in network.vertices():
            if len(network.vertex_neighbors(vkey)) > 1:

                points = [
                    network.edge_point(vkey,
                                       nbr,
                                       t=float(radius) /
                                       network.edge_length(vkey, nbr))
                    for nbr in network.vertex_neighbors(vkey)
                ]
                faces = convex_hull(points)
                mesh = cls.from_vertices_and_faces(points, faces)

                meshes = []

                for fkey in mesh.faces():
                    vertices = [
                        mesh.edge_midpoint(u, v)
                        for u, v in mesh.face_halfedges(fkey)
                    ]
                    faces = [[0, 1, 2]]
                    meshes.append(cls.from_vertices_and_faces(vertices, faces))

                for vkey_2 in mesh.vertices():
                    tops = []
                    bottoms = []
                    n = normalize_vector(
                        subtract_vectors(mesh.vertex_coordinates(vkey_2),
                                         network.vertex_coordinates(vkey)))
                    for i in range(len(mesh.vertex_neighbors(vkey_2))):
                        pt_0 = mesh.edge_midpoint(
                            vkey_2,
                            mesh.vertex_neighbors(vkey_2, ordered=True)[i - 1])
                        bottoms.append(pt_0)
                        pt_1 = mesh.edge_midpoint(
                            vkey_2,
                            mesh.vertex_neighbors(vkey_2, ordered=True)[i])
                        pt_2 = midpoint_line([pt_0, pt_1])
                        pt_2 = add_vectors(
                            scale_vector(n, distance_point_point(pt_0, pt_1)),
                            pt_2)
                        tops.append(pt_2)
                        vertices = [pt_0, pt_2, pt_1]
                        faces = [[0, 1, 2]]
                        meshes.append(
                            cls.from_vertices_and_faces(vertices, faces))
                    for i in range(len(tops)):
                        vertices = [tops[i - 1], tops[i], bottoms[i]]
                        faces = [[0, 1, 2]]
                        meshes.append(
                            cls.from_vertices_and_faces(vertices, faces))
                    #print network.vertex_neighbors(vkey), network.vertex_neighbors(vkey)[vkey_2]
                    tube_extremities[(
                        vkey, network.vertex_neighbors(vkey)[vkey_2])] = tops

                mesh = meshes_join_and_weld(meshes)

                #dense_mesh = trimesh_subdivide_loop(mesh, k = 3)

                nodes.append(mesh)

        return nodes[0]

        meshes_2 = []
        for u, v in network.edges():
            if len(network.vertex_neighbors(u)) > 1 and len(
                    network.vertex_neighbors(v)) > 1:
                #print len(tube_extremities[(u, v)])
                #print len(tube_extremities[(v, u)])
                if len(tube_extremities[(u, v)]) == len(tube_extremities[(v,
                                                                          u)]):
                    n = len(tube_extremities[(u, v)])
                    l = network.edge_length(u, v) - 2 * radius
                    m = math.floor(l / radius) + 1
                    pt_uv = tube_extremities[(u, v)]
                    pt_vu = list(reversed(tube_extremities[(v, u)]))
                    dmin = -1
                    imin = None
                    for i in range(n):
                        distance = sum([
                            distance_point_point(pt_uv[j],
                                                 pt_vu[i + j - len(pt_vu)])
                            for j in range(n)
                        ])
                        if dmin < 0 or distance < dmin:
                            dmin = distance
                            imin = i
                    pt_vu = [pt_vu[imin + j - len(pt_vu)] for j in range(n)]
                    array = [pt_uv]
                    for i in range(int(m)):
                        polygon = []
                        for j in range(int(n)):
                            u = pt_uv[j]
                            v = pt_vu[j]
                            polygon.append(
                                add_vectors(
                                    scale_vector(u, (float(m) - 1 - float(i)) /
                                                 float(m - 1)),
                                    scale_vector(v,
                                                 float(i) / float(m - 1))))
                        array.append(polygon)
                    array.append(pt_vu)
                    #print len(array), len(array[0]), len(array[1]), len(array[2]), len(array[3])
                    for i in range(int(n)):
                        for j in range(int(m)):
                            vertices = [
                                array[i - 1][j - 1], array[i - 1][j],
                                array[i][j]
                            ]
                            faces = [[0, 1, 2]]
                            meshes_2.append(
                                Mesh.from_vertices_and_faces(vertices, faces))

        vertices, faces = join_and_weld_meshes(meshes_2)

        #meshes_2 = rs.AddMesh(vertices, faces)

        meshes = []
        for node in nodes:
            vertices, faces = node.to_vertices_and_faces()
            meshes.append(rs.AddMesh(vertices, faces))
def volmesh_ud(volmesh, network, scale=0.5):
    """Computes temporary vertex coordinates for every halfface of a volmesh, for the visualisation of the unified diagram.

    Parameters
    ----------
    volmesh : VolMesh
        A volmesh object representing a polyhedral force diagram.
    network : Network
        A network object representing a polyhedral form diagram.
    scale : float
        Unified diagram scale factor,

    Returns
    -------
    halffaces : dictionary
        A dictionary of dictionaries: hfkey-{vkey: (x, y, z)}.
    prisms : dictionary
        A dictinoary of dictinoaries: uv - [face coordinates]

    Raises
    ------
    Exception
        If scale is 0, which means the unified diagram is equivalent to the polyhedral force diagram.
    Exception
        If scale is 0, which means the unified diagram is equivalent to the polyhedral form diagram.

    Notes
    -----
    - The prisms are implemented as convex hull of two halffaces for simplicity and to resolve any small geometric errors.
    - Unified diagram with a scale of 0 is equivalent to the polyhedral force diagram, while a scale of 1 is equivalent to the polyhedral form diagram.

    """

    # --------------------------------------------------------------------------
    #   0. evaluate unified diagram scale
    # --------------------------------------------------------------------------
    if scale == 0:
        raise Exception(
            "A unified diagram with a scale of 0 is equivalent to the polyhedral force diagram."
        )

    if scale == 1:
        raise Exception(
            "A unified diagram with a scale of 1 is equivalent to the polyhedral form diagram."
        )

    assert 0 < scale and scale < 1, "Scale needs to be between 0 and 1."

    # --------------------------------------------------------------------------
    #   1. current positions of diagrams
    # --------------------------------------------------------------------------
    volmesh_center = volmesh.centroid()
    network_center = network.datastructure_centroid()
    translation = subtract_vectors(volmesh_center, network_center)

    # --------------------------------------------------------------------------
    #   2. get base points
    # --------------------------------------------------------------------------
    base_xyz = {}

    for vkey in network.nodes():
        init_xyz = network.node_coordinates(vkey)
        base_xyz[vkey] = add_vectors(init_xyz, translation)

    # --------------------------------------------------------------------------
    #   3. compute scaled halffaces
    # --------------------------------------------------------------------------
    # halffaces = {}

    # for ckey in volmesh.cells():
    #     cell_hfs = volmesh.cell_faces(ckey)
    #     for hfkey in cell_hfs:
    #         hf_vertices = {}
    #         for vkey in volmesh.halfface_vertices(hfkey):
    #             xyz = volmesh.vertex_coordinates(vkey)
    #             arm = scale_vector(subtract_vectors(xyz, base_xyz[ckey]), scale)
    #             hf_vertices[vkey] = add_vectors(base_xyz[ckey], arm)
    #         halffaces[hfkey] = hf_vertices

    scaled_halffaces = {}
    cells = {}

    for cell in volmesh.cells():
        gkey_xyz = {}
        faces = []

        for face in volmesh.cell_faces(cell):
            new_face = []
            scaled_face_xyz = []
            for vertex in volmesh.face_vertices(face):
                xyz = volmesh.vertex_coordinates(vertex)
                arm = scale_vector(subtract_vectors(xyz, base_xyz[cell]),
                                   scale)
                scaled_xyz = add_vectors(base_xyz[cell], arm)
                gkey = geometric_key(scaled_xyz)
                gkey_xyz[gkey] = scaled_xyz
                new_face.append(gkey)
                scaled_face_xyz.append(scaled_xyz)
            scaled_halffaces[face] = scaled_face_xyz
            faces.append(new_face)

        gkey_index = dict((gkey, index) for index, gkey in enumerate(gkey_xyz))
        vertices = [list(xyz) for gkey, xyz in gkey_xyz.items()]
        scaled_faces = [[gkey_index[gkey] for gkey in face] for face in faces]

        cells[cell] = {'vertices': vertices, 'faces': scaled_faces}

    # cells = {}
    # for cell in volmesh.cells():
    #     vertices = volmesh.cell_vertices(cell)
    #     faces = volmesh.cell_faces(cell)
    #     vertex_index = dict((vertex, index) for index, vertex in enumerate(vertices))
    #     scaled_vertices = []
    #     for vertex in vertices:
    #         xyz = volmesh.vertex_coordinates(vertex)
    #         arm = scale_vector(subtract_vectors(xyz, base_xyz[cell]), scale)
    #         scaled_vertices.append(add_vectors(base_xyz[cell], arm))
    #     faces = [[vertex_index[vertex] for vertex in volmesh.halfface_vertices(face)] for face in faces]
    #     cells[cell] = {'vertices': scaled_vertices, 'faces': faces}

    # --------------------------------------------------------------------------
    #   4. compute prism faces
    # --------------------------------------------------------------------------
    # prism_faces = {}

    prism_cells = {}

    for u, v in network.edges():
        u_hfkey, v_hfkey = volmesh.cell_pair_halffaces(u, v)
        u_pts = scaled_halffaces[u_hfkey]
        v_pts = scaled_halffaces[v_hfkey]
        pts = u_pts + v_pts
        prism = convex_hull(pts)  # face as indices of pt_list
        prism_cells[(u, v)] = {'vertices': pts, 'faces': prism}

    # for u, v in network.edges():
    #     u_hfkey, v_hfkey = volmesh.cell_pair_halffaces(u, v)
    #     u_pts = halffaces[u_hfkey].values()
    #     v_pts = halffaces[v_hfkey].values()
    #     pt_list = u_pts + v_pts
    #     prism = convex_hull(u_pts + v_pts)  # face as indices of pt_list
    #     face_list = []
    #     for face in prism:
    #         face_xyz = [pt_list[i] for i in face]  # get face xyz in order
    #         face_list.append(face_xyz)
    #     prism_faces[(u, v)] = face_list
    #     prism_cells[(u, v)] = {'vertices': pt_list, 'faces': face_list}

    # --------------------------------------------------------------------------

    # return halffaces, prism_faces
    return cells, prism_cells
Exemple #7
0
def trimesh_skeleton(cls, lines, radius=1):

    network = Network.from_lines(lines)

    tube_extremities = {}

    nodes = []
    for vkey in network.nodes():
        if len(network.adjacency[vkey]) > 1:

            points = {
                nbr: network.edge_point(vkey,
                                        nbr,
                                        t=float(radius) /
                                        network.edge_length(vkey, nbr))
                for nbr in network.adjacency[vkey]
            }
            idx_to_key = {
                i: key
                for i, key in enumerate(network.adjacency[vkey])
            }
            faces = convex_hull(list(points.values()))
            faces = [[idx_to_key[idx] for idx in face] for face in faces]
            mesh = cls.from_vertices_and_faces(points, faces)
            nodes.append(mesh)

            meshes = []

            for fkey in mesh.faces():
                vertices = [
                    mesh.edge_midpoint(u, v)
                    for u, v in mesh.face_halfedges(fkey)
                ]
                faces = [[0, 1, 2]]
                meshes.append(cls.from_vertices_and_faces(vertices, faces))

            for vkey_2 in mesh.vertices():
                tops = []
                bottoms = []
                n = normalize_vector(
                    subtract_vectors(mesh.vertex_coordinates(vkey_2),
                                     network.node_coordinates(vkey)))
                for i in range(len(mesh.vertex_neighbors(vkey_2))):
                    pt_0 = mesh.edge_midpoint(
                        vkey_2,
                        mesh.vertex_neighbors(vkey_2, ordered=True)[i - 1])
                    bottoms.append(pt_0)
                    pt_1 = mesh.edge_midpoint(
                        vkey_2,
                        mesh.vertex_neighbors(vkey_2, ordered=True)[i])
                    pt_2 = midpoint_line([pt_0, pt_1])
                    pt_2 = add_vectors(
                        scale_vector(n, distance_point_point(pt_0, pt_1)),
                        pt_2)
                    tops.append(pt_2)
                    vertices = [pt_0, pt_2, pt_1]
                    faces = [[0, 1, 2]]
                    meshes.append(cls.from_vertices_and_faces(vertices, faces))
                for i in range(len(tops)):
                    vertices = [tops[i - 1], tops[i], bottoms[i]]
                    faces = [[0, 1, 2]]
                    meshes.append(cls.from_vertices_and_faces(vertices, faces))

                tube_extremities[(vkey, vkey_2)] = tops

            mesh = meshes_join_and_weld(meshes)

            nodes.append(mesh)

    all_nodes = meshes_join_and_weld(nodes)

    # leaf node ring
    for u in network.nodes():
        if len(network.adjacency[u]) == 1:
            v = next(iter(network.adjacency[u].keys()))
            ring_v = tube_extremities[(v, u)]
            ring_u = [
                add_vectors(pt, network.edge_vector(v, u))
                for pt in ring_v[::-1]
            ]
            tube_extremities[(u, v)] = ring_u

    beams = []
    for u, v in network.edges():

        geom_key_map = {
            geometric_key(all_nodes.vertex_coordinates(vkey)): vkey
            for vkey in all_nodes.vertices()
        }
        if len(tube_extremities[(u, v)]) != len(tube_extremities[(v, u)]):
            if len(tube_extremities[(u, v)]) < len(tube_extremities[(v, u)]):
                a, b = u, v
            else:
                a, b = v, u
            n = len(tube_extremities[(b, a)]) - len(tube_extremities[(a, b)])
            for i in range(n):
                bdry_vkey = geom_key_map[geometric_key(
                    tube_extremities[(a, b)][0])]
                nbr_vkey = None
                for nbr in all_nodes.vertex_neighbors(bdry_vkey):
                    if not all_nodes.is_edge_on_boundary(bdry_vkey, nbr):
                        nbr_vkey = nbr
                k = tube_extremities[(a, b)].index(
                    all_nodes.vertex_coordinates(bdry_vkey))
                new_vkey = insert_triface_on_boundary(all_nodes, bdry_vkey,
                                                      nbr_vkey)
                tube_extremities[(a, b)].insert(
                    k + 1 - len(tube_extremities[(a, b)]),
                    all_nodes.vertex_coordinates(new_vkey))

        if len(tube_extremities[(u, v)]) == len(tube_extremities[(v, u)]):
            n = len(tube_extremities[(u, v)])
            l = network.edge_length(u, v) - 2 * radius
            m = (floor(l / radius) + 1) * 2
            pt_uv = tube_extremities[(u, v)]
            pt_vu = list(reversed(tube_extremities[(v, u)]))
            dmin = -1
            imin = None
            for i in range(n):
                distance = sum([
                    distance_point_point(pt_uv[j], pt_vu[i + j - len(pt_vu)])
                    for j in range(n)
                ])
                if dmin < 0 or distance < dmin:
                    dmin = distance
                    imin = i
            pt_vu = [pt_vu[imin + j - len(pt_vu)] for j in range(n)]

            # ab = pt_uv# + pt_uv[0:]
            # dc = pt_vu# + pt_vu[0:]
            # line = Polyline([ab[0], dc[0]])
            # ad = [line.point(i / (m - 1)) for i in range(m)]
            # bc = ad
            # vertices, faces = discrete_coons_patch(ab, bc, dc, ad)
            # tri_faces = []
            # for (a, b, c, d) in faces:
            # 	tri_faces += [[a, b, c], [a, c, d]] # reverse?
            # beams.append(Mesh.from_vertices_and_faces(vertices, tri_faces))

            array = [pt_uv]
            for i in range(int(m)):
                polygon = []
                for j in range(int(n)):
                    u = pt_uv[j]
                    v = pt_vu[j]
                    polygon.append(
                        add_vectors(
                            scale_vector(u, (float(m) - 1 - float(i)) /
                                         float(m - 1)),
                            scale_vector(v,
                                         float(i) / float(m - 1))))
                array.append(polygon)
            array.append(pt_vu)
            for i in range(1, int(m + 2)):
                for j in range(int(n)):
                    vertices = [
                        array[i - 1][j - 1], array[i - 1][j], array[i][j - 1],
                        array[i][j]
                    ]  # create staggered pattern?
                    faces = [[3, 1, 0], [2, 3, 0]]
                    beams.append(cls.from_vertices_and_faces(vertices, faces))

    # return all_nodes
    # #return meshes_join_and_weld(beams)
    return meshes_join_and_weld([all_nodes] + beams)
Exemple #8
0
def volmesh_ud(volmesh,
               network,
               scale=0.5):
    """Computes temporary vertex coordinates for every halfface of a volmesh, for the visualisation of the unified diagram.

    Parameters
    ----------
    volmesh : VolMesh
        A volmesh object representing a polyhedral force diagram.
    network : Network
        A network object representing a polyhedral form diagram.
    scale : float
        Unified diagram scale factor,

    Returns
    -------
    halffaces : dictionary
        A dictionary of dictionaries: hfkey-{vkey: (x, y, z)}.
    prisms : dictionary
        A dictinoary of dictinoaries: uv - [face coordinates]

    Raises
    ------
    Exception
        If scale is 0, which means the unified diagram is equivalent to the polyhedral force diagram.
    Exception
        If scale is 0, which means the unified diagram is equivalent to the polyhedral form diagram.

    Notes
    -----
    - The prisms are implemented as convex hull of two halffaces for simplicity and to resolve any small geometric errors.
    - Unified diagram with a scale of 0 is equivalent to the polyhedral force diagram, while a scale of 1 is equivalent to the polyhedral form diagram.

    """

    # --------------------------------------------------------------------------
    #   0. evaluate unified diagram scale
    # --------------------------------------------------------------------------
    if scale == 0:
        raise Exception("A unified diagram with a scale of 0 is equivalent to the polyhedral force diagram.")

    if scale == 1:
        raise Exception("A unified diagram with a scale of 1 is equivalent to the polyhedral form diagram.")

    assert 0 < scale and scale < 1, "Scale needs to be between 0 and 1."

    # --------------------------------------------------------------------------
    #   1. current positions of diagrams
    # --------------------------------------------------------------------------
    volmesh_center = volmesh.centroid()
    network_center = network.datastructure_centroid()
    translation    = subtract_vectors(volmesh_center, network_center)

    # --------------------------------------------------------------------------
    #   2. get base points
    # --------------------------------------------------------------------------
    base_xyz = {}

    for vkey in network.vertex:
        init_xyz       = network.vertex_coordinates(vkey)
        base_xyz[vkey] = add_vectors(init_xyz, translation)

    # --------------------------------------------------------------------------
    #   3. compute scaled halffaces
    # --------------------------------------------------------------------------
    halffaces = {}

    for ckey in volmesh.cell:
        cell_hfs = volmesh.cell_halffaces(ckey)
        for hfkey in cell_hfs:
            hf_vertices = {}
            for vkey in volmesh.halfface_vertices(hfkey):
                xyz = volmesh.vertex_coordinates(vkey)
                arm = scale_vector(subtract_vectors(xyz, base_xyz[ckey]), scale)
                hf_vertices[vkey] = add_vectors(base_xyz[ckey], arm)
            halffaces[hfkey] = hf_vertices

    # --------------------------------------------------------------------------
    #   4. compute prism faces
    # --------------------------------------------------------------------------
    prism_faces = {}

    for u, v in network.edges():
        u_hfkey, v_hfkey = volmesh.cell_pair_halffaces(u, v)
        u_pts   = halffaces[u_hfkey].values()
        v_pts   = halffaces[v_hfkey].values()
        pt_list = u_pts + v_pts
        prism   = convex_hull(u_pts + v_pts)  # face as indices of pt_list
        face_list = []
        for face in prism:
            face_xyz = [pt_list[i] for i in face]  # get face xyz in order
            face_list.append(face_xyz)
        prism_faces[(u, v)] = face_list

    # --------------------------------------------------------------------------

    return halffaces, prism_faces