commit 43262179931460ca9f5dd7f5e43711625a9aed41 Author: Rafal Paluch Date: Mon Mar 23 18:44:14 2026 +0100 first commit diff --git a/any_box_1_1_2.scad b/any_box_1_1_2.scad new file mode 100644 index 0000000..fcdd7fb --- /dev/null +++ b/any_box_1_1_2.scad @@ -0,0 +1,2926 @@ +include +include + +//--->>>> Open the "Customizer" window to adjust parameters! + + + + +/* [⛭️ basic properties and dimensions] */ +//ᑎ +lid=true; +//⊚ +hinge_type="snap"; //[snap, pin:pin ❨filament strand❩ ,print in place,no hinge] +//🔒 +closure_type="snap rim"; //[snap rim, latch, magnets, none] +//[mm]️ +X = 60; +//[mm] +Y = 50; +//[mm] +Z = 50; + +dimensions_for = "inside"; // [inside, outside] + +internal_dimensions = dimensions_for=="inside"?true:false; +//[mm]⭾ +wallthickness= 3; + +hinge=hinge_type=="no hinge"?false:true; + +/* [🖶 printer/slicer setup] */ +//⌀ "line width" to be more specific +nozzle_diameter = 0.42; +//⭿ +layer_height = 0.20; + +/* [∞ Gridfinity] */ +//overides parameters to fit the gridfinity platform and adds slots at the bottom +gridfinity_support=false; +//[42mm]️ +units_X = 2; +//[42mm] +units_Y = 1; +//[7mm] +units_Z = 6; + +fill_bottom=true; + +//works best with the lid turned off +stacking_lip=false; +//adds holes for magnets +base_magnets = false; +//[layer height] +layers_below_magnet = 2; +//[mm] +base_magnet_tolerance = 0.2; +//[mm] +base_magnet_diameter = 6.0; +//[mm] +base_magnet_height = 2.0; +//useful if 'layers below magnet = 0'; +add_prying_notch = false; + + + + +/* [⌗ divider settings] */ + +dividers = false; +//[mm]⭾ + +//amount of dividers ‖ +regular_spaced_X_divider = 2; +//[0.0-1.0 of X] +//irregular_spaced_X_divider = [0.0,0.0,0.0,0.0];//[0.0:0.01:1.0] + +//amount of dividers ═ +regular_spaced_Y_divider = 1; +//[0.0-1.0 of Y] +//irregular_spaced_Y_divider = [0.0,0.0,0.0,0.0];//[0.0:0.01:1.0] + +divider_Z_height = 0.5;//[0:0.01:1] +divider_thickness = 1.3; +divider_rounding = 1.3; +divider_chamfer = 0.8; + + + +/* [✦✨✦ aesthetic settings] */ +//higher values will increase generation time! might cause timout! +resolution=32; //[8:8:128] +$fn=resolution; + +//🟊🌟🟊 +exterior_type="textured";//["basic","textured","complex"] + +//chamfer on the top and bottom ◇ +outer_chamfer= 3; +inner_chamfer= max(outer_chamfer-wallthickness/2,0); +//rounding on the Z edges ⛶ (0 is bugged) +outer_rounding = 10; +overrider_automatic_inner_rounding = false; +inner_rounding = 6; + +/* [↳ ░░ texture type settings] */ + +texture_pattern = "stripes"; //["trunc diamonds", "diamonds", "stripes", "ribs", "round ribs", "noise", "wave", "cubes", "hexagon"] +texture_scale = 12; +//negative=>invert; affects both "textured" and "complex" +tex_depth = 1.2; +//⭮ +rotate_texture = false; +//how much of the tex depth should be added to the wallthickness? +tex_depth_wallthickness_factor= 0.75; //[0:.05:1.0] + + + +/* [↳ ⌧ complex type settings] */ + +complex_pattern = "hex_scaffold";//[weave,hex_scaffold,gyroid] +complex_scale = 12; +//only works on some complex patterns +scaffold_thickness = 0.40; //[0.01:0.01:0.99] + +add_texture_to_complex_shell = false; + +//0 => perforated walls +extra_wall = 0.000 ; //[0:0.025:1] + +//will increase generation time +complex_resolution = 5 ; //[1:1:20] + + + +/* [ᑎ lid shape and options] */ +//⭿ also affects hingless boxes +hinge_height_offset = 6; +//whether "lid angle" or "lid downset" is used +shape_method = "angle";//[angle,downset] +//⦝ +lid_angle = 35;//[0:90] +//[mm] +lid_downset = 10.0;// +//factor +hinge_inset = 0.33;//[0:0.1:1] +hinge_inset_rounding = 0.5;//[0:0.1:1] +//factor +lip_inset = 0.33;//[0:0.1:1] +lip_inset_rounding = 0.5;//[0:0.1:1] +//[mm] +lid_tolerance = 0.1; + + + + + + + + +/* [ᑕ lid helpers] */ +// thanks @quinoje +lid_handle = false; + +lid_handle_alignment = "top"; //[top, lip] + +//[mm] +lid_handle_outset = 1.0; +//[mm] +lid_handle_thickness = 1.0; +//[mm] ⭿ negative possible +lid_handle_offset = 1.0; +//⎹⟷⎸ +lid_handle_width_factor = 0.5;//[0.05:0.05:1] + +//[degrees] ⦝ +lid_handle_angle = 45;//[0:5:65] + +lid_handle_radian = tan(lid_handle_angle); + +lid_handle_chamfer = 0.2; + +// thanks @Best_Geezus +lid_groove = false; + +lid_groove_alignment = "lip"; //[top, lip] + +//[mm] +lid_groove_depth = 2.0; +//[mm] +lid_groove_height = 6.0; +//[mm] ⭿ negative possible +lid_groove_offset = 1.0; +//⎹⟷⎸ +lid_groove_width_factor = 0.5;//[0.05:0.05:1] + +//[degrees] ⦝ +lid_groove_angle = 45;//[0:5:90] + +lid_groove_chamfer = 0.2; + + + + +/* [ ⃤ ▽ snap rim settings] */ + +invert_snap_rim = true; +//0.2=>good fit , 0.3=> tight fit +snap_rim_depth = 0.2; +//best kept default +snap_rim_height_factor = 6; +//best kept default +snap_rim_tolerance = 0.03; + + +/* [▣ latch settings] */ + +latch_clamp_strength = 0.12; + +latch_amount = 1; +//for latch amount>1 +latch_gap = 20; +//[mm] +latch_inset = 2.0; +//[mm] for latch inset >= wallthickness +minimum_back_wall_thickness = 1.6; +//[mm] +latch_thickness = 4.0; +latch_width = 20; +latch_length = 25; +latch_chamfer = 0.2; +latch_tolerance = 0.2; +latch_joint_tolerance = -0.2; +//[mm] +extra_finger_clearance = 4; + +/* [🧲 magnet settings] */ + +Y_magnet_alignment="center";//["center","inside","outside"] +magnet_pause_helper=true; +//only visual +connect_magnets=true; +magnet_chamfer=0.4; +//see "🖶 printer/slicer setup" for layer height +layers_over_magnet=4; +//less=> more magnets +minimum_magnet_gap=3; +//⎹⟷⎸ +magnet_array_width_factor=1;//[0.1:0.1:1] +magnet_type= "cylinder"; //["cylinder","box"] +//[mm] +magnet_tolerance=0.2; +//[mm] +cylinder_diameter=6.0; +//[mm] +cylinder_height=2.0; +//[mm] +box_height=10.0; +//[mm] +box_depth=2.0; +//[mm] +box_length=20.0; + + +/* [▢ rim settings] */ + +//does not work with "snap rim" +rim=true; +//[mm]⭿ +rim_height=0.8; +//makes the rim angled +rim_offset=0.2;//[-.5:0.1:1] +rim_tolerance=0.1; + +/* [🞅 general hinge barrel settings] */ +// Zaznacz, aby wymusić własną liczbę zawiasów +use_custom_barrel_count = false; +// Wpisz ilość (Nieparzystą) zawiasów (działa tylko, gdy powyższe jest zaznaczone) +custom_barrel_count = 2; + +//[mm]⌀ +barrel_diameter= 4.6; +// will try to stay as close to this as possible +max_barrel_length=5.0; +barrel_chamfer=0.2; +//[mm]tolerance betweens the barrels +barrel_tolerance=0.15; +barrel_rotary_tolerance=0.2; +//[degrees] allows for more rotation, does not affect pip hinge +extra_clearance = 15;//[0:60] + + +/* [⚑ Co drukowac / What to print] */ +// Pokaz OBIE wkladki (ukrywa reszte) +show_trays = false; +// Pokaz TYLKO PIERWSZA wkladke +show_only_tray_1 = false; +// Pokaz TYLKO DRUGA wkladke (docinana) +show_only_tray_2 = false; + +// Pokaz TYLKO dol pudelka (bez klipsa) +show_only_box = false; +// Pokaz TYLKO pokrywke +show_only_lid = false; +// Pokaz TYLKO sam klips (zatrzask) +show_only_latch = false; + +// Wysokosc pierwszej wkladki w mm +tray_depth = 15.0; +// Grubosc scianki wkladki w mm +tray_wall_thickness = 1.6; +// Luz pomiedzy pudelkiem a wkladka (na kazda strone) +tray_tolerance = 0.3; + +//ͼϾ + +/* [⨀ snap hinge settings] */ + +//[mm] extra tightness makes it not slip out +snap_hinge_tolerance = -0.1; +//[degrees] ∠ +//slot_direction = 45; //[0:90] + + + +/* [🞇 pin hinge settings] */ + +//diameter of the pin, 2.2 works well for 1.75mm filament +dpin = 2.2; +//higher => pin insert hole more angeled +pin_floppiness = 0.60;//[0:0.05:1] +pin_insert_direction = 45;//[-180:90] + + + +/* [🞉 print in place (pip) hinge settings] */ + +//0=as close as possible; 1=barrel tangent to outer wall +pip_barrel_outset=0.5;//[0:3] +//[mm] ⭾ +pip_body_lid_tolerance=0.1; + + + + + + +/* [Hidden] */ + + +{//for the gridfinity platform +grid_pitch=42; +height_unit=7; +stacking_fix=gridfinity_support&&stacking_lip? + (4.4-nozzle_diameter*2)/2:0; +} + + +{//some basic consts +epsilon = 0.001; +root3=sqrt(3); +root2=sqrt(2); +} + + +{//magnet variables on a global level +magnet_wallthickness=nozzle_diameter*2; +magnet_top_buffer=layer_height*layers_over_magnet; +} + + +{// basic dimensions and co + +/* ++textured walls needs to be thicker +*/ + +t_wallthickness =exterior_type=="basic"?wallthickness:wallthickness+abs(tex_depth)*tex_depth_wallthickness_factor; + + +tmpX = internal_dimensions? X+t_wallthickness*2:X; +tmpY = internal_dimensions? Y+t_wallthickness*2:Y; +tmpZ = internal_dimensions? Z+wallthickness*2:Z; + + + +lid_tolerance_offset=lid&&hinge_type=="print in place"? + round_to(lid_tolerance):lid_tolerance; + +min_tolerance = lid_tolerance_offset % layer_height; + + + +outerX = gridfinity_support?units_X*grid_pitch-.5:tmpX; +outerY = gridfinity_support?units_Y*grid_pitch-.5:tmpY; + +tmpZ_2 = gridfinity_support?units_Z*height_unit:tmpZ; +tmpZ_3 = round_to(tmpZ_2); +outerZ = tmpZ_3 + min_tolerance; //(tmpZ_2>=tmpZ_3?min_tolerance:layer_height-min_tolerance); + +innerX=outerX-t_wallthickness*2; +innerY=outerY-t_wallthickness*2; +innerZ=outerZ-wallthickness*2; + + + +max_rounding = (min(outerX,outerY)/2)-0; + +outer_fillet = gridfinity_support?3.75*1:min(outer_rounding,max_rounding); +inner_fillet = overrider_automatic_inner_rounding?inner_rounding:max(outer_fillet-t_wallthickness,1.6); + +//texutred sketch with an inset of .5 gives the most consisten results +Tsketch = offset(rect([outerX,outerY],rounding=outer_fillet),delta=-abs(tex_depth)/2); + +} + + +{//calculating some stuff for the hinges + +// To zostaje - określa ile miejsca mamy na zawias +hinge_length = outerX-outer_fillet*2; +lip_length = innerX-inner_fillet*2; + +// To jest stara logika automatu (obliczamy ją pomocniczo) +tmp_barrel_count=floor(hinge_length/max_barrel_length); +auto_barrel_count = max(tmp_barrel_count -(tmp_barrel_count % 2 == 0 ? 1 : 0), 3); + +// NOWOŚĆ: Wybór między Twoją liczbą a automatem +barrel_count = use_custom_barrel_count ? custom_barrel_count : auto_barrel_count; + +// To zostaje - przelicza szerokość pojedynczego segmentu na bazie barrel_count +barrel_length=hinge_length/barrel_count; +dbarrel=barrel_diameter; + +// To zostaje - pozycjonowanie osi zawiasu +pin_barrel_alignment_offset=(-dbarrel/2+t_wallthickness/2); +pip_barrel_alignment_offset=pip_barrel_outset*dbarrel/2; +} + +{//calculates stuff for the lid shape + +//global so it can be used by different modules + + +//hinge_offset set to half outerZ +true_hinge_downset=hinge_type=="print in place"?outerZ/2-stacking_fix: + //if pin than barrel tangent to top + //if no hinge wallthickness + round_to(hinge_height_offset+(hinge?dbarrel:wallthickness)); + +true_hinge_upset = outerZ - true_hinge_downset - min_tolerance; + + +hinge_kathete=innerY*(1-hinge_inset-lip_inset); + +lid_radian=shape_method == "angle"?tan(lid_angle):lid_downset/hinge_kathete; + +lip_kathete=round_to( + min(lid_radian*hinge_kathete, + max(outerZ-true_hinge_downset-wallthickness-(closure_type=="snap rim"?snap_rim_depth*snap_rim_height_factor:0),0))); + +//from top to lip +lip_outer_downset=lip_kathete+true_hinge_downset; +lid_hypotenuse=opp_adj_to_hyp(hinge_kathete,lip_kathete); + +//from bot to lip + +lip_outer_upset = outerZ - lip_outer_downset - min_tolerance; + + + +true_lip_inset_rounding=1.5*lip_inset_rounding*min(lip_inset*innerY,lid_hypotenuse); +true_hinge_inset_rounding=1.5*hinge_inset_rounding*min(hinge_inset*innerY,lid_hypotenuse); + +//for finger groove; only calculates when actually needed + + +} + + +{//full 3d lid shape + +sample_gap=min(24/resolution,2); + +path_XY_profile = resample_path(spacing=sample_gap,keep_corners=90,closed=true, + zrot(90,rect([innerY,innerX],rounding=inner_fillet))); + +raw_path_YZ_profile = [ + + [0,-outerY/2,outerZ-lip_outer_downset], + [0,-innerY/2+innerY*lip_inset,outerZ-lip_outer_downset], + [0,innerY/2-innerY*hinge_inset,true_hinge_upset], + [0,outerY/2,true_hinge_upset] + + ]; + +radii_YZ_profile = [0,true_lip_inset_rounding,true_hinge_inset_rounding,0]; + +path_YZ_profile = + round_corners(raw_path_YZ_profile,radius=radii_YZ_profile) + ; + +yz_raw_table = [for (p = path_YZ_profile) [p.y, p.z]]; +yz_lookup_table = sort(yz_raw_table); + +final_path_raw = [ + for (pt = path_XY_profile) + let ( + new_z = lookup(pt.y, yz_lookup_table) + ) + [pt.x, pt.y, new_z] +]; + +final_path= path_merge_collinear(final_path_raw, closed=true, eps=1e-3); +} + + +{//bunch of functions, some even unused might need them later tho + +{function dividers() = +!dividers?undef:let( + + frame_reg = make_region( + difference([ + rect([outerX,outerY]), + offset(rect([innerX,innerY],rounding=inner_fillet),delta=.1,quality=32) + ])), + + + X_dividers_reg = regular_spaced_X_divider==0?[]:[ + for (i = [1 : regular_spaced_X_divider]) + let(pos = i * innerX/(regular_spaced_X_divider+1) - innerX/2) + move([pos, 0], rect([divider_thickness, outerY])) + ], + + Y_dividers_reg = regular_spaced_Y_divider==0?[]:[ + for (i = [1 : regular_spaced_Y_divider]) + let(pos = i * innerY/(regular_spaced_Y_divider+1) - innerY/2) + move([0, pos], rect([outerX, divider_thickness])) + ], + + +all_regs = [for (r=[frame_reg, X_dividers_reg, Y_dividers_reg]) if (len(r) > 0) r], +combined_region = union(all_regs), + + // 5. Apply offset to the entire combined structure + final_region = offset(offset(combined_region, delta=divider_rounding,quality=1),r=-divider_rounding,$fn=resolution/2), + +)final_region;} + + +function round_to(value,multiple=layer_height)=round(value/multiple)*multiple; + +function avrg(list) = sum(list) / len(list); + +function vnf_clamp_to_unit(vnf) = + let( + // Cut X axis + v1 = vnf_halfspace([1,0,0,0],vnf), + v2 = vnf_halfspace([-1,0,0,-1],v1), + + // Cut Y axis + v3 = vnf_halfspace([0,1,0,0],v2), + v4 = vnf_halfspace([0,-1,0,-1],v3), + + // Cut Z axis + v5 = vnf_halfspace([0,0,1,0],v4), + v6 = vnf_halfspace([0,0,-1,-1],v5) + ) + v6; + + +function remove_border_faces(vnf, eps=0.001) = + let( + verts = vnf[0], + faces = vnf[1], + + // Check if a specific value is on the Min (0) or Max (1) border + is_min = function(x) abs(x) < eps, + is_max = function(x) abs(x-1) < eps, + + // A face is a "border face" if ALL its vertices are on the same border plane + keep_face = function(f) + let( + // Get all x and y coordinates for the vertices in this face + xs = [for(i=f) verts[i].x], + ys = [for(i=f) verts[i].y], + + // Check X borders + on_left_wall = [for(x=xs) if(!is_min(x)) 1] == [], // True if list empty + on_right_wall = [for(x=xs) if(!is_max(x)) 1] == [], + + // Check Y borders + on_front_wall = [for(y=ys) if(!is_min(y)) 1] == [], + on_back_wall = [for(y=ys) if(!is_max(y)) 1] == [] + ) + // Keep the face only if it is NOT on any of these walls + !(on_left_wall || on_right_wall || on_front_wall || on_back_wall) + ) + [verts, [for(f=faces) if(keep_face(f)) f]]; + + +function clean_vnf(vnf, e=0.0001) = + let( + verts = vnf[0], + faces = vnf[1], + clean_verts = [for (p=verts) [quant(p.x,e), quant(p.y,e), quant(p.z,e)]] + ) [clean_verts, faces]; + + +function clean_vnf2(vnf) = +let( + verts = vnf[0], + faces = vnf[1], + clean_verts = + [for (p=verts) [constrain(p.x,0,1), constrain(p.y,0,1), constrain(p.z,0,1)]] +) [clean_verts, faces]; + +function boundary_to_3d(boundary_2d, z) = + [for (pt = boundary_2d) + for(pt2=pt) + [pt2[0], pt2[1], z]]; +} + + +{//custom vnf textures + +{function hex_wall(thickness=scaffold_thickness) = +let( + //idk what theses do, sc is needed to correctly scale the hex so it fits into the 1x1 box for it to be tileable. note that when used you have to mulitply the Y size of texture times the root of 3 + hyp=adj_ang_to_hyp(0.5,30), + sc = 1/3/hyp, + + //maxes a hexagon and squishes it + hex_poly = move([0,sc-1],yscale(sc, regular_ngon(n=6,id=1-thickness,spin=90,anchor=CENTER),1)), + + centers = [ [-.5,-.5], [.5,-.5],[-.5,.5],[0,0], [.5,.5] ], + + //places hexagons on the centers + raw_hexes = [for (c=centers) move(c+[0,0], hex_poly)], + //booleans are possible in 2D but not as vnf so doing it now + tile_bounds = square([1,1],center=true), + //clips the hexes so it fits into 1x1 + //"inverts" the hexagons so that the negative of them remains + scaffold_region = difference(tile_bounds, raw_hexes), + + raw_vnf = move([.5,.5,.5],linear_sweep(scaffold_region, h=1) ), + + clamped_vnf = vnf_triangulate(vnf_clamp_to_unit(raw_vnf)), + + cleaned_vnf = vnf_drop_unused_points(remove_border_faces(vnf_merge_points(clean_vnf(clamped_vnf)))) + + +) cleaned_vnf;} + + +function diag_stripes_vnf() =[ + [[0,0,1],//1 + [.5,0,0],[0,.5,0],//1,2 + [0,1,1],[1,0,1],//3,4 + [1,.5,0],[.5,1,0],//5,6 + [1,1,1]],//7 + [[0,2,1],[1,2,3,4],[4,3,6,5],[5,6,7]] +]; + + +{function half_pillars() = vnf_vertex_array( +let( + arc_numbers=2, + + single_arc = arc(d=1/arc_numbers, angle=[180,0],cp=[.5/arc_numbers,0], + $fn=$fn*texture_scale/16), + + arc_list = [ + for(i = [0 : arc_numbers-1]) + move([i * 1/arc_numbers, 0], single_arc) + ], + + final_arc = path_join(arc_list), +) +[ + for (y = [0 : 1]) [ + for (arc = final_arc) + [arc.x , y , arc.y*2*arc_numbers] + ] +],reverse=true);} + + +function diag_weave_vnf() = [ + [[0.2, 0, 0], [0.8, 0, 0], [1, 0.2, 0.5], [1, 0.8, 0.5], [0.7, 0.5, 0.5], + [0.5, 0.3, 0], [0.2, 0, 0.5], [0.8, 0, 0.5], [1, 0.2, 1], [1, 0.8, 1], + [0.7, 0.5, 1], [0.5, 0.3, 0.5], [1, 0.2, 0], [1, 0.8, 0], [0.8, 1, 0.5], + [0.2, 1, 0.5], [0.5, 0.7, 0.5], [0.7, 0.5, 0], [0.8, 1, 1], [0.2, 1, 1], + [0.5, 0.7, 1], [0.8, 1, 0], [0.2, 1, 0], [0, 0.8, 0.5], [0, 0.2, 0.5], + [0.3, 0.5, 0.5], [0.5, 0.7, 0], [0, 0.8, 1], [0, 0.2, 1], [0.3, 0.5, 1], + [0, 0.8, 0], [0, 0.2, 0], [0.3, 0.5, 0], [0.2, 0, 1], [0.8, 0, 1], [0.5, 0.3, 1]], + [[0, 1, 5], [1, 2, 4, 5], [7, 11, 10, 8], [8, 10, 9], [7, 8, 2, 1], [9, 10, 4, 3], + [10, 11, 5, 4], [0, 5, 11, 6], [12, 13, 17], [13, 14, 16, 17], [3, 4, 20, 18], + [18, 20, 19], [3, 18, 14, 13], [19, 20, 16, 15], [20, 4, 17, 16], [12, 17, 4, 2], + [21, 22, 26], [22, 23, 25, 26], [15, 16, 29, 27], [27, 29, 28], [15, 27, 23, 22], + [28, 29, 25, 24], [29, 16, 26, 25], [21, 26, 16, 14], [30, 31, 32], [31, 6, 11, 32], + [24, 25, 35, 33], [33, 35, 34], [24, 33, 6, 31], [34, 35, 11, 7], + [35, 25, 32, 11], [30, 32, 25, 23]] +]; + + +{function gyroid(x,y,z, wavelength) = let( + p = 360/wavelength * [x,y,z] +) sin(p.x)*cos(p.y)+sin(p.y)*cos(p.z)+sin(p.z)*cos(p.x);} + +} + + + + + + + +//back_half(s=1000) + +// hsv(h=170,s=.05,v=.8) +// render() +// printable_box(); + + + +//render() +//pin_body(); +// +//render() +//pin_lid(); + +//gridfinity_bottom(is_bool=true); + + +//back_half(s=1000,y=outerY/2-dbarrel/2){ + + + +//fwd(outerX/2) +//up(outerZ-lip_outer_downset) +//cube([50,30,200],anchor=LEFT); +// +//} +//% +//render() +//pin_lid(); +//color("offwhite") +//pin_body(); +//// +//// +//color("teal") +//fwd(outerY/2+latch_thickness) +//back(latch_inset) +//up(outerZ-lip_outer_downset) +//xrot(90) +//mirror([0,0,1]) +//latch(just_latch=true); + +//lid_handle(is_bool=true); + + +module lid_handle(is_bool=true){ + + + + + lid_handle_downset = lid_handle_alignment=="top"? + outer_chamfer+lid_handle_offset+lid_handle_thickness/2: + lip_outer_downset-lid_handle_offset-lid_handle_thickness/2; + + base_size = [lid_handle_width_factor*hinge_length,lid_handle_thickness]; + + + + cut_knob(); + + + module knob(){ + + up(outerZ-lid_handle_downset) + fwd(outerY/2) + fwd(lid_handle_outset) + + prismoid( + size1=base_size+[outerY/2*lid_handle_radian,outerY*lid_handle_radian], + size2=base_size, + h=outerY/2,orient=FWD,anchor=TOP, + chamfer=latch_chamfer); + }; + + module cut_knob(){ + + difference(){ + + knob(); + up(outerZ) + cube([outerX*2,outerY*2,outerZ*2],anchor=BOT); + + shell_inside(); + } + + + } +}; + + +module lid_groove(is_bool=true){ + + + //caps it it doesn't dig into the inside + true_lid_groove_depth = min(lid_groove_depth,t_wallthickness-nozzle_diameter*2); + + //so the groove doesn't get too large + //it could still become too large and dig into the main body but I don't want it to be too restrictive + true_lid_groove_height = lid_groove_height; + + //so I can use it to scale the chamfer in Z to get the right angle; + lid_groove_radian = tan(lid_groove_angle); + + //if the angle would be so shallow that the depth would decrease it caps it + true_lid_groove_radian = + min( + lid_groove_radian*lid_groove_depth, + lid_groove_height/lid_groove_depth*2); + + //when top then aligned just bellow the outer chamfer + //when lip aligned just over the "lip" + + lid_groove_downset = lid_groove_alignment=="top"? + outer_chamfer+lid_groove_offset: + lip_outer_downset-true_lid_groove_height-lid_groove_offset; + + + if(is_bool) + slot(); + + + module slot(){ + + up(outerZ-lid_groove_downset) + fwd(outerY/2) + + diff() + cuboid([lid_groove_width_factor*hinge_length,true_lid_groove_depth,true_lid_groove_height],anchor=FWD+TOP){ + + if(true_lid_groove_radian!=0) + edge_profile([BOT+BACK]) + yscale(true_lid_groove_radian/true_lid_groove_depth) + mask2d_chamfer(x=true_lid_groove_depth,inset=0); + + edge_profile(BACK) + mask2d_chamfer(lid_groove_chamfer); + + tag("keep") + edge_profile_asym(FRONT,except=BOT, flip=true, corner_type="sharp") + xflip() mask2d_chamfer(lid_groove_chamfer); + } + } +}; + + +module latch(for_bool=false,just_latch=false){ + + +////lalatch_amount = 1; +////for latch amount>1 +//latch_gap = 20; +////[mm] +//latch_thickness = 4.0; +//latch_width = 20; +//latch_length = 20; +////[mm] +//latch_inset = 2; +//latch_tolerance = 0.2;rance = 0.2; + + + +usable_latch = latch_length-latch_thickness*2; + +latch_slot_depth = min(latch_width/3,usable_latch/2); + +latch_cone_offset = .3+nozzle_diameter/4; + +clamp_thickness = nozzle_diameter*2 +; + + + +//fwd(outerY/2+latch_thickness) +//back(latch_inset) +//up(outerZ-lip_outer_downset) +//xrot(90) +//mirror([0,0,1]) +// + +if(closure_type=="latch"&&lid){ + + xcopies(spacing=latch_gap+latch_width,n=latch_amount) + { + if(just_latch) + just_latch(); + + if(!for_bool&&!just_latch) + box_ankers(); + + if(for_bool&&!just_latch) + anker_carver(); + } +} + +module negative_cone(){ + + right(latch_width/2) + back(latch_slot_depth) + back(latch_thickness/2) + up(latch_thickness/2) + union(){ + + xcyl(d2=latch_thickness-latch_chamfer*2-latch_cone_offset,d1=0, + l=(latch_thickness-latch_chamfer*2-latch_cone_offset)/2, + anchor=RIGHT+CENTER); + + xcyl(d=latch_thickness-latch_chamfer*2-latch_cone_offset*2, + l=(latch_thickness), + anchor=LEFT+CENTER); + + + } + +} + +module positive_cone(){ + + right(latch_width/2) + right (latch_tolerance) + back(latch_slot_depth) + back(latch_thickness/2) + up(latch_thickness/2) + xcyl(d2=latch_thickness-latch_chamfer*2-latch_cone_offset,d1=latch_cone_offset*2, + l=(latch_thickness-latch_chamfer*2-latch_cone_offset*3)/2, + anchor=RIGHT+CENTER); + +} + +module just_latch(){ + + +// % +// back(latch_thickness+latch_slot_depth) +// cuboid([latch_width,latch_length, latch_thickness],anchor=BOT+BACK); + + + latch_body(); + + module latch_body(){ + + basic_sketch=[ + + [0,0], + [0,latch_slot_depth], + [latch_width/2,latch_slot_depth], + [latch_width/2-latch_slot_depth,0], + + ]; + + compliant_hole=offset([ + + + [latch_width/2-clamp_thickness*2,latch_slot_depth-clamp_thickness*1], + [latch_width/2-latch_slot_depth+clamp_thickness*1,clamp_thickness*2], + + ],r=clamp_thickness,$fn=resolution/2); + + + bezpath1= path_to_bezpath([ + + [latch_width/2,latch_slot_depth], + [latch_width/2-latch_slot_depth/2+latch_clamp_strength,latch_slot_depth/2-latch_clamp_strength], + [latch_width/2-latch_slot_depth,0], + + + ]); + + offset_bez = bezpath_offset(polar_to_xy(r=clamp_thickness,theta=135),bezpath1); + + path_bez = bezpath_curve(offset_bez,splinesteps=4); + + perforated_quadrant = union(path_bez,difference(basic_sketch,compliant_hole)); + + top_slots = union(perforated_quadrant,xflip(perforated_quadrant)); + + all_slots = union(top_slots,yflip(top_slots)); + + extra_bot = latch_length-latch_slot_depth*2-latch_thickness; + + whole_latch = union( + all_slots, + + fwd(latch_slot_depth,rect([latch_width,extra_bot],anchor=BACK)), + + back(latch_slot_depth,rect([latch_width,latch_thickness/2+latch_chamfer],anchor=BOT)), + + ); + + + +// color("blue") +// stroke(bezpath_curve(offset_bez,splinesteps=4),width=.1,closed=true); +// +// color("red") +// stroke(compliant_hole,width=.1,closed=true); + + difference(){ + union(){ + + offset_sweep(whole_latch,h=latch_thickness,ends=os_chamfer(width=latch_chamfer),$fn=resolution/6); + + back(latch_slot_depth+latch_thickness/2) + xrot(180) + teardrop(d=latch_thickness, h=latch_width,cap_h=latch_thickness/2,anchor=TOP,spin=90,chamfer=latch_chamfer,ang=53); + + }//union ends, difference starts + + up(latch_thickness+layer_height*2) + fwd(extra_bot+latch_slot_depth) + chamfer_edge_mask(l=latch_width,orient=LEFT,chamfer=latch_thickness-latch_chamfer); + + xflip_copy() + union(){ + negative_cone(); + left(latch_joint_tolerance) + chain_hull(){ + positive_cone(); + down(latch_thickness/2) + //fwd(latch_thickness/2) + positive_cone(); + down(latch_thickness) + left(latch_thickness/2) + positive_cone(); + + } + } + + } + } + +} + + module box_ankers(){ + + need_wall = latch_inset>t_wallthickness-minimum_back_wall_thickness?true:false; + + distance_to_back = (need_wall?latch_tolerance:0) + latch_thickness+max(0,t_wallthickness-latch_inset); + + scale_factor = (1 + distance_to_back/latch_thickness)*1; + + distance_to_back_wall = distance_to_back + minimum_back_wall_thickness; + + //minimum_back_wall_thickness + if(need_wall)let(){ + + extra_distance = max(0,latch_inset-t_wallthickness); + + wall_width = latch_width+minimum_back_wall_thickness*4; + wall_length = latch_length+minimum_back_wall_thickness*2 +extra_distance*2 + extra_finger_clearance; + wall_thickness = minimum_back_wall_thickness + extra_distance; + + difference(){ + + fwd(innerY/2) + up(outerZ-lip_outer_downset) + down(wall_length/2) + up(latch_slot_depth+latch_thickness+extra_distance+minimum_back_wall_thickness) + diff() + cuboid([wall_width,wall_thickness,wall_length],anchor=FRONT){ + + edge_profile([BACK],except=["Z"]) + mask2d_chamfer(x=wall_thickness, excess=2); + + edge_profile(["Z"],except=[FWD]) + yscale(wall_thickness/minimum_back_wall_thickness) + mask2d_roundover(r=minimum_back_wall_thickness, excess=2); + }; + + latch_hole(); + } + } + + fwd(outerY/2+latch_thickness) + back(latch_inset) + up(outerZ-lip_outer_downset) + xflip_copy() + difference(){ + union(){ + + + + xrot(90) + mirror([0,0,1]) + positive_cone(); + + + + + base_size=[latch_thickness*0.5,latch_thickness]; + + right(latch_width/2+latch_thickness/4) + right(latch_tolerance) + up(latch_slot_depth+latch_thickness/2) + back(latch_chamfer) + + union(){ + + prismoid( + size1=base_size*scale_factor*4/3, + size2=base_size, + shift=[(base_size[0]*-scale_factor)*4/6+base_size[0]*.5,0], + h=distance_to_back-latch_chamfer,orient=FWD,anchor=TOP, + chamfer=latch_chamfer); + + prismoid( + size1=base_size-[latch_chamfer*2,latch_chamfer*2], + size2=base_size, + h=latch_chamfer,orient=BACK,anchor=TOP, + chamfer=latch_chamfer); + + + } + + right(latch_width/2) + left(latch_slot_depth/2) + difference(){ + + union(){ + + diff() + prismoid( + size1=latch_slot_depth*(root2/2)*scale_factor, + size2=latch_slot_depth*(root2/2), + shift=-latch_slot_depth*(root2/2)*scale_factor*1/2.8, + h=distance_to_back,orient=FWD,anchor=TOP,spin=-45, + chamfer=latch_chamfer) + + attach(RIGHT+BACK,"corner",inside=true) + polygon_edge_mask(mask2d_chamfer(h=latch_thickness*scale_factor,inset=0,mask_angle=$edge_angle), $edge_length+latch_chamfer, scale=0.0001); + + + + ; + + prismoid( + size1=latch_slot_depth*(root2/2)-latch_chamfer*2, + size2=latch_slot_depth*(root2/2), + h=latch_chamfer,orient=BACK,anchor=TOP,spin=-45, + chamfer=latch_chamfer); + + } + fwd(latch_chamfer) + left(latch_slot_depth/4) + back(latch_thickness/1) + cuboid([latch_slot_depth,latch_slot_depth,latch_thickness*2],anchor=RIGHT,chamfer=-latch_chamfer,orient=FWD,edges=TOP); + + } + + + }//diff starts + + + if(need_wall) + right(latch_width/2+latch_tolerance) + back(latch_thickness) + fwd(max(0,latch_inset-t_wallthickness)) + cube([latch_width*2,latch_inset,latch_length*2],anchor=LEFT+FWD); + + + }//diff ends + + } + + + module latch_hole(){ + + max_thickness = t_wallthickness+latch_thickness+latch_inset; + + back_size = [latch_width,latch_length] + [latch_tolerance*2,latch_tolerance*2]+[0,extra_finger_clearance]; + + front_size = back_size + [0,max_thickness*2]; + + fwd(outerY/2) + back(latch_inset+latch_tolerance) + up(outerZ-lip_outer_downset) + down(extra_finger_clearance/2) + down(latch_length/2-latch_slot_depth-latch_thickness) + + prismoid( + size2=back_size, + size1=front_size, + h=max_thickness,orient=BACK,anchor=TOP, + chamfer=latch_chamfer); + + + } + + + module anker_carver(){ + difference(){ + + latch_hole(); + + box_ankers(); + } + } +} + + +module gridfinity_stacking_lip(){ + +if(stacking_lip&&gridfinity_support) + +up(outerZ) + difference(){ + + //up(4.4) + + rect_tube(size=[outerX,outerY], wall=t_wallthickness, h=4.4-nozzle_diameter*2,rounding=3.75,anchor=BOT,chamfer2=0); + + + union(){ + up(.7+1.8) + prismoid(size1=[outerX-1.9*2,outerY-1.9*2], size2=[outerX,outerY], h=1.9,rounding1=3.2/2, rounding2=7.5/2); + + up(0.7) + prismoid(size1=[outerX-1.9*2,outerY-1.9*2], size2=[outerX-1.9*2,outerY-1.9*2], h=1.8,rounding1=3.2/2, rounding2=3.2/2); + + prismoid(size1=[outerX-(2.6)*2,outerY-(2.6)*2], size2=[outerX-1.9*2,outerY-1.9*2], h=0.7,rounding1=1.6/2, rounding2=3.2/2); + + + } + } +} + + +module gridfinity_bottom(is_bool=true){ + +// grid_pitch=42; +// height_unit=7; +// 2.95 + + pos_offset=is_bool?0:wallthickness; + + + if(gridfinity_support) + grid_copies(n=[ceil(outerX/grid_pitch),ceil(outerY/grid_pitch)],spacing=grid_pitch) + bottom_tile(); + + module bottom_tile(){ + + + if(base_magnets) { + + final_base_magnet_diameter = base_magnet_diameter+base_magnet_tolerance*2 + (is_bool?0:nozzle_diameter*3); + final_base_magnet_height = base_magnet_height+base_magnet_tolerance*2 +(is_bool?0:layer_height*5); + magnet_spacing = grid_pitch-(2.15+0.8+4.8)*2; + + magnet_diagonal_spacing = magnet_spacing/(root2/2); + + + zrot(90) + teardrop(h=final_base_magnet_height,d=4,anchor=CENTER,orient=FRONT,ang=1,cap_h=final_base_magnet_diameter/2) + ; + } + + if(!(!is_bool&&fill_bottom)) + difference(){ + cuboid([grid_pitch,grid_pitch,4.75+pos_offset],anchor=BOT); + + up(pos_offset) + scale([grid_pitch/(grid_pitch+pos_offset*2),grid_pitch/(grid_pitch+pos_offset*2),1]){ + prismoid(size1=grid_pitch-(.8+2.15+.25)*2, size2=grid_pitch-(2.15+.25)*2, + h=.8,rounding1=1.6/2,rounding2=3.2/2); + up(.8) + prismoid(size1=grid_pitch-(2.15+.25)*2, size2=grid_pitch-(2.15+.25)*2, + h=1.8,rounding1=3.2/2,rounding2=3.2/2); + + up(.8+1.8) + prismoid(size1=grid_pitch-(2.15+.25)*2, size2=grid_pitch-(.25)*2, + h=2.15,rounding1=3.2/2,rounding2=7.5/2); + } + } + + } + + +} + + +module pin_hole(){ + + hole_length = outer_fillet+barrel_length/2+t_wallthickness; + + handleX = hole_length*((pin_floppiness*.33)+.666); + handleZ = (-hole_length*pin_floppiness)/2; + + bez = [[0,0,0],[hole_length/3,0,0],[handleX,0,handleZ],[hole_length,0,-hole_length*pin_floppiness*2]]; + + path = rot([-pin_insert_direction,0,0],p=bezpath_curve(bez)); + + //the sketch that is being swept + sketch = teardrop2d(d=dpin, ang=55,spin=180); + + //move aligns 0,0,0 to the middle of the back right barrel of the lid + + + difference(){ + move([hinge_length/2-barrel_length, + outerY/2-t_wallthickness/2+pin_barrel_alignment_offset, + outerZ-hinge_height_offset-dbarrel/2]) + path_sweep(sketch,path); + + right(outerX/2) + left(t_wallthickness) + fwd(dbarrel) + cuboid([outerX,outerY,outerZ],anchor=BOT+LEFT); + } + +} + + +module snap_rim(is_lid=false){ + +// snap_rim_depth = 1; +// snap_rim_tolerance + + + local_rim_tolerance=is_lid?snap_rim_tolerance:-snap_rim_tolerance; + + snap_rim_height= snap_rim_depth*snap_rim_height_factor; + + center= wallthickness/2-snap_rim_depth/2; + + + + raw_sketch = + + fwd(snap_rim_height,[ + [0, 0], + [0, snap_rim_height/1.2], + [0, snap_rim_height], + [center, snap_rim_height], + [center+snap_rim_depth-snap_rim_tolerance, snap_rim_height*3.5/5+lid_tolerance_offset/3], + [center+snap_rim_depth-snap_rim_tolerance, snap_rim_height*3/5+lid_tolerance_offset/3], + [center, snap_rim_height*2/5+lid_tolerance_offset/3], + [center, snap_rim_height*1/5], + [wallthickness/2, 0], + [t_wallthickness+epsilon, 0], + [t_wallthickness+epsilon, -snap_rim_height], + [0,-snap_rim_height] + ]); + + + + + body_carve_sketch= + invert_snap_rim? + right(center*2+snap_rim_depth, + mirror([1,0],union( + difference( + union( + square([t_wallthickness+.5+lid_tolerance_offset,snap_rim_height*2],anchor=LEFT), + right(t_wallthickness+.5+lid_tolerance_offset,mirror([0,1],right_triangle(snap_rim_height*2,anchor=LEFT)))), + raw_sketch + ), + + square([t_wallthickness-wallthickness+1,snap_rim_height],anchor=RIGHT+FWD), + + ) + ) + ) + : + difference( + union( + square([2,snap_rim_height],anchor=BOT), + square([t_wallthickness+1,snap_rim_height*2],anchor=LEFT), + ), + raw_sketch + ) + ; + + + lid_carve_sketch= + invert_snap_rim? + right(center*2+snap_rim_depth, + mirror([1,0], + union( + square([2,snap_rim_height],anchor=BOT), + right(wallthickness+.5, + union( + mirror([0,1],right_triangle(snap_rim_height*2,anchor=LEFT)), + rect([1,snap_rim_height*2],anchor=RIGHT))), + make_region( + zrot(180,raw_sketch,cp=[wallthickness/2,-snap_rim_height*2.5/5]) + ) + ) + ) + ) + : + union( + right(wallthickness,square([t_wallthickness-wallthickness+1,(snap_rim_height)*2],anchor=LEFT)), + square([2,snap_rim_height],anchor=BOT), + zrot(180,raw_sketch,cp=[wallthickness/2,-snap_rim_height*2.5/5]) + ) + ; + + final_sketch=path_merge_collinear(is_lid?lid_carve_sketch:body_carve_sketch); + +// color("red") //stroke(raw_sketch, width=0.03, closed=true); +// polygon(raw_sketch); +// move_copies(raw_sketch)cube(.2,center=true); + + //stroke(inverted_raw_sketch, width=0.03, closed=true); + +// color("blue") stroke(body_carve_sketch, width=0.03, closed=true); +// color("teal") stroke(lid_carve_sketch, width=0.03, closed=true); + + if(closure_type=="snap rim") + difference(){ + + + path_sweep( + final_sketch,method="manual",relaxed=false, + final_path,//profiles=true, + closed=true,uniform=false); + +//// stroke(path_YZ_profile,width=1); + + if(hinge){ + + extra_factor=3; + + cut_start=-(innerY/2-inner_fillet)+local_rim_tolerance; + cut_end=cut_start+snap_rim_height*extra_factor; + cut_extra=cut_end+snap_rim_height; + + + point1 = [cut_start,lookup(-cut_start, yz_lookup_table)]; + point2 = [cut_end,lookup(-cut_end, yz_lookup_table)-snap_rim_height*extra_factor]; + point3 = [cut_extra,lookup(-cut_extra, yz_lookup_table)-snap_rim_height*extra_factor]; + + total_path = [ + [point1[0],point1[1]], + [point2[0],point2[1]], + [point3[0],point3[1]], + [cut_end,0], + [-outerY,0], + [-outerY,outerZ], + [cut_start,outerZ], + ]; + + + //stroke(path_YZ_profile,width=2); + + rot([0,-90,0]) + rot([0,0,-90]) + linear_extrude(outerX*2,center=true) + polygon(round_corners(total_path,radius=0)); +// +// up(outerZ-true_hinge_downset-snap_rim_height/2) +// back(innerY/2-inner_fillet-local_rim_tolerance) +// prismoid( +// size1=[outerX*2,outerY], +// size2=[outerX*2,outerY], +// h=outerZ, +// anchor=FWD); + + + } + } + } + + +module rim(is_lid){ + + local_rim_tolerance=is_lid?rim_tolerance/2:-rim_tolerance/2; + + local_rim_height=round_to(rim_height); + + rim_width=wallthickness/2+local_rim_tolerance+rim_tolerance; + + sweep_sketch= [ [-local_rim_height*2-local_rim_tolerance+rim_tolerance/2, 0], + [-local_rim_tolerance+rim_tolerance/2, local_rim_height*2+local_rim_tolerance], + [rim_width-rim_offset, local_rim_height*2+local_rim_tolerance], + [rim_width+rim_offset*2, 0],]; + + + + + if(rim&&closure_type!="snap rim") + + difference(){ + + down(local_rim_height) + path_sweep( + left(rim_tolerance,sweep_sketch),method="manual",relaxed=false, + final_path,closed=true); + + if(hinge) + up(outerZ-true_hinge_downset+local_rim_tolerance) + back(innerY/2-inner_fillet/3) + prismoid( + size1=[outerX,outerY-local_rim_height*10], + size2=[outerX,outerY], + h=local_rim_height*3, + anchor=FWD); + + + if(!hinge&&closure_type=="magnets") + up(outerZ-true_hinge_downset+local_rim_tolerance-local_rim_height*2) + back((innerY+t_wallthickness)/2) + prismoid( + size1=[lip_length-local_rim_height*4,t_wallthickness], + size2=[lip_length+local_rim_height*4,t_wallthickness*2], + h=local_rim_height*4, + anchor=BOT); + + + + if(closure_type=="magnets") + up(outerZ-lip_outer_downset+local_rim_tolerance-local_rim_height*2) + fwd((innerY+t_wallthickness)/2) + prismoid( + size1=[lip_length-local_rim_height*2,t_wallthickness], + size2=[lip_length+local_rim_height*6,t_wallthickness*2], + h=local_rim_height*4, + anchor=BOT); + + } + +} + + + +module printable_box(){ + // Rysowanie zatrzasku (klipsa) + if (show_only_latch) { + // Sam klips wysrodkowany na stole + latch(just_latch=true); + } else if (!show_only_lid && !show_only_box && !show_only_latch) { + // Klips obok pudelka (gdy drukujemy calosc) + zrot(outerX>outerY?90:0) + fwd(max(outerX,outerY)/2+ latch_length) + latch(just_latch=true); + } + + // Rysowanie pudelka i pokrywki (pomijane, gdy chcemy sam klips) + if (!show_only_latch) { + if(lid) { + if(hinge){ + if(hinge_type=="print in place") pip_box_assembled(); + if(hinge_type=="pin") pin_box_assembled(); + if(hinge_type=="snap") snap_box_assembled(); + } else { + unhinged_box_assembled(); + } + } else { + if (!show_only_lid) { + lidless_body(); + } + } + } +} + + + +module rotary_tolerance_booltool(is_lid=false,is_pin=true){ + + last_barrel_number=ceil(barrel_count/2)-1; + + extra_barrel_length = hinge_type!="print in place"?outer_fillet:0; + + local_barrel_count=!is_lid?ceil(barrel_count/2):floor(barrel_count/2); + + module neg_barrel(is_lid=false,barrel_number){ + + true_barrel_length=!is_lid&&barrel_number==0||barrel_number==last_barrel_number?barrel_length+extra_barrel_length:barrel_length; + + barrel_placement_fix=!is_lid&&barrel_number==0?extra_barrel_length: + barrel_number==last_barrel_number?-extra_barrel_length: + 0; + + boolsketch = union( + make_region(circle(d=dbarrel+barrel_rotary_tolerance*2)), + hinge_type!="print in place"? + trapezoid(h=dbarrel,w2=dbarrel+barrel_rotary_tolerance*2,ang=90-extra_clearance,anchor=TOP,spin=180) + : undef + ); + + left(barrel_placement_fix/2) + yrot(90) + offset_sweep(boolsketch, + l=true_barrel_length+(hinge_type!="print in place"?barrel_chamfer*2+barrel_tolerance*2:dbarrel),anchor=FWD,ends=os_chamfer(width=(hinge_type!="print in place"?barrel_chamfer:dbarrel/2))); + } + + up((is_lid?outerZ-true_hinge_downset:true_hinge_upset)+(hinge_type!="print in place"?dbarrel/2:0)) + back(outerY/2-(hinge_type!="print in place"?dbarrel:(pip_barrel_outset*dbarrel/2)+barrel_rotary_tolerance)) + xcopies(n=floor(local_barrel_count), spacing=barrel_length*2) + neg_barrel(is_lid=is_lid,barrel_number=$idx); + +} + + +module pause_reminder(pause_height){ + + magnet_depth=magnet_type=="cylinder"?cylinder_diameter:box_depth; + + true_magnet_depth=magnet_depth+magnet_wallthickness*2-t_wallthickness; + + outset_fix= + Y_magnet_alignment=="center"?true_magnet_depth/2: + Y_magnet_alignment=="outside"?true_magnet_depth:0; + + + + font_size=outerX/10; + font_height=0.0005; + + + if(magnet_pause_helper) + if(closure_type=="magnets") + translate([0,-outerY/2-outset_fix,pause_height+layer_height/PI]){ + text3d(text=str("pause here for magnet"),anchor=BACK,h=font_height,size=font_size/2); + fwd(font_size) + text3d(text=str(pause_height," mm"),anchor=BACK,h=font_height,size=font_size*2); + + back(font_size) + cube([font_height,font_size*3.75,font_height],anchor=BACK); + fwd(font_size*0.48) + cube([outerX,0.0001,font_height],anchor=BACK); + + fwd(font_size*2.75) + cube([outerX,0.0001,font_height],anchor=BACK); + } +} + + +module magnet_array(is_lid=false,for_bool=false){ + + + + lid_mirror=is_lid?1:0; + + center_halfer=Y_magnet_alignment=="center"?0.5:1; + + inner_c_d=cylinder_diameter+magnet_tolerance*2; + outer_c_d=inner_c_d+magnet_wallthickness*2; + inner_c_h=cylinder_height+magnet_tolerance*2; + outer_c_h=inner_c_h+magnet_top_buffer*2; + + + inner_b_h=box_height+magnet_tolerance*2; + outer_b_h=inner_b_h+magnet_top_buffer*2; + inner_b_d=box_depth+magnet_tolerance*2; + outer_b_d=inner_b_d+magnet_wallthickness*2; + inner_b_l=box_length+magnet_tolerance*2; + outer_b_l=inner_b_l+magnet_wallthickness*2; + + final_magnet_depth=magnet_type=="cylinder"?outer_c_d:outer_b_d; + final_magnet_width=magnet_type=="cylinder"?outer_c_d:outer_b_l; + final_magnet_height=magnet_type=="cylinder"?outer_c_h:outer_b_h; + + + magnet_array_width = magnet_array_width_factor*(lip_length-final_magnet_width); + + magnet_count=ceil((magnet_array_width)/(minimum_magnet_gap+final_magnet_width)); + + texture_fix=Y_magnet_alignment=="inside"?exterior_type=="textured"?t_wallthickness-abs(tex_depth):0:0; + + Y_magnet_alignment_offset= + Y_magnet_alignment=="center"?0: + Y_magnet_alignment=="outside"?final_magnet_depth/2-t_wallthickness/2+epsilon: + exterior_type=="textured"?-abs(tex_depth)-final_magnet_depth/2+t_wallthickness/2-epsilon: + -final_magnet_depth/2+t_wallthickness/2-epsilon; + + module magnet_support_tool(){ + back(texture_fix) + back(Y_magnet_alignment_offset) + cuboid([final_magnet_width,0.1, + center_halfer*final_magnet_depth+final_magnet_height],anchor=TOP, + chamfer=magnet_chamfer,edges="Y"); + } + + module magnet_hole(){ + down(magnet_top_buffer*2) + cube([.001,final_magnet_depth*1.1,.001],anchor=TOP);//so the hole doesn't fall out + + down(magnet_top_buffer) + if(magnet_type=="cylinder") + cylinder(d=inner_c_d,h=inner_c_h,anchor=TOP); + else + cube([inner_b_l,inner_b_d,inner_b_h],anchor=TOP); + } + + module magnet_shell(){ + + hull(){ + magnet_support_tool(); + if(magnet_type=="cylinder") + cyl(d=outer_c_d,h=outer_c_h,anchor=TOP,chamfer=magnet_chamfer); + else + cuboid([outer_b_l+magnet_chamfer*2,outer_b_d,outer_b_h], + anchor=TOP,chamfer=magnet_chamfer); + } + } + + + + module assembled(){ + up(lid_tolerance_offset*lid_mirror){ + fwd(outerY/2-t_wallthickness/2) + up(is_lid?lip_outer_upset:lip_outer_upset) + + fwd(Y_magnet_alignment_offset) + + if(closure_type=="magnets") + mirror([0,0,lid_mirror]){ + if(for_bool) + xcopies(n=magnet_count,l=magnet_array_width) + magnet_hole(); + + + if(!for_bool) + if(connect_magnets)hull() + xcopies(n=magnet_count,l=magnet_array_width) + magnet_shell(); + else + xcopies(n=magnet_count,l=magnet_array_width) + magnet_shell(); + } + } + } + + + assembled(); + if(!hinge) + mirror([0,1,0]) + up(lip_kathete) + assembled(); + +} + +module pip_box_assembled(){ + if (!show_only_lid) { + fwd(pip_barrel_alignment_offset) + fwd(outerY/2) + fwd(pip_body_lid_tolerance/2) + union(){ + pip_body(); + pause_reminder(lip_outer_upset-magnet_top_buffer); + } + } + if (!show_only_box) { + back(pip_barrel_alignment_offset) + back(pip_body_lid_tolerance/2) + back(outerY/2){ + up(stacking_fix*2) + up(outerZ) + xrot(180) + pip_lid(); + zrot(180) + pause_reminder(lip_outer_downset-magnet_top_buffer); + } + } +} + + +module pip_body(){ + + intersection(){ + difference(){ + union(){ + difference(){ + final_shell(); + lid_bool_tool(is_lid=false); + rotary_tolerance_booltool(is_pin=false); + pip_barrel_array(is_lid=false,is_bool=true); + } + pip_barrel_array(); + magnet_array(is_lid=false,for_bool=false); + } + magnet_array(is_lid=false,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ],anchor=BOT); + } +} + + +module pip_lid(){ + + intersection(){ + difference(){ + union(){ + difference(){ + intersection(){ + final_shell(); + lid_bool_tool(is_lid=true); + } + rotary_tolerance_booltool(is_pin=false,is_lid=true); + pip_barrel_array(is_lid=true,is_bool=true); + } + magnet_array(is_lid=true,for_bool=false); + pip_barrel_array(is_lid=true); + } + up(epsilon) + magnet_array(is_lid=true,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ*2],anchor=BOT); + } + + +} + + +module pip_barrel(is_lid=false,is_bool=false,barrel_number){ + + pip_cone_offset=nozzle_diameter; + + local_lid_tolerance_offset=is_lid?lid_tolerance_offset:0; + + tangent_factor=sqrt(2)/2; + + bool_mirror=is_bool?1:0; + + lid_mirror=is_lid?1:0; + + back(dbarrel/2) + back(pip_barrel_alignment_offset) + union(){ + difference(){ + union(){ //creates the barrel without a hole + + yrot(90) //barrel + cyl(l=barrel_length-barrel_tolerance*2,d=dbarrel,chamfer=barrel_chamfer,anchor=CENTER); + + + shape = [ + [-local_lid_tolerance_offset,0], + [-tangent_factor*dbarrel/2,-tangent_factor*dbarrel/2], + [-2*tangent_factor*dbarrel/2-pip_barrel_alignment_offset-t_wallthickness, + pip_barrel_alignment_offset+t_wallthickness], + [-local_lid_tolerance_offset,t_wallthickness+pip_barrel_alignment_offset] + + ]; + + mirror([0,bool_mirror,0]) + mirror([0,0,lid_mirror]) + left(barrel_length/2-barrel_tolerance) + rot([0,-90,180]) + offset_sweep(shape, height=barrel_length-barrel_tolerance*2, + ends=os_chamfer(width=barrel_chamfer)); + + } + //negative cone slot + if(!(barrel_number==0&&is_lid)) + + left(barrel_length/2-barrel_tolerance+epsilon) + cyl(d1=0,d2=dbarrel-barrel_chamfer*2-pip_cone_offset, + l=(dbarrel-barrel_chamfer*2-pip_cone_offset)/2, + anchor=TOP,orient=LEFT); + } + + //positve cone + + right(barrel_length/2-barrel_tolerance-epsilon) + cyl(d1=pip_cone_offset,d2=dbarrel-barrel_chamfer*2-pip_cone_offset*2, + l=(dbarrel-barrel_chamfer*2-pip_cone_offset*3)/2, + anchor=TOP,orient=LEFT); + + + + } +} + + +module pip_barrel_array(is_lid=false,is_bool=false){ + + fakeable_is_lid=is_bool?!is_lid:is_lid; + + local_barrel_count=fakeable_is_lid?ceil(barrel_count/2):floor(barrel_count/2); + + up(true_hinge_upset) + //right(hinge_length/2) + back(outerY/2-dbarrel/2) + + xflip_copy() + left_half() + xcopies(n=floor(local_barrel_count), spacing=barrel_length*2) + pip_barrel(is_lid=is_lid,is_bool=is_bool,barrel_number=$idx); +} + + +module snap_box_assembled(){ + distribute(l=min(outerX,outerY)+8,dir=outerX>outerY?FWD:RIGHT){ + if (!show_only_lid) { + union(){ + snap_body(); + pause_reminder(lip_outer_upset-magnet_top_buffer); + }; + } + if (!show_only_box) { + union(){ + up(stacking_fix*2) + up(outerZ) + rot([0,180,0]) + snap_lid(); + pause_reminder(lip_outer_downset-magnet_top_buffer); + } + } + } +} + +module snap_body(){ + intersection(){ + difference(){ + union(){ + difference(){ + + final_shell(); + lid_bool_tool(is_lid=false); + rotary_tolerance_booltool(is_pin=true); + } + snap_barrel_array(is_lid=false); + magnet_array(is_lid=false,for_bool=false); + } + + + magnet_array(is_lid=false,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ],anchor=BOT); + } +} + + +module snap_lid(){ + + intersection(){ + difference(){ + union(){ + difference(){ + intersection(){ + + final_shell(); + lid_bool_tool(is_lid=true,is_pin=true); + } + rotary_tolerance_booltool(is_pin=true,is_lid=true); + } + magnet_array(is_lid=true,for_bool=false); + snap_barrel_array(is_lid=true); + } + up(epsilon) + magnet_array(is_lid=true,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ+stacking_fix*2],anchor=BOT); + } +} + + +module snap_barrel(is_lid=false,barrel_number){ + + snap_cone_offset=.3+nozzle_diameter/4; + + tangent_factor=sqrt(2)/2; + + lid_mirror=is_lid?1:0; + + last_barrel_number=ceil(barrel_count/2)-1; + + extra_barrel_length = outer_fillet; + + true_barrel_length=is_lid&&barrel_number==0||barrel_number==last_barrel_number?barrel_length+extra_barrel_length:barrel_length; + + barrel_placement_fix=is_lid&&barrel_number==0?extra_barrel_length: + barrel_number==last_barrel_number?-extra_barrel_length: + 0; + + + true_hole_length=is_lid&&barrel_number==0||barrel_number==last_barrel_number?barrel_length/2:barrel_length; + + hole_placement_fix=is_lid&&barrel_number==0?barrel_length/4: + barrel_number==last_barrel_number?-barrel_length/4: + 0; + + function sign2(input) = sign(input)==0?1:sign(input); + + module positive_cone(){ + + cyl(d1=snap_cone_offset*3,d2=dbarrel-barrel_chamfer*2-snap_cone_offset*1, + l=(dbarrel-barrel_chamfer*2-snap_cone_offset*4)/2, + anchor=TOP,orient=LEFT,chamfer1=snap_cone_offset/2,chamfang1=35); + + cyl(d=dbarrel-barrel_chamfer*2-snap_cone_offset*1, + l=barrel_length/3,anchor=TOP,orient=RIGHT); + + } + + back(pin_barrel_alignment_offset) + + difference(){ + union(){ + hull(){ //creates the barrel without a hole + left(barrel_placement_fix/2) + xcyl(l=true_barrel_length-barrel_tolerance*2,d=dbarrel,chamfer=barrel_chamfer,anchor=CENTER); + + + if(is_lid==false) //for the main body + fwd(pin_barrel_alignment_offset) //thing so it connects nicely + cuboid([ + barrel_length-barrel_tolerance*2, + t_wallthickness,dbarrel/2+barrel_rotary_tolerance+barrel_chamfer], + anchor=TOP,chamfer=barrel_chamfer) + + cuboid([ + barrel_length-barrel_tolerance*2, + t_wallthickness/2,dbarrel], + anchor=TOP+BACK); + + if(is_lid==true){ //needs some extro logic for offset=outer_chamfer){ + + local_tex_depth=exterior_type=="basic"?0:abs(tex_depth); + + shape = hull_region([ + [0,dbarrel/2], + [0,0], + [0,-dbarrel/2], + [dbarrel/2+barrel_chamfer,-dbarrel/2], + [dbarrel/2+barrel_chamfer+local_tex_depth,-dbarrel/2+local_tex_depth], + [dbarrel/2+barrel_rotary_tolerance*3,-max(dbarrel-t_wallthickness,0)/2], + [dbarrel/2+max(dbarrel-t_wallthickness,0)/2+barrel_chamfer,-dbarrel/2+min(t_wallthickness,dbarrel)], + ]); + + left(barrel_placement_fix/2) + rot([0,-90,180]) + offset_sweep(shape, height=true_barrel_length-barrel_tolerance*2, + ends=os_chamfer(width=barrel_chamfer),anchor="zcenter"); + + } else { + + shape = [ + [tangent_factor*dbarrel/2,tangent_factor*dbarrel/2], + [0,0], + [tangent_factor*dbarrel/2,-tangent_factor*dbarrel/2], + [dbarrel/2,-dbarrel/2+outer_chamfer-hinge_height_offset], + [hinge_height_offset+dbarrel/2,hinge_height_offset], + [hinge_height_offset+dbarrel/2,barrel_chamfer+max(outer_chamfer,dbarrel+barrel_rotary_tolerance)-dbarrel/2], + [hinge_height_offset+dbarrel/2-wallthickness,barrel_chamfer+dbarrel/2+barrel_rotary_tolerance], + + ]; + + left(barrel_placement_fix/2) + rot([0,-90,180]) + offset_sweep(hull_region(shape), height=true_barrel_length-barrel_tolerance*2, + ends=os_chamfer(width=barrel_chamfer),anchor="zcenter"); + + } + } + }//hull ends and union starts + + //if(!is_lid) + xflip_copy(barrel_length/2-barrel_tolerance-epsilon) + if(($idx==1&&!is_lid)||($idx==1&&is_lid)) + positive_cone(); + + }//union ends and difference starts + + //if(is_lid) + + xflip_copy() + //if(!((barrel_number==0&&$idx!=1)||(barrel_number==last_barrel_number&&$idx!=0))) + if((is_lid&&$idx==1)||(!is_lid&&$idx==1)) + right(-barrel_length/2+barrel_tolerance-epsilon) + union(){ + cyl(d1=0,d2=dbarrel-barrel_chamfer*2-snap_cone_offset, + l=(dbarrel-barrel_chamfer*2-snap_cone_offset)/2, + anchor=TOP,orient=LEFT); + //hull carves for the kegs to slot in + + chain_hull(){ + + right(snap_hinge_tolerance-barrel_tolerance*2) + positive_cone(); + + slot_offset = polar_to_xy([dbarrel/2,is_lid?0:-90]); + + move([0,slot_offset[0],-slot_offset[1]]) + right(snap_hinge_tolerance-(barrel_tolerance*2)) + positive_cone(); + + move([dbarrel/2,slot_offset[0]*2,-slot_offset[1]*2]) + right(snap_hinge_tolerance-(barrel_tolerance*2)) + positive_cone(); + + } + + } + + //for clean outer barrels on the lid + down(outerZ/2-true_hinge_downset+dbarrel/2) + fwd(pin_barrel_alignment_offset) + back(t_wallthickness/2) + if(is_lid){ + + + X_offset=barrel_length/2-(exterior_type!="basic"? + min(abs(tex_depth)*2,outer_fillet):0); + + + if(barrel_number==0) + left(barrel_placement_fix) + left(X_offset) + rounding_edge_mask(l=outerZ,excess=dbarrel+abs(tex_depth)*2, r=outer_fillet,spin=-90,chamfer=outer_chamfer) + cuboid([outerY,dbarrel,outerZ],chamfer=-outer_chamfer,anchor=BACK) + ; + + if(barrel_number==last_barrel_number) + left(barrel_placement_fix) + right(X_offset) + rounding_edge_mask(l=outerZ,excess=dbarrel+abs(tex_depth)*2, r=outer_fillet,spin=180,chamfer=outer_chamfer) + cuboid([dbarrel,outerY,outerZ],chamfer=-outer_chamfer,anchor=RIGHT) + ; + + + + } + } +} + + +module snap_barrel_array(is_lid=false){ + + local_barrel_count=is_lid?ceil(barrel_count/2):floor(barrel_count/2); + + //orient the first barrel to the back left + up(true_hinge_upset+dbarrel/2) + //right(-outerX/2+outer_fillet) + back(outerY/2-t_wallthickness/2) + xflip_copy() + left_half() + xcopies(n=floor(local_barrel_count), spacing=barrel_length*2) + snap_barrel(is_lid=is_lid,barrel_number=$idx); +} + + +module pin_box_assembled(){ + distribute(l=min(outerX,outerY)+8,dir=outerX>outerY?FWD:RIGHT){ + if (!show_only_lid) { + union(){ + pin_body(); + pause_reminder(lip_outer_upset-magnet_top_buffer); + }; + } + if (!show_only_box) { + union(){ + up(stacking_fix*2) + up(outerZ) + rot([0,180,0]) + pin_lid(); + pause_reminder(lip_outer_downset-magnet_top_buffer); + } + } + } +} + +module pin_body(){ + intersection(){ + difference(){ + union(){ + difference(){ + + final_shell(); + lid_bool_tool(is_lid=false); + rotary_tolerance_booltool(is_pin=true); + } + pin_barrel_array(is_lid=false); + magnet_array(is_lid=false,for_bool=false); + } + magnet_array(is_lid=false,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ],anchor=BOT); + } +} + + +module pin_lid(){ + + intersection(){ + difference(){ + union(){ + difference(){ + intersection(){ + + final_shell(); + lid_bool_tool(is_lid=true,is_pin=true); + } + rotary_tolerance_booltool(is_pin=true,is_lid=true); + } + magnet_array(is_lid=true,for_bool=false); + pin_barrel_array(is_lid=true); + } + pin_hole(); + up(epsilon) + magnet_array(is_lid=true,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ+stacking_fix*2],anchor=BOT); + } +} + + +module pin_barrel(is_lid=false,barrel_number){ + + tangent_factor=sqrt(2)/2; + + lid_mirror=is_lid?1:0; + + last_barrel_number=ceil(barrel_count/2)-1; + + extra_barrel_length = outer_fillet; + + true_barrel_length=is_lid&&barrel_number==0||barrel_number==last_barrel_number?barrel_length+extra_barrel_length:barrel_length; + + barrel_placement_fix=is_lid&&barrel_number==0?extra_barrel_length: + barrel_number==last_barrel_number?-extra_barrel_length: + 0; + + + true_hole_length=is_lid&&barrel_number==0||barrel_number==last_barrel_number?barrel_length/2:barrel_length; + + hole_placement_fix=is_lid&&barrel_number==0?barrel_length/4: + barrel_number==last_barrel_number?-barrel_length/4: + 0; + + function sign2(input) = sign(input)==0?1:sign(input); + + + back(pin_barrel_alignment_offset) + + difference(){ + + hull(){ //creates the barrel without a hole + left(barrel_placement_fix/2) + + xcyl(l=true_barrel_length-barrel_tolerance*2,d=dbarrel,chamfer=barrel_chamfer,anchor=CENTER); + + + if(is_lid==false) //for the main body + fwd(pin_barrel_alignment_offset) //thing so it connects nicely + cuboid([ + barrel_length-barrel_tolerance*2, + t_wallthickness,dbarrel/2+barrel_rotary_tolerance+barrel_chamfer], + anchor=TOP,chamfer=barrel_chamfer) + + cuboid([ + barrel_length-barrel_tolerance*2, + t_wallthickness/2,dbarrel], + anchor=TOP+BACK); + + if(is_lid==true){ //needs some extro logic for offsetouter_chamfer){ + + local_tex_depth=exterior_type=="basic"?0:abs(tex_depth); + + shape = hull_region([ + [0,dbarrel/2], + [0,0], + [0,-dbarrel/2], + [dbarrel/2+barrel_chamfer,-dbarrel/2], + [dbarrel/2+barrel_chamfer+local_tex_depth,-dbarrel/2+local_tex_depth], + [dbarrel/2+barrel_rotary_tolerance*3,-max(dbarrel-t_wallthickness,0)/2], + [dbarrel/2+max(dbarrel-t_wallthickness,0)/2+barrel_chamfer,-dbarrel/2+min(t_wallthickness,dbarrel)], + ]); + + left(barrel_placement_fix/2) + rot([0,-90,180]) + + + offset_sweep(shape, height=true_barrel_length-barrel_tolerance*2, + ends=os_chamfer(width=barrel_chamfer),anchor="zcenter"); + + } else { + + shape = [ + [tangent_factor*dbarrel/2,tangent_factor*dbarrel/2], + [0,0], + [tangent_factor*dbarrel/2,-tangent_factor*dbarrel/2], + [dbarrel/2,-dbarrel/2+outer_chamfer-hinge_height_offset], + [hinge_height_offset+dbarrel/2,hinge_height_offset], + [hinge_height_offset+dbarrel/2,barrel_chamfer+max(outer_chamfer,dbarrel+barrel_rotary_tolerance)-dbarrel/2], + [hinge_height_offset+dbarrel/2-wallthickness,barrel_chamfer+dbarrel/2+barrel_rotary_tolerance], + + ]; + + left(barrel_placement_fix/2) + rot([0,-90,180]) + offset_sweep(hull_region(shape), height=true_barrel_length-barrel_tolerance*2, + ends=os_chamfer(width=barrel_chamfer),anchor="zcenter"); + + } + } + } + //chamfered teardrop hole + + right(hole_placement_fix) + yrot(180*lid_mirror) + zrot(-90) + teardrop(d=dpin, l=true_hole_length-barrel_tolerance*2+epsilon,ang=55, + chamfer1=-barrel_chamfer*sign2(barrel_placement_fix), + chamfer2=-barrel_chamfer*sign2(-barrel_placement_fix)); + + down(outerZ/2-true_hinge_downset+dbarrel/2) + fwd(pin_barrel_alignment_offset) + back(t_wallthickness/2) + if(is_lid){ + + + X_offset=barrel_length/2-(exterior_type!="basic"? + min(abs(tex_depth)*2,outer_fillet):0); + + + if(barrel_number==0) + left(barrel_placement_fix) + left(X_offset) + rounding_edge_mask(l=outerZ,excess=dbarrel+abs(tex_depth)*2, r=outer_fillet,spin=-90,chamfer=outer_chamfer) + cuboid([outerY,dbarrel,outerZ],chamfer=-outer_chamfer,anchor=BACK) + ; + + if(barrel_number==last_barrel_number) + left(barrel_placement_fix) + right(X_offset) + rounding_edge_mask(l=outerZ,excess=dbarrel+abs(tex_depth)*2, r=outer_fillet,spin=180,chamfer=outer_chamfer) + cuboid([dbarrel,outerY,outerZ],chamfer=-outer_chamfer,anchor=RIGHT) + ; + + + + } + } +} + + +module pin_barrel_array(is_lid=false){ + + local_barrel_count=is_lid?ceil(barrel_count/2):floor(barrel_count/2); + + //orient the first barrel to the back left + up(true_hinge_upset+dbarrel/2) + //right(-outerX/2+outer_fillet) + back(outerY/2-t_wallthickness/2) + xcopies(n=floor(local_barrel_count), spacing=barrel_length*2) + pin_barrel(is_lid=is_lid,barrel_number=$idx); +} + + +module lid_bool_tool(is_lid=false,is_pin=false){ + + //alignment to the back of the + local_lid_bool=is_lid?1:0; + + difference(){ + + //up(lid_tolerance_offset*local_lid_bool) + down(is_lid?0:min_tolerance) + union(){ + shape = [ + [outerZ-lip_outer_downset,innerY/2-innerY*lip_inset], + [outerZ-true_hinge_downset,-innerY/2+innerY*hinge_inset], + [outerZ-true_hinge_downset,-outerY], + [outerZ*2,-outerY], + [outerZ*2,outerY], + [outerZ-lip_outer_downset,outerY+max(cylinder_diameter+box_depth,0)]]; + + + + + radii = [true_lip_inset_rounding,true_hinge_inset_rounding,0,0,0,0]; + + //color("teal") + + rot([0,-90,180]) + linear_extrude(outerX*3,center=true)polygon(round_corners(shape, radius = radii)); + + snap_rim(is_lid=is_lid); + + }; + + rim(is_lid); + + + //this carves out space for the barrel array + if(is_lid&&is_pin){ + barrel_cutter_length=min(hinge_length-barrel_chamfer*2-barrel_tolerance*2-epsilon,innerX); + + //stops before carving into the top wall + + up(outerZ-max(true_hinge_downset-dbarrel+(dividers?divider_chamfer:0),wallthickness)) + back(outerY/2-dbarrel) +// //back(outerY/2-dbarrel-inner_chamfer*2) +// //fwd(inner_chamfer*2) + cuboid([barrel_cutter_length,outerY,outerY],//rounding=dbarrel/2, + anchor=TOP+FRONT); + + + //this then overtakes and carves with a rounded edge + + up(outerZ-true_hinge_downset+dbarrel) + back(outerY/2-t_wallthickness/2+pin_barrel_alignment_offset-dbarrel/2) + fwd(barrel_rotary_tolerance) + cuboid([barrel_cutter_length,outerY,outerY], + rounding=hinge_height_offset==0?0:dbarrel/2, + anchor=TOP+FRONT,edges=TOP+FRONT); + + //rounding for smooth rotation + up(outerZ-true_hinge_downset) + back(outerY/2-t_wallthickness/2+dbarrel/2) + back(pin_barrel_alignment_offset) + xrot(90) + yrot(-90) + rounding_edge_mask(l=outerX, r=dbarrel/2,excess=2); + } + } + +} + +module unhinged_box_assembled(){ + distribute(l=min(outerX,outerY)+8,dir=outerX>outerY?FWD:RIGHT){ + if (!show_only_lid) { + union(){ + unhinged_body(); + pause_reminder(lip_outer_upset-magnet_top_buffer); + } + } + if (!show_only_box) { + union(){ + up(stacking_fix*2) + up(outerZ) + rot([0,180,0]) + unhinged_lid(); + pause_reminder(lip_outer_downset-magnet_top_buffer); + } + } + } +} + + +module unhinged_body(){ + intersection(){ + difference(){ + union(){ + difference(){ + final_shell(); + lid_bool_tool(is_lid=false); + } + magnet_array(is_lid=false,for_bool=false); + } + magnet_array(is_lid=false,for_bool=true); + } + cube([outerX*3,outerY*3,outerZ],anchor=BOT); + } +} + + +module unhinged_lid(){ + intersection(){ + difference(){ + union(){ + intersection(){ + final_shell(); + lid_bool_tool(is_lid=true); + } + magnet_array(is_lid=true,for_bool=false); + } + magnet_array(is_lid=true,for_bool=true); + } + cube([outerX*3,outerY*3,true_outerZ],anchor=BOT); + } +} + + +module lidless_body(){ + + final_shell(); + +} + + +module cached_shell() { + // Convexity helps OpenSCAD preview not look "glitchy" with complex holes + render(convexity=10) + final_shell(); +} + + +module final_shell(){ + // convexity helps OpenSCAD preview (F5) render the inside of hollow objects correctly. + // A value of 10-20 is usually safe for complex shells. + difference(){ + union(){ + render(convexity=12) { + if(exterior_type=="basic") + basic_shell(); + if(exterior_type=="textured") + textured_shell(); + if(exterior_type=="complex") + complex_shell(); + } + latch(for_bool=false); + if(lid_handle) + lid_handle(); + } + latch(for_bool=true); + } +} + + +module shell_inside(){ + + bottom_fill_fix=fill_bottom&&gridfinity_support? + -wallthickness+5+layer_height*3:0; + + stacking_lip_fix=stacking_lip&&gridfinity_support? + .8:0; + + difference(){ + union(){ + up(wallthickness+bottom_fill_fix) + offset_sweep( + rect([innerX,innerY],rounding=inner_fillet), + height=(lid?innerZ-stacking_lip_fix:innerZ+wallthickness+epsilon)-bottom_fill_fix, + bot=os_chamfer(width=inner_chamfer), + top=os_chamfer(width=lid?inner_chamfer: + gridfinity_support&&stacking_lip?0:-t_wallthickness/3), + anchor="base" + ); + + if(gridfinity_support&&stacking_lip){ + up(outerZ) + prismoid(size1=[outerX-(3.4)*2,outerY-(3.4)*2], size2=[outerX-(2.6)*2,outerY-(2.6)*2], h=0.8, rounding2=1.6/2,anchor=TOP); + + if(!lid) + up(outerZ-.8) + prismoid(size2=[outerX-(3.4)*2,outerY-(3.4)*2], + size1=[outerX-(3.4+t_wallthickness)*2,outerY-(3.4+t_wallthickness)*2], h=t_wallthickness,anchor=TOP); + } + } + + + + if(dividers) + up(wallthickness+bottom_fill_fix) + offset_sweep( + dividers(),h=innerZ*divider_Z_height-bottom_fill_fix, + bot=os_chamfer(width=-divider_chamfer), + top=os_chamfer(width=divider_Z_height==1?-divider_chamfer:divider_thickness/3) + ); + + if(gridfinity_support){gridfinity_bottom(is_bool=false);} + } +} + + +module watermark(){ + + smallest= 0.00001; + + text="made by lorenz's Any Box Generator"; + + yflip_copy(smallest/2) + text3d(text, h=smallest,size = smallest, anchor=CENTER,$fn=12); + + cube([len(text)*smallest*0.72,smallest*4,smallest/2],anchor=CENTER); +} + + +module basic_shell(){ + + difference(){ + union(){ + offset_sweep( + rect([outerX,outerY],rounding=outer_fillet), + height=outerZ, + bot=os_chamfer(width=gridfinity_support?0:outer_chamfer), + top=os_chamfer(width=gridfinity_support&&stacking_lip? + 0: + lid?outer_chamfer:t_wallthickness/3), + anchor="base" + ); + + gridfinity_stacking_lip(); + } + + if(lid_groove) + lid_groove(); + + shell_inside(); + gridfinity_bottom(is_bool=true); + + + up(outerZ/2) + zflip_copy(outerZ/2) + watermark(); + } + +} + + +//self explanotaory +true_outerZ=gridfinity_support&&stacking_lip?outerZ+4.75:outerZ; + + +module textured_shell(){ + + + + diff_scaled_textures=["hexagon","cubes","noise"]; + + diff_scaled_tex_factor=in_list(texture_pattern,diff_scaled_textures)?(rotate_texture?1/root3:root3):1; + + shell_circumference=path_length(Tsketch,closed=true); + + //calculates how many tiles are wraped around the shell + horizontal_tiles=round(shell_circumference/texture_scale); + + //how big the tiles actually are + real_texture_scale=shell_circumference/horizontal_tiles; + + function ceil_to_tile(value,multiple=real_texture_scale*diff_scaled_tex_factor)=ceil(value/multiple)*multiple; + + //calculates the height so that the tiles are correctly scaled + ideal_height=ceil_to_tile(true_outerZ); + + rot_var=rotate_texture?90:0; + + + + intersection(){ + + + basic_shell(); + + + + //texture presets are configured here + if(texture_pattern=="cubes") + linear_sweep( + Tsketch, + tex_rot=rot_var, + tex_inset=.5, + tex_depth=tex_depth, + texture=("cubes"), + h=ideal_height, + tex_samples=round_to((texture_scale*$fn)/60,1), + tex_size=[real_texture_scale,real_texture_scale*diff_scaled_tex_factor], + style="quincunx" + ) + ; + + if(texture_pattern=="hexagon") + linear_sweep( + Tsketch, + tex_rot=rot_var, + tex_inset=.5, + tex_depth=tex_depth, + texture=("hex_grid"), + h=ideal_height, + tex_samples=round_to((texture_scale*$fn)/60,1), + tex_size=[real_texture_scale,real_texture_scale*diff_scaled_tex_factor], + style="concave" + ); + + + + if(texture_pattern=="trunc diamonds") + linear_sweep( + Tsketch, + tex_inset=.5, + tex_depth=tex_depth, + texture=rotate_texture?texture("trunc_pyramids_vnf",border=0.15):("trunc_diamonds"), + h=ideal_height, + tex_samples=round_to((texture_scale*$fn)/40,1), + tex_size=[real_texture_scale,real_texture_scale], + style="concave" + ); + + + if(texture_pattern=="diamonds") + linear_sweep( + Tsketch, + tex_inset=.5, + tex_depth=tex_depth, + texture=rotate_texture?"pyramids_vnf":texture("diamonds_vnf"), + h=ideal_height, + tex_samples=2, + tex_size=[real_texture_scale,real_texture_scale], + style="concave" + ); + + if(texture_pattern=="stripes") + linear_sweep( + Tsketch, + tex_rot=rot_var, + tex_inset=.5, + tex_depth=abs(tex_depth), + texture=diag_stripes_vnf(), + tex_samples=round_to((texture_scale*$fn)/40,1), + h=ideal_height, + tex_size=[real_texture_scale,real_texture_scale], + style="alt" + ); + + if(texture_pattern=="ribs") + linear_sweep( + Tsketch, + tex_rot=rot_var, + tex_inset=.5, + tex_depth=tex_depth, + texture=texture("trunc_ribs_vnf", gap=1/3, border=1/6), + tex_samples=round_to((texture_scale*$fn)/40,1), + h=ideal_height, + tex_size=[real_texture_scale,real_texture_scale], + style="concave" + ); + + if(texture_pattern=="noise") + linear_sweep( + Tsketch, + tex_inset=.5, + tex_depth=tex_depth, + texture=texture("rough"), + h=ceil_to_tile(true_outerZ,multiple=real_texture_scale*8), + tex_size=[real_texture_scale*8,real_texture_scale*8], + style="convex" + ); + + + if(texture_pattern=="wave") + linear_sweep( + Tsketch, + tex_inset=.5, + tex_depth=tex_depth, + texture=texture("hills",round_to((texture_scale*$fn)/32,1)), + h=ideal_height, + tex_size=[real_texture_scale,real_texture_scale], + style="default" + ); + + if(texture_pattern=="round ribs") + linear_sweep( + Tsketch, + tex_rot=rot_var, + tex_inset=.5, + tex_depth=tex_depth, + texture=half_pillars(), + h=ideal_height, + tex_samples=rotate_texture?(max(round(texture_scale*$fn/32),2)):2, + tex_size=[real_texture_scale,real_texture_scale], + ); + + + + } + ; +} + + +module complex_shell(){ + + + + inset_fix = 1-((abs(tex_depth)/2)/t_wallthickness); + + diff_scaled_textures=["hex_scaffold"]; + + diff_scaled_tex_factor=in_list(complex_pattern,diff_scaled_textures)? + sqrt(3):1;//root3*1.07221 + + shell_circumference=path_length(Tsketch,closed=true); + + //calculates how many tiles are wraped around the shell + horizontal_tiles=round(shell_circumference/complex_scale); + + //how big the tiles actually are + real_complex_scale=shell_circumference/horizontal_tiles; + + function ceil_to_tile(value,multiple=real_complex_scale*diff_scaled_tex_factor) + =ceil(value/multiple)*multiple; + + //calculates the height so that the tiles are correctly scaled + ideal_height=ceil_to_tile(true_outerZ); + + + intersection(){ + if(!add_texture_to_complex_shell) + basic_shell(); + else + textured_shell(); + + union(){ + + offset_sweep( + offset(rect([innerX,innerY],rounding=inner_fillet),r=-epsilon+t_wallthickness*extra_wall), + height=outerZ, + anchor="base" +); + + + cuboid([outerX,outerY,wallthickness+inner_chamfer],anchor=BOT); + if(lid) + up(outerZ) + cuboid([outerX,outerY,wallthickness+inner_chamfer],anchor=TOP); + + if(complex_pattern=="weave") + linear_sweep( + Tsketch, + tex_inset=inset_fix, + tex_depth=t_wallthickness, + texture=diag_weave_vnf(), + h=ideal_height, + tex_samples=round_to((complex_scale*$fn)/64,1), + tex_size=[real_complex_scale,real_complex_scale] + + ) + ; + + if(complex_pattern=="hex_scaffold") + linear_sweep( + Tsketch, + tex_inset=inset_fix, + tex_depth=t_wallthickness, + texture=hex_wall(), + h=ideal_height, + tex_samples=round_to((complex_scale*$fn)/64,1), + tex_size=[real_complex_scale,real_complex_scale*root3], + spin=180 + ) + ; + + if(complex_pattern=="gyroid"){ + + v_size=1/complex_resolution; + + + vnf= + isosurface(function(x,y,z)gyroid(x,y,z, wavelength=1), + [-scaffold_thickness*1.2,scaffold_thickness*1.2], 1, voxel_size=v_size,closed=true); + up(outerZ/2) + zcopies(complex_scale*1,n=ceil(outerZ/complex_scale)) + grid_copies(complex_scale,n=[ceil(outerX/complex_scale),ceil(outerY/complex_scale)]) + //rot([0,45,0]) + resize([complex_scale,complex_scale,complex_scale*1]) + + vnf_polyhedron(vnf); + } + ; + + + + + } + } +}; + + +module insert_tray(t_outerZ) { + t_outerX = innerX - tray_tolerance * 2; + t_outerY = innerY - tray_tolerance * 2; + + t_outer_fillet = max(inner_fillet - tray_tolerance, 0.1); + t_inner_fillet = max(t_outer_fillet - tray_wall_thickness, 0.1); + + difference() { + offset_sweep( + rect([t_outerX, t_outerY], rounding=t_outer_fillet), + height=t_outerZ, + bot=os_chamfer(width=1), + top=os_chamfer(width=0), + anchor="base" + ); + + up(tray_wall_thickness) + offset_sweep( + rect([t_outerX - tray_wall_thickness*2, t_outerY - tray_wall_thickness*2], rounding=t_inner_fillet), + height=t_outerZ + epsilon, + bot=os_chamfer(width=0), + top=os_chamfer(width=-tray_wall_thickness/3), + anchor="base" + ); + } +} + + + + +// ============================================== +// GLOWNE WYWOLANIE (Pudelko albo wkladki) +// ============================================== + +if (show_trays || show_only_tray_1 || show_only_tray_2) { + // Oblicza pozostale miejsce na druga wkladke (pod sam zawias) + bottom_internal_height = (outerZ - lip_outer_downset) - wallthickness; + auto_depth = max(bottom_internal_height - tray_depth - 0.5, 2); + + if (show_trays) { + // Rysuje obie wkladki obok siebie + insert_tray(tray_depth); + right(outerX + 15) + insert_tray(auto_depth); + } else if (show_only_tray_1) { + // Rysuje tylko pierwsza wkladke (na srodku) + insert_tray(tray_depth); + } else if (show_only_tray_2) { + // Rysuje tylko druga wkladke (na srodku) + insert_tray(auto_depth); + } +} else { + // Rysuje standardowe pudelko + hsv(h=170,s=.05,v=.8) + render() + printable_box(); +}