Add bed bolts - a way of using screws with plywood - to the finger joint
This commit is contained in:
parent
61c95ec0c7
commit
853d024032
184
boxes.py
184
boxes.py
|
@ -17,14 +17,58 @@ def restore(func):
|
||||||
self.ctx.move_to(*pt)
|
self.ctx.move_to(*pt)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
class BoltPolicy:
|
||||||
|
"""Abstract class
|
||||||
|
Distributes (bed) bolts on a number of segments
|
||||||
|
(fingers of a finger joint)
|
||||||
|
"""
|
||||||
|
def drawbolt(self, pos):
|
||||||
|
"""Add a bolt to this segment?"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
def numFingers(self, numfingers):
|
||||||
|
"""returns next smaller, possible number of fingers"""
|
||||||
|
return numFingers
|
||||||
|
|
||||||
|
def _even(self, numFingers):
|
||||||
|
return (numFingers//2) * 2
|
||||||
|
def _odd(self, numFingers):
|
||||||
|
if numFingers % 2:
|
||||||
|
return numFingers
|
||||||
|
else:
|
||||||
|
return numFingers - 1
|
||||||
|
|
||||||
|
class Bolts(BoltPolicy):
|
||||||
|
"""Distribute a fixed number of bolts evenly"""
|
||||||
|
def __init__(self, bolts=1):
|
||||||
|
self.bolts = bolts
|
||||||
|
def numFingers(self, numFingers):
|
||||||
|
if self.bolts % 2:
|
||||||
|
self.fingers = self._even(numFingers)
|
||||||
|
else:
|
||||||
|
self.fingers = numFingers
|
||||||
|
return self.fingers
|
||||||
|
|
||||||
|
def drawBolt(self, pos):
|
||||||
|
if pos > self.fingers//2:
|
||||||
|
pos = self.fingers - pos
|
||||||
|
if pos==0:
|
||||||
|
return False
|
||||||
|
if pos == self.fingers//2 and not (self.bolts % 2):
|
||||||
|
return False
|
||||||
|
result = (math.floor((float(pos)*(self.bolts+1)/self.fingers)-0.01) !=
|
||||||
|
math.floor((float(pos+1)*(self.bolts+1)/self.fingers)-0.01))
|
||||||
|
#print pos, result, ((float(pos)*(self.bolts+1)/self.fingers)-0.01), ((float(pos+1)*(self.bolts+1)/self.fingers)-0.01)
|
||||||
|
return result
|
||||||
|
|
||||||
class Boxes:
|
class Boxes:
|
||||||
|
|
||||||
def __init__(self, width=300, height=200, thickness=3.0):
|
def __init__(self, width=300, height=200, thickness=3.0):
|
||||||
self.thickness = thickness
|
self.thickness = thickness
|
||||||
self.burn = 0.1
|
self.burn = 0.1 # radius
|
||||||
self.fingerJointSettings = (10.0, 10.0)
|
self.fingerJointSettings = (10.0, 10.0)
|
||||||
self.fingerHoleEdgeWidth = 1.0 # multitudes of self.thickness
|
self.fingerHoleEdgeWidth = 1.0 # multitudes of self.thickness
|
||||||
|
self.bedBoltSettings = (3, 5.5, 2, 20, 15) #d, d_nut, h_nut, l, l1
|
||||||
self.doveTailJointSettings = (10, 5, 50, 0.4) # width, depth, angle, radius
|
self.doveTailJointSettings = (10, 5, 50, 0.4) # width, depth, angle, radius
|
||||||
self.flexSettings = (1.5, 3.0, 15.0) # line distance, connects, width
|
self.flexSettings = (1.5, 3.0, 15.0) # line distance, connects, width
|
||||||
self.hexHolesSettings = (5, 3, 'circle') # r, dist, style
|
self.hexHolesSettings = (5, 3, 'circle') # r, dist, style
|
||||||
|
@ -42,7 +86,7 @@ class Boxes:
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
|
|
||||||
ctx.set_source_rgb(0.0, 0.0, 0.0)
|
ctx.set_source_rgb(0.0, 0.0, 0.0)
|
||||||
ctx.set_line_width(0.1)
|
ctx.set_line_width(2*self.burn)
|
||||||
|
|
||||||
|
|
||||||
def cc(self, callback, number, x=0.0, y=0.0):
|
def cc(self, callback, number, x=0.0, y=0.0):
|
||||||
|
@ -63,24 +107,35 @@ class Boxes:
|
||||||
raise
|
raise
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
|
|
||||||
|
def getEntry(self, param, idx):
|
||||||
|
if isinstance(param, list):
|
||||||
|
if len(param)>idx:
|
||||||
|
return param[idx]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return param
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
### Turtle graphics commands
|
### Turtle graphics commands
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
def corner(self, degrees, radius=0):
|
def corner(self, degrees, radius=0):
|
||||||
d = 1 if (degrees > 0) else -1
|
|
||||||
rad = degrees*math.pi/180
|
rad = degrees*math.pi/180
|
||||||
if degrees > 0:
|
if degrees > 0:
|
||||||
self.ctx.arc(0, radius+self.burn, radius+self.burn,
|
self.ctx.arc(0, radius+self.burn, radius+self.burn,
|
||||||
-0.5*math.pi, rad - 0.5*math.pi)
|
-0.5*math.pi, rad - 0.5*math.pi)
|
||||||
else:
|
elif radius > self.burn:
|
||||||
self.ctx.arc_negative(0, -(radius-self.burn), radius-self.burn,
|
self.ctx.arc_negative(0, -(radius-self.burn), radius-self.burn,
|
||||||
0.5*math.pi, rad + 0.5*math.pi)
|
0.5*math.pi, rad + 0.5*math.pi)
|
||||||
|
else: # not rounded inner corner
|
||||||
|
self.ctx.arc_negative(0, self.burn-radius, self.burn-radius,
|
||||||
|
-0.5*math.pi, -0.5*math.pi+rad)
|
||||||
|
|
||||||
self.continueDirection(rad)
|
self.continueDirection(rad)
|
||||||
|
|
||||||
def edge(self, length):
|
def edge(self, length):
|
||||||
|
self.ctx.move_to(0,0)
|
||||||
self.ctx.line_to(length, 0)
|
self.ctx.line_to(length, 0)
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
|
@ -92,48 +147,91 @@ class Boxes:
|
||||||
rad = math.atan2(dy, dx)
|
rad = math.atan2(dy, dx)
|
||||||
self.continueDirection(rad)
|
self.continueDirection(rad)
|
||||||
|
|
||||||
def fingerJoint(self, length, positive=True, settings=None):
|
def bedBoltHole(self, length, bedBoltSettings=None):
|
||||||
|
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
|
||||||
|
self.edge((length-d)/2.0)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge(l1)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge((d_nut-d)/2.0)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge(h_nut)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge((d_nut-d)/2.0)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge(l-l1-h_nut)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge(d)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge(l-l1-h_nut)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge((d_nut-d)/2.0)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge(h_nut)
|
||||||
|
self.corner(-90)
|
||||||
|
self.edge((d_nut-d)/2.0)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge(l1)
|
||||||
|
self.corner(90)
|
||||||
|
self.edge((length-d)/2.0)
|
||||||
|
|
||||||
|
def fingerJoint(self, length, positive=True, settings=None,
|
||||||
|
bedBolts=None, bedBoltSettings=None):
|
||||||
# assumes, we are already moved out by self.burn!
|
# assumes, we are already moved out by self.burn!
|
||||||
# negative also assumes we are moved out by self.thinkness!
|
# negative also assumes we are moved out by self.thinkness!
|
||||||
space, finger = settings or self.fingerJointSettings
|
space, finger = settings or self.fingerJointSettings
|
||||||
fingers = int((length-space) // (space+finger))
|
fingers = int((length-space) // (space+finger))
|
||||||
|
if bedBolts:
|
||||||
|
fingers = bedBolts.numFingers(fingers)
|
||||||
leftover = length - fingers*(space+finger) - finger
|
leftover = length - fingers*(space+finger) - finger
|
||||||
b = self.burn
|
|
||||||
s, f, thickness = space, finger, self.thickness
|
s, f, thickness = space, finger, self.thickness
|
||||||
if not positive:
|
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
|
||||||
b = -b
|
p = 1 if positive else -1
|
||||||
thickness = -thickness
|
|
||||||
|
|
||||||
self.ctx.move_to(0, 0)
|
self.edge(leftover/2.0)
|
||||||
for i in xrange(fingers):
|
for i in xrange(fingers):
|
||||||
pos = leftover/2.0+i*(space+finger)
|
if not positive and bedBolts and bedBolts.drawBolt(i):
|
||||||
self.ctx.line_to(pos+s-b, 0)
|
self.hole(0.5*space,
|
||||||
self.ctx.line_to(pos+s-b, -thickness)
|
0.5*self.thickness, 0.5*d)
|
||||||
self.ctx.line_to(pos+s+f+b, -thickness)
|
if positive and bedBolts and bedBolts.drawBolt(i):
|
||||||
self.ctx.line_to(pos+s+f+b, 0)
|
self.bedBoltHole(s, bedBoltSettings)
|
||||||
self.ctx.line_to(length, 0)
|
else:
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.edge(s)
|
||||||
|
self.corner(-90*p)
|
||||||
|
self.edge(thickness)
|
||||||
|
self.corner(90*p)
|
||||||
|
self.edge(f)
|
||||||
|
self.corner(90*p)
|
||||||
|
self.edge(thickness)
|
||||||
|
self.corner(-90*p)
|
||||||
|
self.edge(s+leftover/2.0)
|
||||||
|
|
||||||
def fingerHoles(self, length, settings=None):
|
def fingerHoles(self, length, settings=None,
|
||||||
space, finger = settings or self.fingerJointSettings
|
bedBolts=None, bedBoltSettings=None):
|
||||||
fingers = int((length-space) // (space+finger))
|
s, f = settings or self.fingerJointSettings
|
||||||
leftover = length - fingers*(space+finger) - finger
|
fingers = int((length-s) // (s+f))
|
||||||
|
if bedBolts:
|
||||||
|
fingers = bedBolts.numFingers(fingers)
|
||||||
|
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
|
||||||
|
leftover = length - fingers*(s+f) - f
|
||||||
b = self.burn
|
b = self.burn
|
||||||
s, f = space, finger
|
|
||||||
for i in xrange(fingers):
|
for i in xrange(fingers):
|
||||||
pos = leftover/2.0+i*(space+finger)
|
pos = leftover/2.0+i*(s+f)
|
||||||
|
if bedBolts and bedBolts.drawBolt(i):
|
||||||
|
self.hole(pos+0.5*s, 0, d*0.5)
|
||||||
self.ctx.rectangle(pos+s+b, -self.thickness/2+b,
|
self.ctx.rectangle(pos+s+b, -self.thickness/2+b,
|
||||||
f-2*b, self.thickness - 2*b)
|
f-2*b, self.thickness - 2*b)
|
||||||
|
|
||||||
self.ctx.move_to(0, length)
|
self.ctx.move_to(0, length)
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
def fingerHoleEdge(self, length, dist=None, settings=None):
|
def fingerHoleEdge(self, length, dist=None, settings=None,
|
||||||
|
bedBolts=None, bedBoltSettings=None):
|
||||||
if dist is None:
|
if dist is None:
|
||||||
dist = self.fingerHoleEdgeWidth * self.thickness
|
dist = self.fingerHoleEdgeWidth * self.thickness
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
self.moveTo(0, dist+self.thickness/2)
|
self.moveTo(0, dist+self.thickness/2)
|
||||||
self.fingerHoles(length, settings)
|
self.fingerHoles(length, settings, bedBolts, bedBoltSettings)
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
# XXX continue path
|
# XXX continue path
|
||||||
self.ctx.move_to(0, 0)
|
self.ctx.move_to(0, 0)
|
||||||
|
@ -300,13 +398,14 @@ class Boxes:
|
||||||
|
|
||||||
# Building blocks
|
# Building blocks
|
||||||
|
|
||||||
def fingerHolesAt(self, x, y, length, angle=90, burn=None):
|
def fingerHolesAt(self, x, y, length, angle=90, burn=None,
|
||||||
|
settings=None, bedBolts=None, bedBoltSettings=None):
|
||||||
if burn is None:
|
if burn is None:
|
||||||
burn = self.burn
|
burn = self.burn
|
||||||
# XXX burn with callbacks
|
# XXX burn with callbacks
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
self.moveTo(x, y+burn, angle)
|
self.moveTo(x, y+burn, angle)
|
||||||
self.fingerHoles(length)
|
self.fingerHoles(length, settings, bedBolts, bedBoltSettings)
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
|
|
||||||
@restore
|
@restore
|
||||||
|
@ -404,7 +503,8 @@ class Boxes:
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def roundedPlate(self, x, y, r, callback=None,
|
def roundedPlate(self, x, y, r, callback=None,
|
||||||
holesMargin=None, holesSettings=None):
|
holesMargin=None, holesSettings=None,
|
||||||
|
bedBolts=None, bedBoltSettings=None):
|
||||||
"""fits surroundingWall
|
"""fits surroundingWall
|
||||||
first edge is split to have a joint in the middle of the side
|
first edge is split to have a joint in the middle of the side
|
||||||
callback is called at the beginning of the straight edges
|
callback is called at the beginning of the straight edges
|
||||||
|
@ -416,13 +516,16 @@ class Boxes:
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
self.moveTo(r, 0)
|
self.moveTo(r, 0)
|
||||||
self.cc(callback, 0)
|
self.cc(callback, 0)
|
||||||
self.fingerJoint(x/2.0-r)
|
self.fingerJoint(x/2.0-r, bedBolts=self.getEntry(bedBolts, 0),
|
||||||
|
bedBoltSettings=self.getEntry(bedBoltSettings, 0))
|
||||||
self.cc(callback, 1)
|
self.cc(callback, 1)
|
||||||
self.fingerJoint(x/2.0-r)
|
self.fingerJoint(x/2.0-r, bedBolts=self.getEntry(bedBolts, 1),
|
||||||
|
bedBoltSettings=self.getEntry(bedBoltSettings, 1))
|
||||||
for i, l in zip(range(3), (y, x, y)):
|
for i, l in zip(range(3), (y, x, y)):
|
||||||
self.corner(90, r)
|
self.corner(90, r)
|
||||||
self.cc(callback, i+2)
|
self.cc(callback, i+2)
|
||||||
self.fingerJoint(l-2*r)
|
self.fingerJoint(l-2*r, bedBolts=self.getEntry(bedBolts, i+2),
|
||||||
|
bedBoltSettings=self.getEntry(bedBoltSettings, i+2))
|
||||||
self.corner(90, r)
|
self.corner(90, r)
|
||||||
|
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
|
@ -438,7 +541,8 @@ class Boxes:
|
||||||
settings=holesSettings)
|
settings=holesSettings)
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
|
|
||||||
def _edge(self, l, style):
|
def _edge(self, l, style,
|
||||||
|
bedBolts=None, bedBoltSettings=None):
|
||||||
if type(style) is tuple:
|
if type(style) is tuple:
|
||||||
style = style[0]
|
style = style[0]
|
||||||
if callable(style):
|
if callable(style):
|
||||||
|
@ -446,11 +550,14 @@ class Boxes:
|
||||||
if style in 'eE':
|
if style in 'eE':
|
||||||
self.edge(l)
|
self.edge(l)
|
||||||
elif style == 'h':
|
elif style == 'h':
|
||||||
self.fingerHoleEdge(l)
|
self.fingerHoleEdge(l, bedBolts=bedBolts,
|
||||||
|
bedBoltSettings=bedBoltSettings)
|
||||||
elif style == 'f':
|
elif style == 'f':
|
||||||
self.fingerJoint(l)
|
self.fingerJoint(l, bedBolts=bedBolts,
|
||||||
|
bedBoltSettings=bedBoltSettings)
|
||||||
elif style == 'F':
|
elif style == 'F':
|
||||||
self.fingerJoint(l, positive=False)
|
self.fingerJoint(l, positive=False, bedBolts=bedBolts,
|
||||||
|
bedBoltSettings=bedBoltSettings)
|
||||||
elif style in 'dD':
|
elif style in 'dD':
|
||||||
self.doveTailJoint(l, positive=(style=='d'))
|
self.doveTailJoint(l, positive=(style=='d'))
|
||||||
|
|
||||||
|
@ -509,13 +616,16 @@ class Boxes:
|
||||||
|
|
||||||
@restore
|
@restore
|
||||||
def rectangularWall(self, x, y, edges="eeee",
|
def rectangularWall(self, x, y, edges="eeee",
|
||||||
holesMargin=None, holesSettings=None):
|
holesMargin=None, holesSettings=None,
|
||||||
|
bedBolts=None, bedBoltSettings=None):
|
||||||
if len(edges) != 4:
|
if len(edges) != 4:
|
||||||
raise ValueError, "four edges required"
|
raise ValueError, "four edges required"
|
||||||
edges += edges # append for wrapping around
|
edges += edges # append for wrapping around
|
||||||
for i, l in enumerate((x, y, x, y)):
|
for i, l in enumerate((x, y, x, y)):
|
||||||
self._edge(self._edgewidth(edges[i-1]), 'e')
|
self._edge(self._edgewidth(edges[i-1]), 'e')
|
||||||
self._edge(l, edges[i])
|
self._edge(l, edges[i],
|
||||||
|
bedBolts=self.getEntry(bedBolts, i),
|
||||||
|
bedBoltSettings=self.getEntry(bedBoltSettings, i))
|
||||||
self._edge(self._edgewidth(edges[i+1]), 'e')
|
self._edge(self._edgewidth(edges[i+1]), 'e')
|
||||||
self.corner(90)
|
self.corner(90)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue