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)
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
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]]))
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)
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
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