Make Edges and their settings callable objects

Hexholes, grip and latch still need to be converted
This commit is contained in:
Florian Festi 2013-07-20 10:49:45 +02:00
parent 48a0e2afe3
commit 01af694fee
6 changed files with 523 additions and 282 deletions

14
box.py
View File

@ -15,21 +15,17 @@ class Box(Boxes):
d3 = Bolts(3)
self.moveTo(t, t)
self.rectangularWall(x, h, "FfeF", bedBolts=[d2])
self.moveTo(x+3*t, 0)
self.rectangularWall(x, h, "FfeF", bedBolts=[d2], move="right")
self.rectangularWall(y, h, "FfeF", bedBolts=[d3], move="up")
self.rectangularWall(y, h, "FfeF", bedBolts=[d3])
self.moveTo(-x-3*t, h+3*t)
self.rectangularWall(x, h, "FfeF", bedBolts=[d2])
self.moveTo(x+3*t, 0)
self.rectangularWall(y, h, "FfeF", bedBolts=[d3])
self.moveTo(-x-2*t, h+5*t)
self.rectangularWall(x, h, "FfeF", bedBolts=[d2], move="left up")
self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3])
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
b = Box(100, 150, 70)
b.edges["f"].settings.setValues(b.thickness, space=3, finger=2)
b.render()

628
boxes.py
View File

