Add first crack files

This commit is contained in:
Tyler 2025-07-07 17:14:10 -04:00
parent c581a35abf
commit 054811a55c
Signed by: tyler
GPG Key ID: 03B27509E17EFDC8
7 changed files with 927 additions and 0 deletions

BIN
MicroscopeLenseHolder.FCStd Normal file

Binary file not shown.

Binary file not shown.

85
gridfinity-constants.scad Normal file
View File

@ -0,0 +1,85 @@
// height of the base
h_base = 5;
// outside rounded radius of bin
r_base = 4;
// lower base chamfer "radius"
r_c1 = 0.8;
// upper base chamfer "radius"
r_c2 = 2.4;
// bottom thiccness of bin
h_bot = 2.2;
// outside radii 1
r_fo1 = 8.5;
// outside radii 2
r_fo2 = 3.2;
// outside radii 3
r_fo3 = 1.6;
// screw hole radius
r_hole1 = 1.5;
// magnet hole radius
r_hole2 = 3.25;
// center-to-center distance between holes
d_hole = 26;
// magnet hole depth
h_hole = 2.4;
// slit depth (printer layer height)
h_slit = 0.2;
// top edge fillet radius
r_f1 = 0.6;
// internal fillet radius
r_f2 = 2.8;
// width of divider between compartments
d_div = 1.2;
// minimum wall thickness
d_wall = 0.95;
// tolerance fit factor
d_clear = 0.25;
// height of tab (yaxis, measured from inner wall)
d_tabh = 15.85;
// maximum width of tab
d_tabw = 42;
// angle of tab
a_tab = 36;
d_wall2 = r_base-r_c1-d_clear*sqrt(2);
d_magic = -2*d_clear-2*d_wall+d_div;
// Baseplate constants
// Baseplate bottom part height (part added with weigthed=true)
bp_h_bot = 6.4;
// Baseplate bottom cutout rectangle size
bp_cut_size = 21.4;
// Baseplate bottom cutout rectangle depth
bp_cut_depth = 4;
// Baseplate bottom cutout rounded thingy width
bp_rcut_width = 8.5;
// Baseplate bottom cutout rounded thingy left
bp_rcut_length = 4.25;
// Baseplate bottom cutout rounded thingy depth
bp_rcut_depth = 2;
// countersink diameter for baseplate
d_cs = 2.5;
// radius of cutout for skeletonized baseplate
r_skel = 2;
// baseplate counterbore radius
r_cb = 2.75;
// baseplate counterbore depth
h_cb = 3;
// minimum baseplate thickness (when skeletonized)
h_skel = 1;

View File

