Exemplo n.º 1
0
def test_meshio_interface(triangle_mesh_2d):
    meshio_mesh = triangle_mesh_2d.to_meshio()
    new_mesh = TriangleMesh.from_meshio(meshio_mesh)

    np.testing.assert_allclose(new_mesh.points, triangle_mesh_2d.points)
    np.testing.assert_allclose(new_mesh.cells, triangle_mesh_2d.cells)
    np.testing.assert_allclose(new_mesh.labels, triangle_mesh_2d.labels)
Exemplo n.º 2
0
    def generate_contour(
        self,
        level: float = None,
    ):
        """Generate contours using marching cubes algorithm.

        Also generates an envelope around the entire data volume
        corresponding to the bounding box.

        The bounding box equals the dimensions of the data volume.

        Parameters
        ----------
        level : float, optional
            Contour value to search for isosurfaces (i.e. the threshold value).
            By default takes the average of the min and max value. Can be
            ignored if a binary image is passed to `Mesher3D`.
        """
        from nanomesh.mesh import TriangleMesh

        points, cells, *_ = measure.marching_cubes(
            self.image,
            level=level,
            allow_degenerate=False,
        )

        mesh = TriangleMesh(points=points, cells=cells)

        bbox = BoundingBox.from_shape(self.image.shape)
        mesh = generate_envelope(mesh, bbox=bbox)

        logger.info(f'Generated contour with {len(mesh.cells)} cells')

        self.contour = mesh
Exemplo n.º 3
0
def test_compare_with_mesh():
    image = np.zeros([5, 5])

    points = np.array([
        [0, 0],
        [0, 2],
        [2, 2],
        [2, 0],
        [3, 3],
        [3, 4],
        [4, 4],
        [4, 3],
    ])
    cells = np.array([
        [0, 1, 2],
        [0, 3, 2],
        [4, 5, 6],
        [4, 7, 6],
    ])

    # 1: small square, 0: big square
    labels = np.array([0, 0, 1, 1])
    mesh = TriangleMesh(points=points, cells=cells, labels=labels)

    compare_mesh_with_image(image, mesh)
Exemplo n.º 4
0
def simple_mesh():
    return TriangleMesh(points=np.array([
        [0., 0.],
        [0., 1.],
        [1., 1.],
        [1., 0.],
    ]),
                        cells=np.array([[1, 0, 3], [3, 2, 1]]))
Exemplo n.º 5
0
def mesh():
    """Box triangle mesh."""
    points = np.array([[0., 0., 0.], [10., 0., 0.], [0., 20., 0.],
                       [10., 20., 0.], [0., 0., 30.], [10., 0., 30.],
                       [0., 20., 30.], [10., 20., 30.]])
    cells = np.array([[0, 4, 6], [0, 6, 2], [5, 1, 3], [5, 3, 7], [0, 1, 5],
                      [0, 5, 4], [6, 7, 3], [6, 3, 2], [1, 0, 2], [1, 2, 3],
                      [4, 5, 7], [4, 7, 6]])

    return TriangleMesh(points=points, cells=cells)
Exemplo n.º 6
0
def add_corner_points(mesh: TriangleMesh, bbox: BoundingBox) -> None:
    """Add corner points from bounding box to mesh points.

    Parameters
    ----------
    mesh : TriangleMesh
        Mesh to add corner points to.
    bbox : BoundingBox
        Container for the bounding box coordinates.
    """
    corners = bbox.to_points()
    mesh.points = np.vstack([mesh.points, corners])
Exemplo n.º 7
0
def compare_mesh_with_image(image: np.ndarray, mesh: TriangleMesh):
    """Compare mesh with image.

    Parameters
    ----------
    image : 2D array
        Image to compare mesh with
    mesh : TriangleMesh
        Triangle mesh to plot on image

    Returns
    -------
    ax : matplotlib.Axes
    """
    fig, ax = plt.subplots()

    mesh.plot_mpl(ax=ax)

    ax.imshow(image)
    ax.axis('image')
    ax.set_xticks([])
    ax.set_yticks([])

    return ax
