예제 #1
0
def clip(source_mesh: Mesh, plane: Plane, vicinity_tol=1e-3, name=None):
    """Return a new mesh containing the source mesh clipped by the plane.

    Parameters
    ----------
    source_mesh : Mesh
        The mesh to be clipped.
    plane : Plane, optional
        The clipping plane.
    vicinity_tol : float, optional
        The absolute tolerance to consider en vertex is on the plane. Default is 1e-3.
    name: string, optional
        A name for the new clipped mesh.
    """
    vertices_data = _vertices_positions_wrt_plane(source_mesh, plane,
                                                  vicinity_tol)

    nb_vertices_above_or_on_plane = np.count_nonzero(
        vertices_data['vertices_above_mask']
        | vertices_data['vertices_on_mask'])
    nb_vertices_below_or_on_plane = np.count_nonzero(
        vertices_data['vertices_below_mask']
        | vertices_data['vertices_on_mask'])

    if nb_vertices_above_or_on_plane == source_mesh.nb_vertices:
        LOG.warning(
            f"Clipping {source_mesh.name} by {plane}: all vertices are removed."
        )
        clipped_mesh = Mesh(None, None)
        clipped_mesh._clipping_data = dict(faces_ids=[])

    elif nb_vertices_below_or_on_plane == source_mesh.nb_vertices:
        LOG.info(f"Clipping {source_mesh.name} by {plane}: no action.")
        clipped_mesh = source_mesh.copy()
        clipped_mesh._clipping_data = dict(
            faces_ids=list(range(source_mesh.nb_faces)))

    else:
        upper_mesh, crown_mesh, lower_mesh = _partition_mesh(
            vertices_data, source_mesh)

        if crown_mesh.nb_faces > 0:
            clipped_crown_mesh = _clip_crown(crown_mesh, plane)
            clipped_mesh = lower_mesh + clipped_crown_mesh
            clipped_mesh._clipping_data = {
                'faces_ids':
                np.concatenate(
                    (lower_mesh._clipping_data['faces_ids'],
                     clipped_crown_mesh._clipping_data['faces_ids']))
            }
        else:
            clipped_mesh = lower_mesh

    if name is None:
        clipped_mesh.name = f'{source_mesh.name}_clipped'
    clipped_mesh.remove_unused_vertices()

    return clipped_mesh
