diff --git a/gridfinity-rebuilt-baseplate.scad b/gridfinity-rebuilt-baseplate.scad index 202dbcb..f58fc4c 100644 --- a/gridfinity-rebuilt-baseplate.scad +++ b/gridfinity-rebuilt-baseplate.scad @@ -48,12 +48,15 @@ fity = 0; // [-1:0.1:1] /* [Styles] */ // baseplate styles -style_plate = 0; // [0: thin, 1:weighted, 2:skeletonized, 3: screw together, 4: screw together minimal] +style_plate = 0; // [0: thin, 1:weighted, 2:skeletonized, 3: screw together, 4: screw together minimal, 5:crosshair, 6:screw together crosshair] // hole styles style_hole = 2; // [0:none, 1:countersink, 2:counterbore] +// spoke width of crosshair +spoke_width = 3; // [2:1:24] + /* [Magnet Hole] */ // Baseplate will have holes for 6mm Diameter x 2mm high magnets. enable_magnet = true; @@ -64,12 +67,12 @@ chamfer_holes = true; hole_options = bundle_hole_options(refined_hole=false, magnet_hole=enable_magnet, screw_hole=false, crush_ribs=crush_ribs, chamfer=chamfer_holes, supportless=false); + // ===== IMPLEMENTATION ===== // color("tomato") gridfinityBaseplate(gridx, gridy, l_grid, distancex, distancey, style_plate, hole_options, style_hole, fitx, fity); - // ===== CONSTRUCTION ===== // module gridfinityBaseplate(gridx, gridy, length, dix, diy, sp, hole_options, sh, fitx, fity) { @@ -109,9 +112,12 @@ module gridfinityBaseplate(gridx, gridy, length, dix, diy, sp, hole_options, sh, else if (sp == 4) translate([0,0,-5*(h_base+off)]) rounded_square(length-2*r_c2-2*r_c1, 10*(h_base+off), r_fo3); + else if (sp == 5 || sp == 6) + linear_extrude(10*(h_base+off), center = true) + profile_crosshair(); - - hole_pattern(){ + single_hole=sp==5||sp==6; + hole_pattern(l=l_grid, single_hole){ mirror([0, 0, 1]) block_base_hole(hole_options); @@ -121,15 +127,14 @@ module gridfinityBaseplate(gridx, gridy, length, dix, diy, sp, hole_options, sh, } } } - screw_together = sp == 3 || sp == 4; + screw_together = sp == 3 || sp == 4 || sp == 6; if (screw_together) cutter_screw_together(gx, gy, off); } - } function calculate_offset(style_plate, enable_magnet, style_hole) = - assert(style_plate >=0 && style_plate <=4) - let (screw_together = style_plate == 3 || style_plate == 4) + assert(style_plate >= 0 && style_plate <= 6) + let (screw_together = style_plate == 3 || style_plate == 4 || style_plate == 6) screw_together ? 6.75 : style_plate==0 ? 0 : style_plate==1 ? bp_h_bot : @@ -157,13 +162,6 @@ module cutter_weight() { } } } -module hole_pattern(){ - pattern_circular(4) - translate([l_grid/2-d_hole_from_side, l_grid/2-d_hole_from_side, 0]) { - render(); - children(); - } -} module cutter_countersink(){ screw_hole(SCREW_HOLE_RADIUS + d_clear, 2*h_base, @@ -192,12 +190,33 @@ module profile_skeleton() { minkowski() { square([l,l]); circle(MAGNET_HOLE_RADIUS+r_skel+2); - } + } } circle(r_skel); } } +module profile_crosshair() { + l_grid_inner = l_grid - 2*r_c2 - 2*r_c1; // l without chamfers + l_grid_inner_minkowski = l_grid_inner / 2 - r_f1; + + // sqrt 2 because of 45 degree angle + spoke_offset=sqrt(2)*spoke_width/2; + + pattern_circular(4) + difference() { + minkowski() { + polygon([ + [spoke_offset, 0], + [l_grid_inner_minkowski, l_grid_inner_minkowski - spoke_offset], + [l_grid_inner_minkowski, -l_grid_inner_minkowski + spoke_offset], + ]); + circle(r_f1); + } + circle(MAGNET_HOLE_RADIUS+r_skel); + } +} + module cutter_screw_together(gx, gy, off) { screw(gx, gy); diff --git a/gridfinity-rebuilt-bins.scad b/gridfinity-rebuilt-bins.scad index 8e908b1..0726d05 100644 --- a/gridfinity-rebuilt-bins.scad +++ b/gridfinity-rebuilt-bins.scad @@ -78,6 +78,8 @@ scoop = 1; //[0:0.1:1] 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; +// Base will have a single hole in the center (use with crosshair style base) +single_hole = false; /* [Base Hole Options] */ // only cut magnet/screw holes at the corners of the bin to save uneccesary print time @@ -111,7 +113,7 @@ gridfinityInit(gridx, gridy, height(gridz, gridz_define, style_lip, enable_zsnap cutCylinders(n_divx=cdivx, n_divy=cdivy, cylinder_diameter=cd, cylinder_height=ch, coutout_depth=c_depth, orientation=c_orientation, chamfer=c_chamfer); } } -gridfinityBase(gridx, gridy, l_grid, div_base_x, div_base_y, hole_options, only_corners=only_corners); +gridfinityBase(gridx, gridy, l_grid, div_base_x, div_base_y, hole_options, only_corners=only_corners, single_hole=single_hole); } diff --git a/gridfinity-rebuilt-utility.scad b/gridfinity-rebuilt-utility.scad index 80f28e2..0260fd6 100644 --- a/gridfinity-rebuilt-utility.scad +++ b/gridfinity-rebuilt-utility.scad @@ -210,7 +210,7 @@ module profile_base() { ]); } -module gridfinityBase(gx, gy, l, dx, dy, hole_options=bundle_hole_options(), off=0, final_cut=true, only_corners=false) { +module gridfinityBase(gx, gy, l, dx, dy, hole_options=bundle_hole_options(), off=0, final_cut=true, only_corners=false, single_hole=false) { 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)); @@ -218,25 +218,27 @@ module gridfinityBase(gx, gy, l, dx, dy, hole_options=bundle_hole_options(), off 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+0.001); + if (final_cut) { + translate([0,0,h_base]) + rounded_rectangle(xx+0.002, yy+0.002, h_bot/1.5, r_fo1+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+0.001); + if (final_cut) { + translate([0,0,-1]) + rounded_rectangle(xx+0.005, yy+0.005, h_base+h_bot/2*10, r_fo1+0.001); + } if(only_corners) { difference(){ pattern_linear(gx/dbnx, gy/dbny, dbnx*l, dbny*l) - block_base(gx, gy, l, dbnx, dbny, 0, off); + block_base(gx, gy, l, dbnx, dbny, [], off); copy_mirror([0, 1, 0]) { copy_mirror([1, 0, 0]) { translate([ - (gx/2)*l_grid - d_hole_from_side, - (gy/2) * l_grid - d_hole_from_side, + (gx/2)*l_grid - (single_hole ? l_grid/2 : d_hole_from_side), + (gy/2)*l_grid - (single_hole ? l_grid/2 : d_hole_from_side), 0 ]) block_base_hole(hole_options, off); @@ -246,13 +248,29 @@ module gridfinityBase(gx, gy, l, dx, dy, hole_options=bundle_hole_options(), off } else { pattern_linear(gx/dbnx, gy/dbny, dbnx*l, dbny*l) - block_base(gx, gy, l, dbnx, dbny, hole_options, off); + block_base(gx, gy, l, dbnx, dbny, hole_options, off, single_hole=single_hole); } } } /** - * @brief A single Gridfinity base. With holes (if set). + * @brief Apply hole pattern to children + * @param l + * @param single_hole Use a single hole, default = false + */ +module hole_pattern(l, single_hole=false){ + hole_offset = single_hole ? 0 : l/2 - d_hole_from_side; + steps= (single_hole || abs(l - d_hole_from_side/2) < 0.001) ? 1 : 4; + + pattern_circular(steps) + translate([hole_offset, hole_offset, 0]) { + render(); + children(); + } +} + +/** + * @brief A single Gridfinity base. With holes (if set). * @param gx * @param gy * @param l @@ -261,14 +279,14 @@ module gridfinityBase(gx, gy, l, dx, dy, hole_options=bundle_hole_options(), off * @param hole_options @see block_base_hole.hole_options * @param off */ -module block_base(gx, gy, l, dbnx, dbny, hole_options, off) { +module block_base(gx, gy, l, dbnx, dbny, hole_options, off, single_hole=false) { render(convexity = 2) difference() { block_base_solid(dbnx, dbny, l, off); - - pattern_circular(abs(l-d_hole_from_side/2)<0.001?1:4) - translate([l/2-d_hole_from_side, l/2-d_hole_from_side, 0]) - block_base_hole(hole_options, off); + + hole_pattern(l, single_hole=single_hole) { + block_base_hole(hole_options, off); + } } } diff --git a/tests/test_baseplate.py b/tests/test_baseplate.py index 9984310..fa28bfd 100644 --- a/tests/test_baseplate.py +++ b/tests/test_baseplate.py @@ -111,6 +111,16 @@ class TestBasePlateHoles(unittest.TestCase): self.scad_runner.camera_arguments = self.scad_runner.camera_arguments.with_rotation(CameraRotations.AngledTop) self.scad_runner.create_image([], Path('magnet_and_counterbored_screw_holes_top.png')) + def test_crosshair_with_magnet(self): + vars = self.scad_runner.parameters + vars["enable_magnet"] = True + vars["chamfer_holes"] = False + vars["crush_ribs"] = False + vars["style_plate"] = 5 + self.scad_runner.create_image([], Path('crosshair_with_magnet_bottom.png')) + self.scad_runner.camera_arguments = self.scad_runner.camera_arguments.with_rotation(CameraRotations.AngledTop) + self.scad_runner.create_image([], Path('crosshair_with_magnet_top.png')) + if __name__ == '__main__': unittest.main()