@ -0,0 +1,147 @@
include <gridfinity-rebuilt-utility.scad>
// ===== INFORMATION ===== //
/*
IMPORTANT: rendering will be better for analyzing the model if fast-csg is enabled. As of writing, this feature is only available in the development builds and not the official release of OpenSCAD, but it makes rendering only take a couple seconds, even for comically large bins. Enable it in Edit > Preferences > Features > fast-csg
https://github.com/kennetek/gridfinity-rebuilt-openscad
*/
// ===== PARAMETERS ===== //
/* [Setup Parameters] */
$fa = 8;
$fs = 0.25;
/* [General Settings] */
// number of bases along x-axis
gridx = 4;
// number of bases along y-axis
gridy = 4;
// base unit
length = 42;
/* [Fit to Drawer] */
// minimum length of baseplate along x (leave zero to ignore, will automatically fill area if gridx is zero)
distancex = 0;
// minimum length of baseplate along y (leave zero to ignore, will automatically fill area if gridy is zero)
distancey = 0;
/* [Styles] */
// baseplate styles
style_plate = 2; // [0: thin, 1:weighted, 2:skeletonized]
// enable magnet hole
enable_magnet = true;
// hole styles
style_hole = 2; // [0:none, 1:contersink, 2:counterbore]
// ===== IMPLEMENTATION ===== //
color("tomato")
gridfinityBaseplate(gridx, gridy, length, distancex, distancey, style_plate, enable_magnet, style_hole);
// ===== CONSTRUCTION ===== //
module gridfinityBaseplate(gridx, gridy, length, dix, diy, sp, sm, sh) {
assert(gridx > 0 || dx > 0, "Must have positive x grid amount!");
assert(gridy > 0 || dy > 0, "Must have positive y grid amount!");
gx = gridx == 0 ? floor(dix/length) : gridx;
gy = gridy == 0 ? floor(diy/length) : gridy;
dx = max(gx*length-0.5, dix);
dy = max(gy*length-0.5, diy);
off = (sp==0?0:sp==1?bp_h_bot:h_skel+(sm?h_hole:0)+(sh==0?0:sh==1?d_cs:h_cb));
difference() {
translate([0,0,h_base])
mirror([0,0,1])
rounded_rectangle(dx, dy, h_base+off, r_base);
gridfinityBase(gx, gy, length, 1, 1, 0, 0.5, false);
translate([0,0,h_base-0.6])
rounded_rectangle(dx*2, dy*2, h_base*2, r_base);
pattern_linear(gx, gy, length) {
if (sm) block_base_hole(1);
if (sp == 1)
translate([0,0,-off])
cutter_weight();
else if (sp == 2)
linear_extrude(10*(h_base+off), center = true)
profile_skeleton();
translate([0,0,-off]) {
if (sh == 1) cutter_countersink();
else if (sh == 2) cutter_counterbore();
}
}
}
}
module cutter_weight() {
union() {
linear_extrude(bp_cut_depth*2,center=true)
square(bp_cut_size, center=true);
pattern_circular(4)
translate([0,10,0])
linear_extrude(bp_rcut_depth*2,center=true)
union() {
square([bp_rcut_width, bp_rcut_length], center=true);
translate([0,bp_rcut_length/2,0])
circle(d=bp_rcut_width);
}
}
}
module cutter_countersink() {
pattern_circular(4)
translate([d_hole/2, d_hole/2, 0]) {
cylinder(r = r_hole1+d_clear, h = 100*h_base, center = true);
translate([0,0,d_cs])
mirror([0,0,1])
hull() {
cylinder(h = d_cs+10, r=r_hole1+d_clear);
translate([0,0,d_cs])
cylinder(h=d_cs+10, r=r_hole1+d_clear+d_cs);
}
}
}
module cutter_counterbore() {
pattern_circular(4)
translate([d_hole/2,d_hole/2,0]) {
cylinder(h=100*h_base, r=r_hole1+d_clear, center=true);
difference() {
cylinder(h = 2*(h_cb+0.2), r=r_cb, center=true);
copy_mirror([0,1,0])
translate([-1.5*r_cb,r_hole1+d_clear+0.1,h_cb-h_slit])
cube([r_cb*3,r_cb*3, 10]);
}
}
}
module profile_skeleton() {
l = length-2*r_c2-2*r_c1;
minkowski() {
difference() {
square([l-2*r_skel+2*d_clear,l-2*r_skel+2*d_clear], center = true);
pattern_circular(4)
translate([d_hole/2,d_hole/2,0])
minkowski() {
square([l,l]);
circle(r_hole2+r_skel+2);
}
}
circle(r_skel);
}
}

View File

