예제 #1
0
def two_tetrahedrons():

    vertices_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])
    vertices_2 = np.array([[2, 0, 0], [3, 0, 0], [2, 1, 0], [2, 0, 2]])

    faces_1 = np.array([[0, 1, 2], [0, 2, 3], [0, 1, 3], [1, 2, 3], [0, 2, 1],
                        [0, 3, 2], [0, 3, 1], [1, 3, 2]])
    faces_2 = np.array([[0, 1, 2], [0, 2, 3], [0, 1, 3], [1, 2, 3], [0, 2, 1],
                        [0, 3, 2], [0, 3, 1], [1, 3, 2]])

    mesh_1 = Trimesh(vertices_1, faces_1)
    mesh_2 = Trimesh(vertices_2, faces_2)

    return mesh_1, mesh_2
예제 #2
0
def box(size=(1, 1, 1), max_edge=0.1):

    box = trimesh.creation.box(extents=size)
    vertices, faces = subdivide_to_size(box.vertices, box.faces, max_edge)
    mesh = Trimesh(vertices, faces)

    return mesh
예제 #3
0
def set_new_mesh_vertices(mesh, vertices):

    mesh_new = Trimesh(vertices=vertices.copy(),
                       faces=mesh.faces,
                       process=False)

    return mesh_new
    def build(self):
        self._load_last_vertices()

        faces_count = (self.vertices.shape[0]) * (
            self.vertices.shape[1]) * 2 - 6
        self.faces = np.zeros((faces_count, 3), dtype=int)
        self.face_normals = np.zeros((faces_count, 3))
        self.next_face = 0

        for i in range(self.vertices.shape[0] - 1):
            for j in range(self.vertices.shape[1] - 1):
                self._add_face(i, j, i + 1, j, i, j + 1)
                if i != self.vertices.shape[0] - 2 or j != self.vertices.shape[
                        0] - 2:
                    self._add_face(i, j + 1, i + 1, j, i + 1, j + 1)
                else:
                    self._add_face(i, j + 1, i + 1, j, 0, 0)

        for i in range(0, self.vertices.shape[0] - 1):
            if i > 0:
                self._add_face(i, 0, 0, 0, i + 1, 0)
            if i < self.vertices.shape[0] - 2:
                self._add_face(i, -1, i + 1, -1, 0, 0)
        for j in range(0, self.vertices.shape[1] - 1):
            if j > 0:
                self._add_face(0, j, 0, j + 1, 0, 0)
            if j < self.vertices.shape[1] - 2:
                self._add_face(-1, j, 0, 0, -1, j + 1)

        return Trimesh(vertices=self.vertices.reshape(-1, 3),
                       faces=self.faces,
                       face_normals=self.face_normals,
                       process=False)
예제 #5
0
    def add_texture_to_mesh(mesh, K, image):
        f, ox, oy = K
        verts, faces = mesh.get_mesh_verts_faces(0)
        verts = verts.tolist()

        pix_pos = []
        for v in verts:
            x, y, z = v
            i = -x * f / z + K[1]
            j = -y * f / z + K[2]
            pix_pos.append([j, i])

        colors = []
        for i in pix_pos:
            try:
                colors.append(list(image[int(i[0])][int(i[1])]) + [1])
            except IndexError:
                print(f"Skipping index: {i}")
                pass

        textured_mesh = Trimesh(vertices=verts,
                                faces=faces,
                                vertex_colors=colors)

        return textured_mesh
예제 #6
0
def add_noise_to_mesh(mesh, noise):

    new_vertices = mesh.vertices.copy()
    new_vertices = new_vertices + noise

    new_mesh = Trimesh(new_vertices, mesh.faces, process=False)

    return new_mesh
예제 #7
0
def apply_transform(mesh, transforms):

    new_vertices = np.array(mesh.vertices.copy())
    new_vertices = np.stack(
        [new_vertices, np.ones(len(new_vertices))[:, None]], axis=1)
    new_vertices = np.matmul(transforms, new_vertices)

    new_mesh = Trimesh(new_vertices, mesh.faces, process=False)

    return new_mesh
