Generating compartment layouts for drawers and boxes

21 keer bekeken / views

Dividing a drawer seems simple… until you want to combine multiple compartment sizes.

Een Nederlandse vertaling van deze post kunt u hier vinden.

In this post I describe two Python programs that I wrote to create nice compartment layouts for my parts boxes.

  • boxGenerator.py
  • gridLayoutGenerator.py

Both generate OpenSCAD programs, but also directly usable .stl files for 3D printing.

This repository contains two scripts that take the puzzle work out of your hands:

  • boxGenerator.py
  • gridLayoutGenerator.py

boxGenerator.py

boxGenerator.py creates a free layout of rectangular compartments within a box.

You specify:

  • dimensions of the box
  • dimensions of the compartments
  • number of compartments per type

The script tries to place those compartments within the available surface.

Interactive Prompt

The program works via an interactive prompt.

  1. First you enter the outer dimensions of the box to be printed.
  2. Then, for each desired compartment, you enter its size (length and width).
  3. Next, you specify how many compartments of this size you want and how many of these compartments should be printed directly adjacent to each other.
  4. Finally, you specify whether you want a preference for the placement of these compartments, for example: ‘random’, ‘top’ or ‘bottom’ of the box.

The script tries to place all compartments. If that fails, it indicates:

  • which compartment does not fit
  • or of which type fewer can be placed

Here you can see how this works in practice:

./boxGenerator.py 
OpenSCAD box generator
----------------------
Select a project:
  [1] evenSpacers
  [2] ladeBox2
  [3] newProject
Choice [1-3]: 2
Project: ladeBox2

Enter outer box size (length x width x height, example: 300x200x80): 190x172x70 <Enter> 
Enter inner wall height in mm: 68.8 <Enter>
Enter outer wall thickness in mm: 1 <Enter>
Enter inner divider thickness in mm: 1 <Enter> 
Enter bottom thickness in mm: 1.2 <Enter> 
Enter leftover compartment size (length x width, '-' = skip): <Enter> 
Enter random seed [12345]: <Enter>
Enter number of layout attempts [120]: <Enter>
Enter number of attempts per cluster group [50]: <Enter>

Enter compartment definitions.
Example size: 25x30
Cluster size means how many equal compartments must touch each other.
Example: size 25x30, count 8, cluster 3 => groups of 3, 3, and 2
Empty size reuses the default size and still shows the remaining questions.
If no default exists yet, empty size finishes input.
Use 'keep' to reuse a default compartment without editing.
Use '0x0' to remove/skip a compartment and skip follow-up questions.

Compartment 1 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 190x55 <Enter>
Compartment 1 count: 2 <Enter>
Compartment 1 cluster size: 1 <Enter>
Compartment 1 preferred placement (random/front/back) [random]: <Enter>

Compartment 2 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 100x55 <Enter>
Compartment 2 count: 1 <Enter>
Compartment 2 cluster size: 1 <Enter>
Compartment 2 preferred placement (random/front/back) [random]: <Enter>

Compartment 3 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 80x50 <Enter>
Compartment 3 count: 1 <Enter>
Compartment 3 cluster size: 1 <Enter>
Compartment 3 preferred placement (random/front/back) [random]: <Enter>

Compartment 4 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): <Enter>

Packing progress: attempt 1/120, best placed compartments 3/4, current missing compartments 3
Packing progress: attempt 10/120, best placed compartments 3/4, current missing compartments 3
Packing progress: attempt 20/120, best placed compartments 3/4, current missing compartments none
Packing progress: attempt 30/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 40/120, best placed compartments 4/4, current missing compartments 3
Packing progress: attempt 50/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 60/120, best placed compartments 4/4, current missing compartments 3
Packing progress: attempt 70/120, best placed compartments 4/4, current missing compartments 3
Packing progress: attempt 80/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 90/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 100/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 110/120, best placed compartments 4/4, current missing compartments none
Packing progress: attempt 120/120, best placed compartments 4/4, current missing compartments none

Placed cluster groups:
  group_1_1      position=(7.5, 0.0) footprint=180.5x55.0 cells=1 orientation=single pref=random/random
  group_1_2      position=(7.5, 115.0) footprint=180.5x55.0 cells=1 orientation=single pref=random/random
  group_2_1      position=(88.0, 60.0) footprint=100.0x55.0 cells=1 orientation=single pref=random/random
  group_3_1      position=(8.0, 55.0) footprint=80.0x50.0 cells=1 orientation=single pref=random/random

