trimesh.util

util.py

Standalone functions which require only imports from numpy and the standard library.

Other libraries may be imported must be wrapped in try/except blocks or imported inside of a function

class trimesh.util.FunctionRegistry(**kwargs)

Bases: Mapping

Non-overwritable mapping of string keys to functions.

This allows external packages to register additional implementations of common functionality without risk of breaking implementations provided by trimesh.

See trimesh.voxel.morphology for example usage.

__init__(**kwargs)
trimesh.util.allclose(a, b, atol: float = 1e-08)

A replacement for np.allclose that does few checks and validation and as a result is faster.

Parameters:
  • a (np.ndarray) – To be compared

  • b (np.ndarray) – To be compared

  • atol (float) – Acceptable distance between a and b to be “close”

Return type:

bool indicating if all elements are within atol.

trimesh.util.append_faces(vertices_seq, faces_seq)

Given a sequence of zero-indexed faces and vertices combine them into a single array of faces and a single array of vertices.

Parameters:
  • vertices_seq ((n, ) sequence of (m, d) float) – Multiple arrays of verticesvertex arrays

  • faces_seq ((n, ) sequence of (p, j) int) – Zero indexed faces for matching vertices

Returns:

  • vertices ((i, d) float) – Points in space

  • faces ((j, 3) int) – Reference vertex indices

trimesh.util.array_to_encoded(array, dtype=None, encoding='base64')

Export a numpy array to a compact serializable dictionary.

Parameters:
  • array (array) – Any numpy array

  • dtype (str or None) – Optional dtype to encode array

  • encoding (str) – ‘base64’ or ‘binary’

Returns:

encoded – Has keys: ‘dtype’: str, of dtype ‘shape’: tuple of shape ‘base64’: str, base64 encoded string

Return type:

dict

trimesh.util.array_to_string(array, col_delim=' ', row_delim='\n', digits=8, value_format='{}')

Convert a 1 or 2D array into a string with a specified number of digits and delimiter. The reason this exists is that the basic numpy array to string conversions are surprisingly bad.

Parameters:
  • array ((n,) or (n, d) float or int) – Data to be converted If shape is (n,) only column delimiter will be used

  • col_delim (str) – What string should separate values in a column

  • row_delim (str) – What string should separate values in a row

  • digits (int) – How many digits should floating point numbers include

  • value_format (str) – Format string for each value or sequence of values If multiple values per value_format it must divide into array evenly.

Returns:

formatted – String representation of original array

Return type:

str

trimesh.util.attach_to_log(level=10, handler=None, loggers=None, colors=True, capture_warnings=True, blacklist=None)

Attach a stream handler to all loggers.

Parameters:
  • level (enum) – Logging level, like logging.INFO

  • handler (None or logging.Handler) – Handler to attach

  • loggers (None or (n,) logging.Logger) – If None, will try to attach to all available

  • colors (bool) – If True try to use colorlog formatter

  • blacklist ((n,) str) – Names of loggers NOT to attach to

trimesh.util.bounds_tree(bounds)

Given a set of axis aligned bounds create an r-tree for broad-phase collision detection.

Parameters:

bounds ((n, 2D) or (n, 2, D) float) – Non-interleaved bounds where D=dimension E.G a 2D bounds tree: [(minx, miny, maxx, maxy), …]

Returns:

tree – Tree containing bounds by index

Return type:

Rtree

trimesh.util.comment_strip(text, starts_with='#', new_line='\n')

Strip comments from a text block.

Parameters:
  • text (str) – Text to remove comments from

  • starts_with (str) – Character or substring that starts a comment

  • new_line (str) – Character or substring that ends a comment

Returns:

stripped – Text with comments stripped

Return type:

str

trimesh.util.compress(info, **kwargs)

Compress data stored in a dict.

Parameters:
  • info (dict) – Data to compress in form: {file name in archive: bytes or file-like object}

  • kwargs (dict) – Passed to zipfile.ZipFile

Returns:

compressed – Compressed file data

Return type:

bytes

trimesh.util.concatenate(a, b=None)

