gridfinity-rebuilt-openscad.../gridfinity-rebuilt.scad
kennetek 2a21923f4e Overhaul of cutter objects for optimized rendering
Old version of cutters had many shared surfaces which caused lag in preview window and caused fast-csg fail to provide speed boosts. Replaced with minkowski function to get the fillets. Benchmark: 5x3x6-5x2 reduced from 8 minutes to 6 seconds. Fixed a small error with the outer size (42mm to 41.5mm) to account for tolerances. Created gifs to illustrate the scripts functions.
2022-08-04 01:10:32 -07:00

381 lines
11 KiB
OpenSCAD

$fa = 8;
$fs = 0.25;
// number of bases along x-axis
gridx = 5;
// number of bases along y-axis
gridy = 3;
// unit height along z-axis (2, 3, or 6, but can be any)
gridz = 6;
// number of x compartments (ideally, coprime w/ gridx)
n_divx = 5;
// number of y compartments (ideally, coprime w/ gridy)
n_divy = 2;
// set n_div values to 0 for a solid bin (for custom bins)
// base unit (if you want to go rogue ig)
length = 42;
// type of tab. alignment only matters if tabs are large enough
// tab style. 0:full, 1:automatic, 2:left, 3:center, 4:right, 5:none
style_tab = 1;
// the rounded edge that allows for easy removal
enable_scoop = true;
// holes on the base for magnet / screw
enable_holes = true;
// extra cut within holes for better slicing
enable_hole_slit = true;
// ===== Info =====
// rendering will be better for analyzing the model if fast-csg is enabled. This feature is only available in the nightly build and not the official release of OpenSCAD, but if makes rendering only take a couple seconds. Enable it in Edit > Preferences > Features > fast-csg
// the plane that is the top of the internal bin solid is d_height+h_base above z=0
// the magnet holes have an extra cut in them to make it easier to print without supports
// tabs will automatically be disabled when gridz is less than 3, as the tabs take up too much space
// ===== Dimensions =====
h_base = 5; // height of the base
r_base = 4; // outside rounded radius of bin
r_c1 = 0.8; // lower base chamfer "radius"
r_c2 = 2.4; // upper base chamfer "radius"
h_bot = 2.2; // bottom thiccness of bin
r_fo1 = 7.5; // outside radii
r_fo2 = 3.2;
r_fo3 = 1.6;
r_hole1 = 1.5; // screw hole radius
r_hole2 = 3.25; // magnet hole radius
d_hole = 26; // center-to-center distance between holes
h_hole = 2.4; // magnet hole depth
r_f1 = 0.6; // top edge fillet radius
r_f2 = 1.5; // internal fillet radius
r_f3 = 0.6; // lip fillet radius
d_div = 1.2; // width of divider between compartments
d_wall = 0.95; // minimum wall thickness
d_clear = 0.25; // tolerance fit factor
d_tabh = 15.85; // height of tab (yaxis, measured from inner wall)
d_tabw = length; // maximum width of tab
a_tab = 36;
d_height = (gridz-1)*7 + 2;
r_scoop = enable_scoop ? length*gridz/12 - r_f2 : 0; // scoop radius
d_wall2 = r_base-r_c1-d_clear*sqrt(2);
d_pitchx = (gridx*length-0.5-2*d_wall-(n_divx-1)*d_div)/n_divx;
d_pitchy = (gridy*length-0.5-2*d_wall-(n_divy-1)*d_div)/n_divy;
color("tomato")
gridfinity();
// ===== Modules =====
module gridfinity() {
difference() {
// solid bin
color("firebrick") block_bottom(d_height);
// subtraction blocks
color("sienna") block_cutter();
}
color("orange") block_base();
color("royalblue") block_wall();
}
module profile_base() {
polygon([
[0,0],
[0,h_base],
[r_base,h_base],
[r_base-r_c2,h_base-r_c2],
[r_base-r_c2,r_c1],
[r_base-r_c2-r_c1,0]
]);
}
module block_base() {
translate([0,0,h_base])
rounded_rectangle(gridx*length-0.5+0.002, gridy*length-0.5+0.002, h_bot/1.5, r_fo1/2+0.001);
pattern_linear(gridx, gridy, length)
render()
difference() {
translate([0,0,h_base])
mirror([0,0,1])
union() {
hull() {
rounded_square(length-0.5-2*r_c2-2*r_c1, h_base, r_fo3/2);
rounded_square(length-0.5-2*r_c2, h_base-r_c1, r_fo2/2);
}
hull() {
rounded_square(length-0.5-2*r_c2, r_c2, r_fo2/2);
mirror([0,0,1])
rounded_square(length-0.5, h_bot/2, r_fo1/2);
}
}
if (enable_holes)
pattern_circular(4)
translate([d_hole/2, d_hole/2, 0]) {
union() {
difference() {
cylinder(h = 2*(h_hole+(enable_hole_slit?0.2:0)), r = r_hole2, center=true);
if (enable_hole_slit)
copy_mirror([0,1,0])
translate([-1.5*r_hole2,r_hole1+0.1,h_hole])
cube([r_hole2*3,r_hole2*3, 0.4]);
}
cylinder(h = 3*h_base, r = r_hole1, center=true);
}
}
}
}
module profile_wall_sub() {
difference() {
polygon([
[0,0],
[d_wall/2,0],
[d_wall/2,d_height-1.2-d_wall2+d_wall/2],
[d_wall2,d_height-1.2],
[d_wall2,d_height+h_base],
[0,d_height+h_base]
]);
color("red")
offset(delta = 0.25)
translate([r_base,d_height,0])
mirror([1,0,0])
profile_base();
square([d_wall,0.1]);
}
}
module profile_wall() {
translate([r_base,0,0])
mirror([1,0,0])
difference() {
profile_wall_sub();
difference() {
translate([0, d_height+h_base-d_clear*sqrt(2), 0])
circle(r_base/2);
offset(r = r_f1)
offset(delta = -r_f1)
profile_wall_sub();
}
}
}
module block_wall() {
translate([0,0,h_base])
sweep_rounded(gridx*length-2*r_base-0.5-0.001, gridy*length-2*r_base-0.5-0.001)
profile_wall();
}
module block_bottom( h = 2.2 ) {
translate([0,0,h_base+0.1])
rounded_rectangle(gridx*length-0.5-d_wall/4, gridy*length-0.5-d_wall/4, d_height-0.1, r_base+0.01);
}
module block_cutter() {
for (j = [1:n_divy])
translate(-(j-1)*(d_pitchy + d_div)*[0,1,0])
for (i = [1:n_divx])
translate(((i-1)-(n_divx-1)/2)*(d_pitchx + d_div)*[1,0,0])
translate([0,gridy*length/2-0.25-d_wall,h_base+h_bot])
rotate([90,0,-90])
cutter(i,j);
}
module cutter(i,j) {
v_len_tab = d_tabh;
v_len_lip = d_wall2-d_wall+1.2;
v_cut_tab = d_tabh - (2*r_f1)/tan(a_tab);
v_cut_lip = d_wall2-d_wall;
v_ang_tab = a_tab;
v_ang_lip = 45;
enable_tab = style_tab != 5;
height = d_height;
extent = (enable_scoop && j==n_divy ? d_wall2-d_wall : 0);
tab = ((gridz < 3 || style_tab == 5) && j == 1) ? v_len_lip : v_len_tab;
ang = ((gridz < 3 || style_tab == 5) && j == 1) ? v_ang_lip : v_ang_tab;
cut = ((gridz < 3 || style_tab == 5) && j == 1) ? v_cut_lip : v_cut_tab;
style = (style_tab > 1 && style_tab < 5) ? style_tab-3 : (i == 1 ? -1 : i == n_divx ? 1 : 0);
if (gridz >= 3 && d_pitchx - d_tabw > 4*r_f2) {
if (style_tab != 0 && style_tab != 5 && j == 1)
fillet_cutter(3,"bisque")
transform_tab(style)
translate([d_wall2-d_wall,0])
profile_cutter(height-h_bot, d_pitchy/2);
if (style_tab != 0 && style_tab != 5)
fillet_cutter(2,"indigo")
transform_tab(style)
difference() {
intersection() {
profile_cutter(height-h_bot, d_pitchy-extent);
profile_cutter_tab(height-h_bot, v_len_tab, v_ang_tab);
}
if (j==1) profile_cutter_tab(height-h_bot, v_len_lip, 45);
}
}
if (!(style_tab == 5 && j != 1))
fillet_cutter(1,"seagreen")
transform_main()
translate([cut,0])
profile_cutter(height-h_bot,d_pitchy/2);
fillet_cutter(0,"hotpink")
transform_main()
difference() {
profile_cutter(height-h_bot, d_pitchy-extent);
if (!((gridz < 3 || style_tab == 5) && j != 1))
profile_cutter_tab(height-h_bot, tab, ang);
if (!enable_scoop && j == n_divy)
translate([d_pitchy-extent,0,0])
mirror([1,0,0])
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
}
if (!enable_scoop && j == n_divy) {
fillet_cutter(5,"darkslategray")
translate([d_pitchy-(d_wall2-d_wall+2*r_f2)-v_cut_lip,0,0])
transform_main()
profile_cutter(height-h_bot,d_wall2-d_wall+2*r_f2);
}
}
module transform_main() {
translate([0,0,-(d_pitchx-2*r_f2)/2])
linear_extrude(d_pitchx-2*r_f2)
children();
}
module transform_tab(type) {
mirror([0,0,type==1?1:0])
copy_mirror([0,0,-(abs(type)-1)])
translate([0,0,-d_pitchx/2])
translate([0,0,r_f2])
linear_extrude((d_pitchx-length)/(1-(abs(type)-1))-2*r_f2)
children();
}
module fillet_cutter(t = 0, c = "goldenrod") {
color(c)
minkowski() {
children();
sphere(r = r_f2-t/1000);
}
}
module profile_cutter(h, length) {
translate([r_f2,r_f2])
hull() {
if (length-r_scoop-2*r_f2 > 0)
square(0.1);
if (r_scoop < h) {
translate([length-2*r_f2,h-r_f2/2])
mirror([1,1])
square(0.1);
translate([0,h-r_f2/2])
mirror([0,1])
square(0.1);
}
difference() {
translate([length-r_scoop-2*r_f2, r_scoop])
if (r_scoop != 0) {
intersection() {
circle(r_scoop);
mirror([0,1]) square(2*r_scoop);
}
} else mirror([1,0]) square(0.1);
translate([length-r_scoop-2*r_f2,-1])
square([-(length-r_scoop-2*r_f2),2*h]);
translate([0,h])
square([2*length,r_scoop]);
}
}
}
module profile_cutter_tab(h, tab, ang) {
if (tab > 0)
color("blue")
offset(delta = r_f2)
polygon([[0,h],[tab,h],[0,h-tab*tan(ang)]]);
}
// ==== Utilities =====
module rounded_rectangle(length, width, height, rad) {
linear_extrude(height)
offset(rad)
offset(-rad)
square([length,width], center = true);
}
module rounded_square(length, height, rad) {
rounded_rectangle(length, length, height, rad);
}
module copy_mirror(vec=[0,1,0]) {
children();
if (vec != [0,0,0])
mirror(vec)
children();
}
module pattern_linear(x = 1, y = 1, spacing = 0) {
translate([-(x-1)*spacing/2,-(y-1)*spacing/2,0])
for (i = [1:x])
for (j = [1:y])
translate([(i-1)*spacing,(j-1)*spacing,0])
children();
}
module pattern_circular(n=2) {
for (i = [1:n])
rotate(i*360/n)
children();
}
module sweep_rounded(w=10, h=10) {
union() pattern_circular(2) {
copy_mirror([1,0,0])
translate([w/2,h/2,0])
rotate_extrude(angle = 90, convexity = 4)
children();
translate([w/2,0,0])
rotate([90,0,0])
linear_extrude(height = h, center = true)
children();
rotate([0,0,90])
translate([h/2,0,0])
rotate([90,0,0])
linear_extrude(height = w, center = true)
children();
}
}