Skip to content

Commit

Permalink
Added underside clearance to bins, more robust variable wall thicknes…
Browse files Browse the repository at this point in the history
…s, GridfinityBox __str__ method
  • Loading branch information
michaelgale committed Feb 11, 2024
1 parent 063e30e commit b9488f4
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
- v.0.5.2 - Adjusted geometry of box/bin floor/lip heights to exactly 7.00 mm intervals
- v.0.5.3 - Removed a potential namespace collision for computing the height of boxes
- v.0.5.4 - Optimized the geometry of the baseplate top height
- v.0.5.5 - Added underside bin clearance and variable wall thickness interior radiusing
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ b1.save_step_file()
- v.0.5.2 - Adjusted geometry of box/bin floor/lip heights to exactly 7.00 mm intervals
- v.0.5.3 - Removed a potential namespace collision for computing the height of boxes
- v.0.5.4 - Optimized the geometry of the baseplate top height
- v.0.5.5 - Added underside bin clearance and variable wall thickness interior radiusing

# References

Expand Down
2 changes: 1 addition & 1 deletion cqgridfinity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# fmt: off
__project__ = 'cqgridfinity'
__version__ = '0.5.4'
__version__ = '0.5.5'
# fmt: on

VERSION = __project__ + "-" + __version__
Expand Down
53 changes: 29 additions & 24 deletions cqgridfinity/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@
GRU = 42
GRU2 = GRU / 2
GRHU = 7
GRU_CUT = 42.2
GR_WALL = 1.0
GR_DIV_WALL = 1.2

GR_RAD = 4
GR_BASE_HEIGHT = 4.75
GRU_CUT = 42.2 # base extrusion width
GR_WALL = 1.0 # nominal exterior wall thickness
GR_DIV_WALL = 1.2 # width of dividing walls
GR_TOL = 0.5 # nominal tolerance

GR_RAD = 4 # nominal exterior filleting radius
GR_BASE_CLR = 0.25 # clearance above the nominal base height
GR_BASE_HEIGHT = 4.75 # nominal base height

# baseplate extrusion profile
GR_BASE_CHAMF_H = 0.98994949 / SQRT2
GR_STR_H = 1.8
GR_BASE_TOP_CHAMF = GR_BASE_HEIGHT - GR_BASE_CHAMF_H - GR_STR_H
Expand All @@ -54,23 +59,20 @@
GR_STR_H + GR_BASE_CHAMF_H,
)

GR_HOLE_D = 6.5
GR_HOLE_H = 2.4
GR_BOLT_D = 3.0
GR_BOLT_H = 3.6 + GR_HOLE_H
GR_HOLE_DIST = 26 / 2
GR_HOLE_SLICE = 0.25

GR_BOT_H = 7
GR_FILLET = 1.2
GR_FLOOR = GR_BOT_H - GR_BASE_HEIGHT
GR_LITE_FLOOR = GR_FLOOR - GR_WALL
GR_LITE_H = GR_LITE_FLOOR - GR_BASE_HEIGHT
GR_BOT_H = 7 # bin nominal floor height
GR_FILLET = 1.1 # inside filleting radius
GR_FLOOR = GR_BOT_H - GR_BASE_HEIGHT # floor offset

# box/bin extrusion profile
GR_BOX_CHAMF_H = 1.1313708 / SQRT2
GR_BOX_TOP_CHAMF = GR_BASE_HEIGHT - GR_BOX_CHAMF_H - GR_STR_H
GR_TOL = 0.5
GR_BOX_TOP_CHAMF = GR_BASE_HEIGHT - GR_BOX_CHAMF_H - GR_STR_H + GR_BASE_CLR
GR_BOX_PROFILE = (
(GR_BOX_TOP_CHAMF * SQRT2, 45),
GR_STR_H,
(GR_BOX_CHAMF_H * SQRT2, 45),
)