예제 #8
0
def mesh_subsample(mesh, vertices):

    num_vertices = len(vertices)
    new_faces = []
    for face in mesh.faces:
        if (face[0] < num_vertices) and (face[1] < num_vertices) and (
                face[2] < num_vertices):
            new_faces += [face]
    new_mesh = Trimesh(vertices, new_faces)

    return new_mesh
예제 #9
0
    def add_uv_texture_to_mesh(mesh, K, image, mask):
        f, ox, oy = K
        verts, faces = mesh.get_mesh_verts_faces(0)
        verts = verts.tolist()
        mesh = Trimesh(vertices=verts, faces=faces)
        mesh = filter_laplacian(mesh)
        verts = mesh.vertices
        faces = mesh.faces

        front_view_faces = MeshRCNNModel.get_front_view_faces(mesh)
        front_view_vertices = np.unique(np.array(front_view_faces))

        uv_map = []
        for vertex_index in range(len(verts)):
            if vertex_index in front_view_vertices:
                x, y, z = verts[vertex_index]
                i = int(-x * f / z + K[1]) / image.shape[1]
                j = int(y * f / z + K[2]) / image.shape[0]
            else:
                i = 0
                j = 0
            uv_map.append([i, j])

        # Average color calculation inside the mask
        color_mask = ~np.repeat(mask[:, :, np.newaxis], 3, axis=2)
        average_color = np.ma.array(image,
                                    mask=color_mask).mean(axis=0).mean(axis=0)

        # Assign average color to pixels outside of the mask
        image[:, :, 0] = np.where(~mask, average_color[0], image[:, :, 0])
        image[:, :, 1] = np.where(~mask, average_color[1], image[:, :, 1])
        image[:, :, 2] = np.where(~mask, average_color[2], image[:, :, 2])

        image_ = Image.fromarray(image)
        texture = TextureVisuals(uv=uv_map, image=image_)
        textured_mesh = Trimesh(vertices=verts, faces=faces, visual=texture)

        return textured_mesh
예제 #10
0
def plane(width=2, length=2, num_points=2500):

    x = np.linspace(0, length, num=int(np.sqrt(num_points)))
    y = np.linspace(0, width, num=int(np.sqrt(num_points)))
    x, y = np.meshgrid(x, y)
    z = np.zeros_like(x)
    tri = mtri.Triangulation(x.flatten(), y.flatten())

    faces = tri.triangles
    faces_dual = faces[:, [0, 2, 1]]
    faces = np.vstack([faces, faces_dual])
    vertices = np.array([x.flatten(), y.flatten(), z.flatten()]).T

    plane = Trimesh(vertices=vertices, faces=faces)

    return plane
예제 #11
0
def remove_duplicate_vertices(mesh):

    unique_vertices, unique_inverse = np.unique(mesh.vertices,
                                                axis=0,
                                                return_inverse=True)
    old2new_vertices = dict(zip(np.arange(len(mesh.vertices)), unique_inverse))
    new_faces = np.copy(mesh.faces)
    for i, face in enumerate(new_faces):
        new_face = np.array([
            old2new_vertices[face[0]], old2new_vertices[face[1]],
            old2new_vertices[face[2]]
        ])
        new_faces[i] = new_face
    new_mesh = Trimesh(unique_vertices, new_faces, process=False)

    return new_mesh, old2new_vertices
예제 #12
0
def monkey_saddle(num_points=2500):
    def f(x, y):
        return x**3 - 3 * x * y**2

    x = np.linspace(-1, 1, num=int(np.sqrt(num_points)))
    y = np.linspace(-1, 1, num=int(np.sqrt(num_points)))
    x, y = np.meshgrid(x, y)
    z = f(x, y)
    tri = mtri.Triangulation(x.flatten(), y.flatten())

    faces = tri.triangles
    faces_dual = faces[:, [0, 2, 1]]
    faces = np.vstack([faces, faces_dual])
    vertices = np.array([x.flatten(), y.flatten(), z.flatten()]).T

    saddle = Trimesh(vertices=vertices, faces=faces)

    return saddle