@ -0,0 +1,158 @@
include <gridfinity-rebuilt-utility.scad>
// ===== INFORMATION ===== //
/*
IMPORTANT: rendering will be better for analyzing the model if fast-csg is enabled. As of writing, this feature is only available in the development builds and not the official release of OpenSCAD, but it makes rendering only take a couple seconds, even for comically large bins. Enable it in Edit > Preferences > Features > fast-csg
the magnet holes can 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
base functions can be found in "gridfinity-rebuilt-utility.scad"
examples at end of file
BIN HEIGHT
the original gridfinity bins had the overall height defined by 7mm increments
a bin would be 7*u millimeters tall
the lip at the top of the bin (3.8mm) added onto this height
The stock bins have unit heights of 2, 3, and 6:
Z unit 2 -> 7*2 + 3.8 -> 17.8mm
Z unit 3 -> 7*3 + 3.8 -> 24.8mm
Z unit 6 -> 7*6 + 3.8 -> 45.8mm
https://github.com/kennetek/gridfinity-rebuilt-openscad
*/
// ===== PARAMETERS ===== //
/* [Setup Parameters] */
$fa = 8;
$fs = 0.25;
/* [General Settings] */
// number of bases along x-axis
gridx = 2;
// number of bases along y-axis
gridy = 3;
// bin height. See bin height information and "gridz_define" below.
gridz = 42;
// base unit
length = 42;
/* [Compartments] */
// number of X Divisions
divx = 1;
// number of y Divisions
divy = 1;
/* [Toggles] */
// internal fillet for easy part removal
enable_scoop = true;
// snap gridz height to nearest 7mm increment
enable_zsnap = false;
// enable upper lip for stacking other bins
enable_lip = true;
/* [Other] */
// determine what the variable "gridz" applies to based on your use case
gridz_define = 2; // [0:gridz is the height of bins in units of 7mm increments - Zack's method,1:gridz is the internal height in millimeters, 2:gridz is the overall external height of the bin in millimeters]
// the type of tabs
style_tab = 1; //[0:Full,1:Auto,2:Left,3:Center,4:Right,5:None]
// overrides internal block height of bin (for solid containers). Leave zero for default height. Units: mm
height_internal = 0;
/* [Base] */
style_hole = 3; // [0:no holes, 1:magnet holes only, 2: magnet and screw holes - no printable slit, 3: magnet and screw holes - printable slit]
// number of divisions per 1 unit of base along the X axis. (default 1, only use integers. 0 means automatically guess the right division)
div_base_x = 0;
// number of divisions per 1 unit of base along the Y axis. (default 1, only use integers. 0 means automatically guess the right division)
div_base_y = 0;
// ===== IMPLEMENTATION ===== //
color("tomato") {
gridfinityInit(gridx, gridy, height(gridz, gridz_define, enable_lip, enable_zsnap), height_internal, length) {
cutEqual(n_divx = divx, n_divy = divy, style_tab = style_tab, enable_scoop = enable_scoop);
}
gridfinityBase(gridx, gridy, length, div_base_x, div_base_y, style_hole);
}
// ===== EXAMPLES ===== //
// 3x3 even spaced grid
/*
gridfinityInit(3, 3, height(6), 0, 42) {
cutEqual(n_divx = 3, n_divy = 3, style_tab = 0, enable_scoop = true);
}
gridfinityBase(3, 3, 42, 0, 0, 1);
*/
// Compartments can be placed anywhere (this includes non-integer positions like 1/2 or 1/3). The grid is defined as (0,0) being the bottom left corner of the bin, with each unit being 1 base long. Each cut() module is a compartment, with the first four values defining the area that should be made into a compartment (X coord, Y coord, width, and height). These values should all be positive. t is the tab style of the compartment (0:full, 1:auto, 2:left, 3:center, 4:right, 5:none). s is a toggle for the bottom scoop.
/*
gridfinityInit(3, 3, height(6), 0, 42) {
cut(x=0, y=0, w=1.5, h=0.5, t=5, s=false);
cut(0, 0.5, 1.5, 0.5, 5, false);
cut(0, 1, 1.5, 0.5, 5, false);
cut(0,1.5,0.5,1.5,5,false);
cut(0.5,1.5,0.5,1.5,5,false);
cut(1,1.5,0.5,1.5,5,false);
cut(1.5, 0, 1.5, 5/3, 2);
cut(1.5, 5/3, 1.5, 4/3, 4);
}
gridfinityBase(3, 3, 42, 0, 0, 1);
*/
// Compartments can overlap! This allows for weirdly shaped compartments, such as this "2" bin.
/*
gridfinityInit(3, 3, height(6), 0, 42) {
cut(0,2,2,1,5,false);
cut(1,0,1,3,5);
cut(1,0,2,1,5);
cut(0,0,1,2);
cut(2,1,1,2);
}
gridfinityBase(3, 3, 42, 0, 0, 1);
*/
// Areas without a compartment are solid material, where you can put your own cutout shapes. using the cut_move() function, you can select an area, and any child shapes will be moved from the origin to the center of that area, and subtracted from the block. For example, a pattern of three cylinderical holes.
/*
gridfinityInit(3, 3, height(6), 0, 42) {
cut(x=0, y=0, w=2, h=3);
cut(x=0, y=0, w=3, h=1, t=5);
cut_move(x=2, y=1, w=1, h=2)
pattern_linear(x=1, y=3, sx=42/2)
cylinder(r=5, h=1000, center=true);
}
gridfinityBase(3, 3, 42, 0, 0, 1);
*/
// You can use loops as well as the bin dimensions to make different parametric functions, such as this one, which divides the box into columns, with a small 1x1 top compartment and a long vertical compartment below
/*
gx = 3;
gy = 3;
gridfinityInit(gx, gy, height(6), 0, 42) {
for(i=[0:gx-1]) {
cut(i,0,1,gx-1);
cut(i,gx-1,1,1);
}
}
gridfinityBase(gx, gy, 42, 0, 0, 1);
*/
// Pyramid scheme bin
/*
gx = 4.5;
gy = 4;
gridfinityInit(gx, gy, height(6), 0, 42) {
for (i = [0:gx-1])
for (j = [0:i])
cut(j*gx/(i+1),gy-i-1,gx/(i+1),1,0);
}
gridfinityBase(gx, gy, 42, 0, 0, 1);
*/

