2024-02-23 19:20:05 +00:00
/**
* @ file gridfinity - rebuilt - utility . scad
* @ brief UTILITY FILE , DO NOT EDIT
* EDIT OTHER FILES IN REPO FOR RESULTS
* /
2022-08-09 20:25:13 +00:00
2023-05-31 15:48:39 +00:00
include < standard.scad >
2024-04-14 18:28:12 +00:00
use < gridfinity-rebuilt-holes.scad >
2022-10-02 06:10:19 +00:00
2022-08-09 20:25:13 +00:00
// ===== User Modules ===== //
2022-10-03 00:35:03 +00:00
// functions to convert gridz values to mm values
2024-02-23 19:20:05 +00:00
/**
* @ Summary Convert a number from Gridfinity values to mm .
* @ details Also can include lip when working with height values .
* @ param gridfinityUnit Gridfinity is normally on a base 7 system .
* @ param includeLipHeight Include the lip height as well .
* @ returns The final value in mm .
* /
function fromGridfinityUnits ( gridfinityUnit , includeLipHeight = false ) =
gridfinityUnit * 7 + ( includeLipHeight ? h_lip : 0 ) ;
/**
* @ Summary Height in mm including fixed heights .
* @ details Also can include lip when working with height values .
* @ param mmHeight Height without other values .
* @ param includeLipHeight Include the lip height as well .
* @ returns The final value in mm .
* /
function includingFixedHeights ( mmHeight , includeLipHeight = false ) =
mmHeight + h_bot + h_base + ( includeLipHeight ? h_lip : 0 ) ;
/**
* @ brief Three Functions in One . For height calculations .
* @ param z Height value
* @ param gridz_define As explained in gridfinity - rebuilt - bins . scad
* @ param l style_lip as explained in gridfinity - rebuilt - bins . scad
* @ returns Height in mm
* /
function hf ( z , gridz_define , style_lip ) =
gridz_define = = 0 ? fromGridfinityUnits ( z , style_lip = = 2 ) :
gridz_define = = 1 ? includingFixedHeights ( z , style_lip = = 2 ) :
z + ( // Just use z (possibly adding/subtracting lip)
style_lip = = 1 ? - h_lip :
style_lip = = 2 ? h_lip : 0
)
;
/**
* @ brief Calculates the proper height for bins . Three Functions in One .
* @ param z Height value
* @ param d gridz_define as explained in gridfinity - rebuilt - bins . scad
* @ param l style_lip as explained in gridfinity - rebuilt - bins . scad
* @ param enable_zsnap Automatically snap the bin size to the nearest 7 mm increment .
* @ returns Height in mm
* /
function height ( z , d = 0 , l = 0 , enable_zsnap = true ) =
(
enable_zsnap ? (
( 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 ;
2022-10-03 00:35:03 +00:00
// Creates equally divided cutters for the bin
2022-08-09 20:25:13 +00:00
//
2023-09-22 06:11:23 +00:00
// 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
2022-08-09 20:25:13 +00:00
// style_tab: tab style for all compartments. see cut()
2023-02-14 16:55:29 +00:00
// scoop_weight: scoop toggle for all compartments. see cut()
module cutEqual ( n_divx = 1 , n_divy = 1 , style_tab = 1 , scoop_weight = 1 ) {
2023-09-22 06:11:23 +00:00
for ( i = [ 1 : n_divx ] )
2022-08-09 20:25:13 +00:00
for ( j = [ 1 : n_divy ] )
2023-02-14 16:55:29 +00:00
cut ( ( i - 1 ) * $ gxx / n_divx , ( j - 1 ) * $ gyy / n_divy , $ gxx / n_divx , $ gyy / n_divy , style_tab , scoop_weight ) ;
2022-08-09 20:25:13 +00:00
}
2024-02-03 01:03:04 +00:00
2023-11-21 20:41:08 +00:00
// Creates equally divided cylindrical cutouts
//
// n_divx: number of x cutouts
// n_divy: number of y cutouts
// set n_div values to 0 for a solid bin
// cylinder_diameter: diameter of cutouts
// cylinder_height: height of cutouts
// coutout_depth: offset from top to solid part of container
// orientation: orientation of cylinder cutouts (0 = x direction, 1 = y direction, 2 = z direction)
2024-02-03 21:49:44 +00:00
// chamfer: chamfer around the top rim of the holes
module cutCylinders ( n_divx = 1 , n_divy = 1 , cylinder_diameter = 1 , cylinder_height = 1 , coutout_depth = 0 , orientation = 0 , chamfer = 0.5 ) {
2023-11-21 20:41:08 +00:00
rotation = ( orientation = = 0 )
? [ 0 , 90 , 0 ]
: ( orientation = = 1 )
? [ 90 , 0 , 0 ]
: [ 0 , 0 , 0 ] ;
gridx_mm = $ gxx * l_grid ;
gridy_mm = $ gyy * l_grid ;
padding = 2 ;
cutout_x = gridx_mm - d_wall * 2 ;
cutout_y = gridy_mm - d_wall * 2 ;
2024-01-06 16:37:37 +00:00
2023-11-21 20:41:08 +00:00
cut_move ( x = 0 , y = 0 , w = $ gxx , h = $ gyy ) {
translate ( [ 0 , 0 , - coutout_depth ] ) {
rounded_rectangle ( cutout_x , cutout_y , coutout_depth * 2 , r_base ) ;
2024-01-06 16:37:37 +00:00
2024-02-03 21:49:44 +00:00
pattern_linear ( x = n_divx , y = n_divy , sx = ( gridx_mm - padding ) / n_divx , sy = ( gridy_mm - padding ) / n_divy )
rotate ( rotation )
union ( ) {
cylinder ( d = cylinder_diameter , h = cylinder_height * 2 , center = true ) ;
if ( chamfer > 0 ) {
translate ( [ 0 , 0 , - chamfer ] ) cylinder ( d1 = cylinder_diameter , d2 = cylinder_diameter + 4 * chamfer , h = 2 * chamfer ) ;
}
} ;
2023-11-21 20:41:08 +00:00
}
}
}
2022-10-03 00:35:03 +00:00
// initialize gridfinity
2024-01-29 03:54:51 +00:00
// sl: lip style of this bin.
// 0:Regular lip, 1:Remove lip subtractively, 2:Remove lip and retain height
module gridfinityInit ( gx , gy , h , h0 = 0 , l = l_grid , sl = 0 ) {
2022-10-03 00:35:03 +00:00
$ gxx = gx ;
$ gyy = gy ;
2023-09-22 06:11:23 +00:00
$ dh = h ;
$ dh0 = h0 ;
2024-01-29 03:54:51 +00:00
$ style_lip = sl ;
2022-10-03 00:35:03 +00:00
color ( "tomato" ) {
difference ( ) {
2023-09-22 06:11:23 +00:00
color ( "firebrick" )
2022-10-03 00:35:03 +00:00
block_bottom ( h0 = = 0 ? $ dh - 0.1 : h0 , gx , gy , l ) ;
children ( ) ;
}
2023-09-22 06:11:23 +00:00
color ( "royalblue" )
2022-10-03 00:35:03 +00:00
block_wall ( gx , gy , l ) {
2024-01-29 03:54:51 +00:00
if ( $ style_lip = = 0 ) profile_wall ( ) ;
2022-10-03 00:35:03 +00:00
else profile_wall2 ( ) ;
2023-09-22 06:11:23 +00:00
}
2022-08-09 20:25:13 +00:00
}
}
// 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.
2023-09-22 06:11:23 +00:00
// y: start coord. y=1 is the bottom side of the bin.
2022-08-09 20:25:13 +00:00
// 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
2023-09-22 06:11:23 +00:00
// 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.
2022-08-09 20:25:13 +00:00
// s: toggle the rounded back corner that allows for easy removal
2024-02-03 01:03:04 +00:00
module cut ( x = 0 , y = 0 , w = 1 , h = 1 , t = 1 , s = 1 , tab_width = d_tabw , tab_height = d_tabh ) {
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 , tab_width , tab_height ) ;
}
// cuts equally sized bins over a given length at a specified position
2024-02-16 11:42:51 +00:00
// bins_x: number of bins along x-axis
// bins_y: number of bins along y-axis
// len_x: length (in gridfinity bases) along x-axis that the bins_x will fill
// len_y: length (in gridfinity bases) along y-axis that the bins_y will fill
// pos_x: start x position of the bins (left side)
// pos_y: start y position of the bins (bottom side)
// style_tab: Style of the tab used on the bins
// scoop: Weight of the scoop on the bottom of the bins
// tab_width: Width of the tab on the bins, in mm.
// tab_height: How far the tab will stick out over the bin, in mm. Default tabs fit 12mm labels, but for narrow bins can take up too much space over the opening. This setting allows 'slimmer' tabs for use with thinner labels, so smaller/narrower bins can be labeled and still keep a reasonable opening at the top. NOTE: The measurement is not 1:1 in mm, so a '3.5' value does not guarantee a tab that fits 3.5mm label tape. Use the 'measure' tool after rendering to check the distance between faces to guarantee it fits your needs.
2024-02-03 01:03:04 +00:00
module cutEqualBins ( bins_x = 1 , bins_y = 1 , len_x = 1 , len_y = 1 , pos_x = 0 , pos_y = 0 , style_tab = 5 , scoop = 1 , tab_width = d_tabw , tab_height = d_tabh ) {
// Calculate width and height of each bin based on total length and number of bins
bin_width = len_x / bins_x ;
bin_height = len_y / bins_y ;
2024-02-16 14:55:06 +00:00
2024-02-03 01:03:04 +00:00
// Loop through each bin position in x and y direction
for ( i = [ 0 : bins_x - 1 ] ) {
for ( j = [ 0 : bins_y - 1 ] ) {
// Calculate the starting position for each bin
// Adjust position by adding pos_x and pos_y to shift the entire grid of bins as needed
bin_start_x = pos_x + i * bin_width ;
bin_start_y = pos_y + j * bin_height ;
2024-02-16 14:55:06 +00:00
2024-02-03 01:03:04 +00:00
// Call the cut module to create each bin with calculated position and dimensions
// Pass through the style_tab and scoop parameters
cut ( bin_start_x , bin_start_y , bin_width , bin_height , style_tab , scoop , tab_width = tab_width , tab_height = tab_height ) ;
}
}
}
2022-08-09 20:25:13 +00:00
// 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 ) {
2022-11-06 06:19:56 +00:00
translate ( [ 0 , 0 , $ dh0 = = 0 ? $ dh + h_base : $ dh0 + h_base ] )
2022-10-03 00:35:03 +00:00
cut_move_unsafe ( clp ( x , 0 , $ gxx ) , clp ( y , 0 , $ gyy ) , clp ( w , 0 , $ gxx - x ) , clp ( h , 0 , $ gyy - y ) )
2022-08-09 20:25:13 +00:00
children ( ) ;
2023-09-22 06:11:23 +00:00
}
2022-08-09 20:25:13 +00:00
// ===== 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 ]
] ) ;
}
2023-03-20 17:48:28 +00:00
module gridfinityBase ( gx , gy , l , dx , dy , style_hole , off = 0 , final_cut = true , only_corners = false ) {
2022-10-03 00:35:03 +00:00
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 ;
2023-09-22 06:11:23 +00:00
2022-11-06 06:19:56 +00:00
if ( final_cut )
2022-08-09 20:25:13 +00:00
translate ( [ 0 , 0 , h_base ] )
2024-02-16 21:01:40 +00:00
rounded_rectangle ( xx + 0.002 , yy + 0.002 , h_bot / 1.5 , r_fo1 + 0.001 ) ;
2022-09-14 16:44:37 +00:00
2022-09-18 12:36:24 +00:00
intersection ( ) {
2023-09-22 06:11:23 +00:00
if ( final_cut )
2022-09-18 12:36:24 +00:00
translate ( [ 0 , 0 , - 1 ] )
2024-02-16 21:01:40 +00:00
rounded_rectangle ( xx + 0.005 , yy + 0.005 , h_base + h_bot / 2 * 10 , r_fo1 + 0.001 ) ;
2023-09-22 06:11:23 +00:00
2023-03-20 17:48:28 +00:00
if ( only_corners ) {
2024-01-29 09:15:25 +00:00
difference ( ) {
2023-09-22 06:11:23 +00:00
pattern_linear ( gx / dbnx , gy / dbny , dbnx * l , dbny * l )
2023-03-20 17:48:28 +00:00
block_base ( gx , gy , l , dbnx , dbny , 0 , off ) ;
2024-01-29 09:15:25 +00:00
if ( style_hole = = 4 ) {
2024-04-14 18:28:12 +00:00
translate_coordinates = [
( gx / 2 ) * l_grid - d_hole_from_side ,
( gy / 2 ) * l_grid - d_hole_from_side ,
h_slit * 2
] ;
translate ( translate_coordinates )
2024-01-29 09:15:25 +00:00
refined_hole ( ) ;
mirror ( [ 1 , 0 , 0 ] )
2024-04-14 18:28:12 +00:00
translate ( translate_coordinates )
2024-01-29 09:15:25 +00:00
refined_hole ( ) ;
mirror ( [ 0 , 1 , 0 ] ) {
2024-04-14 18:28:12 +00:00
translate ( translate_coordinates )
2024-01-29 09:15:25 +00:00
refined_hole ( ) ;
mirror ( [ 1 , 0 , 0 ] )
2024-04-14 18:28:12 +00:00
translate ( translate_coordinates )
2024-01-29 09:15:25 +00:00
refined_hole ( ) ;
}
}
else {
pattern_linear ( 2 , 2 , ( gx - 1 ) * l_grid + d_hole , ( gy - 1 ) * l_grid + d_hole )
block_base_hole ( style_hole , off ) ;
}
2023-03-20 17:48:28 +00:00
}
}
else {
2023-09-22 06:11:23 +00:00
pattern_linear ( gx / dbnx , gy / dbny , dbnx * l , dbny * l )
2023-03-20 17:48:28 +00:00
block_base ( gx , gy , l , dbnx , dbny , style_hole , off ) ;
}
2022-10-01 20:13:51 +00:00
}
}
2024-02-23 23:57:16 +00:00
/**
2024-04-14 18:28:12 +00:00
* @ brief A single Gridfinity base . With holes ( if set )
2024-02-23 23:57:16 +00:00
* @ param gx
* @ param gy
* @ param l
* @ param dbnx
* @ param dbny
2024-04-14 18:28:12 +00:00
* @ param style_hole @ see block_base_hole . style_hole
2024-02-23 23:57:16 +00:00
* @ param off
* /
2023-02-21 21:31:48 +00:00
module block_base ( gx , gy , l , dbnx , dbny , style_hole , off ) {
2023-04-23 02:33:27 +00:00
render ( convexity = 2 )
2023-02-21 21:31:48 +00:00
difference ( ) {
block_base_solid ( dbnx , dbny , l , off ) ;
2023-09-22 06:11:23 +00:00
2023-03-20 17:48:28 +00:00
if ( style_hole > 0 )
2023-09-22 06:11:23 +00:00
pattern_circular ( abs ( l - d_hole_from_side / 2 ) < 0.001 ? 1 : 4 )
2023-09-26 20:53:38 +00:00
if ( style_hole = = 4 )
translate ( [ l / 2 - d_hole_from_side , l / 2 - d_hole_from_side , h_slit * 2 ] )
refined_hole ( ) ;
else
translate ( [ l / 2 - d_hole_from_side , l / 2 - d_hole_from_side , 0 ] )
block_base_hole ( style_hole , off ) ;
2023-02-21 21:31:48 +00:00
}
}
2024-02-23 23:57:16 +00:00
/**
* @ brief A gridfinity base with no holes .
* @ details Used as the "base" with holes removed from it later .
* @ param dbnx
* @ param dbny
* @ param l
* @ param o
* /
2023-09-22 06:11:23 +00:00
module block_base_solid ( dbnx , dbny , l , o ) {
xx = dbnx * l - 0.05 ;
yy = dbny * l - 0.05 ;
2022-10-12 01:34:02 +00:00
oo = ( o / 2 ) * ( sqrt ( 2 ) - 1 ) ;
2022-10-01 20:13:51 +00:00
translate ( [ 0 , 0 , h_base ] )
2022-10-02 06:10:19 +00:00
mirror ( [ 0 , 0 , 1 ] )
union ( ) {
hull ( ) {
2024-02-16 20:17:49 +00:00
rounded_rectangle ( xx - 2 * r_c2 - 2 * r_c1 + o , yy - 2 * r_c2 - 2 * r_c1 + o , h_base + oo , r_fo3 ) ;
2024-02-16 20:32:04 +00:00
rounded_rectangle ( xx - 2 * r_c2 + o , yy - 2 * r_c2 + o , h_base - r_c1 + oo , r_fo2 ) ;
2022-10-02 06:10:19 +00:00
}
2022-11-06 06:19:56 +00:00
translate ( [ 0 , 0 , oo ] )
2022-10-02 06:10:19 +00:00
hull ( ) {
2024-02-16 20:32:04 +00:00
rounded_rectangle ( xx - 2 * r_c2 + o , yy - 2 * r_c2 + o , r_c2 , r_fo2 ) ;
2022-10-02 06:10:19 +00:00
mirror ( [ 0 , 0 , 1 ] )
2024-02-16 21:01:40 +00:00
rounded_rectangle ( xx + o , yy + o , h_bot / 2 + abs ( 10 * o ) , r_fo1 ) ;
2022-10-01 20:13:51 +00:00
}
2022-10-02 06:10:19 +00:00
}
2022-10-01 20:13:51 +00:00
}
2024-04-14 18:28:12 +00:00
/**
* @ brief Refined hole based on Printables @ grizzie17 ' s Gridfinity Refined
* @ details Magnet is pushed in from + X direction , and held in by friction .
* Small slit on the bottom allows removing the magnet .
* @ see https : //www.printables.com/model/413761-gridfinity-refined
* /
2023-09-26 20:53:38 +00:00
module refined_hole ( ) {
// Meassured magnet hole diameter to be 5.86mm (meassured in fusion360
2024-04-14 18:28:12 +00:00
r = MAGNET_HOLE_RADIUS - 0.32 ;
2023-09-26 20:53:38 +00:00
// Magnet height
m = 2 ;
mh = m - 0.1 ;
// Poke through - For removing a magnet using a toothpick
ptl = h_slit * 3 ; // Poke Through Layers
pth = mh + ptl ; // Poke Through Height
ptr = 2.5 ; // Poke Through Radius
union ( ) {
hull ( ) {
// Magnet hole - smaller than the magnet to keep it squeezed
translate ( [ 10 , - r , 0 ] ) cube ( [ 1 , r * 2 , mh ] ) ;
cylinder ( 1.9 , r = r ) ;
}
hull ( ) {
// Poke hole
translate ( [ - 9 + 5.60 , - ptr / 2 , - ptl ] ) cube ( [ 1 , ptr , pth ] ) ;
translate ( [ - 12.53 + 5.60 , 0 , - ptl ] ) cylinder ( pth , d = ptr ) ;
}
}
}
2022-09-18 23:29:27 +00:00
module profile_wall_sub_sub ( ) {
polygon ( [
[ 0 , 0 ] ,
[ d_wall / 2 , 0 ] ,
2022-10-03 00:35:03 +00:00
[ 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 ]
2022-09-18 23:29:27 +00:00
] ) ;
}
2022-08-09 20:25:13 +00:00
module profile_wall_sub ( ) {
difference ( ) {
2022-09-18 23:29:27 +00:00
profile_wall_sub_sub ( ) ;
2022-08-09 20:25:13 +00:00
color ( "red" )
2023-09-22 06:11:23 +00:00
offset ( delta = d_clear )
2022-10-03 00:35:03 +00:00
translate ( [ r_base - d_clear , $ dh , 0 ] )
2023-09-22 06:11:23 +00:00
mirror ( [ 1 , 0 , 0 ] )
2022-08-09 20:25:13 +00:00
profile_base ( ) ;
}
}
module profile_wall ( ) {
translate ( [ r_base , 0 , 0 ] )
mirror ( [ 1 , 0 , 0 ] )
difference ( ) {
profile_wall_sub ( ) ;
2022-09-18 23:29:27 +00:00
difference ( ) {
2023-09-22 06:11:23 +00:00
translate ( [ 0 , $ dh + h_base - d_clear * sqrt ( 2 ) , 0 ] )
2022-08-09 20:25:13 +00:00
circle ( r_base / 2 ) ;
2023-09-22 06:11:23 +00:00
offset ( r = r_f1 )
2022-08-09 20:25:13 +00:00
offset ( delta = - r_f1 )
2022-09-18 23:29:27 +00:00
profile_wall_sub ( ) ;
2022-08-09 20:25:13 +00:00
}
2023-02-06 06:47:50 +00:00
// remove any negtive geometry in edge cases
mirror ( [ 0 , 1 , 0 ] )
2023-05-31 15:46:30 +00:00
square ( 100 * l_grid ) ;
2022-08-09 20:25:13 +00:00
}
}
// lipless profile
module profile_wall2 ( ) {
2023-09-22 06:11:23 +00:00
translate ( [ r_base , 0 , 0 ] )
mirror ( [ 1 , 0 , 0 ] )
2022-10-03 00:35:03 +00:00
square ( [ d_wall , $ dh ] ) ;
2022-08-09 20:25:13 +00:00
}
2022-10-03 00:35:03 +00:00
module block_wall ( gx , gy , l ) {
2023-09-22 06:11:23 +00:00
translate ( [ 0 , 0 , h_base ] )
2022-10-03 00:35:03 +00:00
sweep_rounded ( gx * l - 2 * r_base - 0.5 - 0.001 , gy * l - 2 * r_base - 0.5 - 0.001 )
children ( ) ;
2022-08-09 20:25:13 +00:00
}
2022-10-03 00:35:03 +00:00
module block_bottom ( h = 2.2 , gx , gy , l ) {
2022-08-09 20:25:13 +00:00
translate ( [ 0 , 0 , h_base + 0.1 ] )
2022-10-03 00:35:03 +00:00
rounded_rectangle ( gx * l - 0.5 - d_wall / 4 , gy * l - 0.5 - d_wall / 4 , h , r_base + 0.01 ) ;
2022-08-09 20:25:13 +00:00
}
module cut_move_unsafe ( x , y , w , h ) {
2023-05-31 15:46:30 +00:00
xx = ( $ gxx * l_grid + d_magic ) ;
2023-09-22 06:11:23 +00:00
yy = ( $ gyy * l_grid + d_magic ) ;
2022-10-03 00:35:03 +00:00
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 ] )
2022-08-09 20:25:13 +00:00
children ( ) ;
}
2024-02-03 01:03:04 +00:00
module block_cutter ( x , y , w , h , t , s , tab_width = d_tabw , tab_height = d_tabh ) {
2023-09-22 06:11:23 +00:00
2024-02-03 01:03:04 +00:00
v_len_tab = tab_height ;
2022-08-09 20:25:13 +00:00
v_len_lip = d_wall2 - d_wall + 1.2 ;
2024-02-16 11:42:51 +00:00
v_cut_tab = tab_height - ( 2 * r_f1 ) / tan ( a_tab ) ;
2022-09-15 19:09:12 +00:00
v_cut_lip = d_wall2 - d_wall - d_clear ;
2022-08-09 20:25:13 +00:00
v_ang_tab = a_tab ;
v_ang_lip = 45 ;
2023-09-22 06:11:23 +00:00
2024-01-29 03:54:51 +00:00
ycutfirst = y = = 0 && $ style_lip = = 0 ;
ycutlast = abs ( y + h - $ gyy ) < 0.001 && $ style_lip = = 0 ;
xcutfirst = x = = 0 && $ style_lip = = 0 ;
xcutlast = abs ( x + w - $ gxx ) < 0.001 && $ style_lip = = 0 ;
2022-10-03 00:35:03 +00:00
zsmall = ( $ dh + h_base ) / 7 < 3 ;
2023-09-22 06:11:23 +00:00
ylen = h * ( $ gyy * l_grid + d_magic ) / $ gyy - d_div ;
xlen = w * ( $ gxx * l_grid + d_magic ) / $ gxx - d_div ;
2022-10-03 00:35:03 +00:00
height = $ dh ;
2023-09-22 06:11:23 +00:00
extent = ( abs ( s ) > 0 && ycutfirst ? d_wall2 - d_wall - d_clear : 0 ) ;
tab = ( zsmall || t = = 5 ) ? ( ycutlast ? v_len_lip : 0 ) : v_len_tab ;
2022-08-09 20:25:13 +00:00
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 ) ;
2023-09-22 06:11:23 +00:00
2022-10-15 18:43:17 +00:00
translate ( [ 0 , ylen / 2 , h_base + h_bot ] )
2022-08-09 20:25:13 +00:00
rotate ( [ 90 , 0 , - 90 ] ) {
2023-09-22 06:11:23 +00:00
2024-02-03 01:03:04 +00:00
if ( ! zsmall && xlen - tab_width > 4 * r_f2 && ( t ! = 0 && t ! = 5 ) ) {
2022-08-09 20:25:13 +00:00
fillet_cutter ( 3 , "bisque" )
difference ( ) {
2024-02-03 01:03:04 +00:00
transform_tab ( style , xlen , ( ( xcutfirst && style = = - 1 ) || ( xcutlast && style = = 1 ) ) ? v_cut_lip : 0 , tab_width )
2023-09-22 06:11:23 +00:00
translate ( [ ycutlast ? v_cut_lip : 0 , 0 ] )
2022-08-09 20:25:13 +00:00
profile_cutter ( height - h_bot , ylen / 2 , s ) ;
if ( xcutfirst )
2023-09-22 06:11:23 +00:00
translate ( [ 0 , 0 , ( xlen / 2 - r_f2 ) - v_cut_lip ] )
2022-08-09 20:25:13 +00:00
cube ( [ ylen , height , v_cut_lip * 2 ] ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
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 ( ) {
2024-02-03 01:03:04 +00:00
transform_tab ( style , xlen , ( ( xcutfirst && style = = - 1 ) || ( xcutlast && style = = 1 ) ? v_cut_lip : 0 ) , tab_width )
2022-08-09 20:25:13 +00:00
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 ) ;
2023-09-22 06:11:23 +00:00
}
2022-08-09 20:25:13 +00:00
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 ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
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 ) ;
}
}
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
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 ) )
2023-09-22 06:11:23 +00:00
translate ( [ cut , 0 ] )
2022-08-09 20:25:13 +00:00
profile_cutter ( height - h_bot , ylen - extent - cut - ( ! s && ycutfirst ? v_cut_lip : 0 ) , s ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
fillet_cutter ( 0 , "hotpink" )
difference ( ) {
transform_main ( xlen )
difference ( ) {
profile_cutter ( height - h_bot , ylen - extent , s ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
if ( ! ( ( zsmall || t = = 5 ) && ! ycutlast ) )
profile_cutter_tab ( height - h_bot , tab , ang ) ;
2023-09-22 06:11:23 +00:00
2023-02-14 16:55:29 +00:00
if ( ! ( abs ( s ) > 0 ) && y = = 0 )
2022-08-09 20:25:13 +00:00
translate ( [ ylen - extent , 0 , 0 ] )
mirror ( [ 1 , 0 , 0 ] )
profile_cutter_tab ( height - h_bot , v_len_lip , v_ang_lip ) ;
}
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
if ( xcutfirst )
color ( "indigo" )
2022-10-11 02:19:04 +00:00
translate ( [ ylen / 2 + 0.001 , 0 , xlen / 2 + 0.001 ] )
2022-08-09 20:25:13 +00:00
rotate ( [ 0 , 90 , 0 ] )
transform_main ( 2 * ylen )
profile_cutter_tab ( height - h_bot , v_len_lip , v_ang_lip ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
if ( xcutlast )
color ( "indigo" )
2022-10-11 02:19:04 +00:00
translate ( [ ylen / 2 + 0.001 , 0 , - xlen / 2 + 0.001 ] )
2022-08-09 20:25:13 +00:00
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 ( ) ;
}
2024-02-03 01:03:04 +00:00
module transform_tab ( type , xlen , cut , tab_width = d_tabw ) {
2022-08-09 20:25:13 +00:00
mirror ( [ 0 , 0 , type = = 1 ? 1 : 0 ] )
copy_mirror ( [ 0 , 0 , - ( abs ( type ) - 1 ) ] )
translate ( [ 0 , 0 , - ( xlen ) / 2 ] )
translate ( [ 0 , 0 , r_f2 ] )
2024-02-03 01:03:04 +00:00
linear_extrude ( ( xlen - tab_width - abs ( cut ) ) / ( 1 - ( abs ( type ) - 1 ) ) - 2 * r_f2 )
2022-08-09 20:25:13 +00:00
children ( ) ;
}
module fillet_cutter ( t = 0 , c = "goldenrod" ) {
color ( c )
minkowski ( ) {
children ( ) ;
sphere ( r = r_f2 - t / 1000 ) ;
}
}
2022-10-02 06:10:19 +00:00
module profile_cutter ( h , l , s ) {
2023-09-22 06:11:23 +00:00
scoop = max ( s * $ dh / 2 - r_f2 , 0 ) ;
2022-08-09 20:25:13 +00:00
translate ( [ r_f2 , r_f2 ] )
hull ( ) {
2022-10-02 06:10:19 +00:00
if ( l - scoop - 2 * r_f2 > 0 )
2022-08-09 20:25:13 +00:00
square ( 0.1 ) ;
if ( scoop < h ) {
2023-09-22 06:11:23 +00:00
translate ( [ l - 2 * r_f2 , h - r_f2 / 2 ] )
mirror ( [ 1 , 1 ] )
2022-08-09 20:25:13 +00:00
square ( 0.1 ) ;
2023-09-22 06:11:23 +00:00
translate ( [ 0 , h - r_f2 / 2 ] )
mirror ( [ 0 , 1 ] )
2022-08-09 20:25:13 +00:00
square ( 0.1 ) ;
}
difference ( ) {
2023-09-22 06:11:23 +00:00
translate ( [ l - scoop - 2 * r_f2 , scoop ] )
2022-08-09 20:25:13 +00:00
if ( scoop ! = 0 ) {
intersection ( ) {
circle ( scoop ) ;
mirror ( [ 0 , 1 ] ) square ( 2 * scoop ) ;
}
} else mirror ( [ 1 , 0 ] ) square ( 0.1 ) ;
2023-09-22 06:11:23 +00:00
translate ( [ l - scoop - 2 * r_f2 , - 1 ] )
2022-10-02 06:10:19 +00:00
square ( [ - ( l - scoop - 2 * r_f2 ) , 2 * h ] ) ;
2023-09-22 06:11:23 +00:00
translate ( [ 0 , h ] )
2022-10-02 06:10:19 +00:00
square ( [ 2 * l , scoop ] ) ;
2022-08-09 20:25:13 +00:00
}
}
}
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 ) ] ] ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
}
// ==== Utilities =====
function clp ( x , a , b ) = min ( max ( x , a ) , b ) ;
module rounded_rectangle ( length , width , height , rad ) {
linear_extrude ( height )
2023-09-22 06:11:23 +00:00
offset ( rad )
offset ( - rad )
2022-08-09 20:25:13 +00:00
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 ( ) ;
2023-09-22 06:11:23 +00:00
if ( vec ! = [ 0 , 0 , 0 ] )
mirror ( vec )
2022-08-09 20:25:13 +00:00
children ( ) ;
2023-09-22 06:11:23 +00:00
}
2022-08-09 20:25:13 +00:00
2022-10-03 00:35:03 +00:00
module pattern_linear ( x = 1 , y = 1 , sx = 0 , sy = 0 ) {
2023-09-22 06:11:23 +00:00
yy = sy < = 0 ? sx : sy ;
2022-10-03 00:35:03 +00:00
translate ( [ - ( x - 1 ) * sx / 2 , - ( y - 1 ) * yy / 2 , 0 ] )
2022-10-01 20:13:51 +00:00
for ( i = [ 1 : ceil ( x ) ] )
for ( j = [ 1 : ceil ( y ) ] )
2023-09-22 06:11:23 +00:00
translate ( [ ( i - 1 ) * sx , ( j - 1 ) * yy , 0 ] )
2022-10-01 20:13:51 +00:00
children ( ) ;
}
2022-08-09 20:25:13 +00:00
module pattern_circular ( n = 2 ) {
2023-09-22 06:11:23 +00:00
for ( i = [ 1 : n ] )
rotate ( i * 360 / n )
2022-08-09 20:25:13 +00:00
children ( ) ;
}
module sweep_rounded ( w = 10 , h = 10 ) {
union ( ) pattern_circular ( 2 ) {
2023-09-22 06:11:23 +00:00
copy_mirror ( [ 1 , 0 , 0 ] )
2022-08-09 20:25:13 +00:00
translate ( [ w / 2 , h / 2 , 0 ] )
2023-09-22 06:11:23 +00:00
rotate_extrude ( angle = 90 , convexity = 4 )
2022-08-09 20:25:13 +00:00
children ( ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
translate ( [ w / 2 , 0 , 0 ] )
rotate ( [ 90 , 0 , 0 ] )
linear_extrude ( height = h , center = true )
children ( ) ;
2023-09-22 06:11:23 +00:00
2022-08-09 20:25:13 +00:00
rotate ( [ 0 , 0 , 90 ] )
translate ( [ h / 2 , 0 , 0 ] )
rotate ( [ 90 , 0 , 0 ] )
linear_extrude ( height = w , center = true )
children ( ) ;
}
}