예제 #13
0
def concatenate_with_transforms(parts, transforms):

    concatenated_mesh = trimesh.util.concatenate(parts)
    concatenated_transforms = torch.cat(transforms, dim=0)

    unique_vertices, unique_inverse = np.unique(concatenated_mesh.vertices,
                                                axis=0,
                                                return_inverse=True)
    old2new_vertices = dict(
        zip(np.arange(len(concatenated_mesh.vertices)), unique_inverse))
    new_faces = np.copy(concatenated_mesh.faces)
    for i, face in enumerate(new_faces):
        new_face = np.array([
            old2new_vertices[face[0]], old2new_vertices[face[1]],
            old2new_vertices[face[2]]
        ])
        new_faces[i] = new_face

    new_transforms = torch.zeros((len(unique_vertices), 4, 4))
    for i in range(len(concatenated_transforms)):
        new_transforms[old2new_vertices[i]] = concatenated_transforms[i]
    new_mesh = Trimesh(unique_vertices, new_faces, process=False)

    return new_mesh, new_transforms
예제 #14
0
파일: extrusion.py 프로젝트: c3ypt1c/ddd
def extrude_triangulation(vertices,
                          faces,
                          height,
                          cap=True,
                          base=True,
                          transform=None):
    """
    Based on Trimesh extrude_triangulation, but allows to exclude cap and base.
    """
    vertices = np.asanyarray(vertices, dtype=np.float64)
    height = float(height)
    faces = np.asanyarray(faces, dtype=np.int64)

    if not util.is_shape(vertices, (-1, 2)):
        raise ValueError('Vertices must be (n,2)')
    if not util.is_shape(faces, (-1, 3)):
        raise ValueError('Faces must be (n,3)')
    if np.abs(height) < constants.tol.merge:
        raise ValueError('Height must be nonzero!')

    # Make sure triangulation winding is pointing up
    normal_test = triangles.normals([util.stack_3D(vertices[faces[0]])])[0]

    normal_dot = np.dot(normal_test, [0.0, 0.0, np.sign(height)])[0]

    # Make sure the triangulation is aligned with the sign of
    # the height we've been passed
    if normal_dot < 0.0: faces = np.fliplr(faces)

    # stack the (n,3) faces into (3*n, 2) edges
    edges = geometry.faces_to_edges(faces)
    edges_sorted = np.sort(edges, axis=1)
    # Edges which only occur once are on the boundary of the polygon
    # since the triangulation may have subdivided the boundary of the
    # shapely polygon, we need to find it again
    edges_unique = grouping.group_rows(edges_sorted, require_count=1)

    # (n, 2, 2) set of line segments (positions, not references)
    boundary = vertices[edges[edges_unique]]

    # We are creating two vertical  triangles for every 2D line segment
    # on the boundary of the 2D triangulation
    vertical = np.tile(boundary.reshape((-1, 2)), 2).reshape((-1, 2))
    vertical = np.column_stack(
        (vertical, np.tile([0, height, 0, height], len(boundary))))
    vertical_faces = np.tile([3, 1, 2, 2, 1, 0], (len(boundary), 1))
    vertical_faces += np.arange(len(boundary)).reshape((-1, 1)) * 4
    vertical_faces = vertical_faces.reshape((-1, 3))

    # Stack the (n,2) vertices with zeros to make them (n, 3)
    vertices_3D = util.stack_3D(vertices)

    # A sequence of zero- indexed faces, which will then be appended
    # with offsets to create the final mesh

    if not base and not cap:
        vertices_seq = [vertical]
        faces_seq = [vertical_faces]
    elif not base and cap:
        vertices_seq = [vertices_3D.copy() + [0.0, 0, height], vertical]
        faces_seq = [faces.copy(), vertical_faces]
    elif base and not cap:
        vertices_seq = [vertices_3D, vertical]
        faces_seq = [faces[:, ::-1], vertical_faces]
    else:
        vertices_seq = [
            vertices_3D,
            vertices_3D.copy() + [0.0, 0, height], vertical
        ]
        faces_seq = [faces[:, ::-1], faces.copy(), vertical_faces]

    # Append sequences into flat nicely indexed arrays
    vertices, faces = util.append_faces(vertices_seq, faces_seq)

    # Apply transform here to avoid later bookkeeping
    if transform is not None:
        vertices = transformations.transform_points(vertices, transform)
        # If the transform flips the winding flip faces back so that the normals will be facing outwards
        if transformations.flips_winding(transform):
            faces = np.ascontiguousarray(
                np.fliplr(faces))  # fliplr makes arrays non-contiguous

    # create mesh object with passed keywords
    mesh = Trimesh(vertices=vertices, faces=faces)

    return mesh
