hub/venv/lib/python3.7/site-packages/trimesh/parent.py

230 lines
6.5 KiB
Python

"""
parent.py
-------------
The base class for Trimesh, PointCloud, and Scene objects
"""
import abc
import numpy as np
from . import caching
from . import transformations
from .util import ABC
class Geometry(ABC):
"""Parent of geometry classes.
The `Geometry` object is the parent object of geometry classes, including:
Trimesh, PointCloud, and Scene objects.
By decorating a method with `abc.abstractmethod` it just means the objects
that inherit from `Geometry` MUST implement those methods.
"""
@abc.abstractproperty
def bounds(self):
pass
@abc.abstractproperty
def extents(self):
pass
@abc.abstractmethod
def apply_transform(self, matrix):
pass
@abc.abstractmethod
def is_empty(self):
pass
@abc.abstractmethod
def crc(self):
pass
@abc.abstractmethod
def md5(self):
pass
def __repr__(self):
"""
Print quick summary of the current geometry without
computing properties.
"""
elements = []
if hasattr(self, 'vertices'):
# for Trimesh and PointCloud
elements.append('vertices.shape={}'.format(
self.vertices.shape))
if hasattr(self, 'faces'):
# for Trimesh
elements.append('faces.shape={}'.format(
self.faces.shape))
if hasattr(self, 'geometry') and isinstance(
self.geometry, dict):
# for Scene
elements.append('len(geometry)={}'.format(
len(self.geometry)))
if 'Voxel' in type(self).__name__:
# for VoxelGrid objects
elements.append(str(self.shape)[1:-1])
return '<trimesh.{}({})>'.format(
type(self).__name__, ', '.join(elements))
def apply_translation(self, translation):
"""
Translate the current mesh.
Parameters
----------
translation : (3,) float
Translation in XYZ
"""
translation = np.asanyarray(translation, dtype=np.float64)
if translation.shape != (3,):
raise ValueError('Translation must be (3,)!')
matrix = np.eye(4)
matrix[:3, 3] = translation
return self.apply_transform(matrix)
def apply_scale(self, scaling):
"""
Scale the mesh.
Parameters
----------
scaling : float or (3,) float
Scale factor to apply to the mesh
"""
matrix = transformations.scale_and_translate(scale=scaling)
# apply_transform will work nicely even on negative scales
return self.apply_transform(matrix)
def apply_obb(self):
"""
Apply the oriented bounding box transform to the current mesh.
This will result in a mesh with an AABB centered at the
origin and the same dimensions as the OBB.
Returns
----------
matrix : (4, 4) float
Transformation matrix that was applied
to mesh to move it into OBB frame
"""
matrix = self.bounding_box_oriented.primitive.transform
matrix = np.linalg.inv(matrix)
self.apply_transform(matrix)
return matrix
@abc.abstractmethod
def copy(self):
pass
@abc.abstractmethod
def show(self):
pass
@caching.cache_decorator
def bounding_box(self):
"""
An axis aligned bounding box for the current mesh.
Returns
----------
aabb : trimesh.primitives.Box
Box object with transform and extents defined
representing the axis aligned bounding box of the mesh
"""
from . import primitives
transform = np.eye(4)
# translate to center of axis aligned bounds
transform[:3, 3] = self.bounds.mean(axis=0)
aabb = primitives.Box(transform=transform,
extents=self.extents,
mutable=False)
return aabb
@caching.cache_decorator
def bounding_box_oriented(self):
"""
An oriented bounding box for the current mesh.
Returns
---------
obb : trimesh.primitives.Box
Box object with transform and extents defined
representing the minimum volume oriented
bounding box of the mesh
"""
from . import primitives, bounds
to_origin, extents = bounds.oriented_bounds(self)
obb = primitives.Box(transform=np.linalg.inv(to_origin),
extents=extents,
mutable=False)
return obb
@caching.cache_decorator
def bounding_sphere(self):
"""
A minimum volume bounding sphere for the current mesh.
Note that the Sphere primitive returned has an unpadded, exact
sphere_radius so while the distance of every vertex of the current
mesh from sphere_center will be less than sphere_radius, the faceted
sphere primitive may not contain every vertex
Returns
--------
minball : trimesh.primitives.Sphere
Sphere primitive containing current mesh
"""
from . import primitives, nsphere
center, radius = nsphere.minimum_nsphere(self)
minball = primitives.Sphere(center=center,
radius=radius,
mutable=False)
return minball
@caching.cache_decorator
def bounding_cylinder(self):
"""
A minimum volume bounding cylinder for the current mesh.
Returns
--------
mincyl : trimesh.primitives.Cylinder
Cylinder primitive containing current mesh
"""
from . import primitives, bounds
kwargs = bounds.minimum_cylinder(self)
mincyl = primitives.Cylinder(mutable=False, **kwargs)
return mincyl
@caching.cache_decorator
def bounding_primitive(self):
"""
The minimum volume primitive (box, sphere, or cylinder) that
bounds the mesh.
Returns
---------
bounding_primitive : object
Smallest primitive which bounds the mesh:
trimesh.primitives.Sphere
trimesh.primitives.Box
trimesh.primitives.Cylinder
"""
options = [self.bounding_box_oriented,
self.bounding_sphere,
self.bounding_cylinder]
volume_min = np.argmin([i.volume for i in options])
bounding_primitive = options[volume_min]
return bounding_primitive