Updated solid base creation logic

* Simplified.
* More readable.
* Prevents gaps that could be left by old logic. (rounded_square)
This commit is contained in:
Arthur Moore 2024-10-22 18:48:14 -04:00
parent 1ee99f9c6f
commit d47043fa51
4 changed files with 102 additions and 62 deletions

View file

@ -341,7 +341,7 @@ module square_baseplate_lip(height=0, size = l_grid) {
corner_center_distance = size/2 - BASEPLATE_OUTSIDE_RADIUS; corner_center_distance = size/2 - BASEPLATE_OUTSIDE_RADIUS;
render(convexity = 2) // Fixes ghosting in preview //render(convexity = 2) // Fixes ghosting in preview
union() { union() {
baseplate_lip(height, size, size); baseplate_lip(height, size, size);
pattern_circular(4) pattern_circular(4)

View file

@ -88,7 +88,7 @@ x_l = l_grid/2;
dht = (gridz_define==0)?gridz*7 : (gridz_define==1)?h_bot+gridz+h_base : gridz-(enable_lip?3.8:0); dht = (gridz_define==0)?gridz*7 : (gridz_define==1)?h_bot+gridz+h_base : gridz-(enable_lip?3.8:0);
d_height = (enable_zsnap?((abs(dht)%7==0)?dht:dht+7-abs(dht)%7):dht)-h_base; d_height = (enable_zsnap?((abs(dht)%7==0)?dht:dht+7-abs(dht)%7):dht)-h_base;
d_fo1 = 2*+BASE_OUTSIDE_RADIUS; d_fo1 = 2*+BASE_TOP_RADIUS;
f2c = sqrt(2)*(sqrt(2)-1); // fillet to chamfer ratio f2c = sqrt(2)*(sqrt(2)-1); // fillet to chamfer ratio
me = ((gridx*l_grid-0.5)/n_divx)-nozzle*4-d_fo1-12.7-4; me = ((gridx*l_grid-0.5)/n_divx)-nozzle*4-d_fo1-12.7-4;
@ -171,7 +171,7 @@ module gridfinityBaseVase() {
intersection() { intersection() {
block_base_blank(0); block_base_blank(0);
translate([0,0,-h_base-1]) translate([0,0,-h_base-1])
rounded_square([l_grid-0.5-0.005, l_grid-0.5-0.005, h_base*10], BASE_OUTSIDE_RADIUS+0.001, center=true); rounded_square([l_grid-0.5-0.005, l_grid-0.5-0.005, h_base*10], BASE_TOP_RADIUS+0.001, center=true);
} }
translate([0,0,0.01]) translate([0,0,0.01])
difference() { difference() {
@ -239,7 +239,7 @@ module block_base_blank(o = 0) {
rounded_square(l_grid-o-0.05-2*r_c2, r_fo2, center=true); rounded_square(l_grid-o-0.05-2*r_c2, r_fo2, center=true);
mirror([0,0,1]) mirror([0,0,1])
linear_extrude(d_bottom) linear_extrude(d_bottom)
rounded_square(l_grid-o-0.05, BASE_OUTSIDE_RADIUS, center=true); rounded_square(l_grid-o-0.05, BASE_TOP_RADIUS, center=true);
} }
} }
} }

View file

@ -217,12 +217,12 @@ module cut_move(x, y, w, h) {
// ===== Modules ===== // // ===== Modules ===== //
/** /**
*@summary Create the base of a gridfinity bin, or use it for a custom object. * @brief Create the base of a gridfinity bin, or use it for a custom object.
* @param grid_size Number of bases in each dimension. [x, y] * @param grid_size Number of bases in each dimension. [x, y]
* @param grid_dimensions [length, width] of a single Gridfinity base. * @param grid_dimensions [length, width] of a single Gridfinity base.
* @param thumbscrew Enable "gridfinity-refined" thumbscrew hole in the center of each base unit. This is a ISO Metric Profile, 15.0mm size, M15x1.5 designation. * @param thumbscrew Enable "gridfinity-refined" thumbscrew hole in the center of each base unit. This is a ISO Metric Profile, 15.0mm size, M15x1.5 designation.
*/ */
module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options=bundle_hole_options(), off=0, final_cut=true, only_corners=false, thumbscrew=false) { module gridfinityBase(grid_size, grid_dimensions=GRID_DIMENSIONS_MM, hole_options=bundle_hole_options(), off=0, final_cut=true, only_corners=false, thumbscrew=false) {
assert(is_list(grid_dimensions) && len(grid_dimensions) == 2 && assert(is_list(grid_dimensions) && len(grid_dimensions) == 2 &&
grid_dimensions.x > 0 && grid_dimensions.y > 0); grid_dimensions.x > 0 && grid_dimensions.y > 0);
assert(is_list(grid_size) && len(grid_size) == 2 && assert(is_list(grid_size) && len(grid_size) == 2 &&
@ -235,7 +235,7 @@ module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options=
// Per spec, there's a 0.5mm gap between each base. // Per spec, there's a 0.5mm gap between each base.
// This must be kept constant or half bins may not work correctly. // This must be kept constant or half bins may not work correctly.
gap_mm = l_grid - BASE_SIZE; gap_mm = GRID_DIMENSIONS_MM - BASE_TOP_DIMENSIONS;
// Divisions per grid // Divisions per grid
// Normal, half, or quarter grid sizes supported. // Normal, half, or quarter grid sizes supported.
@ -249,22 +249,26 @@ module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options=
final_grid_size = [grid_size.x * divisions_per_grid.x, grid_size.y * divisions_per_grid.y]; final_grid_size = [grid_size.x * divisions_per_grid.x, grid_size.y * divisions_per_grid.y];
base_center_distance_mm = [grid_dimensions.x / divisions_per_grid.x, grid_dimensions.y / divisions_per_grid.y]; base_center_distance_mm = [grid_dimensions.x / divisions_per_grid.x, grid_dimensions.y / divisions_per_grid.y];
individual_base_size_mm = [base_center_distance_mm.x - gap_mm, base_center_distance_mm.y - gap_mm]; individual_base_size_mm = [base_center_distance_mm.x, base_center_distance_mm.y] - gap_mm;
// Final size of the base top. In mm. // Final size of the base top. In mm.
// subtracting gap_mm here to remove an outer lip along the peremiter. // subtracting gap_mm here to remove an outer lip along the peremiter.
grid_size_mm = [ grid_size_mm = [
base_center_distance_mm.x * final_grid_size.x - gap_mm, base_center_distance_mm.x * final_grid_size.x,
base_center_distance_mm.y * final_grid_size.y - gap_mm base_center_distance_mm.y * final_grid_size.y
]; ] - gap_mm;
// Top which ties all bases together // Top which ties all bases together
if (final_cut) { if (final_cut) {
translate([0, 0, h_base-TOLLERANCE]) translate([0, 0, h_base-TOLLERANCE])
rounded_square([grid_size_mm.x, grid_size_mm.y, h_bot], BASE_OUTSIDE_RADIUS, center=true); rounded_square([grid_size_mm.x, grid_size_mm.y, h_bot], BASE_TOP_RADIUS, center=true);
} }
if(only_corners) { if(only_corners) {
hole_position = foreach_add(
grid_size_mm/2,
- HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x
);
difference(){ difference(){
pattern_linear(final_grid_size.x, final_grid_size.y, base_center_distance_mm.x, base_center_distance_mm.y) pattern_linear(final_grid_size.x, final_grid_size.y, base_center_distance_mm.x, base_center_distance_mm.y)
block_base(bundle_hole_options(), 0, individual_base_size_mm, thumbscrew=thumbscrew); block_base(bundle_hole_options(), 0, individual_base_size_mm, thumbscrew=thumbscrew);
@ -272,8 +276,8 @@ module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options=
copy_mirror([0, 1, 0]) { copy_mirror([0, 1, 0]) {
copy_mirror([1, 0, 0]) { copy_mirror([1, 0, 0]) {
translate([ translate([
grid_size_mm.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x, hole_position.x,
grid_size_mm.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x, hole_position.y,
0 0
]) ])
block_base_hole(hole_options, off); block_base_hole(hole_options, off);
@ -287,31 +291,38 @@ module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options=
} }
} }
/**
* @brief Solid polygon of a gridfinity base.
* @details Ready for use with `sweep_rounded(...)`.
*/
module base_polygon() {
translated_line = foreach_add(BASE_PROFILE, [BASE_BOTTOM_RADIUS, 0]);
solid_profile = concat(translated_line,
[
[0, BASE_PROFILE_MAX.y], // Go in to form a solid polygon
[0, 0], // Needed since start has been translated.
]
);
polygon(solid_profile);
}
/** /**
* @brief A single Gridfinity base. With holes (if set). * @brief A single Gridfinity base. With holes (if set).
* @param hole_options @see block_base_hole.hole_options * @param hole_options @see block_base_hole.hole_options
* @param off * @param off
* @param size [x, y] size of a single base. Only set if deviating from the standard! * @param top_dimensions [x, y] size of a single base. Only set if deviating from the standard!
* @param thumbscrew Enable "gridfinity-refined" thumbscrew hole in the center of each base unit. This is a ISO Metric Profile, 15.0mm size, M15x1.5 designation. * @param thumbscrew Enable "gridfinity-refined" thumbscrew hole in the center of each base unit. This is a ISO Metric Profile, 15.0mm size, M15x1.5 designation.
*/ */
module block_base(hole_options, off=0, size=[BASE_SIZE, BASE_SIZE], thumbscrew=false) { module block_base(hole_options, off=0, top_dimensions=BASE_TOP_DIMENSIONS, thumbscrew=false) {
assert( assert(is_list(top_dimensions) && len(top_dimensions) == 2);
is_list(size) && assert(is_bool(thumbscrew));
len(size) == 2 &&
is_bool(thumbscrew)
);
// How far, in the +x direction, base_bottom = base_bottom_dimensions(top_dimensions);
// the profile needs to be from it's [0, 0] point sweep_inner = foreach_add(base_bottom, -2*BASE_BOTTOM_RADIUS);
// such that when swept by 90 degrees to produce a corner, cube_size = foreach_add(base_bottom, -BASE_BOTTOM_RADIUS);
// the outside edge has the desired radius.
translation_x = BASE_OUTSIDE_RADIUS - BASE_PROFILE_MAX.x;
outer_diameter = [2*BASE_OUTSIDE_RADIUS, 2*BASE_OUTSIDE_RADIUS]; assert(sweep_inner.x > 0 && sweep_inner.y > 0,
base_profile_size = size - outer_diameter; str("Minimum size of a single base must be greater than ", 2*BASE_TOP_RADIUS)
base_bottom_size = base_profile_size + [2*translation_x, 2*translation_x];
assert(base_profile_size.x > 0 && base_profile_size.y > 0,
str("Minimum size of a single base must be greater than ", outer_diameter)
); );
thumbscrew_outerdiam = 15; thumbscrew_outerdiam = 15;
@ -324,19 +335,11 @@ module block_base(hole_options, off=0, size=[BASE_SIZE, BASE_SIZE], thumbscrew=f
render(convexity = 2) render(convexity = 2)
difference() { difference() {
union(){ union(){
sweep_rounded(base_profile_size) sweep_rounded(sweep_inner)
translate([translation_x, 0, 0]) base_polygon();
polygon(BASE_PROFILE);
rounded_square( translate([0, 0, BASE_PROFILE_MAX.y/2])
[ cube([cube_size.x, cube_size.y, BASE_PROFILE_MAX.y], center=true);
base_bottom_size.x + TOLLERANCE,
base_bottom_size.y + TOLLERANCE,
BASE_PROFILE_MAX.y
],
translation_x,
center=true
);
} }
if (thumbscrew) { if (thumbscrew) {
@ -357,8 +360,8 @@ module block_base(hole_options, off=0, size=[BASE_SIZE, BASE_SIZE], thumbscrew=f
j = sign(sin(a+1)); j = sign(sin(a+1));
i = sign(cos(a+1)); i = sign(cos(a+1));
translate([ translate([
i * (base_bottom_size.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), i * (base_bottom.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE),
j * (base_bottom_size.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), j * (base_bottom.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE),
0]) 0])
rotate([0, 0, a]) rotate([0, 0, a])
block_base_hole(hole_options, off); block_base_hole(hole_options, off);

View file

@ -3,9 +3,16 @@
r_c1 = 0.8; r_c1 = 0.8;
// bottom thiccness of bin // bottom thiccness of bin
h_bot = 2.2; h_bot = 2.2;
// length of a grid unit
l_grid = 42;
/**
* @brief Size of a single gridfinity unit. [Length, Width] In millimeters.
*/
GRID_DIMENSIONS_MM = [42, 42];
/**
* @deprecated Use GRID_DIMENSIONS_MM instead.
*/
l_grid = GRID_DIMENSIONS_MM.x;
// Outside rounded radius of bin // Outside rounded radius of bin
// Per spec, matches radius of upper base section. // Per spec, matches radius of upper base section.
@ -96,8 +103,9 @@ STACKING_LIP_SUPPORT_HEIGHT = 1.2;
/** /**
* @Summary Stacking lip as defined in the spec. No support. * @Summary Stacking lip as defined in the spec. No support.
* @Details This is just a line, and will not create a solid polygon.
*/ */
RAW_STACKING_LIP = [ STACKING_LIP_LINE = [
[0, 0], // Inner tip [0, 0], // Inner tip
[0.7, 0.7], // Go out 45 degrees [0.7, 0.7], // Go out 45 degrees
[0.7, (0.7+1.8)], // Vertical increase [0.7, (0.7+1.8)], // Vertical increase
@ -110,7 +118,7 @@ RAW_STACKING_LIP = [
* Including wall thickness. * Including wall thickness.
* "y": The height of the stacking lip. * "y": The height of the stacking lip.
*/ */
STACKING_LIP_SIZE = RAW_STACKING_LIP[3]; STACKING_LIP_SIZE = STACKING_LIP_LINE[3];
_stacking_lip_support_angle = 45; _stacking_lip_support_angle = 45;
@ -123,40 +131,69 @@ _stacking_lip_support_height_mm =
+ tan(90 - _stacking_lip_support_angle) * STACKING_LIP_SIZE.x; + tan(90 - _stacking_lip_support_angle) * STACKING_LIP_SIZE.x;
/** /**
* @Summary Stacking lip with a support. * @Summary Stacking lip with a support. Used to create a polygon.
* @Details Support is so the stacking lip is not floating in mid air when wall width is less than stacking lip depth. * @Details Support is so the stacking lip is not floating in mid air when wall width is less than stacking lip depth.
*/ */
STACKING_LIP = concat(RAW_STACKING_LIP, [ STACKING_LIP = concat(STACKING_LIP_LINE, [
[STACKING_LIP_SIZE.x, -_stacking_lip_support_height_mm], // Down to support bottom [STACKING_LIP_SIZE.x, -_stacking_lip_support_height_mm], // Down to support bottom
[0, -STACKING_LIP_SUPPORT_HEIGHT], // Up and in (to bottom inner support) [0, -STACKING_LIP_SUPPORT_HEIGHT], // Up and in (to bottom inner support)
[0, 0] // Close the shape. Technically not needed. //[0, 0] // Implicit back to start
]); ]);
// **************************************** // ****************************************
// Base constants // Base constants
// Based on https://gridfinity.xyz/specification/ // Based on https://gridfinity.xyz/specification/
// **************************************** // ****************************************
BASE_OUTSIDE_RADIUS = r_base;
/**
* @Summary Profile of a Gridfinity base as described in the spec.
* @Details This is just a line, and will not create a solid polygon.
*/
BASE_PROFILE = [ BASE_PROFILE = [
[0, 0], // Innermost bottom point [0, 0], // Innermost bottom point
[0.8, 0.8], // Up and out at a 45 degree angle [0.8, 0.8], // Up and out at a 45 degree angle
[0.8, (0.8+1.8)], // Straight up [0.8, (0.8+1.8)], // Straight up
[(0.8+2.15), (0.8+1.8+2.15)], // Up and out at a 45 degree angle [(0.8+2.15), (0.8+1.8+2.15)] // Up and out at a 45 degree angle
[0, (0.8+1.8+2.15)], // Go in to form a solid polygon
[0, 0] //Back to start
]; ];
// Maximum [x,y] values/size of the base. /**
* @Summary Corner radius of the top of the base.
*/
BASE_TOP_RADIUS = r_base;
/**
* @Summary Size of the top of the base. [Length, Width]
* @Details Each unit's base is 41.5mm x 41.5mm
* Leaving 0.5mm gap with an l_grid of 42
*/
BASE_TOP_DIMENSIONS = [41.5, 41.5];
/**
* @Summary Maximum [x,y] values/size of the base.
*/
BASE_PROFILE_MAX = BASE_PROFILE[3]; BASE_PROFILE_MAX = BASE_PROFILE[3];
// Each unit's base is 41.5mm x 41.5mm /**
// Leaving 0.5mm gap with an l_grid of 42 * @Summary Corner radius of the bottom of the base.
BASE_SIZE = 41.5; * @Details This is also how much BASE_PROFILE needs to be translated
* to use `sweep_rounded(...)`.
*/
BASE_BOTTOM_RADIUS = BASE_TOP_RADIUS - BASE_PROFILE_MAX.x;
/**
* @Summary Dimensions of the bottom of the base. [Length, Width]
* @Details Supports arbitrary top sizes.
* @param top_dimensions [Length, Width] of the top of the base.
*/
function base_bottom_dimensions(top_dimensions = BASE_TOP_DIMENSIONS) =
assert(is_list(top_dimensions) && len(top_dimensions) == 2
&& is_num(top_dimensions.x) && is_num(top_dimensions.y))
[top_dimensions.x - 2*BASE_PROFILE_MAX.x,
top_dimensions.y - 2*BASE_PROFILE_MAX.x];
/** /**
* @summary Height of the raw base * @summary Height of the raw base
* @Deprecated
*/ */
h_base = BASE_PROFILE_MAX.y; h_base = BASE_PROFILE_MAX.y;
@ -174,7 +211,7 @@ BASEPLATE_LIP = [
[0.7, (0.7+1.8)], // Straight up [0.7, (0.7+1.8)], // Straight up
[(0.7+2.15), (0.7+1.8+2.15)], // Up and out at a 45 degree angle [(0.7+2.15), (0.7+1.8+2.15)], // Up and out at a 45 degree angle
[(0.7+2.15), 0], // Straight down [(0.7+2.15), 0], // Straight down
[0, 0] //Back to start //[0, 0] // Implicit back to start
]; ];
// Height of the baseplate lip. // Height of the baseplate lip.