Concatenate two or more meshes.

Parameters:
  • a (trimesh.Trimesh) – Mesh or list of meshes to be concatenated object, or list of such

  • b (trimesh.Trimesh) – Mesh or list of meshes to be concatenated

Returns:

result – Concatenated mesh

Return type:

trimesh.Trimesh

trimesh.util.convert_like(item, like)

Convert an item to have the dtype of another item

Parameters:
  • item (any) – Item to be converted

  • like (any) – Object with target dtype If None, item is returned unmodified

Returns:

result

Return type:

item, but in dtype of like

trimesh.util.decimal_to_digits(decimal, min_digits=None) int

Return the number of digits to the first nonzero decimal.

Parameters:
  • decimal (float)

  • min_digits (int, minimum number of digits to return)

Returns:

digits

Return type:

int, number of digits to the first nonzero decimal

trimesh.util.decode_keys(store, encoding='utf-8')

If a dictionary has keys that are bytes decode them to a str.

Parameters:

store (dict) – Dictionary with data

Returns:

result – Values are untouched but keys that were bytes are converted to ASCII strings.

Return type:

dict

Example

In [1]: d Out[1]: {1020: ‘nah’, b’hi’: ‘stuff’}

In [2]: trimesh.util.decode_keys(d) Out[2]: {1020: ‘nah’, ‘hi’: ‘stuff’}

trimesh.util.decode_text(text, initial='utf-8')

Try to decode byte input as a string.

Tries initial guess (UTF-8) then if that fails it uses chardet to try another guess before failing.

Parameters:
  • text (bytes) – Data that might be a string

  • initial (str) – Initial guess for text encoding.

Returns:

decoded – Data as a string

Return type:

str

trimesh.util.decompress(file_obj, file_type)

Given an open file object and a file type, return all components of the archive as open file objects in a dict.

Parameters:
  • file_obj (file-like) – Containing compressed data

  • file_type (str) – File extension, ‘zip’, ‘tar.gz’, etc

Returns:

decompressed – Data from archive in format {file name : file-like}

Return type:

dict

trimesh.util.diagonal_dot(a, b)

Dot product by row of a and b.

There are a lot of ways to do this though performance varies very widely. This method uses a dot product to sum the row and avoids function calls if at all possible.

Comparing performance of some equivalent versions: ``` In [1]: import numpy as np; import trimesh

In [2]: a = np.random.random((10000, 3))

In [3]: b = np.random.random((10000, 3))

In [4]: %timeit (a * b).sum(axis=1) 1000 loops, best of 3: 181 us per loop

In [5]: %timeit np.einsum(‘ij,ij->i’, a, b) 10000 loops, best of 3: 62.7 us per loop

In [6]: %timeit np.diag(np.dot(a, b.T)) 1 loop, best of 3: 429 ms per loop

In [7]: %timeit np.dot(a * b, np.ones(a.shape[1])) 10000 loops, best of 3: 61.3 us per loop

In [8]: %timeit trimesh.util.diagonal_dot(a, b) 10000 loops, best of 3: 55.2 us per loop ```

Parameters:
  • a ((m, d) float) – First array

  • b ((m, d) float) – Second array

Returns:

result – Dot product of each row

Return type:

(m,) float

trimesh.util.distance_to_end(file_obj)

For an open file object how far is it to the end

Parameters:

file_obj (open file-like object)

Returns:

distance

Return type:

int, bytes to end of file

trimesh.util.encoded_to_array(encoded)

Turn a dictionary with base64 encoded strings back into a numpy array.

Parameters:

encoded (dict) –

Has keys:

dtype: string of dtype shape: int tuple of shape base64: base64 encoded string of flat array binary: decode result coming from numpy.tobytes

Returns:

array

Return type:

numpy array

trimesh.util.euclidean(a, b) float

DEPRECATED: use np.linalg.norm(a - b) instead of this.

trimesh.util.generate_basis(z, epsilon=1e-12)

Generate an arbitrary basis (also known as a coordinate frame) from a given z-axis vector.