# bin mating lip extrusion profile
GR_UNDER_H = 1.6
GR_TOPSIDE_H = 1.2
GR_LIP_PROFILE = (
Expand All @@ -87,11 +89,14 @@
else:
GR_LIP_H += h
GR_NO_PROFILE = (GR_LIP_H,)
GR_BOX_PROFILE = (
(GR_BOX_TOP_CHAMF * SQRT2, 45),
GR_STR_H,
(GR_BOX_CHAMF_H * SQRT2, 45),
)

# bottom hole nominal dimensions
GR_HOLE_D = 6.5
GR_HOLE_H = 2.4
GR_BOLT_D = 3.0
GR_BOLT_H = 3.6 + GR_HOLE_H
GR_HOLE_DIST = 26 / 2
GR_HOLE_SLICE = 0.25

# Rugged Box constant parameters
GR_RBOX_WALL = 2.5
Expand Down
77 changes: 67 additions & 10 deletions cqgridfinity/gf_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,56 @@ def __init__(self, length_u, width_u, height_u, **kwargs):
self._int_shell = None
self._ext_shell = None

def __str__(self):
s = []
s.append(
"Gridfinity Box %dU x %dU x %dU (%.2f x %.2f x %.2f mm)"
% (
self.length_u,
self.width_u,
self.height_u,
self.length - GR_TOL,
self.width - GR_TOL,
self.height,
)
)
sl = "no mating top lip" if self.no_lip else "with mating top lip"
ss = "Lite style box " if self.lite_style else ""
s.append(" %sWall thickness: %.2f mm %s" % (ss, self.wall_th, sl))
s.append(
" Floor height : %.2f mm Inside height: %.2f mm Top reference height: %.2f mm"
% (self.floor_h + GR_BASE_HEIGHT, self.int_height, self.top_ref_height)
)
if self.solid:
s.append(" Solid filled box with fill ratio %.2f" % (self.solid_ratio))
if self.holes:
s.append(" Bottom mounting holes with %.2f mm diameter" % (GR_HOLE_D))
if self.unsupported_holes:
s.append(" Holes are 3D printer friendly and can be unsupported")
if self.scoops:
s.append(" Lengthwise scoops with %.2f mm radius" % (self.scoop_rad))
if self.labels:
s.append(
" Lengthwise label shelf %.2f mm wide with %.2f mm overhang"
% (self.label_width, self.label_height)
)
if self.length_div:
xl = (self.inner_l - GR_DIV_WALL * (self.length_div)) / (
self.length_div + 1
)
s.append(
" %dx lengthwise divisions for %.2f mm compartment lengths"
% (self.length_div, xl)
)
if self.width_div:
yl = (self.inner_w - GR_DIV_WALL * (self.width_div)) / (self.width_div + 1)
s.append(
" %dx widthwise divisions for %.2f mm compartment widths"
% (self.width_div, yl)
)
s.append(" Auto filename: %s" % (self.filename()))
return "\n".join(s)

def render(self):
"""Returns a CadQuery Workplane object representing this Gridfinity box."""
self._int_shell = None
Expand Down Expand Up @@ -131,12 +181,18 @@ def render(self):
bs = (
HasZCoordinateSelector(heights, min_points=1, tolerance=0.5)
+ VerticalEdgeSelector(">5")
- HasZCoordinateSelector("<%.2f" % (GR_LITE_FLOOR))
- HasZCoordinateSelector("<%.2f" % (self.floor_h))
)
if self.lite_style:
bs = bs - HasZCoordinateSelector("<=%.2f" % (self.floor_h))

r = self.safe_fillet(r, bs, self.safe_fillet_rad)
if self.lite_style and self.width_div < 1 and self.length_div < 1:
bs = FlatEdgeSelector(GR_LITE_FLOOR)
r = self.safe_fillet(r, bs, 0.5)
bs = FlatEdgeSelector(self.floor_h)
if self.wall_th < 1.2:
r = self.safe_fillet(r, bs, 0.5)
elif self.wall_th < 1.5:
r = self.safe_fillet(r, bs, 0.25)
if not self.labels and (self.width_div or self.length_div):
bs = VerticalEdgeSelector(
GR_TOPSIDE_H, tolerance=0.05
Expand Down Expand Up @@ -199,7 +255,7 @@ def render_interior(self, force_solid=False):
profile = GR_NO_PROFILE if self.no_lip else profile
profile = [wall_h, *profile]
if self.int_height < 0:
profile = [wall_h - self.floor_h]
profile = [self.height - GR_BOT_H]
rci = self.extrude_profile(
rounded_rect_sketch(*self.inner_dim, self.inner_rad), profile
)
Expand Down Expand Up @@ -237,13 +293,13 @@ def mask_with_obj(self, obj):

def base_interior(self):
profile = [GR_BASE_HEIGHT, *GR_BOX_PROFILE]
zo = GR_BASE_HEIGHT
zo = GR_BASE_HEIGHT + GR_BASE_CLR
if self.int_height < 0:
h = self.bin_height - GR_BASE_HEIGHT
profile = [h, *profile]
zo += h
r = self.extrude_profile(
rounded_rect_sketch(GRU - GR_TOL, GRU - GR_TOL, GR_RAD),
rounded_rect_sketch(GRU - GR_TOL, GRU - GR_TOL, self.outer_rad),
profile,
)
rx = r.faces("<Z").shell(-self.wall_th)
Expand All @@ -253,16 +309,17 @@ def base_interior(self):
def render_shell(self, as_solid=False):
"""Renders the box shell without any added features."""
r = self.extrude_profile(
rounded_rect_sketch(GRU - GR_TOL, GRU - GR_TOL, GR_RAD), GR_BOX_PROFILE
rounded_rect_sketch(GRU, GRU, self.outer_rad + GR_BASE_CLR), GR_BOX_PROFILE
)
r = r.translate((0, 0, -GR_BASE_CLR))
r = r.mirror(mirrorPlane="XY")
r = composite_from_pts(r, self.grid_centres)
rs = rounded_rect_sketch(*self.outer_dim, GR_RAD)
rs = rounded_rect_sketch(*self.outer_dim, self.outer_rad)
rw = (
cq.Workplane("XY")
.placeSketch(rs)
.extrude(self.bin_height)
.translate((*self.half_dim, 0))
.extrude(self.bin_height - GR_BASE_CLR)
.translate((*self.half_dim, GR_BASE_CLR))
)
rc = (
cq.Workplane("XY")
Expand Down
13 changes: 9 additions & 4 deletions cqgridfinity/gf_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def max_height(self):
@property
def floor_h(self):
if self.lite_style:
return GR_LITE_FLOOR
return GR_FLOOR - self.wall_th
return GR_FLOOR

@property
Expand Down Expand Up @@ -142,9 +142,13 @@ def half_dim(self):
def half_in(self):
return GRU2 - self.wall_th - GR_TOL / 2

@property
def outer_rad(self):
return GR_RAD - GR_TOL / 2

@property
def inner_rad(self):
return GR_RAD - self.wall_th
return self.outer_rad - self.wall_th

@property
def under_h(self):
Expand Down Expand Up @@ -316,8 +320,9 @@ def save_svg_file(self, filename=None, path=None, prefix=None):

def extrude_profile(self, sketch, profile, workplane="XY"):
taper = profile[0][1] if isinstance(profile[0], (list, tuple)) else 0
p0 = profile[0][0] if isinstance(profile[0], (list, tuple)) else profile[0]
zlen = p0 if ZLEN_FIX else p0 / SQRT2
zlen = profile[0][0] if isinstance(profile[0], (list, tuple)) else profile[0]
if abs(taper) > 0:
zlen = zlen if ZLEN_FIX else zlen / SQRT2
r = cq.Workplane(workplane).placeSketch(sketch).extrude(zlen, taper=taper)
for level in profile[1:]:
if isinstance(level, (tuple, list)):
Expand Down
41 changes: 41 additions & 0 deletions tests/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def test_basic_box():
assert b1.filename() == "gf_box_2x3x5_basic"
if _export_files("box"):
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)
b1 = GridfinityBox(2, 3, 5, no_lip=True)
if _export_files("box"):
b1.wall_th = 1.5
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)


def test_lite_box():
Expand All @@ -40,6 +45,17 @@ def test_lite_box():
assert _edges_match(r, ">Z", 16)
assert _edges_match(r, "<Z", 48)
assert b1.filename() == "gf_box_lite_2x3x5"
if _export_files("box"):
b1 = GridfinityBox(2, 3, 5, lite_style=True)
b1.wall_th = 1.2
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)
b1 = GridfinityBox(1, 1, 1, lite_style=True)
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)
b1 = GridfinityBox(1, 1, 2, lite_style=True)
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)


def test_empty_box():
Expand All @@ -54,6 +70,18 @@ def test_empty_box():
assert _edges_match(r, "<Z", 72)
assert b1.filename() == "gf_box_2x3x5_holes"
assert _almost_same(b1.top_ref_height, 7)
if _export_files("box"):
b1 = GridfinityBox(2, 3, 5, holes=True)
b1.wall_th = 1.5
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)

b1 = GridfinityBox(1, 1, 1)
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)
b1 = GridfinityBox(1, 1, 2)
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)


def test_solid_box():
Expand Down Expand Up @@ -114,3 +142,16 @@ def test_all_features_box():
assert _almost_same(size_3d(r), (83.5, 83.5, 24.8))
if _export_files("box"):
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)
b1 = GridfinityBox(
2,
2,
3,
holes=True,
length_div=1,
width_div=1,
scoops=True,
labels=True,
wall_th=1.25,
)
r = b1.render()
b1.save_step_file(path=EXPORT_STEP_FILE_PATH)

0 comments on commit b9488f4

Please sign in to comment.