{"id":8752,"date":"2026-03-30T11:09:17","date_gmt":"2026-03-30T09:09:17","guid":{"rendered":"https:\/\/willem.aandewiel.nl\/?p=8752"},"modified":"2026-03-31T15:28:49","modified_gmt":"2026-03-31T13:28:49","slug":"generating-compartment-layouts-for-drawers-and-boxes","status":"publish","type":"post","link":"https:\/\/willem.aandewiel.nl\/index.php\/2026\/03\/30\/generating-compartment-layouts-for-drawers-and-boxes\/","title":{"rendered":"Generating compartment layouts for drawers and boxes"},"content":{"rendered":"\n<p>111 keer bekeken \/ views<\/p>\n\n\n\n<p>Dividing a drawer seems simple\u2026 until you want to combine multiple compartment sizes.<\/p>\n\n\n\n<p class=\"has-light-gray-background-color has-background\">Een Nederlandse vertaling van deze post kunt u <a href=\"https:\/\/willem.aandewiel.nl\/index.php\/2026\/03\/29\/vakverdeling-genereren-voor-laden-en-dozen\/\">hier<\/a> vinden.<\/p>\n\n\n\n<p>In this post I describe two <a href=\"https:\/\/www.python.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Python <\/a>programs that I wrote to create nice compartment layouts for my parts boxes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>boxGenerator.py<\/li>\n\n\n\n<li>gridLayoutGenerator.py<\/li>\n<\/ul>\n\n\n\n<p>Both generate OpenSCAD programs, but also directly usable <code>.stl<\/code> files for 3D printing.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/mrWheel\/boxGenerator\" target=\"_blank\" rel=\"noreferrer noopener\">This repository<\/a> contains two scripts that take the puzzle work out of your hands:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>boxGenerator.py<\/li>\n\n\n\n<li>gridLayoutGenerator.py<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">boxGenerator.py<\/h1>\n\n\n\n<p>boxGenerator.py creates a free layout of rectangular compartments within a box.<\/p>\n\n\n\n<p>You specify:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>dimensions of the box<\/li>\n\n\n\n<li>dimensions of the compartments<\/li>\n\n\n\n<li>number of compartments per type<\/li>\n<\/ul>\n\n\n\n<p>The script tries to place those compartments within the available surface.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Interactive Prompt<\/h2>\n\n\n\n<p>The program works via an interactive prompt.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>First you enter the outer dimensions of the box to be printed.<\/li>\n\n\n\n<li>Then, for each desired compartment, you enter its size (length and width).<\/li>\n\n\n\n<li>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.<\/li>\n\n\n\n<li>Finally, you specify whether you want a preference for the placement of these compartments, for example: \u2018random\u2019, \u2018top\u2019 or \u2018bottom\u2019 of the box.<\/li>\n<\/ol>\n\n\n\n<p>The script tries to place all compartments. If that fails, it indicates:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>which compartment does not fit<\/li>\n\n\n\n<li>or of which type fewer can be placed<\/li>\n<\/ul>\n\n\n\n<p>Here you can see how this works in practice:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/boxGenerator.py \nOpenSCAD box generator\n----------------------\nSelect a project:\n  [1] evenSpacers\n  [2] ladeBox2\n  [3] newProject\nChoice [1-3]: 2\nProject: ladeBox2\n\nEnter outer box size (length x width x height, example: 300x200x80): 190x172x70 &lt;Enter> \nEnter inner wall height in mm: 68.8 &lt;Enter>\nEnter outer wall thickness in mm: 1 &lt;Enter>\nEnter inner divider thickness in mm: 1 &lt;Enter> \nEnter bottom thickness in mm: 1.2 &lt;Enter> \nEnter leftover compartment size (length x width, '-' = skip): &lt;Enter> \nEnter random seed [12345]: &lt;Enter>\nEnter number of layout attempts [120]: &lt;Enter>\nEnter number of attempts per cluster group [50]: &lt;Enter>\n\nEnter compartment definitions.\nExample size: 25x30\nCluster size means how many equal compartments must touch each other.\nExample: size 25x30, count 8, cluster 3 => groups of 3, 3, and 2\nEmpty size reuses the default size and still shows the remaining questions.\nIf no default exists yet, empty size finishes input.\nUse 'keep' to reuse a default compartment without editing.\nUse '0x0' to remove\/skip a compartment and skip follow-up questions.\n\nCompartment 1 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 190x55 &lt;Enter>\nCompartment 1 count: 2 &lt;Enter>\nCompartment 1 cluster size: 1 &lt;Enter>\nCompartment 1 preferred placement (random\/front\/back) [random]: &lt;Enter>\n\nCompartment 2 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 100x55 &lt;Enter>\nCompartment 2 count: 1 &lt;Enter>\nCompartment 2 cluster size: 1 &lt;Enter>\nCompartment 2 preferred placement (random\/front\/back) [random]: &lt;Enter>\n\nCompartment 3 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): 80x50 &lt;Enter>\nCompartment 3 count: 1 &lt;Enter>\nCompartment 3 cluster size: 1 &lt;Enter>\nCompartment 3 preferred placement (random\/front\/back) [random]: &lt;Enter>\n\nCompartment 4 size (length x width) (empty = default-size, 'keep' = default-all, '0x0' = skip): &lt;Enter>\n\nPacking progress: attempt 1\/120, best placed compartments 3\/4, current missing compartments 3\nPacking progress: attempt 10\/120, best placed compartments 3\/4, current missing compartments 3\nPacking progress: attempt 20\/120, best placed compartments 3\/4, current missing compartments none\nPacking progress: attempt 30\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 40\/120, best placed compartments 4\/4, current missing compartments 3\nPacking progress: attempt 50\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 60\/120, best placed compartments 4\/4, current missing compartments 3\nPacking progress: attempt 70\/120, best placed compartments 4\/4, current missing compartments 3\nPacking progress: attempt 80\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 90\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 100\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 110\/120, best placed compartments 4\/4, current missing compartments none\nPacking progress: attempt 120\/120, best placed compartments 4\/4, current missing compartments none\n\nPlaced cluster groups:\n  group_1_1      position=(7.5, 0.0) footprint=180.5x55.0 cells=1 orientation=single pref=random\/random\n  group_1_2      position=(7.5, 115.0) footprint=180.5x55.0 cells=1 orientation=single pref=random\/random\n  group_2_1      position=(88.0, 60.0) footprint=100.0x55.0 cells=1 orientation=single pref=random\/random\n  group_3_1      position=(8.0, 55.0) footprint=80.0x50.0 cells=1 orientation=single pref=random\/random\n\nRequested cavities:\n  requested_01 position=(0.0, 0.0) size=188.0x55.0\n  requested_02 position=(0.0, 115.0) size=188.0x55.0\n  requested_03 position=(88.0, 55.0) size=100.0x60.0\n  requested_04 position=(0.0, 55.0) size=88.0x60.0\n\nRemaining free cavities:\n  None\n\nAbsorbed tiny gaps between requested cavities:\n  adjustment_01 axis=y between=requested_01\/requested_03 gap=5.000 growth=+0.000\/+5.000\n  adjustment_02 axis=y between=requested_04\/requested_02 gap=10.000 growth=+10.000\/+0.000\n\nOpenSCAD file written: ladeBox2.scad\nSTL file written: ladeBox2.stl\n<\/pre>\n\n\n\n<p>And below is the result:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_3D.png\"><img loading=\"lazy\" decoding=\"async\" width=\"952\" height=\"859\" data-id=\"8727\" src=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_3D.png\" alt=\"\" class=\"wp-image-8727\" srcset=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_3D.png 952w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_3D-300x271.png 300w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_3D-768x693.png 768w\" sizes=\"auto, (max-width: 952px) 100vw, 952px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_top-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"616\" height=\"556\" data-id=\"8729\" src=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_top-1.png\" alt=\"\" class=\"wp-image-8729\" srcset=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_top-1.png 616w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/ladenBox2_top-1-300x271.png 300w\" sizes=\"auto, (max-width: 616px) 100vw, 616px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">gridLayoutGenerator.py<\/h1>\n\n\n\n<p>gridLayoutGenerator.py works with a fixed grid.<\/p>\n\n\n\n<p>Inspired by <a href=\"https:\/\/gridfinitygenerator.com\/en\" target=\"_blank\" rel=\"noreferrer noopener\">Gridfinity<\/a>, but without the overhead and therefore using less filament.<\/p>\n\n\n\n<p>Everything is based on a grid size. All compartments are multiples of that.<\/p>\n\n\n\n<p>This provides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>clean alignment<\/li>\n\n\n\n<li>simple layouts<\/li>\n\n\n\n<li>predictable results<\/li>\n<\/ul>\n\n\n\n<p>Three working modes<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>fixed box length<br>Length specified<br>grid size and width calculated and selectable via a list<\/li>\n\n\n\n<li>fixed box width<br>Width specified<br>grid size and length calculated and selectable via a list<\/li>\n\n\n\n<li>fixed grid size<br>Box dimensions are multiples of the grid size and selectable via a list<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Output<\/h2>\n\n\n\n<p>The program produces two output formats:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OpenSCAD file<br>Can be viewed and modified in <a href=\"https:\/\/openscad.org\" target=\"_blank\" rel=\"noreferrer noopener\">OpenSCAD<\/a><br>Then exported to STL<\/li>\n\n\n\n<li>STL file<br>This file can be sent directly to a 3D printer<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Interactive Prompt<\/h2>\n\n\n\n<p>The program works via an interactive prompt.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>First you choose which of the three modes you want to use.<\/li>\n\n\n\n<li>Then you enter the desired grid size (the grid is always square, so one value is sufficient).<\/li>\n\n\n\n<li>Then you specify the (outer dimension) your box should have. You will see a list of possible lengths and widths to choose from.<\/li>\n\n\n\n<li>Now, for each compartment, you specify how many \u201cgrids\u201d it should consist of.<\/li>\n\n\n\n<li>Next, you specify how many compartments of this size you want.<\/li>\n<\/ol>\n\n\n\n<p>The prompt looks like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">python gritLayoutGenerator.py &lt;Enter>\n\ngridLayoutGenerator\n-------------------\nSelect a project:\n  [1] myLadeInlay\n  [2] newProject\nChoice [1-2]: 1 &lt;Enter>\nProject: myLadeInlay\n\nLayout mode:\n  [1] Fixed grid        (enter gridSize, then box dimensions)\n  [2] Fixed box Length  (suggest gridSize and box Width)\n  [3] Fixed box Width   (suggest gridSize and box Length)\nChoice [1-3]: 1 &lt;Enter> \nEnter random seed (rngSeed) [12345]: &lt;Enter>\nEnter number of layout attempts [100]: &lt;Enter>\nEnter number of attempts per cluster group [50]: &lt;Enter>\nEnter gridSize in mm: 19 &lt;Enter>\nAxis values (gridSize multiples, 100..300): 114, 133, 152, 171, 190, 209, 228, 247, 266, 285\nEnter complete outer box size in mm (LxWxH): 190x228x70 &lt;Enter> \nEnter outer wall thickness (outerWall) in mm: 1 &lt;Enter>\nEnter inner wall thickness (innerWall) in mm: 1 &lt;Enter>\nEnter bottom thickness in mm: 1.4 &lt;Enter>\nEnter inner wall height in mm: 70 &lt;Enter>\n\nEnter compartment requirements.\nUse format NxM (examples: 1x1, 1x2, 2x6, 3x4)\nEmpty size reuses the default size and still asks for count.\nIf no default exists yet, empty size finishes input.\n\nCompartment 1 size in grid units: 2x4 &lt;Enter>\nHow many of 2x4: 3 &lt;Enter>\n\nCompartment 2 size in grid units: 4x4 &lt;Enter>\nHow many of 4x4: 1 &lt;Enter>\n\nCompartment 3 size in grid units: 4x6 &lt;Enter>\nHow many of 4x6: 1 &lt;Enter>\n\nCompartment 4 size in grid units: 4x8 &lt;Enter>\nHow many of 4x8: 1 &lt;Enter> \n\nCompartment 5 size in grid units: 2x3 &lt;Enter>\nHow many of 2x3: 3 &lt;Enter>\n\nCompartment 6 size in grid units: &lt;Enter>\n\nPacking progress: attempt 1\/100, best placed compartments 9\/9, current missing compartments -\n\nGrid: 10 x 12 cells (120 total)\nPlaced compartments: 9\nAll requested compartments fit. Leftover 1x1 compartments added: 6\nOpenSCAD file written: myLadeInlay.scad\nSTL file written: myLadeInlay.stl\n<\/pre>\n\n\n\n<p>.. and this is the result:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_3D.png\"><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"692\" data-id=\"8738\" src=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_3D.png\" alt=\"\" class=\"wp-image-8738\" srcset=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_3D.png 910w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_3D-300x228.png 300w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_3D-768x584.png 768w\" sizes=\"auto, (max-width: 910px) 100vw, 910px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_top.png\"><img loading=\"lazy\" decoding=\"async\" width=\"596\" height=\"683\" data-id=\"8737\" src=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_top.png\" alt=\"\" class=\"wp-image-8737\" srcset=\"https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_top.png 596w, https:\/\/willem.aandewiel.nl\/wp-content\/uploads\/2026\/03\/myLadeInlay_top-262x300.png 262w\" sizes=\"auto, (max-width: 596px) 100vw, 596px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n\n<p class=\"has-background\" style=\"background-color:#06d7f7\">If you want you can <a href=\"https:\/\/willem.aandewiel.nl\/index.php\/2026\/03\/29\/vakverdeling-genereren-voor-laden-en-dozen#respond\">leave a reply.<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n","protected":false},"excerpt":{"rendered":"<p>111 keer bekeken \/ views Dividing a drawer seems simple\u2026 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 &hellip; <a href=\"https:\/\/willem.aandewiel.nl\/index.php\/2026\/03\/30\/generating-compartment-layouts-for-drawers-and-boxes\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":8758,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[149,196,197,175],"class_list":["post-8752","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised","tag-3d","tag-3d-printen","tag-openscad","tag-python3"],"views":111,"_links":{"self":[{"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/posts\/8752","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/comments?post=8752"}],"version-history":[{"count":7,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/posts\/8752\/revisions"}],"predecessor-version":[{"id":8770,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/posts\/8752\/revisions\/8770"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/media\/8758"}],"wp:attachment":[{"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/media?parent=8752"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/categories?post=8752"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/willem.aandewiel.nl\/index.php\/wp-json\/wp\/v2\/tags?post=8752"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}