Parameters:
  • z ((3,) float) – A vector along the positive z-axis.

  • epsilon (float) – Numbers smaller than this considered zero.

Returns:

  • x ((3,) float) – Vector along x axis.

  • y ((3,) float) – Vector along y axis.

  • z ((3,) float) – Vector along z axis.

trimesh.util.grid_arange(bounds, step)

Return a grid from an (2,dimension) bounds with samples step distance apart.

Parameters:
  • bounds ((2,dimension) list of [[min x, min y, etc], [max x, max y, etc]])

  • step (float, or (dimension) floats, separation between points)

Returns:

grid

Return type:

(n, dimension), points inside the specified bounds

trimesh.util.grid_linspace(bounds, count)

Return a grid spaced inside a bounding box with edges spaced using np.linspace.

Parameters:
  • bounds ((2,dimension) list of [[min x, min y, etc], [max x, max y, etc]])

  • count (int, or (dimension,) int, number of samples per side)

Returns:

grid

Return type:

(n, dimension) float, points in the specified bounds

trimesh.util.has_module(name: str) bool

Check to see if a module is installed by name without actually importing the module.

Parameters:

name (str) – The name of the module to check

Returns:

installed – True if module is installed

Return type:

bool

trimesh.util.is_binary_file(file_obj)

Returns True if file has non-ASCII characters (> 0x7F, or 127) Should work in both Python 2 and 3

trimesh.util.is_ccw(points, return_all=False)

Check if connected 2D points are counterclockwise.

Parameters:
  • points ((n, 2) float) – Connected points on a plane

  • return_all (bool) – Return polygon area and centroid or just counter-clockwise.

Returns:

  • ccw (bool) – True if points are counter-clockwise

  • area (float) – Only returned if return_centroid

  • centroid ((2,) float) – Centroid of the polygon.

trimesh.util.is_file(obj)

Check if an object is file-like

Parameters:

obj (object) – Any object type to be checked

Returns:

is_file – True if object is a file

Return type:

bool

trimesh.util.is_instance_named(obj, name)

Given an object, if it is a member of the class ‘name’, or a subclass of ‘name’, return True.

Parameters:
  • obj (instance) – Some object of some class

  • name (str) – The name of the class we want to check for

Returns:

is_instance – Whether the object is a member of the named class

Return type:

bool

trimesh.util.is_none(obj) bool

Check to see if an object is None or not.

Handles the case of np.array(None) as well.

Parameters:

obj (object) – Any object type to be checked

Returns:

is_none – True if obj is None or numpy None-like

Return type:

bool

trimesh.util.is_pathlib(obj)

Check if the object is a pathlib.Path or subclass.

Parameters:

obj (object) – Object to be checked

Returns:

is_pathlib – Is the input object a pathlib path

Return type:

bool

trimesh.util.is_sequence(obj) bool

Check if an object is a sequence or not.

Parameters:

obj (object) – Any object type to be checked

Returns:

is_sequence – True if object is sequence

Return type:

bool

trimesh.util.is_shape(obj, shape, allow_zeros: bool = False) bool

Compare the shape of a numpy.ndarray to a target shape, with any value less than zero being considered a wildcard

Note that if a list-like object is passed that is not a numpy array, this function will not convert it and will return False.

Parameters:
  • obj (np.ndarray) – Array to check the shape on

  • shape (list or tuple) – Any negative term will be considered a wildcard Any tuple term will be evaluated as an OR

  • allow_zeros (bool) – if False, zeros do not match negatives in shape

Returns:

shape_ok – True if shape of obj matches query shape

Return type:

bool

Examples

In [1]: a = np.random.random((100, 3))

In [2]: a.shape Out[2]: (100, 3)

In [3]: trimesh.util.is_shape(a, (-1, 3)) Out[3]: True

In [4]: trimesh.util.is_shape(a, (-1, 3, 5)) Out[4]: False

In [5]: trimesh.util.is_shape(a, (100, -1)) Out[5]: True

In [6]: trimesh.util.is_shape(a, (-1, (3, 4))) Out[6]: True

In [7]: trimesh.util.is_shape(a, (-1, (4, 5))) Out[7]: False

