Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions boxes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ def _buildObjects(self):
**self.edgesettings.get("FingerJoint", {}))
s.edgeObjects(self)
self.addPart(edges.FingerHoles(self, s), name="fingerHolesAt")
self.addPart(edges.TriFingerHoles(self, s), name="triFingerHolesAt")
# Stackable
edges.StackableSettings(self.thickness, True,
**self.edgesettings.get("Stackable", {})).edgeObjects(self)
Expand Down Expand Up @@ -2980,9 +2981,9 @@ def polygonWalls(self, borders, h, bottom="F", top="F", symmetrical=True):
t = self.thickness # XXX edge.margin()

leftsettings = copy.deepcopy(self.edges["f"].settings)
lf, lF, lh = leftsettings.edgeObjects(self, add=False)
lf, lF, _, _ = leftsettings.edgeObjects(self, add=False)
rightsettings = copy.deepcopy(self.edges["f"].settings)
rf, rF, rh = rightsettings.edgeObjects(self, add=False)
rf, rF, _, _ = rightsettings.edgeObjects(self, add=False)

length_correction = 0.
angle = borders[-1]
Expand Down
55 changes: 49 additions & 6 deletions boxes/edges.py
Original file line number Diff line number Diff line change
Expand Up @@ -894,28 +894,30 @@ def checkValues(self) -> None:
if abs(self.space + self.finger) < 0.1:
raise ValueError("FingerJointSettings: space + finger must not be close to zero")

def edgeObjects(self, boxes, chars: str = "fFh", add: bool = True):
def edgeObjects(self, boxes, chars: str = "fFhƒ", add: bool = True):
edges = [FingerJointEdge(boxes, self),
FingerJointEdgeCounterPart(boxes, self),
FingerHoleEdge(boxes, self),
TriFingerJointEdge(boxes, self),
]
return self._edgeObjects(edges, boxes, chars, add)


class FingerJointBase(ABC):
"""Abstract base class for finger joint."""
finger_factor = 1

