diff --git a/docs/tips.rst b/docs/tips.rst index e3aa84eb..8bd9d7f2 100644 --- a/docs/tips.rst +++ b/docs/tips.rst @@ -172,6 +172,14 @@ padding (right): :align: right +By default, the original Z value of all objects packed using the :meth:`pack.pack` function is preserved. +If you want to align all objects so that they are "placed" on the zero Z coordinate, the :meth:`pack` +function has an `align_z` argument. When set to `True`, this will align all objects. + +This can be useful, for example, when preparing print setups for 3D printing, giving you full control +over this alignment so you don't have to leave it to the slicer. + + .. _are_glob_imports_bad_practice: *********************************************** diff --git a/src/build123d/pack.py b/src/build123d/pack.py index dc97650e..88ca5804 100644 --- a/src/build123d/pack.py +++ b/src/build123d/pack.py @@ -14,7 +14,7 @@ from dataclasses import dataclass from typing import Callable, Collection, Optional, cast -from build123d import Location, Shape +from build123d import Location, Shape, Pos def _pack2d( @@ -119,8 +119,18 @@ def grow_down(w, h): return [(t[1], t[2]) for t in sorted(translations, key=lambda t: t[0])] -def pack(objects: Collection[Shape], padding: float) -> Collection[Shape]: - """Pack objects in a squarish area in Plane.XY.""" +def pack(objects: Collection[Shape], padding: float, align_z: bool = False) -> Collection[Shape]: + """Pack objects in a squarish area in Plane.XY. + + Args: + objects (Collection[Shape]): objects to arrange + padding (float): space between objects + align_z (bool, optional): align shape bottoms to Plane.XY. Defaults to False. + + Returns: + Collection[Shape]: rearranged objects + """ + bounding_boxes = {o: o.bounding_box().size + (padding, padding) for o in objects} translations = _pack2d( objects, @@ -128,7 +138,7 @@ def pack(objects: Collection[Shape], padding: float) -> Collection[Shape]: length_fn=lambda o: bounding_boxes[cast(Shape, o)].Y, ) translated = [ - Location((t[0] - o.bounding_box().min.X, t[1] - o.bounding_box().min.Y, 0)) * o + Location((t[0] - o.bounding_box().min.X, t[1] - o.bounding_box().min.Y, 0)) * Pos((0, 0, -o.bounding_box().min.Z if align_z else 0)) * o for (o, t) in zip(objects, translations) ]