예제 #2
0
def _clip_crown(crown_mesh, plane):
    """Performs the clipping operation of the crown_mesh and determines the obtained boundaries.
    This is the heart method of the class.
    """
    vertices = crown_mesh.vertices

    above_vertices_mask = crown_mesh._clipping_data['above_vertices_mask']
    below_vertices_mask = crown_mesh._clipping_data['below_vertices_mask']

    on_vertices_mask = crown_mesh._clipping_data['on_vertices_mask']
    # TODO: Vertices pre-projection to be done here

    vertices_distances = crown_mesh._clipping_data['vertices_distances']

    # Init
    clipped_crown_mesh_faces = list()
    clipped_crown_mesh_relative_faces_ids = list()

    direct_boundary_edges = dict()
    inv_boundary_edges = dict()
    intersections_vertices = list()

    index_new_vertices = crown_mesh.nb_vertices

    for face_id in range(crown_mesh.nb_faces):

        face = crown_mesh.get_face(face_id)

        # # Determining the type of face clipping
        v_above_face = np.where(above_vertices_mask[face])[0]
        v_on_face = np.where(on_vertices_mask[face])[0]
        v_below_face = np.where(below_vertices_mask[face])[0]

        nb_above = len(v_above_face)
        nb_on = len(v_on_face)
        nb_below = len(v_below_face)

        face_type = str(nb_above) + str(nb_on) + str(nb_below)

        if face_type == '202':
            #    0*-----*3
            #     |     |
            # ----o-----o----
            #     |     |
            #    1*-----*2
            if v_above_face[1] == v_above_face[0] + 1:
                face = np.roll(face, -v_above_face[1])
            p0, p1, p2, p3 = vertices[face]
            ileft = plane.get_edge_intersection(p0, p1)
            iright = plane.get_edge_intersection(p2, p3)
            intersections_vertices += [ileft, iright]
            boundary_edge = [index_new_vertices, index_new_vertices + 1]
            clipped_crown_mesh_faces.append(
                [index_new_vertices, face[1], face[2], index_new_vertices + 1])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 2

        elif face_type == '301':
            #      *2
            #     / \
            #    /   \
            #   /     \
            # 3*       *1
            #   \     /
            # ---o---o---
            #     \ /
            #      *0
            face = np.roll(face, -v_below_face[0])
            p0, p1, p3 = vertices[face[[0, 1, 3]]]
            ileft = plane.get_edge_intersection(p0, p3)
            iright = plane.get_edge_intersection(p0, p1)
            intersections_vertices += [ileft, iright]
            boundary_edge = [index_new_vertices, index_new_vertices + 1]
            clipped_crown_mesh_faces.append([
                index_new_vertices, face[0], index_new_vertices + 1,
                index_new_vertices
            ])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 2

        elif face_type == '103':
            #      *0
            #     / \
            # ---o---o---
            #   /     \
            # 1* - - - *3
            #   \     /
            #    \   /
            #     \ /
            #      *2
            face = np.roll(face, -v_above_face[0])
            p0, p1, p3 = vertices[face[[0, 1, 3]]]
            ileft = plane.get_edge_intersection(p0, p1)
            iright = plane.get_edge_intersection(p0, p3)
            intersections_vertices += [ileft, iright]
            boundary_edge = [index_new_vertices, index_new_vertices + 1]
            clipped_crown_mesh_faces.append(
                [index_new_vertices, face[1], face[3], index_new_vertices + 1])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            clipped_crown_mesh_faces.append(
                [face[1], face[2], face[3], face[1]])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 2

        elif face_type == '102':
            #      *O
            #     / \
            # ---o---o---
            #   /     \
            # 1*-------*2
            face = np.roll(face, -v_above_face[0])
            p0, p1, p2 = vertices[face]
            ileft = plane.get_edge_intersection(p0, p1)
            iright = plane.get_edge_intersection(p0, p2)
            intersections_vertices += [ileft, iright]
            boundary_edge = [index_new_vertices, index_new_vertices + 1]
            clipped_crown_mesh_faces.append(
                [index_new_vertices, face[1], face[2], index_new_vertices + 1])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 2

        elif face_type == '201':  # done
            #  2*-------*1
            #    \     /
            #  ---o---o---
            #      \ /
            #       *0
            face = np.roll(face, -v_below_face[0])
            p0, p1, p2 = vertices[face]
            ileft = plane.get_edge_intersection(p0, p2)
            iright = plane.get_edge_intersection(p0, p1)
            intersections_vertices += [ileft, iright]
            boundary_edge = [index_new_vertices, index_new_vertices + 1]
            clipped_crown_mesh_faces.append([
                index_new_vertices, face[0], index_new_vertices + 1,
                index_new_vertices
            ])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 2

        elif face_type == '211':
            #        *3                   *1
            #       / \                  / \
            #      /   *2       or     2*   \
            #    0/   /                  \   \0
            # ---*---o---              ---o---*---
            #     \ /                      \ /
            #      *1                       *3
            #

            face = np.roll(face, -v_on_face[0])
            if vertices_distances[face[1]] < 0.:
                p1, p2 = vertices[face[[1, 2]]]
                iright = plane.get_edge_intersection(p1, p2)
                intersections_vertices.append(iright)
                boundary_edge = [face[0], index_new_vertices]
                clipped_crown_mesh_faces.append(
                    [face[0], face[1], index_new_vertices, face[0]])
            else:
                p2, p3 = vertices[face[[2, 3]]]
                ileft = plane.get_edge_intersection(p2, p3)
                intersections_vertices.append(ileft)
                boundary_edge = [index_new_vertices, face[0]]
                clipped_crown_mesh_faces.append(
                    [index_new_vertices, face[3], face[0], index_new_vertices])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 1

        elif face_type == '112':
            #       *3                     *1
            #      / \                    / \
            #  ---*---o---      or    ---o---*---
            #     0\   \                /   /0
            #       \   *2            2*   /
            #        \ /                \ /
            #         *1                 *3
            face = np.roll(face, -v_on_face[0])
            if vertices_distances[face[1]] < 0.:
                p2, p3 = vertices[face[[2, 3]]]
                iright = plane.get_edge_intersection(p2, p3)
                intersections_vertices.append(iright)
                boundary_edge = [face[0], index_new_vertices]
                clipped_crown_mesh_faces.append(
                    [face[0], face[1], face[2], index_new_vertices])
            else:
                p1, p2 = vertices[face[[1, 2]]]
                ileft = plane.get_edge_intersection(p1, p2)
                intersections_vertices.append(ileft)
                boundary_edge = [index_new_vertices, face[0]]
                clipped_crown_mesh_faces.append(
                    [index_new_vertices, face[2], face[3], face[0]])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 1

        elif face_type == '013':
            # -----*-----
            #     / \
            #    /   \
            #   *     *
            #    \   /
            #     \ /
            #      *
            boundary_edge = None
            clipped_crown_mesh_faces.append(list(face))
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '210' or face_type == '310':
            #   *-------*               *
            #    \ 210 /               / \ 310
            #     \   /               *   *
            #      \ /                 \ /
            #   ----*----           ----*----
            boundary_edge = None

        elif face_type == '111':
            #        *2              *1
            #       /|               |\
            #      / |               | \
            #  ---*--o---    or   ---o--*---
            #     0\ |               | /0
            #       \|               |/
            #        *1              *2
            face = np.roll(face, -v_on_face[0])
            p1, p2 = vertices[face[[1, 2]]]
            if vertices_distances[face[1]] < 0.:
                iright = plane.get_edge_intersection(p1, p2)
                intersections_vertices.append(iright)
                boundary_edge = [face[0], index_new_vertices]
                clipped_crown_mesh_faces.append(
                    [face[0], face[1], index_new_vertices, face[0]])
            else:
                ileft = plane.get_edge_intersection(p1, p2)
                intersections_vertices.append(ileft)
                boundary_edge = [index_new_vertices, face[0]]
                clipped_crown_mesh_faces.append(
                    [index_new_vertices, face[2], face[0], index_new_vertices])
            clipped_crown_mesh_relative_faces_ids.append(face_id)
            index_new_vertices += 1

        elif face_type == '120':
            #         *O
            #        / \
            #       /   \
            #     1/     \2
            # ----*-------*----
            # face = np.roll(face, -v_above_face[0])
            # boundary_edge = [face[1], face[2]]
            # FIXME: quick fix here : robust ?
            boundary_edge = None

        elif face_type == '021':
            #  ----*-------*----
            #      2\     /1
            #        \   /
            #         \ /
            #          *0
            face = np.roll(face, -v_below_face[0])
            boundary_edge = [face[2], face[1]]
            face = list(face)
            face.append(face[0])
            clipped_crown_mesh_faces.append(face)
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '022':
            # ----*-----*----
            #    0|     |3
            #     |     |
            #    1*-----*2
            if v_on_face[1] == v_on_face[0] + 1:
                face = np.roll(face, -v_on_face[1])
            boundary_edge = [face[0], face[3]]
            clipped_crown_mesh_faces.append(list(face))
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '012':
            #   ------*------
            #        / \
            #       /   \
            #      /     \
            #     *-------*
            boundary_edge = None
            face = list(face)
            face.append(face[0])
            clipped_crown_mesh_faces.append(face)
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '220':
            #    0*-----*3
            #     |     |
            #    1|     |2
            # ----*-----*----

            # if v_above_face[1] == v_above_face[0] + 1:
            #     face = np.roll(face, -v_above_face[1])
            # boundary_edge = [face[1], face[2]]
            # FIXME: quick fix here : robust ?
            boundary_edge = None

        elif face_type == '121':
            #       *0
            #      / \
            #     /   \
            # ---*-----*---
            #    1\   /3
            #      \ /
            #       *2
            face = np.roll(face, -v_above_face[0])
            boundary_edge = [face[1], face[3]]
            clipped_crown_mesh_faces.append(
                [face[1], face[2], face[3], face[1]])
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '300' or face_type == '400':
            #       *               *-----*
            #      / \              |     |
            #     /300\      or     | 400 |
            #    *-----*            *-----*
            # ____________       ______________
            boundary_edge = None

        elif face_type == '003':
            #  -----------
            #       *
            #      / \
            #     /   \
            #    *-----*
            boundary_edge = None
            face = list(face)
            face.append(face[0])
            clipped_crown_mesh_faces.append(face)
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '004':
            #  ---------------
            #      *-----*
            #      |     |
            #      |     |
            #      *-----*
            boundary_edge = None
            clipped_crown_mesh_faces.append(list(face))
            clipped_crown_mesh_relative_faces_ids.append(face_id)

        elif face_type == '030' or face_type == '040':
            # Face is totally on the plane --> rare case...
            boundary_edge = None

        else:
            raise Exception("Face %u clipping case %s not known." %
                            (face_id, face_type))

        # Building boundary connectivity
        if boundary_edge is not None:
            direct_boundary_edges[boundary_edge[0]] = boundary_edge[1]
            inv_boundary_edges[boundary_edge[1]] = boundary_edge[0]

    if len(intersections_vertices) > 0:
        vertices = np.concatenate((vertices, intersections_vertices))

    clipped_crown_mesh = Mesh(vertices, clipped_crown_mesh_faces)
    clipped_crown_mesh._clipping_data = {
        'faces_ids':
        crown_mesh._clipping_data['faces_ids']
        [clipped_crown_mesh_relative_faces_ids]
    }

    return clipped_crown_mesh