trimesh.util.is_string(obj) bool

Check if an object is a string.

Parameters:

obj (object) – Any object type to be checked

Returns:

is_string – True if obj is a string

Return type:

bool

trimesh.util.isclose(a, b, atol: float = 1e-08)

A replacement for np.isclose that does fewer checks and validation and as a result is roughly 4x faster.

Note that this is used in tight loops, and as such a and b MUST be np.ndarray, not list or “array-like”

Parameters:
  • a (np.ndarray) – To be compared

  • b (np.ndarray) – To be compared

  • atol (float) – Acceptable distance between a and b to be “close”

Returns:

close – Per-element closeness

Return type:

np.ndarray, bool

trimesh.util.jsonify(obj, **kwargs)

A version of json.dumps that can handle numpy arrays by creating a custom encoder for numpy dtypes.

Parameters:
  • obj (list, dict) – A JSON-serializable blob

  • kwargs (dict) – Passed to json.dumps

Returns:

dumped – JSON dump of obj

Return type:

str

trimesh.util.make_sequence(obj)

Given an object, if it is a sequence return, otherwise add it to a length 1 sequence and return.

Useful for wrapping functions which sometimes return single objects and other times return lists of objects.

Parameters:

obj (object) – An object to be made a sequence

Returns:

as_sequence – Contains input value

Return type:

(n,) sequence

trimesh.util.multi_dict(pairs)

Given a set of key value pairs, create a dictionary. If a key occurs multiple times, stack the values into an array.

Can be called like the regular dict(pairs) constructor

Parameters:

pairs ((n, 2) array of key, value pairs)

Returns:

result

Return type:

dict, with all values stored (rather than last with regular dict)

trimesh.util.pairwise(iterable)

For an iterable, group values into pairs.

Parameters:

iterable ((m, ) list) – A sequence of values

Returns:

pairs – Pairs of sequential values

Return type:

(n, 2)

Example

In [1]: data Out[1]: [0, 1, 2, 3, 4, 5, 6]

In [2]: list(trimesh.util.pairwise(data)) Out[2]: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

trimesh.util.row_norm(data)

Compute the norm per-row of a numpy array.

This is identical to np.linalg.norm(data, axis=1) but roughly three times faster due to being less general.

In [3]: %timeit trimesh.util.row_norm(a) 76.3 us +/- 651 ns per loop

In [4]: %timeit np.linalg.norm(a, axis=1) 220 us +/- 5.41 us per loop

Parameters:

data ((n, d) float) – Input 2D data to calculate per-row norm of

Returns:

norm – Norm of each row of input array

Return type:

(n,) float

trimesh.util.sigfig_int(values, sigfig)

Convert a set of floating point values into integers with a specified number of significant figures and an exponent.

Parameters:
  • values ((n,) float or int) – Array of values

  • sigfig ((n,) int) – Number of significant figures to keep

Returns:

  • as_int ((n,) int) – Every value[i] has sigfig[i] digits

  • multiplier ((n, int)) – Exponent, so as_int * 10 ** multiplier is the same order of magnitude as the input

trimesh.util.sigfig_round(values, sigfig=1)

Round a single value to a specified number of significant figures.

Parameters:
  • values (float) – Value to be rounded

  • sigfig (int) – Number of significant figures to reduce to

Returns:

rounded – Value rounded to the specified number of significant figures

Return type:

float

Examples

In [1]: trimesh.util.round_sigfig(-232453.00014045456, 1) Out[1]: -200000.0

In [2]: trimesh.util.round_sigfig(.00014045456, 1) Out[2]: 0.0001

In [3]: trimesh.util.round_sigfig(.00014045456, 4) Out[3]: 0.0001405

trimesh.util.spherical_to_vector(spherical)

Convert an array of (n, 2) spherical angles to (n, 3) unit vectors.

Parameters:

spherical ((n , 2) float) – Angles, in radians

Returns:

vectors – Unit vectors

Return type:

(n, 3) float

trimesh.util.split_extension(file_name, special=None)

