trimesh.path.packing module

packing.py

Pack rectangular regions onto larger rectangular regions.

class trimesh.path.packing.RectangleBin(bounds)

Bases: object

An N-dimensional binary space partition tree for packing hyper-rectangles. Split logic is pure numpy but behaves similarly to scipy.spatial.Rectangle.

Mostly useful for packing 2D textures and 3D boxes and has not been tested outside of 2 and 3 dimensions.

Original article about using this for packing textures: http://www.blackpawn.com/texts/lightmaps/

__init__(bounds)

Create a rectangular bin.

Parameters:

bounds ((2, dimension *) float) – Bounds array are [mins, maxes]

property extents

Bounding box size.

Returns:

extents – Edge lengths of bounding box

Return type:

(dimension,) float

insert(size, rotate=True)

Insert a rectangle into the bin.

Parameters:

size ((dimension,) float) – Size of rectangle to insert/

Returns:

inserted – Position of insertion in the tree or None if the insertion was unsuccessful.

Return type:

(2,) float or None

trimesh.path.packing.bounds_overlap(bounds, epsilon=1e-08)

Check to see if multiple axis-aligned bounding boxes contains overlaps using rtree.

Parameters:
  • bounds ((n, 2, dimension) float) – Axis aligned bounding boxes

  • epsilon (float) – Amount to shrink AABB to avoid spurious floating point hits.

Returns:

overlap – True if any bound intersects any other bound.

Return type:

bool

trimesh.path.packing.images(images, power_resize: bool = False, deduplicate: bool = False, iterations: int | integer | unsignedinteger | None = 50, seed: int | integer | unsignedinteger | None = None, spacing: float | floating | int | integer | unsignedinteger | None = None, mode: str | None = None)

Pack a list of images and return result and offsets.

Parameters:
  • images ((n,) PIL.Image) – Images to be packed

  • power_resize (bool) – Should the result image be upsized to the nearest power of two? Not every GPU supports materials that aren’t a power of two size.

  • deduplicate – Should images that have identical hashes be inserted more than once?

  • mode – If passed return an output image with the requested mode, otherwise will be picked from the input images.

Returns:

  • packed (PIL.Image) – Multiple images packed into result

  • offsets ((n, 2) int) – Offsets for original image to pack

trimesh.path.packing.meshes(meshes, **kwargs)

Pack 3D meshes into a rectangular volume using box packing.

Parameters:
  • meshes ((n,) trimesh.Trimesh) – Input geometry to pack

  • **kwargs (dict) – Passed to packing.rectangles

Returns:

  • placed ((m,) trimesh.Trimesh) – Meshes moved into the rectangular volume.

  • transforms ((m, 4, 4) float) – Homogeneous transform moving mesh from original position to being packed in a rectangular volume.

  • consume ((n,) bool) – Which of the original meshes were inserted, i.e. consume.sum() == m

trimesh.path.packing.paths(paths, **kwargs)

Pack a list of Path2D objects into a rectangle.

Parameters:

paths ((n,) Path2D) – Geometry to be packed

Returns:

  • packed (trimesh.path.Path2D) – All paths packed into a single path object.

  • transforms ((m, 3, 3) float) – Homogeneous transforms to move paths from their original position to the new one.

  • consume ((n,) bool) – Which of the original paths were inserted, i.e. consume.sum() == m

trimesh.path.packing.polygons(polygons, **kwargs)

Pack polygons into a rectangle by taking each Polygon’s OBB and then packing that as a rectangle.

Parameters:
  • polygons ((n,) shapely.geometry.Polygon) – Source geometry

  • **kwargs (dict) – Passed through to packing.rectangles.

Returns:

  • transforms ((m, 3, 3) float) – Homogeonous transforms from original frame to packed frame.

  • consume ((n,) bool) – Which of the original polygons was packed, i.e. consume.sum() == m

trimesh.path.packing.rectangles(extents, size=None, density_escape=0.99, spacing=None, iterations=50, rotate=True, quanta=None, seed=None)

Run multiple iterations of rectangle packing, this is the core function for all rectangular packing.

Parameters:
  • extents ((n, dimension) float) – Size of hyper-rectangle to be packed

  • size (None or (dimension,) float) – Size of sheet to pack onto. If not passed tree will be allowed to create new volume-minimizing parent nodes.

  • density_escape (float) – Exit early if rectangular density is above this threshold.

  • spacing (float) – Distance to allow between rectangles

  • iterations (int) – Number of iterations to run

  • rotate (bool) – Allow right angle rotations or not.

  • quanta (None or float) – Discrete “snap” interval.

  • seed – If deterministic results are needed seed the RNG here.

Returns:

  • bounds ((m, 2, dimension) float) – Axis aligned bounding boxes of inserted hyper-rectangle.

  • inserted ((n,) bool) – Which of the original rect were packed.

trimesh.path.packing.rectangles_single(extents, size=None, shuffle=False, rotate=True, random=None)

Execute a single insertion order of smaller rectangles onto a larger rectangle using a binary space partition tree.

Parameters:
  • extents ((n, dimension) float) – The size of the hyper-rectangles to pack.

  • size (None or (dim,) float) – Maximum size of container to pack onto. If not passed it will re-root the tree when items larger than any available node are inserted.

  • shuffle (bool) – Whether or not to shuffle the insert order of the smaller rectangles, as the final packing density depends on insertion order.

  • rotate (bool) – If True, allow integer-roll rotation.

Returns:

  • bounds ((m, 2, dim) float) – Axis aligned resulting bounds in space

  • transforms ((m, dim + 1, dim + 1) float) – Homogeneous transformation including rotation.

  • consume ((n,) bool) – Which of the original rectangles were packed, i.e. consume.sum() == m

trimesh.path.packing.roll_transform(bounds: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes], extents: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes]) ndarray[tuple[int, ...], dtype[float64]]

Packing returns rotations with integer “roll” which needs to be converted into a homogeneous rotation matrix.

Currently supports dimension=2 and dimension=3.

Parameters:
  • bounds ((n, 2, dimension) float) – Axis aligned bounding boxes of packed position

  • extents ((n, dimension) float) – Original pre-rolled extents will be used to determine rotation to move to bounds.

Returns:

transforms – Homogeneous transformation to move cuboid at the origin into the position determined by bounds.

Return type:

(n, dimension + 1, dimension + 1) float

trimesh.path.packing.visualize(extents, bounds)

Visualize a 3D box packing.

Parameters:
  • extents ((n, 3) float) – AABB size before packing.

  • bounds ((n, 2, 3) float) – AABB location after packing.

Returns:

scene – Scene with boxes at requested locations.

Return type:

trimesh.Scene