View File

@ -0,0 +1,93 @@
include <gridfinity-rebuilt-utility.scad>
// ===== INFORMATION ===== //
/*
IMPORTANT: rendering will be better for analyzing the model if fast-csg is enabled. As of writing, this feature is only available in the development builds and not the official release of OpenSCAD, but it makes rendering only take a couple seconds, even for comically large bins. Enable it in Edit > Preferences > Features > fast-csg
https://github.com/kennetek/gridfinity-rebuilt-openscad
*/
// ===== PARAMETERS ===== //
/* [Setup Parameters] */
$fa = 8;
$fs = 0.25;
/* [General Settings] */
// number of bases along x-axis
gridx = 3;
// number of bases along y-axis
gridy = 3;
// bin height. See bin height information and "gridz_define" below.
gridz = 6;
// base unit
length = 42;
/* [Compartments] */
// number of X Divisions
divx = 2;
// number of y Divisions
divy = 2;
/* [Toggles] */
// snap gridz height to nearest 7mm increment
enable_zsnap = false;
// enable upper lip for stacking other bins
enable_lip = true;
/* [Other] */
// determine what the variable "gridz" applies to based on your use case
gridz_define = 0; // [0:gridz is the height of bins in units of 7mm increments - Zack's method,1:gridz is the internal height in millimeters, 2:gridz is the overall external height of the bin in millimeters]
// the type of tabs
style_tab = 1; //[0:Full,1:Auto,2:Left,3:Center,4:Right,5:None]
/* [Base] */
style_hole = 0; // [0:no holes, 1:magnet holes only, 2: magnet and screw holes - no printable slit, 3: magnet and screw holes - printable slit]
// number of divisions per 1 unit of base along the X axis. (default 1, only use integers. 0 means automatically guess the right division)
div_base_x = 0;
// number of divisions per 1 unit of base along the Y axis. (default 1, only use integers. 0 means automatically guess the right division)
div_base_y = 0;
// ===== IMPLEMENTATION ===== //
// Input all the cutter types in here
color("tomato")
gridfinityLite(gridx, gridy, gridz, gridz_define, enable_lip, enable_zsnap, length, div_base_x, div_base_y, style_hole) {
cutEqual(n_divx = divx, n_divy = divy, style_tab = style_tab, enable_scoop = false);
}
// ===== CONSTRUCTION ===== //
module gridfinityLite(gridx, gridy, gridz, gridz_define, enable_lip, enable_zsnap, length, div_base_x, div_base_y, style_hole) {
difference() {
union() {
gridfinityInit(gridx, gridy, height(gridz, gridz_define, enable_lip, enable_zsnap), 0, length)
children();
gridfinityBase(gridx, gridy, length, div_base_x, div_base_y, style_hole);
}
difference() {
union() {
intersection() {
difference() {
gridfinityBase(gridx, gridy, length, div_base_x, div_base_y, style_hole, -d_wall*2, false);
translate([-gridx*length/2,-gridy*length/2,2*h_base])
cube([gridx*length,gridy*length,1000]);
}
translate([0,0,-1])
rounded_rectangle(gridx*length-0.5005-d_wall*2, gridy*length-0.5005-d_wall*2, 1000, r_f2);
}
translate([0,0,h_base+d_clear])
rounded_rectangle(gridx*length-0.5005-d_wall*2, gridy*length-0.5005-d_wall*2, h_base, r_f2);
}
translate([0,0,-4*h_base])
gridfinityInit(gridx, gridy, height(20,0), 0, length)
children();
}
}
}

View File