Find the file extension of a file name, including support for special case multipart file extensions (like .tar.gz)

Parameters:
  • file_name (str) – File name

  • special (list of str) – Multipart extensions eg: [‘tar.bz2’, ‘tar.gz’]

Returns:

extension – Last characters after a period, or a value from ‘special’

Return type:

str

trimesh.util.stack_3D(points, return_2D=False)

For a list of (n, 2) or (n, 3) points return them as (n, 3) 3D points, 2D points on the XY plane.

Parameters:
  • points ((n, 2) or (n, 3) float) – Points in either 2D or 3D space

  • return_2D (bool) – Were the original points 2D?

Returns:

  • points ((n, 3) float) – Points in space

  • is_2D (bool) – [OPTIONAL] if source points were (n, 2)

trimesh.util.stack_lines(indices)

Stack a list of values that represent a polyline into individual line segments with duplicated consecutive values.

Parameters:

indices ((m,) any) – List of items to be stacked

Returns:

stacked – Stacked items

Return type:

(n, 2) any

Examples

In [1]: trimesh.util.stack_lines([0, 1, 2]) Out[1]: array([[0, 1],

[1, 2]])

In [2]: trimesh.util.stack_lines([0, 1, 2, 4, 5]) Out[2]: array([[0, 1],

[1, 2], [2, 4], [4, 5]])

In [3]: trimesh.util.stack_lines([[0, 0], [1, 1], [2, 2], [3, 3]]) Out[3]: array([[0, 0],

[1, 1], [1, 1], [2, 2], [2, 2], [3, 3]])

trimesh.util.structured_array_to_string(array, col_delim=' ', row_delim='\n', digits=8, value_format='{}')

Convert an unstructured array into a string with a specified number of digits and delimiter. The reason thisexists is that the basic numpy array to string conversionsare surprisingly bad.

Parameters:
  • array ((n,) or (n, d) float or int) – Data to be converted If shape is (n,) only column delimiter will be used

  • col_delim (str) – What string should separate values in a column

  • row_delim (str) – What string should separate values in a row

  • digits (int) – How many digits should floating point numbers include

  • value_format (str) – Format string for each value or sequence of values If multiple values per value_format it must divide into array evenly.

Returns:

formatted – String representation of original array

Return type:

str

trimesh.util.submesh(mesh, faces_sequence, repair=True, only_watertight=False, min_faces=None, append=False)

Return a subset of a mesh.

Parameters:
  • mesh (Trimesh) – Source mesh to take geometry from

  • faces_sequence (sequence (p,) int) – Indexes of mesh.faces

  • repair (bool) – Try to make submeshes watertight

  • only_watertight (bool) – Only return submeshes which are watertight

  • append (bool) – Return a single mesh which has the faces appended, if this flag is set, only_watertight is ignored

Returns:

  • if append (Trimesh object)

  • else list of Trimesh objects

trimesh.util.to_ascii(text)

Force a string or other to ASCII text ignoring errors.

Parameters:

text (any) – Input to be converted to ASCII string

Returns:

ascii – Input as an ASCII string

Return type:

str

trimesh.util.tolist(data)

Ensure that any arrays or dicts passed containing numpy arrays are properly converted to lists

Parameters:

data (any) – Usually a dict with some numpy arrays as values

Returns:

result – JSON-serializable version of data

Return type:

any

trimesh.util.triangle_fans_to_faces(fans)

Convert fans of m + 2 vertex indices in fan format to m triangles

Parameters:

fans ((n,) list of (m + 2,) int) – Vertex indices

Returns:

faces – Vertex indices representing triangles

Return type:

(m, 3) int

trimesh.util.triangle_strips_to_faces(strips)

Convert a sequence of triangle strips to (n, 3) faces.

Processes all strips at once using np.concatenate and is significantly faster than loop-based methods.

From the OpenGL programming guide describing a single triangle strip [v0, v1, v2, v3, v4]:

Draws a series of triangles (three-sided polygons) using vertices v0, v1, v2, then v2, v1, v3 (note the order), then v2, v3, v4, and so on. The ordering is to ensure that the triangles are all drawn with the same orientation so that the strip can correctly form part of a surface.