Exemplo n.º 8
0
def close_side(mesh: TriangleMesh,
               *,
               side: str,
               bbox: BoundingBox,
               ax: plt.Axes = None):
    """Fill a side of the bounding box with triangles.

    Parameters
    ----------
    mesh : TriangleMesh
        Input contour mesh.
    side : str
        Side of the volume to close. Must be one of
        `left`, `right`, `top`, `bottom`, `front`, `back`.
    bbox : BoundingBox
        Coordinates of the bounding box.
    ax : plt.Axes, optional
        Plot the generated side on a matplotlib axis.

    Returns
    -------
    mesh : TriangleMesh
        Triangle mesh with the given side closed.

    Raises
    ------
    ValueError
        When the value of `side` is invalid.
    """
    from nanomesh.mesh import TriangleMesh
    all_points = mesh.points

    if side == 'top':
        edge_col = 2
        edge_value = bbox.zmin
    elif side == 'bottom':
        edge_col = 2
        edge_value = bbox.zmax
    elif side == 'left':
        edge_col = 1
        edge_value = bbox.ymin
    elif side == 'right':
        edge_col = 1
        edge_value = bbox.ymax
    elif side == 'front':
        edge_col = 0
        edge_value = bbox.xmin
    elif side == 'back':
        edge_col = 0
        edge_value = bbox.xmax
    else:
        raise ValueError('Side must be one of `right`, `left`, `bottom`'
                         f'`top`, `front`, `back`. Got {side=}')

    keep_cols = [col for col in (0, 1, 2) if col != edge_col]
    is_edge = all_points[:, edge_col] == edge_value

    coords = all_points[is_edge][:, keep_cols]

    edge_mesh = simple_triangulate(points=coords, opts='')
    cells = edge_mesh.cells_dict['triangle'].copy()

    shape = cells.shape
    new_cells = cells.ravel()

    mesh_edge_index = np.argwhere(is_edge).flatten()
    new_edge_index = np.arange(len(mesh_edge_index))
    mapping = np.vstack([new_edge_index, mesh_edge_index])

    mask = np.in1d(new_cells, mapping[0, :])
    new_cells[mask] = mapping[1,
                              np.searchsorted(mapping[0, :], new_cells[mask])]
    new_cells = new_cells.reshape(shape)

    new_labels = np.ones(len(new_cells))

    points = all_points
    cells = np.vstack([mesh.cells, new_cells])
    labels = np.hstack([mesh.labels, new_labels])

    mesh = TriangleMesh(points=points, cells=cells, labels=labels)

    if ax:
        edge_mesh.plot(ax=ax)
        ax.set_title(side)

    return mesh
Exemplo n.º 9
0
def pad(mesh: TriangleMesh,
        *,
        side: str,
        width: int,
        label: int = None) -> TriangleMesh:
    """Pad a triangle mesh (3D).

    Parameters
    ----------
    mesh : TriangleMesh
        The mesh to pad.
    side : str
        Side to pad, must be one of `left`, `right`, `top`,
        `bottom`, `back`, `front`.
    width : int
        Width of the padded area.
    label : int, optional
        The label to assign to the padded area. If not defined, generates the
        next unique label based on the existing ones.

    Returns
    -------
    new_mesh : TriangleMesh
        Padded tetrahedral mesh.

    Raises
    ------
    ValueError
        When the value of `side` is invalid.
    """
    if label is None:
        label = mesh.labels.max() + 1

    if width == 0:
        return mesh

    bbox = BoundingBox.from_points(mesh.points)

    if side == 'top':
        edge_col = 2
        edge_value = bbox.zmax
        extra_coords = np.array([
            [bbox.xmin, bbox.ymin, bbox.zmax + width],
            [bbox.xmin, bbox.ymax, bbox.zmax + width],
            [bbox.xmax, bbox.ymin, bbox.zmax + width],
            [bbox.xmax, bbox.ymax, bbox.zmax + width],
        ])
        column_order = (0, 1, 1, 0)
    elif side == 'bottom':
        edge_col = 2
        edge_value = bbox.zmin
        extra_coords = np.array([
            [bbox.xmin, bbox.ymin, bbox.zmin - width],
            [bbox.xmin, bbox.ymax, bbox.zmin - width],
            [bbox.xmax, bbox.ymin, bbox.zmin - width],
            [bbox.xmax, bbox.ymax, bbox.zmin - width],
        ])
        column_order = (0, 1, 1, 0)
    elif side == 'left':
        edge_col = 1
        edge_value = bbox.ymin
        extra_coords = np.array([
            [bbox.xmin, bbox.ymin - width, bbox.zmin],
            [bbox.xmin, bbox.ymin - width, bbox.zmax],
            [bbox.xmax, bbox.ymin - width, bbox.zmin],
            [bbox.xmax, bbox.ymin - width, bbox.zmax],
        ])
        column_order = (0, 2, 2, 0)
    elif side == 'right':
        edge_col = 1
        edge_value = bbox.ymax
        extra_coords = np.array([
            [bbox.xmin, bbox.ymax + width, bbox.zmin],
            [bbox.xmin, bbox.ymax + width, bbox.zmax],
            [bbox.xmax, bbox.ymax + width, bbox.zmin],
            [bbox.xmax, bbox.ymax + width, bbox.zmax],
        ])
        column_order = (0, 2, 2, 0)
    elif side == 'front':
        edge_col = 0
        edge_value = bbox.xmin
        extra_coords = np.array([
            [bbox.xmin - width, bbox.ymin, bbox.zmin],
            [bbox.xmin - width, bbox.ymin, bbox.zmax],
            [bbox.xmin - width, bbox.ymax, bbox.zmin],
            [bbox.xmin - width, bbox.ymax, bbox.zmax],
        ])
        column_order = (1, 2, 2, 1)
    elif side == 'back':
        edge_col = 0
        edge_value = bbox.xmax
        extra_coords = np.array([
            [bbox.xmax + width, bbox.ymin, bbox.zmin],
            [bbox.xmax + width, bbox.ymin, bbox.zmax],
            [bbox.xmax + width, bbox.ymax, bbox.zmin],
            [bbox.xmax + width, bbox.ymax, bbox.zmax],
        ])
        column_order = (1, 2, 2, 1)
    else:
        raise ValueError('Side must be one of `right`, `left`, `bottom`'
                         f'`top`, `front`, `back`. Got {side=}')

    n_points = len(mesh.points)
    points = np.vstack([mesh.points, extra_coords])

    new_triangles = [
        np.array((0, 1, 2)) + n_points,
        np.array((3, 1, 2)) + n_points,
    ]

    for corner, col in zip(extra_coords, column_order):
        connect_to = np.argwhere((points[:, edge_col] == edge_value)
                                 & (points[:, col] == corner[col]))

        additional_points = np.argwhere(
            extra_coords[:, col] == corner[col]) + n_points

        first, last = additional_points
        first_point = points[first]

        sorted_by_distance = np.argsort(
            np.linalg.norm(first_point - points[connect_to].squeeze(), axis=1))
        connect_to = connect_to[sorted_by_distance]
        connect_to = np.vstack([connect_to, last]).squeeze()

        for pair in pairwise(connect_to):
            tri = np.hstack((first, pair))
            new_triangles.append(tri)

    new_triangles = np.array(new_triangles).squeeze()

    cells = np.vstack([mesh.cells, new_triangles])

    new_mesh = mesh.__class__(
        points=points,
        cells=cells,
        region_markers=mesh.region_markers,
    )

    # add marker for new region
    center = extra_coords.mean(axis=0)
    center[col] = (center[col] + edge_value) / 2

    new_mesh.add_region_marker(RegionMarker(label, center))

    return new_mesh
