// SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT // Circular set of boxes for storing cards of different types for a game // in one unit. // Include box and layout definitions for Dragons Down include ; // Make utility functions available. include ; // Define circumradius function. include ; // Accurracy depends somewhat on nozzle size. // We want to use the slop as extra space on the inside of the boxes, // so that cards will still fit with some print varience. nozzle = .4; slop = nozzle/4; // Define overlap to use for parts that just touch. This is used to make // sure parts are connected if they don't really overlap. overlap = .001; // Use more segments for circles than the default. $fn = 64; // Define some thicknesses. // Bottom of card storer bottom_thick = 5; // Box walls wall_thick = 2; // Radius for box joints. radius_thick = 6; // Space around the cards, so they are not tight against opposite walls. gap = 1.5; // Box total extra length / width. box_extra = 2*slop+2*gap+2*wall_thick; // Depth of lettering. letter_depth = 2*nozzle; // Margin for lettering. letter_margin = 4; // Define a 2d cutout with two rounded corners that will be made to make // space for getting under card decks to lift them. // The circles are put on the high side width. module cutout(width, length, radius) { hull() { square(overlap); translate([width-overlap,0,0]) square(overlap); translate([radius,length-radius,0]) circle(radius); translate([width-radius,length-radius,0]) circle(radius); } } // Define a box for holding cards that are width by length. Height affects // how many will fit in the box. Width is for the side that will be part // of the cyclic polygon and both those sides will have slots in them for // extracting cards. Extra spacing and such will be calculated by the caller. module box(width, length, height, label, use_length) { // Fraction of width used for the extraction gap. extract = 1/2; // Fraction of indent in the base for the extraction gaps. indent = 1/10; // Base fillet radius for indents. fillet = 4; // Make the base of the box. difference() { linear_extrude(height=bottom_thick) { difference() { translate([overlap,overlap,0]) square([width-2*overlap,length-2*overlap]); union() { translate([width*(1-extract)/2,-overlap, 0]) cutout(width*extract, length*indent+overlap, fillet); translate([width*(1-extract)/2,length+overlap, 0]) mirror([0,1,0]) cutout(width*extract, length*indent+overlap, fillet); } } } translate([width/2,length/2,bottom_thick-letter_depth]) linear_extrude(height=letter_depth+overlap) { rotate(90) resize([((is_undef(use_length)||use_length)?(length*(1-2*indent)-2*letter_margin):0),((is_undef(use_length)||use_length)?0:width-2*wall_thick-2*letter_margin),0], auto=[true,true,false]) text(text=((!is_undef(label))&&is_string(label)&&len(label)>0)?label:" ", halign="center", valign="center"); } } // Make the walls of a box. translate([0,0,overlap]) linear_extrude(height=height+bottom_thick-overlap) { square([wall_thick, length]); translate([width-wall_thick,0,0]) square([wall_thick, length]); square([width*(1-extract)/2, wall_thick]); translate([0,length-wall_thick,0]) square([width*(1-extract)/2, wall_thick]); translate([width*(1+extract)/2,0,0]) square([width*(1-extract)/2, wall_thick]); translate([width*(1+extract)/2,length-wall_thick,0]) square([width*(1-extract)/2, wall_thick]); } } // Place a box on the circle. // Place it at the point given by the previous total angle and rotate // it by the previous total angle plus half the curent angle. And then // make call o place next box. module place_box(placement, order, angle, i, n) { translate([placement[0]*sin(angle),placement[0]*cos(angle),0]) rotate(-(angle+placement[1][i]/2)) box(order[i][0]+box_extra, order[i][1]+box_extra, order[i][2], order[i][3], order[i][4]); if (i+1