Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update documentation for pack function #641

Merged
merged 2 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions docs/assemblies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,96 @@ adds the following attributes to :class:`~topology.Shape`:
Any iterator can be assigned to the ``children`` attribute but subsequently the children
are stored as immutable ``tuple`` objects. To add a child to an existing :class:`~topology.Compound`
object, the ``children`` attribute will have to be reassigned.

.. _pack:

******
pack
******

The :meth:`pack.pack` function arranges objects in a compact, non-overlapping layout within a square(ish) 2D area. It is designed to minimize the space between objects while ensuring that no two objects overlap.

.. py:module:: pack


.. autofunction:: pack



Detailed Description
---------------------

The ``pack`` function uses a bin-packing algorithm to efficiently place objects within a 2D plane, ensuring that there is no overlap and that the space between objects is minimized. This is particularly useful in scenarios where spatial efficiency is crucial, such as layout design and object arrangement in constrained spaces.

The function begins by calculating the bounding boxes for each object, including the specified padding. It then uses a helper function ``_pack2d`` to determine the optimal positions for each object within the 2D plane. The positions are then translated back to the original objects, ensuring that they are arranged without overlapping.

Usage Note
----------

The ``align_z`` parameter is especially useful when creating print-plates for 3D printing. By aligning the bottoms of the shapes to the same XY plane, you ensure that the objects are perfectly positioned for slicing software, which will no longer need to perform this alignment for you. This can streamline the process and improve the accuracy of the print setup.

Example Usage
-------------

.. code:: python

# [import]
from build123d import *
from ocp_vscode import *


# [initial space]
b1 = Box(100, 100, 100, align=(Align.CENTER, Align.CENTER, Align.MIN))
b2 = Box(54, 54, 54, align=(Align.CENTER, Align.CENTER, Align.MAX), mode=Mode.SUBTRACT)
b3 = Box(34, 34, 34, align=(Align.MIN, Align.MIN, Align.CENTER), mode=Mode.SUBTRACT)
b4 = Box(24, 24, 24, align=(Align.MAX, Align.MAX, Align.CENTER), mode=Mode.SUBTRACT)



.. image:: assets/pack_demo_initial_state.svg
:align: center


.. code:: python

# [pack 2D]

xy_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=False
)


.. image:: assets/pack_demo_packed_xy.svg
:align: center


.. code:: python

# [Pack and align_z]

z_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=True
)

.. image:: assets/pack_demo_packed_z.svg
:align: center


Tip
---

If you place the arranged objects into a ``Compound``, you can easily determine their bounding box and check whether the objects fit on your print bed.


.. code:: python

# [bounding box]
print(Compound(xy_pack).bounding_box())
# bbox: 0.0 <= x <= 159.0, 0.0 <= y <= 129.0, -54.0 <= z <= 100.0

print(Compound(z_pack).bounding_box())
# bbox: 0.0 <= x <= 159.0, 0.0 <= y <= 129.0, 0.0 <= z <= 100.0
5 changes: 5 additions & 0 deletions docs/import_export.rst
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ For example:
.. autoclass:: mesher.Mesher

.. note::

If you need to align multiple components for 3D printing, you can use the :ref:`pack() <pack>` function to arrange the objects side by side and align them on the same plane. This ensures that your components are well-organized and ready for the printing process.


2D Importers
============
.. py:module:: importers
Expand Down
78 changes: 78 additions & 0 deletions docs/pack_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""

name: pack_demo.py
by: roman-dvorak <[email protected]>
date: June 3rd 2024

desc:

This example shows ability of pack function to pack objects.

"""



# [import]
from build123d import *
from ocp_vscode import *


# [initial space]
b1 = Box(100, 100, 100, align=(Align.CENTER, Align.CENTER, Align.MIN))
b2 = Box(54, 54, 54, align=(Align.CENTER, Align.CENTER, Align.MAX), mode=Mode.SUBTRACT)
b3 = Box(34, 34, 34, align=(Align.MIN, Align.MIN, Align.CENTER), mode=Mode.SUBTRACT)
b4 = Box(24, 24, 24, align=(Align.MAX, Align.MAX, Align.CENTER), mode=Mode.SUBTRACT)




# [Export SVG files]
def write_svg(part, filename: str, view_port_origin=(-100, 100, 150)):
"""Save an image of the BuildPart object as SVG"""
visible, hidden = part.project_to_viewport(view_port_origin)
max_dimension = max(*Compound(children=visible + hidden).bounding_box().size)
exporter = ExportSVG(scale=100 / max_dimension)
exporter.add_layer("Visible", line_weight=0.2)
exporter.add_layer("Hidden", line_color=(99, 99, 99), line_type=LineType.ISO_DOT)
exporter.add_shape(visible, layer="Visible")
exporter.add_shape(hidden, layer="Hidden")
exporter.write(f"assets/{filename}.svg")




write_svg(
Compound(
[b1, b2, b3, b4,],
"pack_demo_initial_state"
),
"pack_demo_initial_state.svg",
(50, 0, 100),
)

# [pack 2D]

xy_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=False
)

write_svg(Compound(xy_pack), "pack_demo_packed_xy.svg", (50, 0, 100))


# [Pack and align_z]


z_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=True
)

write_svg(Compound(z_pack), "pack_demo_packed_z.svg", (50, 0, 100))


# [bounding box]
print(Compound(xy_pack).bounding_box())
print(Compound(z_pack).bounding_box())
Loading