Exemplo n.º 10
0
def triangle_mesh():
    """Generate mesh.

    This mesh is a cube with a rectangular 'pore' through the middle.
    """
    points = np.array([
        # cube
        [0.0, 0.0, 0.0],  # A
        [4.0, 0.0, 0.0],  # B
        [4.0, 4.0, 0.0],  # C
        [0.0, 4.0, 0.0],  # D
        [0.0, 0.0, 4.0],  # E
        [4.0, 0.0, 4.0],  # F
        [4.0, 4.0, 4.0],  # G
        [0.0, 4.0, 4.0],  # H
        # inside rectangle ('pore')
        [1.0, 1.0, 0.0],  # a
        [3.0, 1.0, 0.0],  # b
        [3.0, 3.0, 0.0],  # c
        [1.0, 3.0, 0.0],  # d
        [1.0, 1.0, 4.0],  # e
        [3.0, 1.0, 4.0],  # f
        [3.0, 3.0, 4.0],  # g
        [1.0, 3.0, 4.0],  # h
    ])

    cells = np.array([
        # top face
        [0, 11, 8],
        [1, 8, 9],
        [2, 9, 10],
        [3, 10, 11],
        [0, 8, 1],
        [1, 9, 2],
        [2, 10, 3],
        [3, 11, 0],
        # side faces
        [0, 1, 5],
        [5, 4, 0],
        [1, 2, 6],
        [6, 5, 1],
        [3, 2, 6],
        [6, 7, 3],
        [0, 3, 7],
        [7, 4, 0],
        # bottom face
        [4, 15, 12],
        [5, 12, 13],
        [6, 13, 14],
        [7, 14, 15],
        [4, 12, 5],
        [5, 13, 6],
        [6, 14, 7],
        [7, 15, 4],
        # inside rectangle ('pore')
        [8, 9, 10],
        [10, 11, 8],
        [8, 9, 13],
        [13, 12, 8],
        [9, 10, 14],
        [14, 13, 9],
        [11, 10, 14],
        [14, 15, 11],
        [8, 11, 15],
        [15, 12, 8],
        [13, 14, 15],
        [15, 12, 13],
    ])

    mesh = TriangleMesh(points=points, cells=cells)
    return mesh