예제 #15
0
파일: extrusion.py 프로젝트: c3ypt1c/ddd
def extrude_coords(coords_a, coords_b, distance, base_height=0):

    vertices = []
    vertices.extend([(x, y, base_height) for x, y, *z in coords_a])
    vertices_b_idx = len(vertices)
    vertices.extend([(x, y, base_height + distance) for x, y, *z in coords_b])

    shape_a_idx = 0
    shape_b_idx = 0

    def va(shape_a_idx):
        return vertices[shape_a_idx]

    def vb(shape_b_idx):
        return vertices[(shape_b_idx) + vertices_b_idx]

    def ang(v):
        return (math.atan2(v[1], v[0]) + (math.pi * 2)) % (math.pi * 2)

    def diff(va, vb):
        return [va[0] - vb[0], va[1] - vb[1], va[2] - vb[2]]

    def distsqr(v):
        return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]

    faces = []
    finished_a = False
    finished_b = False
    last_tri = None
    while not (finished_a and finished_b):

        la = distsqr(diff(va(shape_a_idx + 1), vb(shape_b_idx))) if (
            shape_a_idx < len(coords_a) - 1) else float("inf")
        lb = distsqr(diff(vb(shape_b_idx + 1), va(shape_a_idx))) if (
            shape_b_idx < len(coords_b) - 1) else float("inf")
        aa = ang(va(shape_a_idx))
        aan = ang(va(shape_a_idx +
                     1)) if (shape_a_idx < len(coords_a) - 1) else float("inf")
        ab = ang(vb(shape_b_idx))
        abn = ang(vb(shape_b_idx +
                     1)) if (shape_b_idx < len(coords_b) - 1) else float("inf")

        #norm = 'l2'
        norm = 'l2'
        if norm == 'angle':
            advance_b = (abs(abn - aa) < abs(aan - ab))
        elif norm == 'l2':
            advance_b = lb < la

        if advance_b or finished_a:
            ntri = [
                shape_a_idx, shape_b_idx + vertices_b_idx,
                (shape_b_idx + 1) + vertices_b_idx
            ]
            shape_b_idx += 1
        elif not advance_b or finished_b:
            ntri = [
                shape_a_idx, shape_b_idx + vertices_b_idx, (shape_a_idx + 1)
            ]
            shape_a_idx += 1
        else:
            raise AssertionError()

        if last_tri == ntri: break

        faces.append(ntri)
        last_tri = ntri
        #print(ntri)

        if shape_a_idx >= len(coords_a) - 1:
            finished_a = True
        if shape_b_idx >= len(coords_b) - 1:
            finished_b = True

    #print(vertices)
    #print(faces)
    return Trimesh(vertices, faces)
