from __future__ import annotations
from typing import TYPE_CHECKING
import matplotlib.pyplot as plt
import numpy as np
import pyvista as pv
import scipy
from .._doc import doc
from .._tetgen_wrapper import tetrahedralize
from ._mesh import Mesh
from ._mixin import PruneZ0Mixin
if TYPE_CHECKING:
import open3d
from nanomesh import MeshContainer
[docs]@doc(Mesh,
prefix='Data class for triangle meshes',
dim_points='2 or 3',
dim_cells='3')
class TriangleMesh(Mesh, PruneZ0Mixin, cell_dim=3):
cell_type = 'triangle'
[docs] def plot(self, **kwargs):
"""Shortcut for :meth:`TriangleMesh.plot_mpl` or
:meth:`TriangleMesh.plot_itk` depending on dimensions."""
if self.dimensions == 2:
return self.plot_mpl(**kwargs)
else:
return self.plot_itk(**kwargs)
[docs] def plot_mpl(self, *args, **kwargs) -> plt.Axes:
"""Simple triangle mesh plot using :mod::mod:`matplotlib`. See
:func:`plotting.trianglemeshplot` for details.
Parameters
----------
*args
Arguments passed to :func:`plotting.trianglemeshplot`
**kwargs
Keyword arguments passed to :func:`plotting.trianglemeshplot`
Returns
-------
plt.Axes
"""
from ..plotting import trianglemeshplot
return trianglemeshplot(self, *args, **kwargs)
[docs] def to_trimesh(self):
"""Return instance of :class:`trimesh.Trimesh`."""
import trimesh
return trimesh.Trimesh(vertices=self.points, faces=self.cells)
[docs] def to_open3d(self) -> 'open3d.geometry.TriangleMesh':
"""Return instance of :class:`open3d.geometry.TriangleMesh`."""
import open3d
return open3d.geometry.TriangleMesh(
vertices=open3d.utility.Vector3dVector(self.points),
triangles=open3d.utility.Vector3iVector(self.cells))
[docs] def to_polydata(self) -> 'pv.PolyData':
"""Return instance of :class:`pyvista.Polydata`."""
points = self.points
cells = self.cells
# preprend 3 to indicate number of points per cell
stacked_cells = np.hstack(np.insert(cells, 0, values=3,
axis=1)) # type: ignore
return pv.PolyData(points, stacked_cells, n_faces=len(cells))
[docs] @classmethod
def from_open3d(cls, mesh: 'open3d.geometry.TriangleMesh') -> TriangleMesh:
"""Return instance of :class:`TriangleMesh` from open3d."""
points = np.asarray(mesh.vertices)
cells = np.asarray(mesh.triangles)
return cls(points=points, cells=cells)
[docs] @classmethod
def from_scipy(cls, mesh: 'scipy.spatial.qhull.Delaunay') -> TriangleMesh:
"""Return instance of :class:`TriangleMesh` from
:class:`scipy.spatial.Delaunay` object."""
points = mesh.points
cells = mesh.simplices
return cls(points=points, cells=cells)
[docs] @classmethod
def from_trimesh(cls, mesh) -> TriangleMesh:
"""Return instance of :class:`TriangleMesh` from :mod:`trimesh`."""
return cls(points=mesh.vertices, cells=mesh.faces)
[docs] @classmethod
def from_triangle_dict(cls, dct: dict) -> TriangleMesh:
"""Return instance of :class:`TriangleMesh` from triangle results
dict."""
from .mesh_container import MeshContainer
mesh = MeshContainer.from_triangle_dict(dct)
return mesh.get('triangle')
[docs] def optimize(self,
*,
method='CVT (block-diagonal)',
tol: float = 1.0e-3,
max_num_steps: int = 10,
**kwargs) -> TriangleMesh:
"""Optimize mesh using :mod:`optimesh`.
Parameters
----------
method : str, optional
Method name
tol : float, optional
Tolerance
max_num_steps : int, optional
Maximum number of optimization steps.
**kwargs
Arguments to pass to :func:`optimesh.optimize_points_cells`
Returns
-------
TriangleMesh
"""
import optimesh
points, cells = optimesh.optimize_points_cells(
X=self.points,
cells=self.cells,
method=method,
tol=tol,
max_num_steps=max_num_steps,
**kwargs,
)
return TriangleMesh(points=points, cells=cells)
[docs] @doc(tetrahedralize,
prefix='Tetrahedralize mesh using :func:`tetrahedralize`')
def tetrahedralize(self, **kwargs) -> 'MeshContainer':
mesh = tetrahedralize(self, **kwargs)
return mesh