diff --git a/gridfinity-rebuilt-baseplate.scad b/gridfinity-rebuilt-baseplate.scad index bd3885c..ce9380c 100644 --- a/gridfinity-rebuilt-baseplate.scad +++ b/gridfinity-rebuilt-baseplate.scad @@ -341,7 +341,7 @@ module square_baseplate_lip(height=0, size = l_grid) { corner_center_distance = size/2 - BASEPLATE_OUTSIDE_RADIUS; - render(convexity = 2) // Fixes ghosting in preview + //render(convexity = 2) // Fixes ghosting in preview union() { baseplate_lip(height, size, size); pattern_circular(4) diff --git a/gridfinity-spiral-vase.scad b/gridfinity-spiral-vase.scad index b616c99..b8f1625 100644 --- a/gridfinity-spiral-vase.scad +++ b/gridfinity-spiral-vase.scad @@ -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); 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 me = ((gridx*l_grid-0.5)/n_divx)-nozzle*4-d_fo1-12.7-4; @@ -171,7 +171,7 @@ module gridfinityBaseVase() { intersection() { block_base_blank(0); 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]) 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); mirror([0,0,1]) 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); } } } diff --git a/src/core/gridfinity-rebuilt-utility.scad b/src/core/gridfinity-rebuilt-utility.scad index 0f0c38a..4de939c 100644 --- a/src/core/gridfinity-rebuilt-utility.scad +++ b/src/core/gridfinity-rebuilt-utility.scad @@ -217,12 +217,12 @@ module cut_move(x, y, w, h) { // ===== 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_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. */ -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 && grid_dimensions.x > 0 && grid_dimensions.y > 0); 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. // 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 // 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]; 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. // subtracting gap_mm here to remove an outer lip along the peremiter. grid_size_mm = [ - base_center_distance_mm.x * final_grid_size.x - gap_mm, - base_center_distance_mm.y * final_grid_size.y - gap_mm - ]; + base_center_distance_mm.x * final_grid_size.x, + base_center_distance_mm.y * final_grid_size.y + ] - gap_mm; // Top which ties all bases together if (final_cut) { 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) { + hole_position = foreach_add( + grid_size_mm/2, + - HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x + ); difference(){ 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); @@ -272,8 +276,8 @@ module gridfinityBase(grid_size, grid_dimensions=[l_grid, l_grid], hole_options= copy_mirror([0, 1, 0]) { copy_mirror([1, 0, 0]) { translate([ - grid_size_mm.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x, - grid_size_mm.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE - BASE_PROFILE_MAX.x, + hole_position.x, + hole_position.y, 0 ]) 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). * @param hole_options @see block_base_hole.hole_options * @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. */ -module block_base(hole_options, off=0, size=[BASE_SIZE, BASE_SIZE], thumbscrew=false) { - assert( - is_list(size) && - len(size) == 2 && - is_bool(thumbscrew) - ); +module block_base(hole_options, off=0, top_dimensions=BASE_TOP_DIMENSIONS, thumbscrew=false) { + assert(is_list(top_dimensions) && len(top_dimensions) == 2); + assert(is_bool(thumbscrew)); - // How far, in the +x direction, - // the profile needs to be from it's [0, 0] point - // such that when swept by 90 degrees to produce a corner, - // the outside edge has the desired radius. - translation_x = BASE_OUTSIDE_RADIUS - BASE_PROFILE_MAX.x; + base_bottom = base_bottom_dimensions(top_dimensions); + sweep_inner = foreach_add(base_bottom, -2*BASE_BOTTOM_RADIUS); + cube_size = foreach_add(base_bottom, -BASE_BOTTOM_RADIUS); - outer_diameter = [2*BASE_OUTSIDE_RADIUS, 2*BASE_OUTSIDE_RADIUS]; - base_profile_size = size - outer_diameter; - 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) + assert(sweep_inner.x > 0 && sweep_inner.y > 0, + str("Minimum size of a single base must be greater than ", 2*BASE_TOP_RADIUS) ); thumbscrew_outerdiam = 15; @@ -323,20 +334,12 @@ module block_base(hole_options, off=0, size=[BASE_SIZE, BASE_SIZE], thumbscrew=f render(convexity = 2) difference() { - union() { - sweep_rounded(base_profile_size) - translate([translation_x, 0, 0]) - polygon(BASE_PROFILE); + union(){ + sweep_rounded(sweep_inner) + base_polygon(); - rounded_square( - [ - base_bottom_size.x + TOLLERANCE, - base_bottom_size.y + TOLLERANCE, - BASE_PROFILE_MAX.y - ], - translation_x, - center=true - ); + translate([0, 0, BASE_PROFILE_MAX.y/2]) + cube([cube_size.x, cube_size.y, BASE_PROFILE_MAX.y], center=true); } 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)); i = sign(cos(a+1)); translate([ - i * (base_bottom_size.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), - j * (base_bottom_size.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), + i * (base_bottom.x/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), + j * (base_bottom.y/2 - HOLE_DISTANCE_FROM_BOTTOM_EDGE), 0]) rotate([0, 0, a]) block_base_hole(hole_options, off); diff --git a/src/core/standard.scad b/src/core/standard.scad index c294098..372fec9 100644 --- a/src/core/standard.scad +++ b/src/core/standard.scad @@ -3,9 +3,16 @@ r_c1 = 0.8; // bottom thiccness of bin 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 // 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. + * @Details This is just a line, and will not create a solid polygon. */ -RAW_STACKING_LIP = [ +STACKING_LIP_LINE = [ [0, 0], // Inner tip [0.7, 0.7], // Go out 45 degrees [0.7, (0.7+1.8)], // Vertical increase @@ -110,7 +118,7 @@ RAW_STACKING_LIP = [ * Including wall thickness. * "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; @@ -123,40 +131,69 @@ _stacking_lip_support_height_mm = + 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. */ -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 [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 // 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 = [ [0, 0], // Innermost bottom point [0.8, 0.8], // Up and out at a 45 degree angle [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, (0.8+1.8+2.15)], // Go in to form a solid polygon - [0, 0] //Back to start + [(0.8+2.15), (0.8+1.8+2.15)] // Up and out at a 45 degree angle ]; -// 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]; -// Each unit's base is 41.5mm x 41.5mm -// Leaving 0.5mm gap with an l_grid of 42 -BASE_SIZE = 41.5; +/** + * @Summary Corner radius of the bottom of the base. + * @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 + * @Deprecated */ h_base = BASE_PROFILE_MAX.y; @@ -174,7 +211,7 @@ BASEPLATE_LIP = [ [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], // Straight down - [0, 0] //Back to start + //[0, 0] // Implicit back to start ]; // Height of the baseplate lip.