diff --git a/wargame_box.scad b/wargame_box.scad index 20d0b50..34b4690 100644 --- a/wargame_box.scad +++ b/wargame_box.scad @@ -57,7 +57,7 @@ thumb_grooves = true; // How the lid is held shut. "latch": snap latches hinged on // short pieces of filament (see README). "friction": original // push fit. -lid_style = "latch"; // [latch, friction] +lid_style = "friction"; // [latch, friction] // Latches per long (front/back) wall, spread out evenly latches_per_side = 2; // Diameter of the filament used as hinge pin @@ -95,19 +95,27 @@ notch_d = 22; // ------------------------------------------------------------ // Compartment layout // ------------------------------------------------------------ -// One entry per row (front to back). Each entry is -// [row_depth_weight, [column_width_weights]] -// Weights are relative, so the layout always fills the insert -// exactly no matter what the box dimensions are. +// The layout is a recursive grid. Each cell is one of +// * a number -> a compartment, sized by that weight +// * [weight, [cells]] -> a cell split perpendicular to its +// parent into the given sub-cells +// * [cells] -> shorthand for [1, [cells]] +// The top level splits the insert front-to-back into rows, each +// row splits left-to-right into columns, and so on, alternating +// direction at every nesting level. Weights are relative, so the +// layout always fills the insert exactly. +// Caveat: a two-element list whose second element is a list is +// always read as [weight, [cells]]; use the explicit weight form +// if that's not what you mean. // -// Default: a wide slot for measuring tapes across the back, -// and two rows of token compartments in front. +// Default: one full-depth bay on the left (weight 2, ~67 mm wide +// here - fits a deck of standard cards lying flat), two medium +// bays, and a right column split into three equal token bins. layout = [ - [1.0, [1, 1, 1, 1]], // front row: 4 small token bins - [1.0, [2, 1, 1]], // middle row: 1 medium + 2 small - [0.8, [1]] // back row: full-width slot (tapes etc.) + [1.0, [2, 1, 1, [1, 1, 1]]], ]; + $fn = $preview ? 32 : 64; // ------------------------------------------------------------ @@ -165,7 +173,12 @@ function sum(v, i = 0) = i >= len(v) ? 0 : v[i] + sum(v, i + 1); // sum of the first n elements function psum(v, n) = n <= 0 ? 0 : v[n - 1] + psum(v, n - 1); -function row_weights() = [for (r = layout) r[0]]; +// layout cell accessors (see "Compartment layout" above) +function cell_weight(c) = is_num(c) ? c + : len(c) == 2 && is_list(c[1]) ? c[0] : 1; +function cell_children(c) = is_num(c) ? undef + : len(c) == 2 && is_list(c[1]) ? c[1] : c; +function cell_weights(cells) = [for (c = cells) cell_weight(c)]; // rounded-corner rectangle, centered at origin corner (0,0) module rrect(x, y, r) { @@ -356,34 +369,12 @@ module placed_latch(x0) { module insert() { iw_x = ins_x - 2 * insert_wall; // usable interior iw_y = ins_y - 2 * insert_wall; - n_rows = len(layout); - rw = row_weights(); - avail_y = iw_y - (n_rows - 1) * divider_t; difference() { rbox(ins_x, ins_y, ins_h, inner_r); // compartment cavities - for (ri = [0 : n_rows - 1]) { - row_y0 = insert_wall - + avail_y * psum(rw, ri) / sum(rw) - + ri * divider_t; - row_dy = avail_y * rw[ri] / sum(rw); - - cols = layout[ri][1]; - n_cols = len(cols); - avail_x = iw_x - (n_cols - 1) * divider_t; - - for (ci = [0 : n_cols - 1]) { - col_x0 = insert_wall - + avail_x * psum(cols, ci) / sum(cols) - + ci * divider_t; - col_dx = avail_x * cols[ci] / sum(cols); - - translate([col_x0, row_y0, insert_floor]) - cube([col_dx, row_dy, ins_h]); - } - } + carve(layout, insert_wall, insert_wall, iw_x, iw_y, false); // finger notches on the short (left/right) walls if (finger_notches) @@ -395,6 +386,27 @@ module insert() { } } +// carve the cells into the region [x0, y0]..[x0+dx, y0+dy], +// split along x or y; nested cells recurse on the other axis +module carve(cells, x0, y0, dx, dy, split_x) { + n = len(cells); + w = cell_weights(cells); + avail = (split_x ? dx : dy) - (n - 1) * divider_t; + for (i = [0 : n - 1]) { + off = avail * psum(w, i) / sum(w) + i * divider_t; + sz = avail * w[i] / sum(w); + cx = split_x ? x0 + off : x0; + cy = split_x ? y0 : y0 + off; + cdx = split_x ? sz : dx; + cdy = split_x ? dy : sz; + sub = cell_children(cells[i]); + if (is_undef(sub)) + translate([cx, cy, insert_floor]) cube([cdx, cdy, ins_h]); + else + carve(sub, cx, cy, cdx, cdy, !split_x); + } +} + // ------------------------------------------------------------ // Output // ------------------------------------------------------------