Parameters:

strips ((n,) list of (m,) int) – Vertex indices

Returns:

faces – Vertex indices representing triangles

Return type:

(m, 3) int

trimesh.util.type_bases(obj, depth=4)

Return the bases of the object passed.

trimesh.util.type_named(obj, name)

Similar to the type() builtin, but looks in class bases for named instance.

Parameters:
  • obj (any) – Object to look for class of

  • name (str) – Nnme of class

Returns:

class – Camed class, or None

Return type:

Optional[Callable]

trimesh.util.unique_id(length=12)

Generate a random alphaNumber unique identifier using UUID logic.

Parameters:

length (int) – Length of desired identifier

Returns:

unique – Unique alphaNumber identifier

Return type:

str

trimesh.util.unique_name(start, contains, counts=None)

Deterministically generate a unique name not contained in a dict, set or other grouping with __includes__ defined. Will create names of the form “start_10” and increment accordingly.

Parameters:
  • start (str) – Initial guess for name.

  • contains (dict, set, or list) – Bundle of existing names we can not use.

  • counts (None or dict) – Maps name starts encountered before to increments in order to speed up finding a unique name as otherwise it potentially has to iterate through all of contains. Should map to “how many times has this start been attempted, i.e. counts[start]: int. Note that this will be mutated in-place by this function!

Returns:

unique – A name that is not contained in contains

Return type:

str

trimesh.util.unitize(vectors, check_valid=False, threshold=None)

Unitize a vector or an array or row-vectors.

Parameters:
  • vectors ((n,m) or (j) float) – Vector or vectors to be unitized

  • check_valid (bool) – If set, will return mask of nonzero vectors

  • threshold (float) – Cutoff for a value to be considered zero.

Returns:

  • unit ((n,m) or (j) float) – Input vectors but unitized

  • valid ((n,) bool or bool) – Mask of nonzero vectors returned if check_valid

trimesh.util.vector_hemisphere(vectors, return_sign=False)

For a set of 3D vectors alter the sign so they are all in the upper hemisphere.

If the vector lies on the plane all vectors with negative Y will be reversed.

If the vector has a zero Z and Y value vectors with a negative X value will be reversed.

Parameters:
  • vectors ((n, 3) float) – Input vectors

  • return_sign (bool) – Return the sign mask or not

Returns:

  • oriented ((n, 3) float) – Vectors with same magnitude as source but possibly reversed to ensure all vectors are in the same hemisphere.

  • sign ((n,) float) – [OPTIONAL] sign of original vectors

trimesh.util.vector_to_spherical(cartesian)

Convert a set of cartesian points to (n, 2) spherical unit vectors.

Parameters:

cartesian ((n, 3) float) – Points in space

Returns:

spherical – Angles, in radians

Return type:

(n, 2) float

trimesh.util.vstack_empty(tup)

A thin wrapper for numpy.vstack that ignores empty lists.

Parameters:

tup (tuple or list of arrays) – With the same number of columns

Returns:

stacked – With same number of columns as constituent arrays.

Return type:

(n, d) array

trimesh.util.wrap_as_stream(item)

Wrap a string or bytes object as a file object.

Parameters:

item (str or bytes) – Item to be wrapped

Returns:

wrapped – Contains data from item

Return type:

file-like object

trimesh.util.write_encoded(file_obj, stuff, encoding='utf-8')

If a file is open in binary mode and a string is passed, encode and write.

If a file is open in text mode and bytes are passed decode bytes to str and write.

Assumes binary mode if file_obj does not have a ‘mode’ attribute (e.g. io.BufferedRandom).

Parameters:
  • file_obj (file object) – With ‘write’ and ‘mode’

  • stuff (str or bytes) – Stuff to be written

  • encoding (str) – Encoding of text

trimesh.util.zero_pad(data, count, right=True)
Parameters:
  • data ((n,)) – 1D array

  • count (int) – Minimum length of result array

Returns:

padded – 1D array where m >= count

Return type:

(m,)