예제 #16
0
파일: extrusion.py 프로젝트: c3ypt1c/ddd
def extrude_step(obj, shape, offset, cap=True, method=EXTRUSION_METHOD_WRAP):
    """
    Extrude a shape into another.
    """
    last_shape = obj.extra['_extrusion_last_shape']

    #obj = last_shape.individualize()
    #shape = shape.individualize()

    #obj_a.assert_single()
    #obj_b.assert_single()
    geom_a = last_shape.geom
    geom_b = shape.geom

    result = obj.copy()

    if geom_a is None or geom_a.is_empty:
        logger.debug(
            "Should be extruding from point or line, ignoring and returning argument."
        )
        # Previous step was empty, avoid destroy the object
        # TODO: this can be improved, previous could be point or line
        return result
    elif geom_a.type in ('MultiPolygon', 'GeometryCollection'):
        logger.warn(
            "Cannot extrude a step from a 'MultiPolygon' or 'GeometryCollection'."
        )
        return result

    if geom_b is None:
        logger.warn(
            "Cannot extrude-step to None (ignoring and returning argument).")
        return result
    elif geom_b.type in ('MultiPolygon', 'GeometryCollection'):
        logger.warn(
            "Cannot extrude a step to a 'MultiPolygon' or 'GeometryCollection' (skipping/flattening)."
        )
        geom_b = Point()
    elif geom_b.is_empty and method == EXTRUSION_METHOD_WRAP:
        logger.debug("Extruding to point (should be using line too).")
        geom_b = geom_a.centroid
    elif geom_b.type == "LineString" and method == EXTRUSION_METHOD_WRAP:
        geom_b = Polygon(list(geom_b.coords) + [geom_b.coords[0]])
    elif geom_b.is_empty and method == EXTRUSION_METHOD_SUBTRACT:
        logger.debug(
            "Cannot extrude subtract to empty geometry. Skipping / flattening."
        )
    elif geom_b.type == "LineString" and method == EXTRUSION_METHOD_SUBTRACT:
        logger.info(
            "Cannot extrude subtract to linestring. Skipping / flattening.")
        geom_b = Point()

    vertices = list(result.mesh.vertices) if result.mesh else []
    faces = list(result.mesh.faces) if result.mesh else []

    # Remove previous last cap before extruding.
    last_cap_idx = result.extra.get('_extrusion_last_cap_idx', None)
    if last_cap_idx is not None:
        faces = faces[:last_cap_idx]

    if not geom_b.is_empty:
        result.extra['_extrusion_last_shape'] = shape
        result.extra['_extrusion_last_offset'] = obj.extra.get(
            '_extrusion_last_offset', 0) + offset

    if not (geom_a.is_empty or geom_b.is_empty):

        mesh = None

        if method == EXTRUSION_METHOD_WRAP:
            mesh = extrude_between_geoms_wrap(
                geom_a, geom_b, offset,
                obj.extra.get('_extrusion_last_offset', 0))
        elif method == EXTRUSION_METHOD_SUBTRACT:
            try:
                mesh = extrude_between_geoms_subtract(
                    last_shape, shape, offset,
                    obj.extra.get('_extrusion_last_offset', 0))
            except DDDException as e:
                logger.error(
                    "Could not extrude subtract between geometries (%s): %s",
                    obj, e)
                mesh = None
                result.extra['_extrusion_last_shape'] = last_shape
                result.extra['_extrusion_last_offset'] = result.extra[
                    '_extrusion_last_offset'] - offset
        else:
            raise DDDException("Invalid extrusion method: %s", method)

        if mesh:
            faces = faces + [[
                f[0] + len(vertices), f[1] + len(vertices),
                f[2] + len(vertices)
            ] for f in mesh.faces]
            vertices = vertices + list(mesh.vertices)
            result.extra[
                '_extrusion_steps'] = result.extra['_extrusion_steps'] + 1

    result.extra['_extrusion_last_cap_idx'] = len(faces)

    if cap and not result.extra['_extrusion_last_shape'].geom.is_empty:
        #print(result.extra['_extrusion_last_shape'])
        #result.extra['_extrusion_last_shape'].dump()
        #print(result.extra['_extrusion_last_shape'].geom)
        try:
            cap_mesh = result.extra['_extrusion_last_shape'].triangulate(
            ).translate([0, 0,
                         result.extra.get('_extrusion_last_offset', 0)])

            if cap_mesh and cap_mesh.mesh:
                faces = faces + [[
                    f[0] + len(vertices), f[1] + len(vertices),
                    f[2] + len(vertices)
                ] for f in cap_mesh.mesh.faces]
                vertices = vertices + list(cap_mesh.mesh.vertices)
            else:
                result.extra['_extrusion_last_offset'] = result.extra[
                    '_extrusion_last_offset'] - offset
                cap_mesh = last_shape.triangulate().translate(
                    [0, 0, result.extra['_extrusion_last_offset']])
                faces = faces + [[
                    f[0] + len(vertices), f[1] + len(vertices),
                    f[2] + len(vertices)
                ] for f in cap_mesh.mesh.faces]
                vertices = vertices + list(cap_mesh.mesh.vertices)
        except Exception as e:
            logger.error(
                "Could not generate extrude cap triangulation (%s): %s",
                result.extra['_extrusion_last_shape'], e)
            cap_mesh = None

    # Merge
    if len(vertices) > 0 and len(faces) > 0:
        mesh = Trimesh(vertices, faces)
        mesh.merge_vertices()
        #mesh.fix_normals()
        result.mesh = mesh

    return result