Requested cavities:
  requested_01 position=(0.0, 0.0) size=188.0x55.0
  requested_02 position=(0.0, 115.0) size=188.0x55.0
  requested_03 position=(88.0, 55.0) size=100.0x60.0
  requested_04 position=(0.0, 55.0) size=88.0x60.0

Remaining free cavities:
  None

Absorbed tiny gaps between requested cavities:
  adjustment_01 axis=y between=requested_01/requested_03 gap=5.000 growth=+0.000/+5.000
  adjustment_02 axis=y between=requested_04/requested_02 gap=10.000 growth=+10.000/+0.000

OpenSCAD file written: ladeBox2.scad
STL file written: ladeBox2.stl

And below is the result:


gridLayoutGenerator.py

gridLayoutGenerator.py works with a fixed grid.

Inspired by Gridfinity, but without the overhead and therefore using less filament.

Everything is based on a grid size. All compartments are multiples of that.

This provides:

  • clean alignment
  • simple layouts
  • predictable results

Three working modes

  1. fixed box length
    Length specified
    grid size and width calculated and selectable via a list
  2. fixed box width
    Width specified
    grid size and length calculated and selectable via a list
  3. fixed grid size
    Box dimensions are multiples of the grid size and selectable via a list

Output

The program produces two output formats:

  • OpenSCAD file
    Can be viewed and modified in OpenSCAD
    Then exported to STL
  • STL file
    This file can be sent directly to a 3D printer

Interactive Prompt

The program works via an interactive prompt.

  1. First you choose which of the three modes you want to use.
  2. Then you enter the desired grid size (the grid is always square, so one value is sufficient).
  3. Then you specify the (outer dimension) your box should have. You will see a list of possible lengths and widths to choose from.
  4. Now, for each compartment, you specify how many “grids” it should consist of.
  5. Next, you specify how many compartments of this size you want.

The prompt looks like this:

python gritLayoutGenerator.py <Enter>

gridLayoutGenerator
-------------------
Select a project:
  [1] myLadeInlay
  [2] newProject
Choice [1-2]: 1 <Enter>
Project: myLadeInlay

Layout mode:
  [1] Fixed grid        (enter gridSize, then box dimensions)
  [2] Fixed box Length  (suggest gridSize and box Width)
  [3] Fixed box Width   (suggest gridSize and box Length)
Choice [1-3]: 1 <Enter> 
Enter random seed (rngSeed) [12345]: <Enter>
Enter number of layout attempts [100]: <Enter>
Enter number of attempts per cluster group [50]: <Enter>
Enter gridSize in mm: 19 <Enter>
Axis values (gridSize multiples, 100..300): 114, 133, 152, 171, 190, 209, 228, 247, 266, 285
Enter complete outer box size in mm (LxWxH): 190x228x70 <Enter> 
Enter outer wall thickness (outerWall) in mm: 1 <Enter>
Enter inner wall thickness (innerWall) in mm: 1 <Enter>
Enter bottom thickness in mm: 1.4 <Enter>
Enter inner wall height in mm: 70 <Enter>

Enter compartment requirements.
Use format NxM (examples: 1x1, 1x2, 2x6, 3x4)
Empty size reuses the default size and still asks for count.
If no default exists yet, empty size finishes input.

Compartment 1 size in grid units: 2x4 <Enter>
How many of 2x4: 3 <Enter>

Compartment 2 size in grid units: 4x4 <Enter>
How many of 4x4: 1 <Enter>

Compartment 3 size in grid units: 4x6 <Enter>
How many of 4x6: 1 <Enter>

Compartment 4 size in grid units: 4x8 <Enter>
How many of 4x8: 1 <Enter> 

Compartment 5 size in grid units: 2x3 <Enter>
How many of 2x3: 3 <Enter>

Compartment 6 size in grid units: <Enter>

Packing progress: attempt 1/100, best placed compartments 9/9, current missing compartments -

Grid: 10 x 12 cells (120 total)
Placed compartments: 9
All requested compartments fit. Leftover 1x1 compartments added: 6
OpenSCAD file written: myLadeInlay.scad
STL file written: myLadeInlay.stl

.. and this is the result:

This entry was posted in Uncategorised and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

The maximum upload file size: 4 MB. You can upload: image, other. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here

This site uses Akismet to reduce spam. Learn how your comment data is processed.