@ -0,0 +1,444 @@
// UTILITY FILE, DO NOT EDIT
// EDIT OTHER FILES IN REPO FOR RESULTS
include <gridfinity-constants.scad>
// ===== User Modules ===== //
// functions to convert gridz values to mm values
function hf (z, d, l) = (d==0)?z*7:(d==1)?h_bot+z+h_base:z-(l?3.8:0);
function height (z,d=0,l=true,s=true) = (s?((abs(hf(z,d,l))%7==0)?hf(z,d,l):hf(z,d,l)+7-abs(hf(z,d,l))%7):hf(z,d,l))-h_base;
// Creates equally divided cutters for the bin
//
// n_divx: number of x compartments (ideally, coprime w/ gridx)
// n_divy: number of y compartments (ideally, coprime w/ gridy)
// set n_div values to 0 for a solid bin
// style_tab: tab style for all compartments. see cut()
// enable_scoop: scoop toggle for all compartments. see cut()
module cutEqual(n_divx=1, n_divy=1, style_tab=1, enable_scoop=true) {
for (i = [1:n_divx])
for (j = [1:n_divy])
cut((i-1)*$gxx/n_divx,(j-1)*$gyy/n_divy, $gxx/n_divx, $gyy/n_divy, style_tab, enable_scoop);
}
// initialize gridfinity
module gridfinityInit(gx, gy, h, h0 = 0, l) {
$gxx = gx;
$gyy = gy;
$dh = h;
$dh0 = h0;
color("tomato") {
difference() {
color("firebrick")
block_bottom(h0==0?$dh-0.1:h0, gx, gy, l);
children();
}
color("royalblue")
block_wall(gx, gy, l) {
if (enable_lip) profile_wall();
else profile_wall2();
}
}
}
// Function to include in the custom() module to individually slice bins
// Will try to clamp values to fit inside the provided base size
//
// x: start coord. x=1 is the left side of the bin.
// y: start coord. y=1 is the bottom side of the bin.
// w: width of compartment, in # of bases covered
// h: height of compartment, in # of basese covered
// t: tab style of this specific compartment.
// alignment only matters if the compartment size is larger than d_tabw
// 0:full, 1:auto, 2:left, 3:center, 4:right, 5:none
// Automatic alignment will use left tabs for bins on the left edge, right tabs for bins on the right edge, and center tabs everywhere else.
// s: toggle the rounded back corner that allows for easy removal
module cut(x=0, y=0, w=1, h=1, t=1, s=true) {
translate([0,0,-$dh-h_base])
cut_move(x,y,w,h)
block_cutter(clp(x,0,$gxx), clp(y,0,$gyy), clp(w,0,$gxx-x), clp(h,0,$gyy-y), t, s);
}
// Translates an object from the origin point to the center of the requested compartment block, can be used to add custom cuts in the bin
// See cut() module for parameter descriptions
module cut_move(x, y, w, h) {
translate([0,0,$dh0==0?$dh+h_base:$dh0+h_base])
cut_move_unsafe(clp(x,0,$gxx), clp(y,0,$gyy), clp(w,0,$gxx-x), clp(h,0,$gyy-y))
children();
}
// ===== Modules ===== //
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 gridfinityBase(gx, gy, l, dx, dy, style_hole, off=0, final_cut=true) {
dbnxt = [for (i=[1:5]) if (abs(gx*i)%1 < 0.001 || abs(gx*i)%1 > 0.999) i];
dbnyt = [for (i=[1:5]) if (abs(gy*i)%1 < 0.001 || abs(gy*i)%1 > 0.999) i];
dbnx = 1/(dx==0 ? len(dbnxt) > 0 ? dbnxt[0] : 1 : round(dx));
dbny = 1/(dy==0 ? len(dbnyt) > 0 ? dbnyt[0] : 1 : round(dy));
xx = gx*l-0.5;
yy = gy*l-0.5;
if (final_cut)
translate([0,0,h_base])
rounded_rectangle(xx+0.002, yy+0.002, h_bot/1.5, r_fo1/2+0.001);
intersection(){
if (final_cut)
translate([0,0,-1])
rounded_rectangle(xx+0.005, yy+0.005, h_base+h_bot/2*10, r_fo1/2+0.001);
render()
difference() {
pattern_linear(gx/dbnx, gy/dbny, dbnx*l, dbny*l)
block_base_solid(dbnx, dbny, l, off);
if (style_hole > 0)
pattern_linear(gx, gy, l)
block_base_hole(style_hole, off);
}
}
}
module block_base_solid(dbnx, dbny, l, o) {
xx = dbnx*l-0.05;
yy = dbny*l-0.05;
oo = (o/2)*(sqrt(2)-1);
translate([0,0,h_base])
mirror([0,0,1])
union() {
hull() {
rounded_rectangle(xx-2*r_c2-2*r_c1+o, yy-2*r_c2-2*r_c1+o, h_base+oo, r_fo3/2);
rounded_rectangle(xx-2*r_c2+o, yy-2*r_c2+o, h_base-r_c1+oo, r_fo2/2);
}
translate([0,0,oo])
hull() {
rounded_rectangle(xx-2*r_c2+o, yy-2*r_c2+o, r_c2, r_fo2/2);
mirror([0,0,1])
rounded_rectangle(xx+o, yy+o, h_bot/2+abs(10*o), r_fo1/2);
}
}
}
module block_base_hole(style_hole, o=0) {
r1 = r_hole1-o/2;
r2 = r_hole2-o/2;
pattern_circular(abs(d_hole)<0.001?1:4)
translate([d_hole/2, d_hole/2, 0])
union() {
difference() {
cylinder(h = 2*(h_hole-o+(style_hole==3?h_slit:0)), r=r2, center=true);
if (style_hole==3)
copy_mirror([0,1,0])
translate([-1.5*r2,r1+0.1,h_hole-o])
cube([r2*3,r2*3, 10]);
}
if (style_hole > 1)
cylinder(h = 2*h_base-o, r = r1, center=true);
}
}
module profile_wall_sub_sub() {
polygon([
[0,0],
[d_wall/2,0],
[d_wall/2,$dh-1.2-d_wall2+d_wall/2],
[d_wall2-d_clear,$dh-1.2],
[d_wall2-d_clear,$dh+h_base],
[0,$dh+h_base]
]);
}
module profile_wall_sub() {
difference() {
profile_wall_sub_sub();
color("red")
offset(delta = d_clear)
translate([r_base-d_clear,$dh,0])
mirror([1,0,0])
profile_base();
square([d_wall,0]);
}
}
module profile_wall() {
translate([r_base,0,0])
mirror([1,0,0])
difference() {
profile_wall_sub();
difference() {
translate([0, $dh+h_base-d_clear*sqrt(2), 0])
circle(r_base/2);
offset(r = r_f1)
offset(delta = -r_f1)
profile_wall_sub();
}
}
}
// lipless profile
module profile_wall2() {
translate([r_base,0,0])
mirror([1,0,0])
square([d_wall,$dh]);
}
module block_wall(gx, gy, l) {
translate([0,0,h_base])
sweep_rounded(gx*l-2*r_base-0.5-0.001, gy*l-2*r_base-0.5-0.001)
children();
}
module block_bottom( h = 2.2, gx, gy, l ) {
translate([0,0,h_base+0.1])
rounded_rectangle(gx*l-0.5-d_wall/4, gy*l-0.5-d_wall/4, h, r_base+0.01);
}
module cut_move_unsafe(x, y, w, h) {
xx = ($gxx*length+d_magic);
yy = ($gyy*length+d_magic);
translate([(x)*xx/$gxx,(y)*yy/$gyy,0])
translate([(-xx+d_div)/2,(-yy+d_div)/2,0])
translate([(w*xx/$gxx-d_div)/2,(h*yy/$gyy-d_div)/2,0])
children();
}
module block_cutter(x,y,w,h,t,s) {
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-d_clear;
v_ang_tab = a_tab;
v_ang_lip = 45;
ycutfirst = y == 0 && enable_lip;
ycutlast = abs(y+h-$gyy)<0.001 && enable_lip;
xcutfirst = x == 0 && enable_lip;
xcutlast = abs(x+w-$gxx)<0.001 && enable_lip;
zsmall = ($dh+h_base)/7 < 3;
ylen = h*($gyy*length+d_magic)/$gyy-d_div;
xlen = w*($gxx*length+d_magic)/$gxx-d_div;
height = $dh;
extent = (s && ycutfirst ? d_wall2-d_wall-d_clear : 0);
tab = (zsmall || t == 5) ? (ycutlast?v_len_lip:0) : v_len_tab;
ang = (zsmall || t == 5) ? (ycutlast?v_ang_lip:0) : v_ang_tab;
cut = (zsmall || t == 5) ? (ycutlast?v_cut_lip:0) : v_cut_tab;
style = (t > 1 && t < 5) ? t-3 : (x == 0 ? -1 : xcutlast ? 1 : 0);
translate([0,ylen/2,h_base+h_bot])
rotate([90,0,-90]) {
if (!zsmall && xlen - d_tabw > 4*r_f2 && t != 0) {
fillet_cutter(3,"bisque")
difference() {
transform_tab(style, xlen, ((xcutfirst&&style==-1)||(xcutlast&&style==1))?v_cut_lip:0)
translate([ycutlast?v_cut_lip:0,0])
profile_cutter(height-h_bot, ylen/2, s);
if (xcutfirst)
translate([0,0,(xlen/2-r_f2)-v_cut_lip])
cube([ylen,height,v_cut_lip*2]);
if (xcutlast)
translate([0,0,-(xlen/2-r_f2)-v_cut_lip])
cube([ylen,height,v_cut_lip*2]);
}
if (t != 0 && t != 5)
fillet_cutter(2,"indigo")
difference() {
transform_tab(style, xlen, ((xcutfirst&&style==-1)||(xcutlast&&style==1))?v_cut_lip:0)
difference() {
intersection() {
profile_cutter(height-h_bot, ylen-extent, s);
profile_cutter_tab(height-h_bot, v_len_tab, v_ang_tab);
}
if (ycutlast) profile_cutter_tab(height-h_bot, v_len_lip, 45);
}
if (xcutfirst)
translate([ylen/2,0,xlen/2])
rotate([0,90,0])
transform_main(2*ylen)
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
if (xcutlast)
translate([ylen/2,0,-xlen/2])
rotate([0,-90,0])
transform_main(2*ylen)
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
}
}
fillet_cutter(1,"seagreen")
translate([0,0,xcutlast?v_cut_lip/2:0])
translate([0,0,xcutfirst?-v_cut_lip/2:0])
transform_main(xlen-(xcutfirst?v_cut_lip:0)-(xcutlast?v_cut_lip:0))
translate([cut,0])
profile_cutter(height-h_bot, ylen-extent-cut-(!s&&ycutfirst?v_cut_lip:0), s);
fillet_cutter(0,"hotpink")
difference() {
transform_main(xlen)
difference() {
profile_cutter(height-h_bot, ylen-extent, s);
if (!((zsmall || t == 5) && !ycutlast))
profile_cutter_tab(height-h_bot, tab, ang);
if (!s && y == 0)
translate([ylen-extent,0,0])
mirror([1,0,0])
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
}
if (xcutfirst)
color("indigo")
translate([ylen/2+0.001,0,xlen/2+0.001])
rotate([0,90,0])
transform_main(2*ylen)
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
if (xcutlast)
color("indigo")
translate([ylen/2+0.001,0,-xlen/2+0.001])
rotate([0,-90,0])
transform_main(2*ylen)
profile_cutter_tab(height-h_bot, v_len_lip, v_ang_lip);
}
}
}
module transform_main(xlen) {
translate([0,0,-(xlen-2*r_f2)/2])
linear_extrude(xlen-2*r_f2)
children();
}
module transform_tab(type, xlen, cut) {
mirror([0,0,type==1?1:0])
copy_mirror([0,0,-(abs(type)-1)])
translate([0,0,-(xlen)/2])
translate([0,0,r_f2])
linear_extrude((xlen-d_tabw-abs(cut))/(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, l, s) {
scoop = s ? (length*(($dh-2)/7+1)/12-r_f2) : 0;
translate([r_f2,r_f2])
hull() {
if (l-scoop-2*r_f2 > 0)
square(0.1);
if (scoop < h) {
translate([l-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([l-scoop-2*r_f2, scoop])
if (scoop != 0) {
intersection() {
circle(scoop);
mirror([0,1]) square(2*scoop);
}
} else mirror([1,0]) square(0.1);
translate([l-scoop-2*r_f2,-1])
square([-(l-scoop-2*r_f2),2*h]);
translate([0,h])
square([2*l,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 =====
function clp(x,a,b) = min(max(x,a),b);
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, sx = 0, sy = 0) {
yy = sy <= 0 ? sx : sy;
translate([-(x-1)*sx/2,-(y-1)*yy/2,0])
for (i = [1:ceil(x)])
for (j = [1:ceil(y)])
translate([(i-1)*sx,(j-1)*yy,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();
}
}