예제 #17
0
파일: extrusion.py 프로젝트: jjmontesl/ddd
def extrude_coords(coords_a, coords_b, distance, base_height=0):

    # Note that last vertex in polygons is repeated, we ignore it and use modulus for referring to vertex indices
    # This reuses the vertices when closing the loop

    is_poly_a = (coords_a[0] == coords_a[-1]) and len(coords_a) > 1
    is_poly_b = (coords_b[0] == coords_b[-1]) and len(coords_b) > 1
    modulus_a = (len(coords_a) - 1) if is_poly_a else len(coords_a)
    modulus_b = (len(coords_b) - 1) if is_poly_b else len(coords_b)

    vertices = []
    vertices.extend([(x, y, base_height)
                     for x, y, *z in (coords_a[:-1] if is_poly_a else coords_a)
                     ])
    vertices_b_idx = len(vertices)
    vertices.extend([(x, y, base_height + distance)
                     for x, y, *z in (coords_b[:-1] if is_poly_b else coords_b)
                     ])

    shape_a_idx = 0
    shape_b_idx = 0

    def va(shape_a_idx):
        return vertices[shape_a_idx % modulus_a]

    def vb(shape_b_idx):
        return vertices[(shape_b_idx % modulus_b) + vertices_b_idx]

    def ang(v):
        return (math.atan2(v[1], v[0]) + (math.pi * 2)) % (math.pi * 2)

    def diff(va, vb):
        return [va[0] - vb[0], va[1] - vb[1], va[2] - vb[2]]

    def distsqr(v):
        return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]

    faces = []
    finished_a = False
    finished_b = False
    last_tri = None
    while not (finished_a and finished_b):

        la = distsqr(diff(va(shape_a_idx + 1), vb(shape_b_idx))) if (
            shape_a_idx < modulus_a) else float("inf")
        lb = distsqr(diff(vb(shape_b_idx + 1), va(shape_a_idx))) if (
            shape_b_idx < modulus_b) else float("inf")
        aa = ang(va(shape_a_idx))
        aan = ang(va(shape_a_idx +
                     1)) if (shape_a_idx < len(coords_a) - 1) else float("inf")
        ab = ang(vb(shape_b_idx))
        abn = ang(vb(shape_b_idx +
                     1)) if (shape_b_idx < len(coords_b) - 1) else float("inf")

        #norm = 'l2'
        norm = 'l2'
        if norm == 'angle':
            advance_b = (abs(abn - aa) < abs(aan - ab))
        elif norm == 'l2':
            advance_b = lb < la

        # Vertex modulus is used to handle repeated first-last vertex in polys
        if advance_b or finished_a:
            ntri = [
                shape_a_idx % modulus_a,
                shape_b_idx % modulus_b + vertices_b_idx,
                (shape_b_idx + 1) % modulus_b + vertices_b_idx
            ]
            shape_b_idx += 1
        elif not advance_b or finished_b:
            ntri = [
                shape_a_idx % modulus_a,
                shape_b_idx % modulus_b + vertices_b_idx,
                (shape_a_idx + 1) % modulus_a
            ]
            shape_a_idx += 1
        else:
            raise AssertionError()

        if last_tri == ntri: break

        #print(ntri)
        last_tri = ntri
        if ntri[0] != ntri[1] and ntri[0] != ntri[2] and ntri[1] != ntri[2]:
            faces.append(ntri)

        if shape_a_idx >= len(coords_a) - 1:
            finished_a = True
        if shape_b_idx >= len(coords_b) - 1:
            finished_b = True

    return Trimesh(vertices, faces)