@ -61,19 +61,339 @@ class Bolts(BoltPolicy):
#print pos, result, ((float(pos)*(self.bolts+1)/self.fingers)-0.01), ((float(pos+1)*(self.bolts+1)/self.fingers)-0.01)
return result
#############################################################################
### Settings
#############################################################################
class Settings:
absolute_params = { }
relative_params = { }
def __init__(self, thickness, relative=True, **kw):
self.values = self.absolute_params.copy()
factor = 1.0
if relative:
factor = thickness
for name, value in self.relative_params.iteritems():
self.values[name] = value * factor
self.setValues(thickness, relative, **kw)
def setValues(self, thickness, relative=True, **kw):
factor = 1.0
if relative:
factor = thickness
for name, value in kw.iteritems():
if name in self.absolute_params:
self.values[name] = value
elif name in self.relative_params:
self.values[name] = value * factor
else:
raise ValueError, "Unknown parameter for %s: %s" % (
self.__class__.__name__, name)
def __getattr__(self, name):
return self.values[name]
#############################################################################
### Edges
#############################################################################
class Edge:
char = 'e'
def __init__(self, boxes, settings):
self.boxes = boxes
self.ctx = boxes.ctx
self.settings = settings
def __getattr__(self, name):
"""Hack for using unalter code form Boxes class"""
return getattr(self.boxes, name)
def __call__(self, length, **kw):
self.ctx.move_to(0,0)
self.ctx.line_to(length, 0)
self.ctx.translate(*self.ctx.get_current_point())
def width(self):
return 0.0
def margin(self):
return self.boxes.spacing
def spacing(self):
return self.width() + self.margin()
def startAngle(self):
return 0.0
def endAngle(self):
return 0.0
class OutSetEdge(Edge):
char = 'E'
def width(self):
return self.boxes.thickness
class FingerJointSettings(Settings):
relative_params = {
"space" : 1.0,
"finger" : 1.0,
}
class FingerJointEdge(Edge):
char = 'f'
positive = True
def __call__(self, length,
bedBolts=None, bedBoltSettings=None, **kw):
positive = self.positive
space, finger = self.settings.space, self.settings.finger
fingers = int((length-space) // (space+finger))
if bedBolts:
fingers = bedBolts.numFingers(fingers)
leftover = length - fingers*(space+finger) - space
s, f, thickness = space, finger, self.thickness
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
p = 1 if positive else -1
self.edge(leftover/2.0)
for i in xrange(fingers):
if not positive and bedBolts and bedBolts.drawBolt(i):
self.hole(0.5*space,
0.5*self.thickness, 0.5*d)
if positive and bedBolts and bedBolts.drawBolt(i):
self.bedBoltHole(s, bedBoltSettings)
else:
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 margin(self):
return self.boxes.spacing + self.boxes.thickness
class FingerJointEdgeCounterPart(FingerJointEdge):
char = 'F'
positive = False
def width(self):
return self.boxes.thickness
def margin(self):
return self.boxes.spacing
class FingerHoleEdge(Edge):
char = 'h'
def __call__(self, length, dist=None,
bedBolts=None, bedBoltSettings=None, **kw):
if dist is None:
dist = self.fingerHoleEdgeWidth * self.thickness
self.ctx.save()
self.moveTo(0, dist+self.thickness/2)
self.fingerHoles(length, bedBolts, bedBoltSettings)
self.ctx.restore()
# XXX continue path
self.ctx.move_to(0, 0)
self.ctx.line_to(length, 0)
self.ctx.translate(*self.ctx.get_current_point())
def width(self):
return (self.fingerHoleEdgeWidth+1) * self.thickness
class DoveTailSettings(Settings):
absolute_params = {
"angle" : 50,
}
relative_params = {
"size" : 3,
"depth" : 1.5,
"radius" : 0.2,
}
class DoveTailJoint(Edge):
char = 'd'
positive = True
def __call__(self, length, **kw):
s = self.settings
radius = max(s.radius, self.boxes.burn) # no smaller than burn
positive = self.positive
a = s.angle + 90
alpha = 0.5*math.pi - math.pi*s.angle/180.0
l1 = radius/math.tan(alpha/2.0)
diffx = 0.5*s.depth/math.tan(alpha)
l2 = 0.5*s.depth / math.sin(alpha)
sections = int((length) // (s.size*2))
leftover = length - sections*s.size*2
p = 1 if positive else -1
self.edge((s.size+leftover)/2.0+diffx-l1)
for i in xrange(sections):
self.corner(-1*p*a, radius)
self.edge(2*(l2-l1))
self.corner(p*a, radius)
self.edge(2*(diffx-l1)+s.size)
self.corner(p*a, radius)
self.edge(2*(l2-l1))
self.corner(-1*p*a, radius)
if i<sections-1: # all but the last
self.edge(2*(diffx-l1)+s.size)
self.edge((s.size+leftover)/2.0+diffx-l1)
self.ctx.translate(*self.ctx.get_current_point())
def margin(self):
return self.settings.depth + self.boxes.spacing
class DoveTailJointCounterPart(DoveTailJoint):
char = 'D'
positive = False
def width(self):
return self.settings.depth
def margin(self):
return self.boxes.spacing
class FlexSettings(Settings):
relative_params = {
"distance" : 0.5,
"connection" : 1.0,
"width" : 5.0,
}
absolute_params = {
"stretch" : 1.0,
}
class FlexEdge(Edge):
char = 'X'
def __call__(self, x, h, **kw):
dist = self.settings.distance
connection = self.settings.connection
width = self.settings.width
burn = self.boxes.burn
h += 2*burn
lines = int(x // dist)
leftover = x - lines * dist
sections = int((h-connection) // width)
sheight = ((h-connection) / sections)-connection
for i in xrange(lines):
pos = i*dist + leftover/2
if i % 2:
self.ctx.move_to(pos, 0)
self.ctx.line_to(pos, connection+sheight)
for j in range((sections-1)/2):
self.ctx.move_to(pos, (2*j+1)* sheight+ (2*j+2)*connection)
self.ctx.line_to(pos, (2*j+3)* (sheight+ connection))
if not sections % 2:
self.ctx.move_to(pos, h - sheight- connection)
self.ctx.line_to(pos, h)
else:
if sections % 2:
self.ctx.move_to(pos, h)
self.ctx.line_to(pos, h-connection-sheight)
for j in range((sections-1)/2):
self.ctx.move_to(
pos, h-((2*j+1)* sheight+ (2*j+2)*connection))
self.ctx.line_to(
pos, h-(2*j+3)* (sheight+ connection))
else:
for j in range(sections/2):
self.ctx.move_to(pos,
h-connection-2*j*(sheight+connection))
self.ctx.line_to(pos, h-2*(j+1)*(sheight+connection))
self.ctx.move_to(0, 0)
self.ctx.line_to(x, 0)
self.ctx.translate(*self.ctx.get_current_point())
#############################################################################
### Building blocks
#############################################################################
class FingerHoles:
def __init__(self, boxes, settings):
self.boxes = boxes
self.ctx = boxes.ctx
self.settings = settings
def __call__(self, length, bedBolts=None, bedBoltSettings=None):
s, f = self.settings.space, self.settings.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.boxes.burn
for i in xrange(fingers):
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.boxes.thickness/2+b,
f-2*b, self.boxes.thickness - 2*b)
self.ctx.move_to(0, length)
self.ctx.translate(*self.ctx.get_current_point())
class Boxes:
def __init__(self, width=300, height=200, thickness=3.0, burn=0.1):
self.thickness = thickness
self.burn = burn
self.fingerJointSettings = (10.0, 10.0)
self.spacing = 2*self.burn + 0.5 * 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.flexSettings = (1.5, 3.0, 15.0) # line distance, connects, width
self.hexHolesSettings = (5, 3, 'circle') # r, dist, style
self.output = "box.svg"
self._init_surface(width, height)
self._buildObjects()
def addPart(self, part, name=None):
if name is None:
name = part.__class__.__name__
name = name[0].lower() + name[1:]
setattr(self, name, part)
if isinstance(part, Edge):
self.edges[part.char] = part
def _buildObjects(self):
self.edges = {}
self.addPart(Edge(self, None))
self.addPart(OutSetEdge(self, None))
# Share settings object
s = FingerJointSettings(self.thickness)
self.addPart(FingerJointEdge(self, s))
self.addPart(FingerJointEdgeCounterPart(self, s))
self.addPart(FingerHoleEdge(self, s))
self.addPart(FingerHoles(self, s))
s = DoveTailSettings(self.thickness)
self.addPart(DoveTailJoint(self, s))
self.addPart(DoveTailJointCounterPart(self, s))
s = FlexSettings(self.thickness)
self.addPart(FlexEdge(self, s))
def _init_surface(self, width, height):
mm2pt = 90 / 25.4 / 1.25
@ -121,6 +441,7 @@ class Boxes:
else:
return param
############################################################
### Turtle graphics commands
############################################################
@ -180,138 +501,6 @@ class Boxes:
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!
# negative also assumes we are moved out by self.thinkness!
space, finger = settings or self.fingerJointSettings
fingers = int((length-space) // (space+finger))
if bedBolts:
fingers = bedBolts.numFingers(fingers)
leftover = length - fingers*(space+finger) - finger
s, f, thickness = space, finger, self.thickness
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
p = 1 if positive else -1
self.edge(leftover/2.0)
for i in xrange(fingers):
if not positive and bedBolts and bedBolts.drawBolt(i):
self.hole(0.5*space,
0.5*self.thickness, 0.5*d)
if positive and bedBolts and bedBolts.drawBolt(i):
self.bedBoltHole(s, bedBoltSettings)
else:
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,
bedBolts=None, bedBoltSettings=None):
s, f = settings or self.fingerJointSettings
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
for i in xrange(fingers):
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,
f-2*b, self.thickness - 2*b)
self.ctx.move_to(0, length)
self.ctx.translate(*self.ctx.get_current_point())
def fingerHoleEdge(self, length, dist=None, settings=None,
bedBolts=None, bedBoltSettings=None):
if dist is None:
dist = self.fingerHoleEdgeWidth * self.thickness
self.ctx.save()
self.moveTo(0, dist+self.thickness/2)
self.fingerHoles(length, settings, bedBolts, bedBoltSettings)
self.ctx.restore()
# XXX continue path
self.ctx.move_to(0, 0)
self.ctx.line_to(length, 0)
self.ctx.translate(*self.ctx.get_current_point())
def doveTailJoint(self, length, positive=True, settings=None):
width, depth, angle, radius = settings or self.doveTailJointSettings
radius = max(radius, self.burn) # no smaller than burn
a = angle + 90
alpha = 0.5*math.pi - math.pi*angle/180.0
l1 = radius/math.tan(alpha/2.0)
diffx = 0.5*depth/math.tan(alpha)
l2 = 0.5*depth / math.sin(alpha)
sections = int((length) // (width*2))
leftover = length - sections*width*2
p = 1 if positive else -1
self.edge((width+leftover)/2.0+diffx-l1)
for i in xrange(sections):
self.corner(-1*p*a, radius)
self.edge(2*(l2-l1))
self.corner(p*a, radius)
self.edge(2*(diffx-l1)+width)
self.corner(p*a, radius)
self.edge(2*(l2-l1))
self.corner(-1*p*a, radius)
if i<sections-1: # all but the last
self.edge(2*(diffx-l1)+width)
self.edge((width+leftover)/2.0+diffx-l1)
self.ctx.translate(*self.ctx.get_current_point())
def flex(self, x, h, settings=None, burn=None):
dist, connection, width = settings or self.flexSettings
if burn is None:
burn = self.burn
h += 2*burn
lines = int(x // dist)
leftover = x - lines * dist
sections = int((h-connection) // width)
sheight = ((h-connection) / sections)-connection
for i in xrange(lines):
pos = i*dist + leftover/2
if i % 2:
self.ctx.move_to(pos, 0)
self.ctx.line_to(pos, connection+sheight)
for j in range((sections-1)/2):
self.ctx.move_to(pos, (2*j+1)* sheight+ (2*j+2)*connection)
self.ctx.line_to(pos, (2*j+3)* (sheight+ connection))
if not sections % 2:
self.ctx.move_to(pos, h - sheight- connection)
self.ctx.line_to(pos, h)
else:
if sections % 2:
self.ctx.move_to(pos, h)
self.ctx.line_to(pos, h-connection-sheight)
for j in range((sections-1)/2):
self.ctx.move_to(
pos, h-((2*j+1)* sheight+ (2*j+2)*connection))
self.ctx.line_to(
pos, h-(2*j+3)* (sheight+ connection))
else:
for j in range(sections/2):
self.ctx.move_to(pos,
h-connection-2*j*(sheight+connection))
self.ctx.line_to(pos, h-2*(j+1)*(sheight+connection))
self.ctx.move_to(0, 0)
self.ctx.line_to(x, 0)
self.ctx.translate(*self.ctx.get_current_point())
def grip(self, length, depth):
"""corrugated edge useful as an gipping area"""
@ -392,7 +581,8 @@ class Boxes:
### Navigation
def moveTo(self, x, y, degrees=0):
def moveTo(self, x, y=0.0, degrees=0):
self.ctx.move_to(0, 0)
self.ctx.translate(x, y)
self.ctx.rotate(degrees*math.pi/180.0)
self.ctx.move_to(0, 0)
@ -401,16 +591,48 @@ class Boxes:
self.ctx.translate(*self.ctx.get_current_point())
self.ctx.rotate(angle)
def move(self, x, y, where, before=False):
"""Intended to be used by parts
where can be combinations of "up", "down", "left", "right" and "only"
when "only" is included the move is only done when before is True
The function returns whether actual drawing of the part
should be omited.
"""
if not where:
return False
terms = where.split()
dontdraw = before and "only" in terms
moves = {
"up": (0, y, False),
"down" : (0, -y, True),
"left" : (-x, 0, True),
"right" : (x, 0, False),
"only" : (0, 0, None),
}
for term in terms:
if not term in moves:
raise ValueError, "Unknown direction: '%s'" % term
x, y, movebeforeprint = moves[term]
if movebeforeprint and before:
self.moveTo(x, y)
elif (not movebeforeprint and not before) or dontdraw:
self.moveTo(x, y)
return dontdraw
# Building blocks
def fingerHolesAt(self, x, y, length, angle=90, burn=None,
settings=None, bedBolts=None, bedBoltSettings=None):
bedBolts=None, bedBoltSettings=None):
if burn is None:
burn = self.burn
# XXX burn with callbacks
self.ctx.save()
self.moveTo(x, y+burn, angle)
self.fingerHoles(length, settings, bedBolts, bedBoltSettings)
self.fingerHoles(length, bedBolts, bedBoltSettings)
self.ctx.restore()
@restore
@ -487,7 +709,6 @@ class Boxes:
cy = 2 * int((h-4*dist)// (4*w)) + 1
leftover = h-2*r-(cy-1)*2*r
print h, leftover
if grow=='space ':
b += leftover / (cy-1) / 2
@ -509,7 +730,8 @@ class Boxes:
def roundedPlate(self, x, y, r, callback=None,
holesMargin=None, holesSettings=None,
bedBolts=None, bedBoltSettings=None):
bedBolts=None, bedBoltSettings=None,
move=None):
"""fits surroundingWall
first edge is split to have a joint in the middle of the side
callback is called at the beginning of the straight edges
@ -518,18 +740,25 @@ class Boxes:
set holesMargin to get hex holes.
"""
overallwidth = x+2*self.fingerJointEdge.spacing()
overallheight = y+2*self.fingerJointEdge.spacing()
if self.move(overallwidth, overallheight, move, before=True):
return
self.ctx.save()
self.moveTo(r, 0)
self.moveTo(r+self.fingerJointEdge.spacing(), self.fingerJointEdge.spacing())
self.cc(callback, 0)
self.fingerJoint(x/2.0-r, bedBolts=self.getEntry(bedBolts, 0),
self.fingerJointEdge(x/2.0-r, bedBolts=self.getEntry(bedBolts, 0),
bedBoltSettings=self.getEntry(bedBoltSettings, 0))
self.cc(callback, 1)
self.fingerJoint(x/2.0-r, bedBolts=self.getEntry(bedBolts, 1),
self.fingerJointEdge(x/2.0-r, bedBolts=self.getEntry(bedBolts, 1),
bedBoltSettings=self.getEntry(bedBoltSettings, 1))
for i, l in zip(range(3), (y, x, y)):
self.corner(90, r)
self.cc(callback, i+2)
self.fingerJoint(l-2*r, bedBolts=self.getEntry(bedBolts, i+2),
self.fingerJointEdge(l-2*r, bedBolts=self.getEntry(bedBolts, i+2),
bedBoltSettings=self.getEntry(bedBoltSettings, i+2))
self.corner(90, r)
@ -545,40 +774,12 @@ class Boxes:
self.hexHolesPlate(x-2*holesMargin, y-2*holesMargin, r,
settings=holesSettings)
self.ctx.restore()
def _edge(self, l, style,
bedBolts=None, bedBoltSettings=None):
if type(style) is tuple:
style = style[0]
if callable(style):
return style(l)
if style in 'eE':
self.edge(l)
elif style == 'h':
self.fingerHoleEdge(l, bedBolts=bedBolts,
bedBoltSettings=bedBoltSettings)
elif style == 'f':
self.fingerJoint(l, bedBolts=bedBolts,
bedBoltSettings=bedBoltSettings)
elif style == 'F':
self.fingerJoint(l, positive=False, bedBolts=bedBolts,
bedBoltSettings=bedBoltSettings)
elif style in 'dD':
self.doveTailJoint(l, positive=(style=='d'))
def _edgewidth(self, style):
"""return how far a given edge type needs to be set out"""
if type(style) is tuple:
return style[1]
if style == 'h':
return (self.fingerHoleEdgeWidth+1) * self.thickness
elif style in 'FE':
return self.thickness
return 0.0
self.move(overallwidth, overallheight, move)
def surroundingWall(self, x, y, r, h,
bottom='e', top='e',
callback=None):
callback=None,
move=None):
"""
h : inner height, not counting the joints
callback is called a beginn of the flat sides with
@ -589,17 +790,32 @@ class Boxes:
"""
c4 = (r+self.burn)*math.pi*0.5 # circumference of quarter circle
c4 = 0.9 * c4 # stretch flex 10%
topwidth = self._edgewidth(top)
bottomwidth = self._edgewidth(bottom)
top = self.edges.get(top, top)
bottom = self.edges.get(bottom, bottom)
topwidth = top.width()
bottomwidth = bottom.width()
overallwidth = 2*x + 2*y - 8*r + 4*c4 + \
self.edges["d"].spacing() + self.edges["D"].spacing()
overallheight = h + top.spacing() + bottom.spacing()
if self.move(overallwidth, overallheight, move, before=True):
return
self.ctx.save()
self.moveTo(self.edges["D"].margin(), bottom.margin())
self.cc(callback, 0, y=bottomwidth+self.burn)
self._edge(x/2.0-r, bottom)
bottom(x/2.0-r)
for i, l in zip(range(4), (y, x, y, 0)):
self.flex(c4, h+topwidth+bottomwidth)
self.flexEdge(c4, h+topwidth+bottomwidth)
self.cc(callback, i+1, y=bottomwidth+self.burn)
if i < 3:
self._edge(l-2*r, bottom)
self._edge(x/2.0-r, bottom)
bottom(l-2*r)
bottom(x/2.0-r)
self.corner(90)
self.edge(bottomwidth)
@ -607,38 +823,59 @@ class Boxes:
self.edge(topwidth)
self.corner(90)
self._edge(x/2.0-r, top)
top(x/2.0-r)
for i, l in zip(range(4), (y, x, y, 0)):
self.edge(c4)
if i < 3:
self._edge(l - 2*r, top)
self._edge(x/2.0-r, top)
top(l - 2*r)
top(x/2.0-r)
self.corner(90)
self.edge(topwidth)
self.doveTailJoint(h, positive=False)
self.doveTailJointCounterPart(h)
self.edge(bottomwidth)
self.corner(90)
@restore
self.ctx.restore()
self.move(overallwidth, overallheight, move)
def rectangularWall(self, x, y, edges="eeee",
holesMargin=None, holesSettings=None,
bedBolts=None, bedBoltSettings=None):
callbacks=None,
bedBolts=None, bedBoltSettings=None,
move=None):
if len(edges) != 4:
raise ValueError, "four edges required"
edges = [self.edges.get(e, e,) for e in edges]
edges += edges # append for wrapping around
overallwidth = x + edges[-1].spacing() + edges[1].spacing()
overallheight = y + edges[0].spacing() + edges[2].spacing()
if self.move(overallwidth, overallheight, move, before=True):
return
self.ctx.save()
self.moveTo(edges[-1].margin(), edges[0].margin())
for i, l in enumerate((x, y, x, y)):
self._edge(self._edgewidth(edges[i-1]), 'e')
self._edge(l, edges[i],
bedBolts=self.getEntry(bedBolts, i),
bedBoltSettings=self.getEntry(bedBoltSettings, i))
self._edge(self._edgewidth(edges[i+1]), 'e')
self.corner(90)
self.cc(callbacks, i)
self.edge(edges[i-1].width())
edges[i](l,
bedBolts=self.getEntry(bedBolts, i),
bedBoltSettings=self.getEntry(bedBoltSettings, i))
self.edge(edges[i+1].width())
self.corner(90-edges[i].endAngle()-edges[i+1].startAngle())
if holesMargin is not None:
self.moveTo(holesMargin+self._edgewidth(edges[-1]),
holesMargin+self._edgewidth(edges[0]))
self.moveTo(holesMargin+edges[-1].width(),
holesMargin+edges[0].width())
self.hexHolesRectangle(x-2*holesMargin, y-2*holesMargin)
self.ctx.restore()
self.move(overallwidth, overallheight, move)
##################################################
### main
@ -664,6 +901,7 @@ class Boxes:
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
if __name__ == '__main__':
b = Boxes(900, 700)

View File

@ -18,12 +18,10 @@ class FlexBox(boxes.Boxes):
@boxes.restore
def flexBoxSide(self, x, y, r, callback=None):
space, finger = self.fingerJointSettings
self.moveTo(r, 0)
for i, l in zip(range(2), (x, y)):
self.cc(callback, i)
self.fingerJoint(l-2*r)
self.fingerJointEdge(l-2*r)
self.corner(90, r)
self.cc(callback, 2)
self.edge(x-2*r)
@ -31,7 +29,7 @@ class FlexBox(boxes.Boxes):
self.cc(callback, 3)
self.latch(self.latchsize)
self.cc(callback, 4)
self.fingerJoint(y-2*r-self.latchsize)
self.fingerJointEdge(y-2*r-self.latchsize)
self.corner(90, r)
def surroundingWall(self):
@ -39,27 +37,25 @@ class FlexBox(boxes.Boxes):
c4 = math.pi * r * 0.5
space, finger = self.fingerJointSettings
self.fingerJoint(y-2*r-self.latchsize, False)
self.flex(c4, z+2*self.thickness)
self.fingerJoint(x-2*r, False)
self.flex(c4, z+2*self.thickness)
self.fingerJoint(y-2*r, False)
self.flex(c4, z+2*self.thickness)
self.edges["F"](y-2*r-self.latchsize, False)
self.flexEdge(c4, z+2*self.thickness)
self.edges["F"](x-2*r, False)
self.flexEdge(c4, z+2*self.thickness)
self.edges["F"](y-2*r, False)
self.flexEdge(c4, z+2*self.thickness)
self.edge(x-2*r)
self.flex(c4, z+2*self.thickness)
self.flexEdge(c4, z+2*self.thickness)
self.latch(self.latchsize, False)
self.edge(z+2*self.thickness)
self.latch(self.latchsize, False, True)
self.edge(c4)
self.edge(x-2*r)
self.edge(c4)
self.fingerJoint(y-2*r, False)
self.edges["F"](y-2*r, False)
self.edge(c4)
self.fingerJoint(x-2*r, False)
self.edges["F"](x-2*r, False)
self.edge(c4)
self.fingerJoint(y-2*r-self.latchsize, False)
self.edges["F"](y-2*r-self.latchsize, False)
self.corner(90)
self.edge(z+2*self.thickness)
self.corner(90)
@ -73,7 +69,7 @@ class FlexBox(boxes.Boxes):
self.ctx.scale(-1, 1)
self.flexBoxSide(self.x, self.y, self.r)
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
if __name__=="__main__":

View File

@ -21,10 +21,10 @@ class FlexBox(Boxes):
@restore
def flexBoxSide(self, x, y, r, callback=None):
self.cc(callback, 0)
self.fingerJoint(x)
self.fingerJointEdge(x)
self.corner(90, 0)
self.cc(callback, 1)
self.fingerJoint(y-r)
self.fingerJointEdge(y-r)
self.corner(90, r)
self.cc(callback, 2)
self.edge(x-2*r)
@ -32,26 +32,26 @@ class FlexBox(Boxes):
self.cc(callback, 3)
self.latch(self.latchsize)
self.cc(callback, 4)
self.fingerJoint(y-r-self.latchsize)
self.fingerJointEdge(y-r-self.latchsize)
self.corner(90)
def surroundingWall(self):
x, y, z, r = self.x, self.y, self.z, self.r
self.fingerJoint(y-r, False)
self.flex(self.c4, z+2*self.thickness)
self.edges["F"](y-r, False)
self.flexEdge(self.c4, z+2*self.thickness)
self.edge(x-2*r)
self.flex(self.c4, z+2*self.thickness)
self.flexEdge(self.c4, z+2*self.thickness)
self.latch(self.latchsize, False)
self.edge(z+2*self.thickness)
self.latch(self.latchsize, False, True)
self.edge(self.c4)
self.edge(x-2*r)
self.edge(self.c4)
self.fingerJoint(y-r, False)
self.edges["F"](y-r, False)
self.corner(90)
self.edge(self.thickness)
self.fingerJoint(z)
self.edges["f"](z)
self.edge(self.thickness)
self.corner(90)
@ -71,7 +71,7 @@ class FlexBox(Boxes):
self.moveTo(2*self.thickness, 0)
self.rectangularWall(self.z, self.y-self.r-self.latchsize, edges="fFeF")
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
if __name__=="__main__":

91
lamp.py
View File

@ -1,26 +1,26 @@
#!/usr/bin/python
from boxes import Boxes
from boxes import *
import math
class Lamp(Boxes):
def __init__(self):
Boxes.__init__(self, width=1000, height=1000)
self.fingerJointSettings = (5, 5)
class RoundedTriangleSettings(Settings):
absolute_params = {
"angle" : 60,
"radius" : 30,
"r_hole" : None,
}
def ring(self, r, w):
self.ctx.save()
d = 2*(r+w)
self.roundedPlate(d, d, r)
class RoundedTriangle(Edge):
char = "t"
def __call__(self, length, **kw):
angle = self.settings.angle
r = self.settings.radius
self.moveTo(r+w, w)
self.corner(360, r)
self.ctx.restore()
if self.settings.r_hole:
x = 0.5*(length-2*r)*math.tan(math.radians(angle))
y = 0.5*(length)
self.hole(x, y, self.settings.r_hole)
def roundedTriangle(self, length, angle, r=0.0):
x = 0.5*(length-2*r)*math.tan(math.radians(angle))
y = 0.5*(length)
self.hole(x, y, 2)
l = 0.5 * (length-2*r) / math.cos(math.radians(angle))
self.corner(90-angle, r)
self.edge(l)
@ -28,12 +28,28 @@ class Lamp(Boxes):
self.edge(l)
self.corner(90-angle, r)
def startAngle(self):
return 90
def endAngle(self):
return 90
class Lamp(Boxes):
def __init__(self):
Boxes.__init__(self, width=1000, height=1000, thickness=5.0)
self.fingerJointSettings = (5, 5) # XXX
s = RoundedTriangleSettings(self.thickness, angle=72, r_hole=2)
self.addPart(RoundedTriangle(self, s))
def side(self, y, h):
self.fingerJoint(y)
return
self.fingerJointEdge(y)
self.corner(90)
self.fingerJoint(h)
self.fingerJointEdge(h)
self.roundedTriangle(y, 70, 25)
self.fingerJoint(h)
self.fingerJointEdge(h)
self.corner(90)
def render(self, r, w, x, y, h):
@ -41,35 +57,30 @@ class Lamp(Boxes):
r : radius of lamp
w : width of surrounding ring
"""
t = self.thickness
self.fingerJointEdge.settings.setValues(self.thickness, finger=5, space=5, relative=False)
d = 2*(r+w)
self.ctx.save()
self.moveTo(2*self.thickness, 2*t)
self.ring(r, w)
self.moveTo(2*(r+w)+3*t, 0)
self.roundedPlate(d, d, r, move="right", callback=[
lambda: self.hole(w, r+w, r),])
self.roundedPlate(d, d, r, holesMargin=w/2.0)
self.roundedPlate(d, d, r, move="only left up")
self.surroundingWall(d, d, r, 150, top='h', bottom='h', move="up")
self.ctx.save()
self.rectangularWall(x, y, edges="fFfF", holesMargin=5, move="right")
self.rectangularWall(x, y, edges="fFfF", holesMargin=5, move="right")
# sides
self.rectangularWall(y, h, "fftf", move="right")
self.rectangularWall(y, h, "fftf")
self.ctx.restore()
self.moveTo(2*t, 2*(r+w)+4*t)
self.surroundingWall(d, d, r, 150, top='h', bottom='h')
self.moveTo(0, 150+6*t)
self.rectangularWall(x, y, edges="fFfF", holesMargin=5,
move="up only")
self.rectangularWall(x, y, edges="fFfF", holesMargin=5)
self.moveTo(x+3*t, 0)
self.rectangularWall(x, y, edges="fFfF", holesMargin=5)
self.moveTo(x+4*t, 0)
self.side(y, h)
self.moveTo(y+3*t, 0)
self.side(y, h)
self.moveTo(0, y+3*t)
self.moveTo(-x-y-7*t, 0)
self.rectangularWall(x, h, edges='hFFF', holesMargin=5)
self.moveTo(-x-3*t, 0)
self.rectangularWall(x, h, edges='hFFF', holesMargin=5, move="right")
self.rectangularWall(x, h, edges='hFFF', holesMargin=5)
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
l = Lamp()

View File

@ -22,27 +22,31 @@ class Silverware(Boxes):
1 : lambda: self.fingerHolesAt(y/2.0-r, 0, h-10),
3 : lambda: self.fingerHolesAt(y/2.0-r, 0, h-10),
2 : lambda: self.fingerHolesAt(x/2.0-r, 0, h-10),
})
},
move="up")
def centerWall(self, x, h):
self.ctx.save()
self.moveTo(self.fingerJointEdge.spacing(), self.fingerJointEdge.spacing())
for i in range(2, 5):
self.fingerHolesAt(i*x/6.0, 0, h-10)
self.fingerJoint(x)
self.fingerJointEdge(x)
self.corner(90)
self.fingerJoint(h-10)
self.fingerJointEdge(h-10)
self.corner(90)
self.handle(x, 150, 120)
#self.handle(x, 40, 30, r=2)
self.corner(90)
self.fingerJoint(h-10)
self.fingerJointEdge(h-10)
self.corner(90)
self.ctx.restore()
self.moveTo(x+2*self.fingerJointEdge.spacing())
##################################################
### main
##################################################
@ -52,24 +56,20 @@ class Silverware(Boxes):
b = self.burn
self.ctx.save()
self.moveTo(2, 2)
self.wall(x, y, h, r)
self.moveTo(t, h+3*t+8*b)
self.centerWall(x, h)
self.moveTo(x+2*t+8*b, 0)
self.centerWall(x,h)
l = (y-t)/2.0
for i in range(3):
self.rectangularWall(l, h-10, edges="ffef")
self.moveTo(l+2*t+8*b, 0)
self.rectangularWall(l, h-10, edges="ffef", move="right")
self.moveTo(-3.0*(l+2*t+8*b), h-10+t+8*b)
self.moveTo(-3.0*(l+2*t+8*b), h-10+2*t+8*b)
self.basePlate(x, y, r)
self.ctx.restore()
self.ctx.stroke()
self.surface.flush()
self.surface.finish()
b = Silverware(900, 700, thickness=5.0, burn=0.05)
b.render(250, 250/1.618, 120, 30)