def calcFingers(self, length: float, bedBolts) -> tuple[int, float]:
space, finger = self.settings.space, self.settings.finger # type: ignore
fingers = int((length - (self.settings.surroundingspaces - 1) * space) // (space + finger)) # type: ignore
fingers = int((length - (self.settings.surroundingspaces - 1) * space) // (space + self.finger_factor * finger)) # type: ignore
# shrink surrounding space up to half a thickness each side
if fingers == 0 and length > finger + 1.0 * self.settings.thickness: # type: ignore
fingers = 1
if not finger:
fingers = 0
if bedBolts:
fingers = bedBolts.numFingers(fingers)
leftover = length - fingers * (space + finger) + space
leftover = length - fingers * (space + self.finger_factor * finger) + space

if fingers <= 0:
fingers = 0
Expand Down Expand Up @@ -983,6 +985,20 @@ def draw_finger(self, f, h, style, positive: bool = True, firsthalf: bool = True
else:
self.polyline(0, 90, h, -90, f, -90, h, 90)

def addTriFingerSpace(self, i, fingers, pattern) -> bool:
# no double finger - no space
if self.finger_factor == 1:
return False
# ensure symmetric pattern
j = min(i, fingers - i - 1)
# check if space is needed
if (j % 2) == 0 and pattern == 'A':
return True
if (j % 2) == 1 and pattern == 'B':
return True
# otherwise no space
return False

def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw):

positive = self.positive
Expand Down Expand Up @@ -1025,8 +1041,12 @@ def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw):
self.bedBoltHole(s, bedBoltSettings)
else:
self.edge(s)
if self.addTriFingerSpace(i, fingers, 'B'):
self.edge(f)
self.draw_finger(f, h, style,
positive, i < fingers // 2)
if self.addTriFingerSpace(i, fingers, 'A'):
self.edge(f)

self.edge(leftover / 2.0, tabs=1)

Expand Down Expand Up @@ -1088,14 +1108,14 @@ def __call__(self, x, y, length, angle=90, bedBolts=None, bedBoltSettings=None):
self.ctx.rectangle(b, -self.settings.width / 2 + b,
length - 2 * b, self.settings.width - 2 * b)
for i in range(fingers):
pos = leftover / 2.0 + i * (s + f)
pos = leftover / 2.0 + i * (s + self.finger_factor * f)

if bedBolts and bedBolts.drawBolt(i):
d = (bedBoltSettings or self.boxes.bedBoltSettings)[0]
self.boxes.hole(pos - 0.5 * s, 0, d * 0.5)

self.boxes.rectangularHole(pos + 0.5 * f, 0,
f + p, self.settings.width + p)
self.boxes.rectangularHole(pos + 0.5 * self.finger_factor * f, 0,
self.finger_factor * f + p, self.settings.width + p)


class FingerHoleEdge(BaseEdge):
Expand Down Expand Up @@ -1156,6 +1176,29 @@ def startWidth(self) -> float:
return self.outset


# The TriFingerJoint can be used to join two edges from oposing sides into a
# single wall. The holes in the wall have doubled length and the fingers have
# two spaces (one space sized and on finger sizes). For each hole the order of
# the fingers changes, to ensure a tight fit, if only one side is used. joint
# will like like the following:
# w = wall, l/r = fingers from left/right side
# lr w rl w lr w ... w rl w lr
# Note: the order of the pairs "lr" and "rl" is kepts symmetric. This causes a
# rectangularWall() with two opposing TriFingerJointEdges to cover the left and
# right sied, as the edges of an rectangularWall() are printed clockwise.
class TriFingerJointEdge(FingerJointEdge):
"""Tri finger joint edge"""
char = 'ƒ'
description = "Tri Finger Joint"
finger_factor = 2


class TriFingerHoles(FingerHoles):
"""Hole matching a tri finger joint edge"""
description = "Edge (parallel Tri Finger Joint Holes)"
finger_factor = 2


#############################################################################
#### Stackable Joints
#############################################################################
Expand Down
42 changes: 31 additions & 11 deletions boxes/generators/hobbycase.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,23 @@ def __init__(self) -> None:
self.argparser.add_argument("--add_rails", action="store", type=boolarg, default=True, help="Should rails be generated for slots unpopulated by shelves?")
self.argparser.add_argument("--add_cover", action="store", type=boolarg, default=True, help="Should cover for the case be generated?")
self.argparser.add_argument("--inset_shelves", action="store", type=boolarg, default=True, help="Should the inner dividers and shelves be inset from the front edge?")
self.argparser.add_argument("--double_vertical_wall", action="store", type=boolarg, default=True, help="Use double vertical walls")
self.addSettingsArgs(boxes.edges.StackableSettings, angle=90, width=0.0, height=2.0)


def prepare(self):
# derive double_vertical_wall parameters
if self.double_vertical_wall:
self.wall_factor = 2
self.shelve_edge = "f"
else:
self.wall_factor = 1
self.shelve_edge = "ƒ"

self.cols = len(self.unit_w)

self.sum_w = sum(self.unit_w)
self.inside_w = self.sum_w + 2 * (self.cols - 1) * self.thickness
self.inside_w = self.sum_w + self.wall_factor * (self.cols - 1) * self.thickness
self.outside_w = self.inside_w + 2 * self.thickness

self.sum_h = self.rows * self.unit_h
Expand Down Expand Up @@ -86,7 +95,7 @@ def vertical_walls(self, move="up"):

self.verticalWall(self.outside_depth, self.inside_h, label="left")

for i in range(2 * (self.cols - 1)):
for i in range(self.wall_factor * (self.cols - 1)):
self.verticalWall(self.inside_depth, self.inside_h, label="vertical wall")

self.verticalWall(self.outside_depth, self.inside_h, move="up", label="right")
Expand All @@ -98,7 +107,7 @@ def verticalWall(self, x, y, edges="feff", move="right", label=None):
self.rectangularWall(x, y, edges, callback=[self.slotsHolesCallback], move=move, label=label)

def slotsHolesCallback(self):
self.cut_shelve_holes_in_single_column(self.inside_depth, 0)
self.cut_shelve_side_holes_in_single_column(self.inside_depth, 0)

# Cover
def cover(self, move="up"):
Expand All @@ -120,7 +129,7 @@ def shelves(self, move="up"):
y = self.inside_depth
self.partsMatrix(self.shelves_n[columnIndex], 0, move,
self.rectangularWall,
x, y, "efff", label=f"shelf (column {columnIndex})\n({x}x{y})")
x, y, "e" + self.shelve_edge + "f" + self.shelve_edge, label=f"shelf (column {columnIndex})\n({x}x{y})")

# Rails
def rails(self, move="up"):
Expand All @@ -130,9 +139,9 @@ def rails(self, move="up"):

def railSet(self, sideLength, backLength, move=None):
self.ctx.save()
self.rectangularWall( sideLength,0, "feSe", move="right")
self.rectangularWall( sideLength,0, self.shelve_edge + "eSe", move="right")
self.rectangularWall( backLength - 8*self.thickness,0, "feSe", move="right")
self.rectangularWall( sideLength,0, "feSe", move="right")
self.rectangularWall( sideLength,0, self.shelve_edge + "eSe", move="right")
self.move(2*sideLength+backLength, 3 * self.thickness, move)

# Base plate
Expand All @@ -143,8 +152,8 @@ def base_plate(self, move="up"):

def baseplate_callback(self):
for col in range(self.cols):
posx = sum(self.unit_w[:col]) + col * 2 * self.thickness
self.cut_shelve_holes_in_single_column(self.unit_w[col], posx)
posx = sum(self.unit_w[:col]) + col * self.wall_factor * self.thickness
self.cut_shelve_back_holes_in_single_column(self.unit_w[col], posx)
self.cut_double_wall_holes(self.inside_h)

# Render
Expand All @@ -162,10 +171,21 @@ def render(self):
# Helper functions
def cut_double_wall_holes(self, length):
for col in range(1, self.cols):
posx = self.thickness + sum(self.unit_w[:col]) + (col-1) * 2 * self.thickness
self.doubleFingerHolesAt(posx, 0, length, angle=90)
posx = 0.5 * self.wall_factor * self.thickness + sum(self.unit_w[:col]) + (col-1) * self.wall_factor * self.thickness
if self.double_vertical_wall:
self.doubleFingerHolesAt(posx, 0, length, angle=90)
else:
self.fingerHolesAt(posx, 0, length, angle=90)

def cut_shelve_holes_in_single_column(self, length, posx = 0):
def cut_shelve_back_holes_in_single_column(self, length, posx = 0):
for row in range(1, self.rows):
posy = 0.5 * self.thickness + row * self.unit_h + (row-1) * self.thickness
self.fingerHolesAt(posx, posy, length, angle=0)

def cut_shelve_side_holes_in_single_column(self, length, posx = 0):
for row in range(1, self.rows):
posy = 0.5 * self.thickness + row * self.unit_h + (row-1) * self.thickness
if self.double_vertical_wall:
self.fingerHolesAt(posx, posy, length, angle=0)
else:
self.triFingerHolesAt(posx, posy, length, angle=0)
Loading