예제 #18
0
def SplitByPlaneOneSide(mesh,
                        plane_normal,
                        plane_origin,
                        cap=False,
                        cached_dots=None,
                        reversed=False,
                        **kwargs):
    """
    Slice a mesh with a plane, returning a new mesh that is the
    portion of the original mesh to the positive normal side of the plane
    Parameters
    ---------
    mesh : Trimesh object
      Source mesh to slice
    plane_normal : (3,) float
      Normal vector of plane to intersect with mesh
    plane_origin :  (3,) float
      Point on plane to intersect with mesh
    cap : bool
      If True, cap the result with a triangulated polygon
    cached_dots : (n, 3) float
      If an external function has stored dot
      products pass them here to avoid recomputing
    kwargs : dict
      Passed to the newly created sliced mesh
    Returns
    ----------
    new_vertices : (n, 3) float
        Vertices of sliced mesh
    new_faces : (n, 3) int
        Faces of sliced mesh
    """
    # check input for none
    if mesh is None:
        return None

    # check input plane
    plane_normal = np.asanyarray(plane_normal, dtype=np.float64)
    plane_origin = np.asanyarray(plane_origin, dtype=np.float64)

    # check to make sure origins and normals have acceptable shape
    shape_ok = (
        (plane_origin.shape == (3, ) or util.is_shape(plane_origin,
                                                      (-1, 3))) and
        (plane_normal.shape == (3, ) or util.is_shape(plane_normal, (-1, 3)))
        and plane_origin.shape == plane_normal.shape)
    if not shape_ok:
        raise ValueError('plane origins and normals must be (n, 3)!')

    # start with copy of original mesh, faces, and vertices
    sliced_mesh = mesh.copy()
    vertices = mesh.vertices.copy()
    faces = mesh.faces.copy()

    # slice away specified planes
    for origin, normal in zip(plane_origin.reshape((-1, 3)),
                              plane_normal.reshape((-1, 3))):

        # calculate dots here if not passed in to save time
        # in case of cap
        if cached_dots is None:
            # dot product of each vertex with the plane normal indexed by face
            # so for each face the dot product of each vertex is a row
            # shape is the same as faces (n,3)
            dots = np.einsum('i,ij->j', normal, (vertices - origin).T)[faces]
        else:
            dots = cached_dots
        # save the new vertices and faces
        vertices, faces = intersections.slice_faces_plane(vertices=vertices,
                                                          faces=faces,
                                                          plane_normal=normal,
                                                          plane_origin=origin,
                                                          cached_dots=dots)

        # check if cap arg specified
        if cap:
            # check if mesh is watertight (can't cap if not)
            if not sliced_mesh.is_watertight:
                raise ValueError('Input mesh must be watertight to cap slice')
            path = sliced_mesh.section(plane_normal=normal,
                                       plane_origin=origin)
            if not path:
                if reversed:
                    return sliced_mesh
                else:
                    return None
            # transform Path3D onto XY plane for triangulation
            on_plane, to_3D = path.to_planar()

            # triangulate each closed region of 2D cap
            # without adding any new vertices
            v, f = [], []
            for polygon in on_plane.polygons_full:
                t = triangulate_polygon(polygon,
                                        triangle_args='pY',
                                        engine='triangle')
                v.append(t[0])
                f.append(t[1])

                if tol.strict:
                    # in unit tests make sure that our triangulation didn't
                    # insert any new vertices which would break watertightness
                    from scipy.spatial import cKDTree
                    # get all interior and exterior points on tree
                    check = [np.array(polygon.exterior.coords)]
                    check.extend(np.array(i.coords) for i in polygon.interiors)
                    tree = cKDTree(np.vstack(check))
                    # every new vertex should be on an old vertex
                    assert np.allclose(tree.query(v[-1])[0], 0.0)

            # append regions and reindex
            vf, ff = util.append_faces(v, f)

            # make vertices 3D and transform back to mesh frame
            vf = tf.transform_points(np.column_stack((vf, np.zeros(len(vf)))),
                                     to_3D)

            # check to see if our new faces are aligned with our normal
            #check = windings_aligned(vf[ff], normal)
            #
            ## if 50% of our new faces are aligned with the normal flip
            #if check.astype(np.float64).mean() > 0.5:
            #    ff = np.fliplr(ff)

            # add cap vertices and faces and reindex
            vertices, faces = util.append_faces([vertices, vf], [faces, ff])

            # Update mesh with cap (processing needed to merge vertices)
            sliced_mesh = Trimesh(vertices=vertices, faces=faces)
            vertices, faces = sliced_mesh.vertices.copy(
            ), sliced_mesh.faces.copy()

    return sliced_mesh
예제 #19
0
 def _getModelMesh(self, points):
     return Trimesh(vertices=points.T, faces=self.triangles)