Code Reformat #1
This commit is contained in:
parent
af167295b8
commit
93af56ff9c
|
@ -8,3 +8,4 @@
|
|||
build/
|
||||
dist/
|
||||
boxes.py.egg-info/
|
||||
.idea
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
try:
|
||||
import cairocffi
|
||||
|
||||
cairocffi.install_as_pycairo()
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -31,6 +32,7 @@ from boxes import gears
|
|||
from boxes import pulley
|
||||
from boxes import parts
|
||||
|
||||
|
||||
### Helpers
|
||||
|
||||
def dist(dx, dy):
|
||||
|
@ -42,6 +44,7 @@ def dist(dx, dy):
|
|||
"""
|
||||
return (dx * dx + dy * dy) ** 0.5
|
||||
|
||||
|
||||
def restore(func):
|
||||
"""
|
||||
Wrapper: Restore coordiantes after function
|
||||
|
@ -49,6 +52,7 @@ def restore(func):
|
|||
:param func: function to wrap
|
||||
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def f(self, *args, **kw):
|
||||
self.ctx.save()
|
||||
|
@ -56,8 +60,10 @@ def restore(func):
|
|||
func(self, *args, **kw)
|
||||
self.ctx.restore()
|
||||
self.ctx.move_to(*pt)
|
||||
|
||||
return f
|
||||
|
||||
|
||||
def holeCol(func):
|
||||
"""
|
||||
Wrapper: color holes differently
|
||||
|
@ -65,6 +71,7 @@ def holeCol(func):
|
|||
:param func: function to wrap
|
||||
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def f(self, *args, **kw):
|
||||
self.ctx.stroke()
|
||||
|
@ -72,8 +79,8 @@ def holeCol(func):
|
|||
func(self, *args, **kw)
|
||||
self.ctx.stroke()
|
||||
self.ctx.set_source_rgb(0.0, 0.0, 0.0)
|
||||
return f
|
||||
|
||||
return f
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
@ -121,6 +128,7 @@ class NutHole:
|
|||
self.boxes.edge(side)
|
||||
self.boxes.corner(-60)
|
||||
|
||||
|
||||
##############################################################################
|
||||
### Argument types
|
||||
##############################################################################
|
||||
|
@ -146,6 +154,7 @@ def argparseSections(s):
|
|||
except ValueError:
|
||||
raise argparse.ArgumentTypeError("Don't understand sections string")
|
||||
|
||||
|
||||
class ArgparseEdgeType:
|
||||
names = edges.getDescriptions()
|
||||
edges = []
|
||||
|
@ -169,6 +178,7 @@ class ArgparseEdgeType:
|
|||
e, self.names.get(e, "")) for e in self.edges))
|
||||
return """<select name="%s" size="1">\n%s</select>\n""" % (name, options)
|
||||
|
||||
|
||||
##############################################################################
|
||||
### Main class
|
||||
##############################################################################
|
||||
|
@ -354,9 +364,11 @@ class Boxes:
|
|||
self.addPart(edges.ClickEdge(self, s))
|
||||
# Hinges
|
||||
s = edges.HingeSettings(self.thickness)
|
||||
|
||||
for i in range(1, 4):
|
||||
self.addPart(edges.Hinge(self, s, i))
|
||||
self.addPart(edges.HingePin(self, s, i))
|
||||
|
||||
# Nuts
|
||||
self.addPart(NutHole(self, None))
|
||||
# Gears
|
||||
|
@ -376,6 +388,7 @@ class Boxes:
|
|||
walls += e1.startwidth() + e1.margin()
|
||||
elif e1:
|
||||
walls += self.thickness
|
||||
|
||||
if isinstance(e2, edges.BaseEdge):
|
||||
walls += e2.startwidth + e2.margin()
|
||||
elif e2:
|
||||
|
@ -414,6 +427,7 @@ class Boxes:
|
|||
callback()
|
||||
else:
|
||||
callback(number)
|
||||
|
||||
elif hasattr(callback, '__getitem__'):
|
||||
try:
|
||||
callback = callback[number]
|
||||
|
@ -424,6 +438,7 @@ class Boxes:
|
|||
except:
|
||||
self.ctx.restore()
|
||||
raise
|
||||
|
||||
self.ctx.restore()
|
||||
|
||||
def getEntry(self, param, idx):
|
||||
|
@ -840,7 +855,6 @@ class Boxes:
|
|||
y * 0.5 * holedistance,
|
||||
0.5 * diameter)
|
||||
|
||||
|
||||
# hexHoles
|
||||
|
||||
def hexHolesRectangle(self, x, y, settings=None, skip=None):
|
||||
|
@ -909,6 +923,7 @@ class Boxes:
|
|||
:param settings: (Default value = None)
|
||||
|
||||
"""
|
||||
|
||||
def skip(x, y, r, b, posx, posy):
|
||||
"""
|
||||
|
||||
|
@ -1102,7 +1117,6 @@ class Boxes:
|
|||
self.edges["d"].spacing() + self.edges["D"].spacing()
|
||||
overallheight = h + top.spacing() + bottom.spacing()
|
||||
|
||||
|
||||
if self.move(overallwidth, overallheight, move, before=True):
|
||||
return
|
||||
|
||||
|
|
113
boxes/edges.py
113
boxes/edges.py
|
@ -18,6 +18,7 @@
|
|||
import math
|
||||
import inspect
|
||||
|
||||
|
||||
def getDescriptions():
|
||||
d = {edge.char: edge.description for edge in globals().values()
|
||||
if inspect.isclass(edge) and issubclass(edge, BaseEdge)
|
||||
|
@ -25,6 +26,7 @@ def getDescriptions():
|
|||
d['k'] = "Straight edge with hinge eye (both ends)"
|
||||
return d
|
||||
|
||||
|
||||
class BoltPolicy(object):
|
||||
"""Abstract class
|
||||
|
||||
|
@ -32,6 +34,7 @@ class BoltPolicy(object):
|
|||
(fingers of a finger joint)
|
||||
|
||||
"""
|
||||
|
||||
def drawbolt(self, pos):
|
||||
"""Add a bolt to this segment?
|
||||
|
||||
|
@ -46,7 +49,7 @@ class BoltPolicy(object):
|
|||
:param numfingers: number of fingers to aim for
|
||||
|
||||
"""
|
||||
return numFingers
|
||||
return numfingers
|
||||
|
||||
def _even(self, numFingers):
|
||||
"""
|
||||
|
@ -56,6 +59,7 @@ class BoltPolicy(object):
|
|||
|
||||
"""
|
||||
return (numFingers // 2) * 2
|
||||
|
||||
def _odd(self, numFingers):
|
||||
"""
|
||||
Return same or next smaller odd number
|
||||
|
@ -68,8 +72,10 @@ class BoltPolicy(object):
|
|||
else:
|
||||
return numFingers - 1
|
||||
|
||||
|
||||
class Bolts(BoltPolicy):
|
||||
"""Distribute a fixed number of bolts evenly"""
|
||||
|
||||
def __init__(self, bolts=1):
|
||||
self.bolts = bolts
|
||||
|
||||
|
@ -78,6 +84,7 @@ class Bolts(BoltPolicy):
|
|||
self.fingers = self._even(numFingers)
|
||||
else:
|
||||
self.fingers = numFingers
|
||||
|
||||
return self.fingers
|
||||
|
||||
def drawBolt(self, pos):
|
||||
|
@ -89,14 +96,16 @@ class Bolts(BoltPolicy):
|
|||
"""
|
||||
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) !=
|
||||
|
||||
return (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
|
||||
|
||||
|
||||
#############################################################################
|
||||
### Settings
|
||||
|
@ -150,6 +159,7 @@ class Settings(object):
|
|||
def __getattr__(self, name):
|
||||
return self.values[name]
|
||||
|
||||
|
||||
#############################################################################
|
||||
### Edges
|
||||
#############################################################################
|
||||
|
@ -198,11 +208,13 @@ class BaseEdge(object):
|
|||
"""Not yet supported"""
|
||||
return 0.0
|
||||
|
||||
|
||||
class Edge(BaseEdge):
|
||||
"""Straight edge"""
|
||||
char = 'e'
|
||||
description = "Straight Edge"
|
||||
|
||||
|
||||
class OutSetEdge(BaseEdge):
|
||||
"""Straight edge out set by one thickness"""
|
||||
char = 'E'
|
||||
|
@ -211,6 +223,7 @@ class OutSetEdge(BaseEdge):
|
|||
def startwidth(self):
|
||||
return self.boxes.thickness
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Gripping Edge
|
||||
#############################################################################
|
||||
|
@ -239,11 +252,11 @@ Values:
|
|||
"depth": 0.3,
|
||||
}
|
||||
|
||||
|
||||
class GrippingEdge(BaseEdge):
|
||||
description = """Corrugated edge useful as an gipping area"""
|
||||
char = 'g'
|
||||
|
||||
|
||||
def A(self, length):
|
||||
depth = self.settings.depth
|
||||
grooves = int(length // (depth * 2.0)) + 1
|
||||
|
@ -260,15 +273,18 @@ class GrippingEdge(BaseEdge):
|
|||
grooves = int(length // (depth * 2.0)) + 1
|
||||
depth = length / grooves / 2.0
|
||||
o = 1 if self.settings.outset else -1
|
||||
|
||||
if self.settings.outset:
|
||||
self.corner(-90)
|
||||
else:
|
||||
self.corner(90)
|
||||
self.edge(depth)
|
||||
self.corner(-180)
|
||||
|
||||
for groove in range(grooves):
|
||||
self.corner(180, depth)
|
||||
self.corner(-180, 0)
|
||||
|
||||
if self.settings.outset:
|
||||
self.corner(90)
|
||||
else:
|
||||
|
@ -286,12 +302,14 @@ class GrippingEdge(BaseEdge):
|
|||
return
|
||||
getattr(self, self.settings.style)(length)
|
||||
|
||||
|
||||
class CompoundEdge(BaseEdge):
|
||||
"""Edge composed of multiple different Edges"""
|
||||
description = "Compound Edge"
|
||||
|
||||
def __init__(self, boxes, types, lengths):
|
||||
super(CompoundEdge, self).__init__(boxes, None)
|
||||
|
||||
self.types = [self.edges.get(edge, edge) for edge in types]
|
||||
self.lengths = lengths
|
||||
self.length = sum(lengths)
|
||||
|
@ -309,8 +327,10 @@ class CompoundEdge(BaseEdge):
|
|||
if length and abs(length - self.length) > 1E-5:
|
||||
raise ValueError("Wrong length for CompoundEdge")
|
||||
lastwidth = self.types[0].startwidth()
|
||||
|
||||
for e, l in zip(self.types, self.lengths):
|
||||
diff = e.startwidth() - lastwidth
|
||||
|
||||
if diff > 1E-5:
|
||||
self.boxes.corner(-90)
|
||||
self.boxes.edge(diff)
|
||||
|
@ -319,9 +339,11 @@ class CompoundEdge(BaseEdge):
|
|||
self.boxes.corner(90)
|
||||
self.boxes.edge(-diff)
|
||||
self.boxes.corner(-90)
|
||||
|
||||
e(l)
|
||||
lastwidth = e.endwidth()
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Slots
|
||||
#############################################################################
|
||||
|
@ -333,6 +355,7 @@ class Slot(BaseEdge):
|
|||
|
||||
def __init__(self, boxes, depth):
|
||||
super(Slot, self).__init__(boxes, None)
|
||||
|
||||
self.depth = depth
|
||||
|
||||
def __call__(self, length, **kw):
|
||||
|
@ -347,12 +370,14 @@ class Slot(BaseEdge):
|
|||
else:
|
||||
self.boxes.edge(self.length)
|
||||
|
||||
|
||||
class SlottedEdge(BaseEdge):
|
||||
"""Edge with multiple slots"""
|
||||
description = "Straight Edge with slots"
|
||||
|
||||
def __init__(self, boxes, sections, edge="e", slots=0):
|
||||
super(SlottedEdge, self).__init__(boxes, None)
|
||||
|
||||
self.edge = self.edges.get(edge, edge)
|
||||
self.sections = sections
|
||||
self.slots = slots
|
||||
|
@ -367,14 +392,18 @@ class SlottedEdge(BaseEdge):
|
|||
return self.edge.margin()
|
||||
|
||||
def __call__(self, length, **kw):
|
||||
|
||||
for l in self.sections[:-1]:
|
||||
self.edge(l)
|
||||
|
||||
if self.slots:
|
||||
Slot(self.boxes, self.slots)(self.thickness)
|
||||
else:
|
||||
self.edge(self.thickness)
|
||||
|
||||
self.edge(self.sections[-1])
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Finger Joints
|
||||
#############################################################################
|
||||
|
@ -411,17 +440,17 @@ Values:
|
|||
"edge_width": 1.0,
|
||||
}
|
||||
|
||||
|
||||
class FingerJointEdge(BaseEdge):
|
||||
"""Finger joint edge """
|
||||
char = 'f'
|
||||
description = "Finger Joint"
|
||||
positive = True
|
||||
|
||||
def __call__(self, length,
|
||||
bedBolts=None, bedBoltSettings=None, **kw):
|
||||
def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw):
|
||||
|
||||
positive = self.positive
|
||||
space, finger = self.settings.space, self.settings.finger
|
||||
|
||||
fingers = int((length - (self.settings.surroundingspaces - 1) * space) //
|
||||
(space + finger))
|
||||
|
||||
|
@ -438,15 +467,18 @@ class FingerJointEdge(BaseEdge):
|
|||
leftover = length
|
||||
|
||||
self.edge(leftover / 2.0)
|
||||
|
||||
for i in range(fingers):
|
||||
if i != 0:
|
||||
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(self.settings.height)
|
||||
self.corner(90 * p)
|
||||
|
@ -454,12 +486,14 @@ class FingerJointEdge(BaseEdge):
|
|||
self.corner(90 * p)
|
||||
self.edge(self.settings.height)
|
||||
self.corner(-90 * p)
|
||||
|
||||
self.edge(leftover / 2.0)
|
||||
|
||||
def margin(self):
|
||||
""" """
|
||||
return self.boxes.thickness
|
||||
|
||||
|
||||
class FingerJointEdgeCounterPart(FingerJointEdge):
|
||||
"""Finger joint edge - other side"""
|
||||
char = 'F'
|
||||
|
@ -474,8 +508,10 @@ class FingerJointEdgeCounterPart(FingerJointEdge):
|
|||
""" """
|
||||
return 0.0
|
||||
|
||||
|
||||
class FingerHoles:
|
||||
"""Hole matching a finger joint edge"""
|
||||
|
||||
def __init__(self, boxes, settings):
|
||||
self.boxes = boxes
|
||||
self.ctx = boxes.ctx
|
||||
|
@ -502,30 +538,36 @@ class FingerHoles:
|
|||
if bedBolts:
|
||||
fingers = bedBolts.numFingers(fingers)
|
||||
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.boxes.bedBoltSettings
|
||||
|
||||
leftover = length - fingers * (s + f) - f
|
||||
b = self.boxes.burn
|
||||
|
||||
if self.boxes.debug:
|
||||
self.ctx.rectangle(0, -self.settings.width / 2 + b,
|
||||
length, self.settings.width - 2 * b)
|
||||
for i in range(fingers):
|
||||
pos = leftover / 2.0 + i * (s + f)
|
||||
|
||||
if bedBolts and bedBolts.drawBolt(i):
|
||||
self.boxes.hole(pos + 0.5 * s, 0, d * 0.5)
|
||||
|
||||
self.boxes.rectangularHole(pos + s + 0.5 * f, 0,
|
||||
f, self.settings.width)
|
||||
|
||||
self.ctx.restore()
|
||||
|
||||
|
||||
class FingerHoleEdge(BaseEdge):
|
||||
"""Edge with holes for a parallel finger joint"""
|
||||
char = 'h'
|
||||
description = "Edge (parallel Finger Joint Holes)"
|
||||
|
||||
def __init__(self, boxes, fingerHoles=None, **kw):
|
||||
super(FingerHoleEdge, self).__init__(boxes, None, **kw)
|
||||
|
||||
self.fingerHoles = fingerHoles or boxes.fingerHolesAt
|
||||
|
||||
def __call__(self, length,
|
||||
bedBolts=None, bedBoltSettings=None, **kw):
|
||||
def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw):
|
||||
dist = self.fingerHoles.settings.edge_width
|
||||
self.ctx.save()
|
||||
self.fingerHoles(0, dist + self.thickness / 2, length, 0,
|
||||
|
@ -540,6 +582,7 @@ class FingerHoleEdge(BaseEdge):
|
|||
""" """
|
||||
return self.fingerHoles.settings.edge_width + self.thickness
|
||||
|
||||
|
||||
class CrossingFingerHoleEdge(BaseEdge):
|
||||
"""Edge with holes for finger joints 90° above"""
|
||||
|
||||
|
@ -547,6 +590,7 @@ class CrossingFingerHoleEdge(BaseEdge):
|
|||
|
||||
def __init__(self, boxes, height, fingerHoles=None, **kw):
|
||||
super(CrossingFingerHoleEdge, self).__init__(boxes, None, **kw)
|
||||
|
||||
self.fingerHoles = fingerHoles or boxes.fingerHolesAt
|
||||
self.height = height
|
||||
|
||||
|
@ -554,6 +598,7 @@ class CrossingFingerHoleEdge(BaseEdge):
|
|||
self.fingerHoles(length / 2.0, 0, self.height)
|
||||
super(CrossingFingerHoleEdge, self).__call__(length)
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Stackable Joints
|
||||
#############################################################################
|
||||
|
@ -578,12 +623,14 @@ Values:
|
|||
absolute_params = {
|
||||
"angle": 60,
|
||||
}
|
||||
|
||||
relative_params = {
|
||||
"height": 2.0,
|
||||
"width": 4.0,
|
||||
"holedistance": 1.0,
|
||||
}
|
||||
|
||||
|
||||
class StackableEdge(BaseEdge):
|
||||
"""Edge for having stackable Boxes. The Edge creates feet on the bottom
|
||||
and has matching recesses on the top corners."""
|
||||
|
@ -594,6 +641,7 @@ class StackableEdge(BaseEdge):
|
|||
|
||||
def __init__(self, boxes, settings, fingerjointsettings):
|
||||
super(StackableEdge, self).__init__(boxes, settings)
|
||||
|
||||
self.fingerjointsettings = fingerjointsettings
|
||||
|
||||
def __call__(self, length, **kw):
|
||||
|
@ -623,17 +671,18 @@ class StackableEdge(BaseEdge):
|
|||
def margin(self):
|
||||
return 0 if self.bottom else self._height()
|
||||
|
||||
|
||||
class StackableEdgeTop(StackableEdge):
|
||||
char = "S"
|
||||
description = "Stackable (top)"
|
||||
bottom = False
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Hinges
|
||||
#############################################################################
|
||||
|
||||
class HingeSettings(Settings):
|
||||
|
||||
"""Settings for Hinge and HingePin classes
|
||||
Values:
|
||||
|
||||
|
@ -664,15 +713,17 @@ Values:
|
|||
"grip_length": 0,
|
||||
}
|
||||
|
||||
class Hinge(BaseEdge):
|
||||
|
||||
class Hinge(BaseEdge):
|
||||
char = 'i'
|
||||
description = "Straight edge with hinge eye"
|
||||
|
||||
def __init__(self, boxes, settings=None, layout=1):
|
||||
super(Hinge, self).__init__(boxes, settings)
|
||||
|
||||
if not (0 < layout <= 3):
|
||||
raise ValueError("layout must be 1, 2 or 3 (got %i)" % layout)
|
||||
|
||||
self.layout = layout
|
||||
self.char = "eijk"[layout]
|
||||
self.description = self.description + ('', ' (start)', ' (end)', ' (both ends)')[layout]
|
||||
|
@ -697,6 +748,7 @@ class Hinge(BaseEdge):
|
|||
(180, t + pos), 0,
|
||||
(-90, 0.5 * t), 0
|
||||
)
|
||||
|
||||
if _reversed:
|
||||
hinge = reversed(hinge)
|
||||
self.polyline(*hinge)
|
||||
|
@ -710,6 +762,7 @@ class Hinge(BaseEdge):
|
|||
r = 0.5 * self.settings.axle
|
||||
alpha = math.degrees(math.asin(0.5 * t / r))
|
||||
pos = math.cos(math.radians(alpha)) * r
|
||||
|
||||
return 2 * pos + 1.5 * t
|
||||
|
||||
def B(self, _reversed=False):
|
||||
|
@ -731,6 +784,7 @@ class Hinge(BaseEdge):
|
|||
else:
|
||||
self.hole(pos, -0.5 * t, 0.5 * self.settings.axle)
|
||||
self.boxes.rectangularHole(pos, -0.5 * t, pinl, self.thickness)
|
||||
|
||||
self.polyline(*hinge)
|
||||
|
||||
def Blen(self):
|
||||
|
@ -738,20 +792,26 @@ class Hinge(BaseEdge):
|
|||
|
||||
def __call__(self, l, **kw):
|
||||
hlen = getattr(self, self.settings.style + 'len')()
|
||||
|
||||
if self.layout & 1:
|
||||
getattr(self, self.settings.style)()
|
||||
|
||||
self.edge(l - (self.layout & 1) * hlen - bool(self.layout & 2) * hlen)
|
||||
|
||||
if self.layout & 2:
|
||||
getattr(self, self.settings.style)(True)
|
||||
|
||||
|
||||
class HingePin(BaseEdge):
|
||||
char = 'I'
|
||||
description = "Edge with hinge pin"
|
||||
|
||||
def __init__(self, boxes, settings=None, layout=1):
|
||||
super(HingePin, self).__init__(boxes, settings)
|
||||
|
||||
if not (0 < layout <= 3):
|
||||
raise ValueError("layout must be 1, 2 or 3 (got %i)" % layout)
|
||||
|
||||
self.layout = layout
|
||||
self.char = "EIJK"[layout]
|
||||
self.description = self.description + ('', ' (start)', ' (end)', ' (both ends)')[layout]
|
||||
|
@ -794,8 +854,10 @@ class HingePin(BaseEdge):
|
|||
)
|
||||
else:
|
||||
pin += (pos - 0.5 * pinl,)
|
||||
|
||||
if _reversed:
|
||||
pin = reversed(pin)
|
||||
|
||||
self.polyline(*pin)
|
||||
|
||||
def Alen(self):
|
||||
|
@ -829,22 +891,28 @@ class HingePin(BaseEdge):
|
|||
90,
|
||||
0,
|
||||
)
|
||||
|
||||
if _reversed:
|
||||
pin = reversed(pin)
|
||||
|
||||
self.polyline(*pin)
|
||||
|
||||
def Blen(self):
|
||||
l = self.settings.hingestrength + self.settings.axle
|
||||
|
||||
if self.settings.outset:
|
||||
l += self.settings.hingestrength + 0.5 * self.thickness
|
||||
|
||||
return l
|
||||
|
||||
def __call__(self, l, **kw):
|
||||
plen = getattr(self, self.settings.style + 'len')()
|
||||
glen = l * self.settings.grip_percentage + \
|
||||
self.settings.grip_length
|
||||
|
||||
if not self.settings.outset:
|
||||
glen = 0.0
|
||||
|
||||
glen = min(glen, l - plen)
|
||||
|
||||
if self.layout & 1 and self.layout & 2:
|
||||
|
@ -860,6 +928,7 @@ class HingePin(BaseEdge):
|
|||
self.edge(l - plen - glen)
|
||||
getattr(self, self.settings.style)(True)
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Click Joints
|
||||
#############################################################################
|
||||
|
@ -874,6 +943,7 @@ class ClickSettings(Settings):
|
|||
"bottom_radius": 0.1,
|
||||
}
|
||||
|
||||
|
||||
class ClickConnector(BaseEdge):
|
||||
char = "c"
|
||||
description = "Click on (bottom side)"
|
||||
|
@ -917,15 +987,16 @@ class ClickConnector(BaseEdge):
|
|||
r = self.settings.bottom_radius
|
||||
c = math.cos(math.radians(a))
|
||||
s = math.sin(math.radians(a))
|
||||
|
||||
return 2 * s * d * c + 0.5 * c * t + c * 4 * r
|
||||
|
||||
def hookOffset(self):
|
||||
t = self.thickness
|
||||
a = self.settings.angle
|
||||
d = self.settings.depth
|
||||
r = self.settings.bottom_radius
|
||||
c = math.cos(math.radians(a))
|
||||
s = math.sin(math.radians(a))
|
||||
|
||||
return s * d * c + 2 * r
|
||||
|
||||
def finger(self, length):
|
||||
|
@ -955,6 +1026,7 @@ class ClickConnector(BaseEdge):
|
|||
def margin(self):
|
||||
return 2 * self.thickness
|
||||
|
||||
|
||||
class ClickEdge(ClickConnector):
|
||||
char = "C"
|
||||
description = "Click on (top)"
|
||||
|
@ -983,6 +1055,7 @@ class ClickEdge(ClickConnector):
|
|||
self.edge(length - 2 * (6 * t + 2 * w) + 2 * o)
|
||||
self.polyline(*reversed(p1))
|
||||
|
||||
|
||||
#############################################################################
|
||||
#### Dove Tail Joints
|
||||
#############################################################################
|
||||
|
@ -1006,14 +1079,17 @@ Values:
|
|||
absolute_params = {
|
||||
"angle": 50,
|
||||
}
|
||||
|
||||
relative_params = {
|
||||
"size": 3,
|
||||
"depth": 1.5,
|
||||
"radius": 0.2,
|
||||
}
|
||||
|
||||
|
||||
class DoveTailJoint(BaseEdge):
|
||||
"""Edge with dove tail joints """
|
||||
|
||||
char = 'd'
|
||||
description = "Dove Tail Joint"
|
||||
positive = True
|
||||
|
@ -1035,6 +1111,7 @@ class DoveTailJoint(BaseEdge):
|
|||
p = 1 if positive else -1
|
||||
|
||||
self.edge((s.size + leftover) / 2.0 + diffx - l1)
|
||||
|
||||
for i in range(sections):
|
||||
self.corner(-1 * p * a, radius)
|
||||
self.edge(2 * (l2 - l1))
|
||||
|
@ -1043,8 +1120,10 @@ class DoveTailJoint(BaseEdge):
|
|||
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())
|
||||
|
||||
|
@ -1052,6 +1131,7 @@ class DoveTailJoint(BaseEdge):
|
|||
""" """
|
||||
return self.settings.depth
|
||||
|
||||
|
||||
class DoveTailJointCounterPart(DoveTailJoint):
|
||||
"""Edge for other side of dove joints """
|
||||
char = 'D'
|
||||
|
@ -1062,6 +1142,7 @@ class DoveTailJointCounterPart(DoveTailJoint):
|
|||
def margin(self):
|
||||
return 0.0
|
||||
|
||||
|
||||
class FlexSettings(Settings):
|
||||
"""Settings for one directional flex cuts
|
||||
|
||||
|
@ -1083,10 +1164,12 @@ Values:
|
|||
"connection": 1.0,
|
||||
"width": 5.0,
|
||||
}
|
||||
|
||||
absolute_params = {
|
||||
"stretch": 1.05,
|
||||
}
|
||||
|
||||
|
||||
class FlexEdge(BaseEdge):
|
||||
"""Edge with flex cuts - use straight edge for the opposing side"""
|
||||
char = 'X'
|
||||
|
@ -1106,12 +1189,15 @@ class FlexEdge(BaseEdge):
|
|||
|
||||
for i in range(1, 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)
|
||||
|
@ -1119,6 +1205,7 @@ class FlexEdge(BaseEdge):
|
|||
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))
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import subprocess
|
||||
import tempfile
|
||||
import os
|
||||
|
@ -6,8 +5,8 @@ import cairo
|
|||
import re
|
||||
from boxes import svgutil
|
||||
|
||||
class PSFile:
|
||||
|
||||
class PSFile:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
|
||||
|
@ -15,16 +14,18 @@ class PSFile:
|
|||
with open(self.filename, "r+") as f:
|
||||
s = f.read(1024)
|
||||
m = re.search(r"%%BoundingBox: (\d+) (\d+) (\d+) (\d+)", s)
|
||||
|
||||
if not m:
|
||||
raise ValueError("%%BoundingBox in Postscript file not found")
|
||||
|
||||
x1, y1, x2, y2 = m.groups()
|
||||
m = re.search(r"%%DocumentMedia: \d+x\d+mm ((\d+) (\d+)) 0 \(", s)
|
||||
f.seek(m.start(1))
|
||||
media = "%i %i" % (int(x1) + int(x2), int(y1) + int(y2))
|
||||
f.write(media + " " * (len(m.group(1)) - len(media)))
|
||||
|
||||
class Formats:
|
||||
|
||||
class Formats:
|
||||
pstoedit = "/usr/bin/pstoedit"
|
||||
|
||||
formats = {
|
||||
|
@ -86,11 +87,14 @@ class Formats:
|
|||
else:
|
||||
ps = PSFile(filename)
|
||||
ps.adjustDocumentMedia()
|
||||
|
||||
if fmt not in ("svg", "ps"):
|
||||
fd, tmpfile = tempfile.mkstemp()
|
||||
cmd = [self.pstoedit] + self.formats[fmt] + [filename, tmpfile]
|
||||
err = subprocess.call(cmd)
|
||||
|
||||
if err:
|
||||
# XXX show stderr output
|
||||
raise ValueError("Conversion failed. pstoedit returned %i" % err)
|
||||
|
||||
os.rename(tmpfile, filename)
|
||||
|
|
|
@ -107,26 +107,22 @@ def gear_calculations(num_teeth, circular_pitch, pressure_angle, clearance=0, ri
|
|||
pitch_diameter = num_teeth / diametral_pitch
|
||||
pitch_radius = pitch_diameter / 2.0
|
||||
addendum = 1 / diametral_pitch
|
||||
#dedendum = 1.157 / diametral_pitch # auto calc clearance
|
||||
dedendum = addendum
|
||||
dedendum *= 1+profile_shift
|
||||
addendum *= 1-profile_shift
|
||||
|
||||
if ring_gear:
|
||||
addendum = addendum + clearance # our method
|
||||
else:
|
||||
dedendum = dedendum + clearance # our method
|
||||
#
|
||||
#
|
||||
|
||||
base_radius = pitch_diameter * cos(radians(pressure_angle)) / 2.0
|
||||
outer_radius = pitch_radius + addendum
|
||||
root_radius = pitch_radius - dedendum
|
||||
|
||||
# Tooth thickness: Tooth width along pitch circle.
|
||||
tooth_thickness = ( pi * pitch_diameter ) / ( 2.0 * num_teeth )
|
||||
# we don't use these
|
||||
working_depth = 2 / diametral_pitch
|
||||
whole_depth = 2.157 / diametral_pitch
|
||||
#outside_diameter = (num_teeth + 2) / diametral_pitch
|
||||
#
|
||||
|
||||
return (pitch_radius, base_radius,
|
||||
addendum, dedendum, outer_radius, root_radius,
|
||||
tooth_thickness
|
||||
|
@ -146,6 +142,7 @@ def generate_rack_points(tooth_count, pitch, addendum, pressure_angle,
|
|||
(one extra tooth on the right hand side, if number of teeth is even)
|
||||
"""
|
||||
spacing = 0.5 * pitch # rolling one pitch distance on the spur gear pitch_diameter.
|
||||
|
||||
# roughly center rack in drawing, exact position is so that it meshes
|
||||
# nicely with the spur gear.
|
||||
# -0.5*spacing has a gap in the center.
|
||||
|
@ -158,7 +155,7 @@ def generate_rack_points(tooth_count, pitch, addendum, pressure_angle,
|
|||
base_bot = addendum+clearance+base_height
|
||||
|
||||
x_lhs = -pitch * int(0.5*tooth_count-.5) - spacing - tab_length - tasc + fudge
|
||||
#inkex.debug("angle=%s spacing=%s"%(pressure_angle, spacing))
|
||||
|
||||
# Start with base tab on LHS
|
||||
points = [] # make list of points
|
||||
points.append((x_lhs, base_bot))
|
||||
|
@ -175,6 +172,7 @@ def generate_rack_points(tooth_count, pitch, addendum, pressure_angle,
|
|||
points.append((x+spacing-tas, -addendum))
|
||||
points.append((x+spacing+tasc, base_top))
|
||||
x += pitch
|
||||
|
||||
x -= spacing # remove last adjustment
|
||||
# add base on RHS
|
||||
x_rhs = x+tasc+tab_length
|
||||
|
@ -189,7 +187,7 @@ def generate_rack_points(tooth_count, pitch, addendum, pressure_angle,
|
|||
p = []
|
||||
p.append( (x_lhs + 0.5 * tab_length, 0) )
|
||||
p.append( (x_rhs - 0.5 * tab_length, 0) )
|
||||
# return points ready for use in an SVG 'path'
|
||||
|
||||
return (points, p)
|
||||
|
||||
|
||||
|
@ -233,6 +231,7 @@ def generate_spur_points(teeth, base_radius, pitch_radius, outer_radius, root_ra
|
|||
p_tmp = points1 + points_on_outer_radius[1:-1] + points2[::-1] + points_on_root # [::-1] reverses list
|
||||
|
||||
points.extend( p_tmp )
|
||||
|
||||
return (points)
|
||||
|
||||
def inkbool(val):
|
||||
|
@ -257,6 +256,7 @@ class OptionParser(argparse.ArgumentParser):
|
|||
self.add_argument(*names, **kw)
|
||||
|
||||
class Gears():
|
||||
|
||||
def __init__(self, boxes, **kw):
|
||||
# an alternate way to get debug info:
|
||||
# could use inkex.debug(string) instead...
|
||||
|
@ -385,12 +385,16 @@ class Gears():
|
|||
help="Let the user confirm a warning dialog if undercut occurs. This dialog also shows helpful hints against undercut")
|
||||
|
||||
def drawPoints(self, lines, kerfdir=1):
|
||||
|
||||
if kerfdir != 0:
|
||||
lines = kerf(lines, self.boxes.burn*kerfdir)
|
||||
|
||||
self.boxes.ctx.save()
|
||||
self.boxes.ctx.move_to(*lines[0])
|
||||
|
||||
for x, y in lines[1:]:
|
||||
self.boxes.ctx.line_to(x, y)
|
||||
|
||||
self.boxes.ctx.line_to(*lines[0])
|
||||
self.boxes.ctx.restore()
|
||||
|
||||
|
@ -406,6 +410,7 @@ class Gears():
|
|||
circular_pitch = dimension
|
||||
else:
|
||||
raise ValueError("unknown system '%s', try CP, DP, MM" % self.options.system)
|
||||
|
||||
# circular_pitch defines the size in mm
|
||||
return circular_pitch
|
||||
|
||||
|
@ -436,6 +441,7 @@ class Gears():
|
|||
# check for mount hole collision with inner spokes
|
||||
if mount_radius <= mount_hole/2:
|
||||
adj_factor = (r_outer - mount_hole/2) / 5
|
||||
|
||||
if adj_factor < 0.1:
|
||||
# not enough reasonable room
|
||||
collision = True
|
||||
|
@ -446,6 +452,7 @@ class Gears():
|
|||
# then check to see if cross-over on spoke width
|
||||
for i in range(spoke_count):
|
||||
angle = spokes[i]-spokes[i-1]
|
||||
|
||||
if spoke_width >= angle * mount_radius:
|
||||
adj_factor = 1.2 # wrong value. its probably one of the points distances calculated below
|
||||
mount_radius += adj_factor
|
||||
|
@ -458,6 +465,7 @@ class Gears():
|
|||
if collision: # don't draw spokes if no room.
|
||||
messages.append("Not enough room for Spokes. Decrease Spoke width.")
|
||||
else: # draw spokes
|
||||
|
||||
for i in range(spoke_count):
|
||||
self.boxes.ctx.save()
|
||||
start_a, end_a = spokes[i], spokes[i+1]
|
||||
|
@ -486,6 +494,7 @@ class Gears():
|
|||
)
|
||||
|
||||
self.boxes.ctx.restore()
|
||||
|
||||
return messages
|
||||
|
||||
def sizes(self, **kw):
|
||||
|
@ -517,8 +526,10 @@ class Gears():
|
|||
|
||||
def gearCarrier(self, r, spoke_width, positions, mount_radius, mount_hole, circle=True, move=None):
|
||||
width = (r+spoke_width)*2
|
||||
|
||||
if self.boxes.move(width, width, move, before=True):
|
||||
return
|
||||
|
||||
try:
|
||||
positions = [i*360/positions for i in range(positions)]
|
||||
except TypeError:
|
||||
|
@ -528,11 +539,13 @@ class Gears():
|
|||
self.boxes.moveTo(width/2.0, width/2.0)
|
||||
self.generate_spokes(r+0.5*spoke_width, spoke_width, positions, mount_radius, mount_hole, 1, "")
|
||||
self.boxes.hole(0, 0, mount_hole)
|
||||
|
||||
for angle in positions:
|
||||
self.boxes.ctx.save()
|
||||
self.boxes.moveTo(0, 0, angle)
|
||||
self.boxes.hole(r, 0, mount_hole)
|
||||
self.boxes.ctx.restore()
|
||||
|
||||
self.boxes.moveTo(r+0.5*spoke_width+self.boxes.burn, 0, 90)
|
||||
self.boxes.corner(360, r+0.5*spoke_width)
|
||||
|
||||
|
@ -578,6 +591,7 @@ class Gears():
|
|||
else: accuracy_involute = 6
|
||||
else:
|
||||
accuracy_involute = self.options.accuracy
|
||||
|
||||
accuracy_circular = max(3, int(accuracy_involute/2) - 1) # never less than three
|
||||
# print >>self.tty, "accuracy_circular=%s accuracy_involute=%s" % (accuracy_circular, accuracy_involute)
|
||||
# Pitch (circular pitch): Length of the arc from one tooth to the next)
|
||||
|
@ -599,17 +613,20 @@ class Gears():
|
|||
height = base_height+ 2* addendum
|
||||
if self.boxes.move(width, height, move, before=True):
|
||||
return
|
||||
|
||||
self.boxes.cc(callback, None, s+b, s+b)
|
||||
self.boxes.moveTo(width/2.0, base_height+addendum, -180)
|
||||
self.drawPoints(points)
|
||||
self.drawPoints(guide_points, kerfdir=0)
|
||||
self.boxes.move(width, height, move)
|
||||
|
||||
return
|
||||
|
||||
# Move only
|
||||
width = height = 2 * outer_radius
|
||||
if self.options.internal_ring:
|
||||
width = height = width + 2 * self.options.spoke_width
|
||||
|
||||
if self.boxes.move(width, height, move, before=True):
|
||||
return
|
||||
|
||||
|
@ -624,6 +641,7 @@ class Gears():
|
|||
# alas annotation cannot handle the degree symbol. Also it ignore newlines.
|
||||
# so split and make a list
|
||||
warnings.extend(msg.split("\n"))
|
||||
|
||||
if self.options.undercut_alert:
|
||||
inkex.debug(msg)
|
||||
else:
|
||||
|
@ -653,6 +671,7 @@ class Gears():
|
|||
self.boxes.moveTo(r, 0)
|
||||
self.boxes.ctx.arc(-r, 0, r, 0, 2*pi)
|
||||
self.boxes.ctx.restore()
|
||||
|
||||
# Add center
|
||||
if centercross:
|
||||
cs = pitch / 3.0 # centercross length
|
||||
|
@ -667,12 +686,13 @@ class Gears():
|
|||
if pitchcircle:
|
||||
self.boxes.hole(0, 0, pitch_radius)
|
||||
|
||||
|
||||
# Add Annotations (above)
|
||||
if self.options.annotation:
|
||||
outer_dia = outer_radius * 2
|
||||
|
||||
if self.options.internal_ring:
|
||||
outer_dia += 2 * spoke_width
|
||||
|
||||
notes = []
|
||||
notes.extend(warnings)
|
||||
#notes.append('Document (%s) scale conversion = %2.4f' % (self.document.getroot().find(inkex.addNS('namedview', 'sodipodi')).get(inkex.addNS('document-units', 'inkscape')), unit_factor))
|
||||
|
@ -690,6 +710,7 @@ class Gears():
|
|||
text_height = max(10, min(10+(outer_dia-60)/24, 22))
|
||||
# position above
|
||||
y = - outer_radius - (len(notes)+1) * text_height * 1.2
|
||||
|
||||
for note in notes:
|
||||
self.boxes.text(note, -outer_radius, y)
|
||||
y += text_height * 1.2
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class Box(Boxes):
|
||||
"""Fully closed box"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "outside")
|
||||
|
@ -53,10 +55,12 @@ class Box(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Box()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -120,6 +120,7 @@ class Box2(Boxes):
|
|||
bedBolts=[d2], move="up only")
|
||||
|
||||
self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right")
|
||||
|
||||
if self.top_edge == "c":
|
||||
self.rectangularWall(x, y, "CCCC", bedBolts=[d2, d3, d2, d3], move="up")
|
||||
elif self.top_edge == "i":
|
||||
|
|
|
@ -18,6 +18,7 @@ from boxes import *
|
|||
|
||||
class Box3(Boxes):
|
||||
"""Box with just 3 walls"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "outside")
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
class Castle(Boxes):
|
||||
|
||||
class Castle(Boxes):
|
||||
webinterface = False
|
||||
|
||||
def __init__(self):
|
||||
|
@ -28,19 +28,19 @@ class Castle(Boxes):
|
|||
s = edges.FingerJointSettings(self.thickness, relative=False,
|
||||
space=10, finger=10, height=10,
|
||||
width=self.thickness)
|
||||
|
||||
p = edges.FingerJointEdge(self, s)
|
||||
p.char = "p"
|
||||
self.addPart(p)
|
||||
|
||||
P = edges.FingerJointEdgeCounterPart(self, s)
|
||||
P.char = "P"
|
||||
self.addPart(P)
|
||||
|
||||
self.moveTo(0, 0)
|
||||
self.rectangularWall(t_x, t_h, edges="efPf", move="right", callback=
|
||||
[lambda: self.fingerHolesAt(t_x*0.5, 0, w1_h, 90),])
|
||||
self.rectangularWall(t_x, t_h, edges="efPf", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w1_h, 90), ])
|
||||
self.rectangularWall(t_x, t_h, edges="efPf", move="right")
|
||||
self.rectangularWall(t_x, t_h, edges="eFPF", move="right", callback=
|
||||
[lambda: self.fingerHolesAt(t_x*0.5, 0, w2_h, 90),])
|
||||
self.rectangularWall(t_x, t_h, edges="eFPF", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w2_h, 90), ])
|
||||
self.rectangularWall(t_x, t_h, edges="eFPF", move="right")
|
||||
|
||||
self.rectangularWall(w1_x, w1_h, "efpe", move="right")
|
||||
|
@ -48,10 +48,12 @@ class Castle(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
c = Castle()
|
||||
c.parseArgs()
|
||||
c.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class DrillBox(Boxes):
|
||||
"""Not yet parametrized box for drills from 1 to 12.5mm
|
||||
in 0.5mm steps, 3 holes each size"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.x, self.y, self.h = 120, 240, 60
|
||||
|
@ -31,7 +33,6 @@ in 0.5mm steps, 3 holes each size"""
|
|||
self.fingerHolesAt(0, 5, self.y, angle=0)
|
||||
self.fingerHolesAt(0, 25, self.y, angle=0)
|
||||
|
||||
|
||||
def drillholes(self):
|
||||
for i in range(6):
|
||||
for j in range(4):
|
||||
|
@ -48,34 +49,30 @@ in 0.5mm steps, 3 holes each size"""
|
|||
self.text("%.1f" % d, i * 60 + 20, 19 * j + 6,
|
||||
align="center")
|
||||
|
||||
|
||||
def render(self):
|
||||
x, y, h = self.x, self.y, self.h
|
||||
t = self.thickness
|
||||
|
||||
self.open()
|
||||
self.edges["f"].settings.setValues(self.thickness, space=3, finger=3,
|
||||
surroundingspaces=1)
|
||||
self.edges["f"].settings.setValues(self.thickness, space=3, finger=3, surroundingspaces=1)
|
||||
|
||||
self.rectangularWall(x, h, "FfeF", callback=[self.holesx], move="right")
|
||||
self.rectangularWall(y, h, "FfeF", callback=[self.holesy], move="up")
|
||||
self.rectangularWall(y, h, "FfeF", callback=[self.holesy])
|
||||
self.rectangularWall(x, h, "FfeF", callback=[self.holesx],
|
||||
move="left up")
|
||||
self.rectangularWall(x, h, "FfeF", callback=[self.holesx], move="left up")
|
||||
|
||||
self.rectangularWall(x, y, "ffff", move="up")
|
||||
self.rectangularWall(x, y, "ffff", callback=[self.drillholes],
|
||||
move="up")
|
||||
self.rectangularWall(x, y, "ffff", callback=[self.drillholes,
|
||||
self.description],
|
||||
move="up")
|
||||
self.rectangularWall(x, y, "ffff", callback=[self.drillholes], move="up")
|
||||
self.rectangularWall(x, y, "ffff", callback=[self.drillholes, self.description], move="up")
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = DrillBox()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
import boxes
|
||||
import math
|
||||
|
||||
|
||||
class FlexBox(boxes.Boxes):
|
||||
"""Box with living hinge and round corners"""
|
||||
|
||||
def __init__(self):
|
||||
boxes.Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "outside")
|
||||
|
@ -29,10 +31,12 @@ class FlexBox(boxes.Boxes):
|
|||
@boxes.restore
|
||||
def flexBoxSide(self, x, y, r, callback=None):
|
||||
self.moveTo(r, 0)
|
||||
|
||||
for i, l in zip(range(2), (x, y)):
|
||||
self.cc(callback, i)
|
||||
self.edges["f"](l - 2 * r)
|
||||
self.corner(90, r)
|
||||
|
||||
self.cc(callback, 2)
|
||||
self.edge(x - 2 * r)
|
||||
self.corner(90, r)
|
||||
|
@ -102,10 +106,12 @@ class FlexBox(boxes.Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = FlexBox()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
class FlexBox2(Boxes):
|
||||
"""Box with living hinge and top corners rounded"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "outside")
|
||||
|
@ -47,12 +49,14 @@ class FlexBox2(Boxes):
|
|||
x, y, h, r = self.x, self.y, self.h, self.radius
|
||||
|
||||
self.edges["F"](y - r, False)
|
||||
|
||||
if (x - 2 * r < self.thickness):
|
||||
self.edges["X"](2 * self.c4 + x - 2 * r, h + 2 * self.thickness)
|
||||
else:
|
||||
self.edges["X"](self.c4, h + 2 * self.thickness)
|
||||
self.edge(x - 2 * r)
|
||||
self.edges["X"](self.c4, h + 2 * self.thickness)
|
||||
|
||||
self.latch(self.latchsize, False)
|
||||
self.edge(h + 2 * self.thickness)
|
||||
self.latch(self.latchsize, False, True)
|
||||
|
@ -67,6 +71,7 @@ class FlexBox2(Boxes):
|
|||
self.corner(90)
|
||||
|
||||
def render(self):
|
||||
|
||||
if self.outside:
|
||||
self.x = self.adjustSize(self.x)
|
||||
self.y = self.adjustSize(self.y)
|
||||
|
@ -85,23 +90,29 @@ class FlexBox2(Boxes):
|
|||
self.moveTo(2 * self.thickness, self.thickness)
|
||||
self.ctx.save()
|
||||
self.surroundingWall()
|
||||
|
||||
self.moveTo(self.x + self.y - 3 * self.radius + 2 * self.c4 + self.latchsize + 1 * self.thickness, 0)
|
||||
self.rectangularWall(self.x, self.h, edges="FFFF")
|
||||
self.ctx.restore()
|
||||
|
||||
self.moveTo(0, self.h + 4 * self.thickness)
|
||||
self.flexBoxSide(self.x, self.y, self.radius)
|
||||
|
||||
self.moveTo(2 * self.x + 3 * self.thickness, 0)
|
||||
self.ctx.scale(-1, 1)
|
||||
self.flexBoxSide(self.x, self.y, self.radius)
|
||||
self.ctx.scale(-1, 1)
|
||||
|
||||
self.moveTo(2 * self.thickness, 0)
|
||||
self.rectangularWall(self.h, self.y - self.radius - self.latchsize, edges="fFeF")
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = FlexBox2()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
class FlexBox3(Boxes):
|
||||
"""Box with living hinge"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "outside")
|
||||
|
@ -116,13 +118,13 @@ class FlexBox3(Boxes):
|
|||
|
||||
self.open()
|
||||
|
||||
self.edges["f"].settings.setValues(
|
||||
self.thickness, finger=2, space=2, surroundingspaces=1)
|
||||
self.edges["f"].settings.setValues(self.thickness, finger=2, space=2, surroundingspaces=1)
|
||||
|
||||
s = edges.FingerJointSettings(self.thickness, surroundingspaces=1)
|
||||
g = edges.FingerJointEdge(self, s)
|
||||
g.char = "g"
|
||||
self.addPart(g)
|
||||
|
||||
G = edges.FingerJointEdgeCounterPart(self, s)
|
||||
G.char = "G"
|
||||
self.addPart(G)
|
||||
|
@ -132,8 +134,7 @@ class FlexBox3(Boxes):
|
|||
self.surroundingWall()
|
||||
self.moveTo(x + y - 2 * r + self.c4 + 2 * self.thickness, -2 * d - self.thickness)
|
||||
self.rectangularWall(x, z, edges="FFFF", move="right")
|
||||
self.rectangularWall(h, z+2*(d+self.thickness),
|
||||
edges="GeGF", move="right")
|
||||
self.rectangularWall(h, z + 2 * (d + self.thickness), edges="GeGF", move="right")
|
||||
self.lidSide()
|
||||
self.moveTo(2 * h + 5 * self.thickness, 0)
|
||||
self.ctx.scale(-1, 1)
|
||||
|
@ -151,10 +152,12 @@ class FlexBox3(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = FlexBox3() # 100, 40, 100, r=20, h=10, thickness=4.0)
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
class FlexBox4(Boxes):
|
||||
"""Box with living hinge and left corners rounded"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "outside")
|
||||
|
@ -53,6 +55,7 @@ class FlexBox4(Boxes):
|
|||
self.edges["X"](self.c4, h + 2 * self.thickness)
|
||||
self.edge(x - 2 * r)
|
||||
self.edges["X"](self.c4, h + 2 * self.thickness)
|
||||
|
||||
self.edge(y - r - self.latchsize)
|
||||
self.latch(self.latchsize, False)
|
||||
self.edge(h + 2 * self.thickness)
|
||||
|
@ -98,10 +101,12 @@ class FlexBox4(Boxes):
|
|||
self.rectangularWall(self.x, self.h, edges="FeFF")
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = FlexBox4()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class FlexTest(Boxes):
|
||||
"Piece for testing different flex settings"
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y")
|
||||
|
@ -53,10 +55,12 @@ class FlexTest(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
f = FlexTest()
|
||||
f.parseArgs()
|
||||
f.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class FlexTest2(Boxes):
|
||||
"Piece for testing 2D flex settings"
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y")
|
||||
|
@ -27,15 +29,17 @@ class FlexTest2(Boxes):
|
|||
|
||||
def render(self):
|
||||
x, y = self.x, self.y
|
||||
t = self.thickness
|
||||
|
||||
self.open()
|
||||
self.rectangularWall(x, y, callback=[lambda: self.flex2D(x, y, self.fw)])
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
f = FlexTest()
|
||||
f.parseArgs()
|
||||
f.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
class Folder(Boxes):
|
||||
"""Book cover with flex for the spine"""
|
||||
|
||||
|
@ -52,5 +53,6 @@ def main():
|
|||
f.parseArgs()
|
||||
f.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class GearBox(Boxes):
|
||||
"""Gearbox with multiple identical stages"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.argparser.add_argument(
|
||||
|
@ -43,13 +45,12 @@ class GearBox(Boxes):
|
|||
if self.teeth2 < self.teeth1:
|
||||
self.teeth2, self.teeth1 = self.teeth1, self.teeth2
|
||||
|
||||
pitch1, size1, xxx = self.gears.sizes(teeth=self.teeth1,
|
||||
dimension=self.modulus)
|
||||
pitch2, size2, xxx = self.gears.sizes(teeth=self.teeth2,
|
||||
dimension=self.modulus)
|
||||
pitch1, size1, xxx = self.gears.sizes(teeth=self.teeth1, dimension=self.modulus)
|
||||
pitch2, size2, xxx = self.gears.sizes(teeth=self.teeth2, dimension=self.modulus)
|
||||
|
||||
t = self.thickness
|
||||
x = 1.1 * t * self.stages
|
||||
|
||||
if self.stages == 1:
|
||||
y = size1 + size2
|
||||
y1 = y / 2 - (pitch1 + pitch2) + pitch1
|
||||
|
@ -65,7 +66,6 @@ class GearBox(Boxes):
|
|||
t = "e" # prepare for close box
|
||||
mh = self.shaft
|
||||
|
||||
|
||||
def sideCB():
|
||||
self.hole(y1, h / 2, mh / 2)
|
||||
self.hole(y2, h / 2, mh / 2)
|
||||
|
@ -81,24 +81,26 @@ class GearBox(Boxes):
|
|||
|
||||
profile_shift = 20
|
||||
pressure_angle = 20
|
||||
|
||||
for i in range(self.stages - 1):
|
||||
self.gears(teeth=self.teeth2, dimension=self.modulus,
|
||||
angle=pressure_angle,
|
||||
self.gears(teeth=self.teeth2, dimension=self.modulus, angle=pressure_angle,
|
||||
mount_hole=mh, profile_shift=profile_shift, move="up")
|
||||
self.gears(teeth=self.teeth2, dimension=self.modulus,
|
||||
angle=pressure_angle,
|
||||
|
||||
self.gears(teeth=self.teeth2, dimension=self.modulus, angle=pressure_angle,
|
||||
mount_hole=mh, profile_shift=profile_shift, move="right")
|
||||
|
||||
for i in range(self.stages):
|
||||
self.gears(teeth=self.teeth1, dimension=self.modulus,
|
||||
angle=pressure_angle,
|
||||
self.gears(teeth=self.teeth1, dimension=self.modulus, angle=pressure_angle,
|
||||
mount_hole=mh, profile_shift=profile_shift, move="down")
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Box()
|
||||
b = GearBox()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
from boxes import *
|
||||
import random
|
||||
|
||||
|
||||
class JigsawPuzzle(Boxes): # change class name here and below
|
||||
"""Fractal jigsaw puzzle. Still aplha"""
|
||||
|
||||
|
@ -32,15 +33,14 @@ class JigsawPuzzle(Boxes): # change class name here and below
|
|||
"--depth", action="store", type=int, default=5,
|
||||
help="depth of the recursion/level of detail")
|
||||
|
||||
|
||||
def peano(self, level):
|
||||
if level == 0:
|
||||
self.edge(self.size / self.depth)
|
||||
return
|
||||
|
||||
self.peano(self, level - 1)
|
||||
self.corner()
|
||||
|
||||
|
||||
def edge(self, l):
|
||||
self.count += 1
|
||||
Boxes.edge(self, l)
|
||||
|
@ -53,13 +53,16 @@ class JigsawPuzzle(Boxes): # change class name here and below
|
|||
# rotate and draw first subcurve with opposite parity to big curve
|
||||
self.corner(parity * 90)
|
||||
self.hilbert(level - 1, -parity)
|
||||
|
||||
# interface to and draw second subcurve with same parity as big curve
|
||||
self.edge(self.size / 2 ** self.depth)
|
||||
self.corner(parity * -90)
|
||||
self.hilbert(level - 1, parity)
|
||||
|
||||
# third subcurve
|
||||
self.edge(self.size / 2 ** self.depth)
|
||||
self.hilbert(level - 1, parity)
|
||||
|
||||
# if level == 3: self.corner(-360, 0.4*self.size/2**self.depth)
|
||||
# fourth subcurve
|
||||
self.corner(parity * -90)
|
||||
|
@ -85,10 +88,12 @@ class JigsawPuzzle(Boxes): # change class name here and below
|
|||
self.hilbert(self.depth)
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = JigsawPuzzle()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
"""
|
||||
22x7.5x7cm
|
||||
D=23cm, d=21cm
|
||||
d = 8" D = 9"
|
||||
"""
|
||||
|
||||
|
||||
class RoundedTriangleSettings(edges.Settings):
|
||||
absolute_params = {
|
||||
"angle": 60,
|
||||
|
@ -31,8 +31,10 @@ class RoundedTriangleSettings(edges.Settings):
|
|||
"r_hole": None,
|
||||
}
|
||||
|
||||
|
||||
class RoundedTriangle(edges.Edge):
|
||||
char = "t"
|
||||
|
||||
def __call__(self, length, **kw):
|
||||
angle = self.settings.angle
|
||||
r = self.settings.radius
|
||||
|
@ -55,8 +57,8 @@ class RoundedTriangle(edges.Edge):
|
|||
def endAngle(self):
|
||||
return 90
|
||||
|
||||
class Lamp(Boxes):
|
||||
|
||||
class Lamp(Boxes):
|
||||
webinterface = False
|
||||
|
||||
def __init__(self):
|
||||
|
@ -94,6 +96,7 @@ class Lamp(Boxes):
|
|||
|
||||
self.roundedPlate(d, d, r, move="right", callback=[
|
||||
lambda: self.hole(w, r + w, r), ])
|
||||
|
||||
# dist = ((2**0.5)*r-r) / (2**0.5) + 4
|
||||
# pos = (w-dist, dist)
|
||||
self.roundedPlate(d, d, r, holesMargin=w / 2.0) # , callback=[
|
||||
|
@ -119,10 +122,12 @@ class Lamp(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
l = Lamp()
|
||||
l.parseArgs()
|
||||
l.render(r=4 * 25.4, w=20, x=270, y=150, h=100)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class MagazinFile(Boxes):
|
||||
"""Open magazine file"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("x", "y", "h", "hi", "outside")
|
||||
|
@ -28,6 +30,7 @@ class MagazinFile(Boxes):
|
|||
|
||||
def side(self, w, h, hi):
|
||||
r = min(h - hi, w) / 2.0
|
||||
|
||||
if (h - hi) > w:
|
||||
r = w / 2.0
|
||||
lx = 0
|
||||
|
@ -58,8 +61,8 @@ class MagazinFile(Boxes):
|
|||
self.edge(e_w)
|
||||
self.corner(90)
|
||||
|
||||
|
||||
def render(self):
|
||||
|
||||
if self.outside:
|
||||
self.x = self.adjustSize(self.x)
|
||||
self.y = self.adjustSize(self.y)
|
||||
|
@ -85,10 +88,12 @@ class MagazinFile(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = MagazinFile()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
from boxes import *
|
||||
import math
|
||||
|
||||
|
||||
class Planetary(Boxes):
|
||||
"""Gearbox with multiple identical stages"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.argparser.add_argument(
|
||||
|
@ -60,6 +62,7 @@ class Planetary(Boxes):
|
|||
|
||||
t = self.thickness
|
||||
planets = int(math.pi // math.asin((self.planetteeth + 2) / (self.planetteeth + self.sunteeth)))
|
||||
|
||||
if self.maxplanets:
|
||||
planets = min(self.maxplanets, planets)
|
||||
|
||||
|
@ -85,6 +88,7 @@ class Planetary(Boxes):
|
|||
angle=pressure_angle,
|
||||
mount_hole=self.shaft, profile_shift=profile_shift, move="up")
|
||||
numplanets = planets
|
||||
|
||||
if self.deltateeth:
|
||||
numplanets += planets
|
||||
deltamodulus = self.modulus * ringteeth / (ringteeth - self.deltateeth)
|
||||
|
@ -100,10 +104,12 @@ class Planetary(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Box()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
class Printer(Boxes):
|
||||
|
||||
class Printer(Boxes):
|
||||
"""Work in progress"""
|
||||
|
||||
webinterface = False
|
||||
|
@ -32,7 +32,6 @@ class Printer(Boxes):
|
|||
self.d_i = 5.0
|
||||
self.w_i = 7.0 # includes washers
|
||||
|
||||
|
||||
def mainPlate(self, nr):
|
||||
r = self.r
|
||||
t2 = 0.5 * self.thickness
|
||||
|
@ -45,9 +44,11 @@ class Printer(Boxes):
|
|||
w_i2 = self.w_i / 2
|
||||
|
||||
d_c2 = self.d_c / 2
|
||||
|
||||
for i in range(6):
|
||||
self.ctx.save()
|
||||
self.moveTo(0, 0, i * 60)
|
||||
|
||||
# winches
|
||||
if i % 2:
|
||||
self.fingerHolesAt(r - 80, (d_c2 + 20), 70, angle=0)
|
||||
|
@ -59,13 +60,14 @@ class Printer(Boxes):
|
|||
# idler buck
|
||||
else:
|
||||
d = 0.5 * (self.thickness) + w_i2
|
||||
|
||||
for y in (-d - d_c2, d - d_c2, -d + d_c2, d + d_c2):
|
||||
self.fingerHolesAt(r - 30, y, 30, angle=0)
|
||||
|
||||
self.hole(r - 15 + D_i2, -self.d_c / 2, 0.4)
|
||||
self.hole(r - 15 + D_i2, self.d_c / 2, 0.4)
|
||||
self.ctx.restore()
|
||||
|
||||
|
||||
def head(self):
|
||||
d_c = self.d_c
|
||||
|
||||
|
@ -78,10 +80,10 @@ class Printer(Boxes):
|
|||
self.hole(0, 5, 0.3)
|
||||
self.corner(120, 10)
|
||||
|
||||
|
||||
def support(self, x, y, edges="ff", pair=False, callback=None, move=None):
|
||||
if len(edges) != 2:
|
||||
raise ValueError("Two edges required")
|
||||
|
||||
edges = [self.edges.get(e, e, ) for e in edges]
|
||||
|
||||
overallwidth = x + edges[0].spacing() + self.edges["e"].spacing()
|
||||
|
@ -127,6 +129,7 @@ class Printer(Boxes):
|
|||
self.open()
|
||||
self.edges["f"].settings.setValues(self.thickness, surroundingspaces=0)
|
||||
self.ctx.save()
|
||||
|
||||
for i in range(3):
|
||||
# motor mounts
|
||||
self.rectangularWall(70, 70, edges="feee", callback=[
|
||||
|
@ -138,25 +141,30 @@ class Printer(Boxes):
|
|||
lambda: self.hole(35, 35, 8.5),
|
||||
None,
|
||||
lambda: self.fingerHolesAt(10, 0, 50)], move="right")
|
||||
|
||||
self.support(40, 50, move="right", pair=True)
|
||||
self.support(40, 50, move="right")
|
||||
self.ctx.restore()
|
||||
self.moveTo(0, 80)
|
||||
self.ctx.save()
|
||||
|
||||
# idler bucks
|
||||
for i in range(12):
|
||||
self.rectangularWall(30, 30, edges="feee", callback=[
|
||||
lambda: self.hole(15, 15, 3), ], move="right")
|
||||
# Cable adjustment blocks
|
||||
self.ctx.save()
|
||||
|
||||
for i in range(6):
|
||||
def holes():
|
||||
self.hole(5, 4, 1.5)
|
||||
self.hole(15, 4, 1.5)
|
||||
|
||||
self.rectangularWall(20, 8, edges="feee", callback=[holes, ],
|
||||
move="right")
|
||||
self.ctx.restore()
|
||||
self.moveTo(0, 20)
|
||||
|
||||
# Cable adjustment glyders
|
||||
for i in range(6):
|
||||
self.rectangularWall(8, 10, move="right", callback=[
|
||||
|
@ -178,10 +186,12 @@ class Printer(Boxes):
|
|||
self.head()
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
p = Printer()
|
||||
p.parseArgs()
|
||||
p.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -18,8 +18,10 @@ from boxes import *
|
|||
from boxes import pulley
|
||||
import math
|
||||
|
||||
|
||||
class Pulley(Boxes):
|
||||
"""Timing belt pulleys for different profiles"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
# remove cli params you do not need
|
||||
|
@ -43,16 +45,19 @@ class Pulley(Boxes):
|
|||
# "--XX", action="store", type=float, default=0.5,
|
||||
# help="DESCRIPTION")
|
||||
|
||||
|
||||
def disk(self, diameter, hole, callback=None, move=""):
|
||||
w = diameter + 2 * self.spacing
|
||||
|
||||
if self.move(w, w, move, before=True):
|
||||
return
|
||||
|
||||
self.ctx.save()
|
||||
self.moveTo(w / 2, w / 2)
|
||||
self.cc(callback, None, 0.0, 0.0)
|
||||
|
||||
if hole:
|
||||
self.hole(0, 0, hole / 2.0)
|
||||
|
||||
self.moveTo(diameter / 2 + self.burn, 0, 90)
|
||||
self.corner(360, diameter / 2)
|
||||
self.ctx.restore()
|
||||
|
@ -63,19 +68,23 @@ class Pulley(Boxes):
|
|||
t = self.thickness
|
||||
# Initialize canvas
|
||||
self.open()
|
||||
|
||||
if self.top:
|
||||
self.disk(
|
||||
self.pulley.diameter(self.teeth, self.profile) + 2 * self.top,
|
||||
self.axle, move="right")
|
||||
|
||||
for i in range(int(math.ceil(self.h / self.thickness))):
|
||||
self.pulley(self.teeth, self.profile, r_axle=self.axle / 2.0, move="right")
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Box()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class MotorEdge(edges.BaseEdge):
|
||||
# def margin(self):
|
||||
# return 30
|
||||
|
@ -27,12 +28,15 @@ class MotorEdge(edges.BaseEdge):
|
|||
25 * 2 ** 0.5, 45,
|
||||
55)
|
||||
|
||||
|
||||
class OutsetEdge(edges.OutSetEdge):
|
||||
def startwidth(self):
|
||||
return 20
|
||||
|
||||
|
||||
class HangerEdge(edges.BaseEdge):
|
||||
char = "H"
|
||||
|
||||
def margin(self):
|
||||
return 40
|
||||
|
||||
|
@ -49,9 +53,11 @@ class HangerEdge(edges.BaseEdge):
|
|||
l - 28, 45,
|
||||
2 ** 0.5 * 5, 45, 5, -90)
|
||||
|
||||
|
||||
class RollerEdge(edges.BaseEdge):
|
||||
def margin(self):
|
||||
return 20
|
||||
|
||||
def __call__(self, l, **kw):
|
||||
m = 40 + 100
|
||||
self.polyline((l - m) / 2.0, -45,
|
||||
|
@ -60,6 +66,7 @@ class RollerEdge(edges.BaseEdge):
|
|||
2 ** 0.5 * 20, -45,
|
||||
(l - m) / 2.0)
|
||||
|
||||
|
||||
class RollerEdge2(edges.BaseEdge):
|
||||
def margin(self):
|
||||
return self.thickness
|
||||
|
@ -71,8 +78,10 @@ class RollerEdge2(edges.BaseEdge):
|
|||
self.polyline(0, a, f * 25, -a, l - 190, -a, f * 25, a, 0)
|
||||
self.edges["f"](70)
|
||||
|
||||
|
||||
class Rotary(Boxes):
|
||||
"""Rotary Attachment for engraving cylindrical objects in a laser cutter"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
# remove cli params you do not need
|
||||
|
@ -91,8 +100,6 @@ class Rotary(Boxes):
|
|||
"--knifethickness", action="store", type=float, default=8.,
|
||||
help="thickness of the knifes in mm. Use 0 for use with honey comb table.")
|
||||
|
||||
|
||||
|
||||
def mainPlate(self):
|
||||
# Motor block outer side
|
||||
t = self.thickness
|
||||
|
@ -129,14 +136,17 @@ class Rotary(Boxes):
|
|||
overallwidth = x + y
|
||||
overallheight = y
|
||||
ra = a / 2.0
|
||||
|
||||
if self.move(overallwidth, overallheight, move, before=True):
|
||||
return
|
||||
|
||||
self.moveTo(y / 2.0, 0)
|
||||
self.hole(0, y / 2., ra)
|
||||
self.hole(x, y / 2., ra)
|
||||
|
||||
if middleHole:
|
||||
self.hole(x / 2., y / 2., ra)
|
||||
|
||||
self.edge(10)
|
||||
self.edges["F"](60)
|
||||
self.polyline(x - 70, (180, y / 2.), x, (180, y / 2.))
|
||||
|
@ -154,6 +164,7 @@ class Rotary(Boxes):
|
|||
d = self.diameter / 2.0 + 1
|
||||
y = -0.6 * self.diameter + 2 * self.hh
|
||||
print(y)
|
||||
|
||||
self.hole(self.hl / 2 + d, y, self.axle / 2.0)
|
||||
self.hole(self.hl / 2 - d, y, self.axle / 2.0)
|
||||
self.hole(self.hl / 2 + d, y, self.diameter / 2.0)
|
||||
|
@ -181,29 +192,34 @@ class Rotary(Boxes):
|
|||
hh = self.hh = 40.
|
||||
hl = self.hl = 240
|
||||
# Base
|
||||
self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB, None, lambda:self.rectangularHole(hl/2+50, hh-t/2-1, 60, t+2)], move="up")
|
||||
self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB, None,
|
||||
lambda: self.rectangularHole(hl / 2 + 50, hh - t / 2 - 1,
|
||||
60, t + 2)], move="up")
|
||||
self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB], move="up")
|
||||
self.rectangularWall(hl, hw, edges="ffff", callback=[
|
||||
lambda: self.hole(hl/2-16-20, 25, 5)], move="up")
|
||||
self.rectangularWall(hl, hw, edges="ffff", callback=[lambda: self.hole(hl / 2 - 16 - 20, 25, 5)], move="up")
|
||||
self.ctx.save()
|
||||
self.rectangularWall(hw, hh, edges="hFeF", callback=[
|
||||
lambda: self.hole(hw/2, 15, 4)],move="right")
|
||||
|
||||
self.rectangularWall(hw, hh, edges="hFeF", callback=[lambda: self.hole(hw / 2, 15, 4)], move="right")
|
||||
self.rectangularWall(hw, hh, edges="hFeF", move="right")
|
||||
# Top
|
||||
th = 30
|
||||
# sides
|
||||
|
||||
self.rectangularWall(hw + 20, th, edges="fFeF", move="right",
|
||||
callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)])
|
||||
self.rectangularWall(hw + 20, th, edges="fFeF", move="right",
|
||||
callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)])
|
||||
self.ctx.restore()
|
||||
|
||||
self.rectangularWall(hw, hh, edges="hFeF", move="up only")
|
||||
outset = OutsetEdge(self, None)
|
||||
roller2 = RollerEdge2(self, None)
|
||||
self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[
|
||||
lambda:self.hole(20, 15, a/2), None, lambda:self.rectangularHole(50, th-15, 70, a, r=a/2)], move="up")
|
||||
lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15, 70, a, r=a / 2)],
|
||||
move="up")
|
||||
self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[
|
||||
lambda:self.hole(20, 15, a/2), None, lambda:self.rectangularHole(50, th-15-t, 70, a, r=a/2)], move="up")
|
||||
lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15 - t, 70, a, r=a / 2)],
|
||||
move="up")
|
||||
self.rectangularWall(hl, th, edges=[roller2, "f", RollerEdge(self, None), "f"], callback=[
|
||||
self.holderTopCB], move="up")
|
||||
self.rectangularWall(hl, 20 - t, edges="feee", move="up")
|
||||
|
@ -248,6 +264,7 @@ class Rotary(Boxes):
|
|||
|
||||
self.ctx.restore()
|
||||
self.rectangularWall(30, 30, move="up only")
|
||||
|
||||
# Other side
|
||||
if self.knifethickness:
|
||||
ow = 10
|
||||
|
@ -265,8 +282,10 @@ class Rotary(Boxes):
|
|||
|
||||
# Motor block
|
||||
mw = 40
|
||||
self.rectangularWall(3.6*d, 1.1*d, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.mainPlate], move="up")
|
||||
self.rectangularWall(3.6*d, 1.1*d, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.frontPlate], move="up")
|
||||
self.rectangularWall(3.6 * d, 1.1 * d, edges=["h", "f", MotorEdge(self, None), "f"], callback=[self.mainPlate],
|
||||
move="up")
|
||||
self.rectangularWall(3.6 * d, 1.1 * d, edges=["h", "f", MotorEdge(self, None), "f"], callback=[self.frontPlate],
|
||||
move="up")
|
||||
self.rectangularWall(3.6 * d, mw, edges="ffff", move="up")
|
||||
self.ctx.save()
|
||||
self.rectangularWall(mw, 1.1 * d, edges="hFeH", move="right")
|
||||
|
@ -277,16 +296,19 @@ class Rotary(Boxes):
|
|||
self.ctx.restore()
|
||||
self.rectangularWall(mw, 1.1 * d, edges="hFeH", move="up only")
|
||||
self.axle = 19
|
||||
|
||||
for i in range(3):
|
||||
self.parts.disc(self.diameter - 2 * self.rubberthickness,
|
||||
hole=self.axle, move="right")
|
||||
self.parts.disc(self.diameter - 2 * self.rubberthickness,
|
||||
hole=self.axle, move="up right")
|
||||
|
||||
for i in range(3):
|
||||
self.parts.disc(self.diameter - 2 * self.rubberthickness,
|
||||
hole=self.axle, move="left")
|
||||
self.parts.disc(self.diameter - 2 * self.rubberthickness,
|
||||
hole=self.axle, move="left up")
|
||||
|
||||
for i in range(3):
|
||||
self.parts.disc(self.diameter - 2 * self.rubberthickness + 4,
|
||||
hole=self.axle, move="right")
|
||||
|
@ -295,10 +317,12 @@ class Rotary(Boxes):
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Box()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
from boxes import Boxes
|
||||
|
||||
|
||||
class Silverware(Boxes):
|
||||
"""Not yet parametrized cuttlery stand with carrying grip
|
||||
using flex for rounded corners"""
|
||||
|
@ -78,6 +79,7 @@ using flex for rounded corners"""
|
|||
self.centerWall(x, h)
|
||||
|
||||
l = (y - t) / 2.0
|
||||
|
||||
for i in range(3):
|
||||
self.rectangularWall(l, h - 10, edges="ffef", move="right")
|
||||
|
||||
|
@ -86,10 +88,12 @@ using flex for rounded corners"""
|
|||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = Silverware()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,13 +16,16 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class TrayInsert(Boxes):
|
||||
"""Tray insert without floor and outer walls - allows only continuous walls"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("sx", "sy", "h", "outside")
|
||||
|
||||
def render(self):
|
||||
|
||||
if self.outside:
|
||||
self.sx = self.adjustSize(self.sx, False, False)
|
||||
self.sy = self.adjustSize(self.sy, False, False)
|
||||
|
@ -37,19 +40,20 @@ class TrayInsert(Boxes):
|
|||
# Inner walls
|
||||
for i in range(len(self.sx) - 1):
|
||||
e = [edges.SlottedEdge(self, self.sy, slots=0.5 * h), "e", "e", "e"]
|
||||
self.rectangularWall(y, h, e,
|
||||
move="up")
|
||||
self.rectangularWall(y, h, e, move="up")
|
||||
|
||||
for i in range(len(self.sy) - 1):
|
||||
e = ["e", "e",
|
||||
edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5*h), "e"]
|
||||
self.rectangularWall(x, h, e,
|
||||
move="up")
|
||||
e = ["e", "e", edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * h), "e"]
|
||||
self.rectangularWall(x, h, e, move="up")
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = TrayInsert()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -18,8 +18,8 @@ import sys, re
|
|||
from boxes import *
|
||||
import boxes
|
||||
|
||||
class Layout(Boxes):
|
||||
|
||||
class Layout(Boxes):
|
||||
"""Generate a typetray from a layout file"""
|
||||
|
||||
webinterface = False
|
||||
|
@ -50,14 +50,17 @@ class Layout(Boxes):
|
|||
|
||||
def __str__(self):
|
||||
r = []
|
||||
|
||||
for i, x in enumerate(self.x):
|
||||
r.append(" |" * (i) + " ,> %.1fmm\n" % x)
|
||||
|
||||
for hwalls, vwalls, floors, y in zip(
|
||||
self.hwalls, self.vwalls, self.floors, self.y):
|
||||
r.append("".join(("+" + " -"[h] for h in hwalls)) + "+\n")
|
||||
r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors)))
|
||||
+ " |"[vwalls[-1]] + " %.1fmm\n" % y)
|
||||
r.append("".join(("+" + " -"[h] for h in self.hwalls[-1])) + "+\n")
|
||||
|
||||
return "".join(r)
|
||||
|
||||
def vWalls(self, x, y):
|
||||
|
@ -65,8 +68,10 @@ class Layout(Boxes):
|
|||
result = 0
|
||||
if y > 0 and self.vwalls[y - 1][x]:
|
||||
result += 1
|
||||
|
||||
if y < len(self.y) and self.vwalls[y][x]:
|
||||
result += 1
|
||||
|
||||
return result
|
||||
|
||||
def hWalls(self, x, y):
|
||||
|
@ -99,6 +104,7 @@ class Layout(Boxes):
|
|||
self.x = self.adjustSize(self.x)
|
||||
self.y = self.adjustSize(self.y)
|
||||
self.h = self.adjustSize(self.h, e2=False)
|
||||
|
||||
if self.hi:
|
||||
self.hi = self.adjustSize(self.hi, e2=False)
|
||||
|
||||
|
@ -128,20 +134,28 @@ class Layout(Boxes):
|
|||
h = self.h
|
||||
else:
|
||||
h = self.hi
|
||||
|
||||
start = 0
|
||||
end = 0
|
||||
|
||||
while end < lx:
|
||||
lengths = []
|
||||
edges = []
|
||||
while start < lx and not self.hwalls[y][start]: start += 1
|
||||
|
||||
while start < lx and not self.hwalls[y][start]:
|
||||
start += 1
|
||||
|
||||
if start == lx:
|
||||
break
|
||||
|
||||
end = start
|
||||
|
||||
while end < lx and self.hwalls[y][end]:
|
||||
if self.hFloor(end, y):
|
||||
edges.append("f")
|
||||
else:
|
||||
edges.append("e") # XXX E?
|
||||
|
||||
lengths.append(self.x[end])
|
||||
edges.append("eCs"[self.vWalls(end + 1, y)])
|
||||
lengths.append(self.thickness)
|
||||
|
@ -170,18 +184,24 @@ class Layout(Boxes):
|
|||
h = self.hi
|
||||
start = 0
|
||||
end = 0
|
||||
|
||||
while end < ly:
|
||||
lengths = []
|
||||
edges = []
|
||||
while start < ly and not self.vwalls[start][x]: start += 1
|
||||
while start < ly and not self.vwalls[start][x]:
|
||||
start += 1
|
||||
|
||||
if start == ly:
|
||||
break
|
||||
|
||||
end = start
|
||||
|
||||
while end < ly and self.vwalls[end][x]:
|
||||
if self.vFloor(x, end):
|
||||
edges.append("f")
|
||||
else:
|
||||
edges.append("e") # XXX E?
|
||||
|
||||
lengths.append(self.y[end])
|
||||
edges.append("eCs"[self.hWalls(x, end + 1)])
|
||||
lengths.append(self.thickness)
|
||||
|
@ -308,7 +328,6 @@ class Layout(Boxes):
|
|||
pass
|
||||
# raise ValueError(line)
|
||||
|
||||
|
||||
hwalls.append(w)
|
||||
if line[0] in " |":
|
||||
w = []
|
||||
|
@ -349,7 +368,8 @@ class Layout(Boxes):
|
|||
raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly))
|
||||
for nr, walls in enumerate(vwalls):
|
||||
if len(walls) != lx + 1:
|
||||
raise ValueError("Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx+1))
|
||||
raise ValueError(
|
||||
"Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1))
|
||||
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
@ -357,8 +377,8 @@ class Layout(Boxes):
|
|||
self.vwalls = vwalls
|
||||
self.floors = floors
|
||||
|
||||
class TrayLayout(Layout):
|
||||
|
||||
class TrayLayout(Layout):
|
||||
"""Type tray with each wall and floor tile being optional"""
|
||||
|
||||
webinterface = True
|
||||
|
@ -376,8 +396,8 @@ class TrayLayout(Layout):
|
|||
def render(self):
|
||||
return
|
||||
|
||||
class TrayLayout2(Layout):
|
||||
|
||||
class TrayLayout2(Layout):
|
||||
"""Generate a typetray from a layout file"""
|
||||
|
||||
webinterface = True
|
||||
|
@ -388,6 +408,7 @@ class TrayLayout2(Layout):
|
|||
self.argparser.add_argument(
|
||||
"--layout", action="store", type=str)
|
||||
|
||||
|
||||
def main():
|
||||
l = Layout()
|
||||
l.parseArgs()
|
||||
|
@ -404,5 +425,6 @@ def main():
|
|||
else:
|
||||
l.argparser.print_usage()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
from boxes import *
|
||||
|
||||
|
||||
class TypeTray(Boxes):
|
||||
"""Type tray - allows only continuous walls"""
|
||||
|
||||
def __init__(self):
|
||||
Boxes.__init__(self)
|
||||
self.buildArgParser("sx", "sy", "h", "hi", "outside")
|
||||
|
@ -88,35 +90,31 @@ class TypeTray(Boxes):
|
|||
self.open()
|
||||
|
||||
# outer walls
|
||||
self.rectangularWall(x, h, "Ffef", callback=[
|
||||
self.xHoles, None, self.gripHole],
|
||||
move="right")
|
||||
self.rectangularWall(y, h, "FFeF", callback=[self.yHoles,],
|
||||
move="up")
|
||||
self.rectangularWall(x, h, "Ffef", callback=[self.xHoles, None, self.gripHole], move="right")
|
||||
self.rectangularWall(y, h, "FFeF", callback=[self.yHoles, ], move="up")
|
||||
self.rectangularWall(y, h, "FFeF", callback=[self.yHoles, ])
|
||||
self.rectangularWall(x, h, "Ffef", callback=[self.xHoles,],
|
||||
move="left up")
|
||||
self.rectangularWall(x, h, "Ffef", callback=[self.xHoles, ], move="left up")
|
||||
|
||||
# floor
|
||||
self.rectangularWall(x, y, "ffff",
|
||||
callback=[self.xSlots, self.ySlots],
|
||||
move="right")
|
||||
self.rectangularWall(x, y, "ffff", callback=[self.xSlots, self.ySlots],move="right")
|
||||
# Inner walls
|
||||
for i in range(len(self.sx) - 1):
|
||||
e = [edges.SlottedEdge(self, self.sy, "f", slots=0.5 * hi), "f", "e", "f"]
|
||||
self.rectangularWall(y, hi, e,
|
||||
move="up")
|
||||
self.rectangularWall(y, hi, e, move="up")
|
||||
|
||||
for i in range(len(self.sy) - 1):
|
||||
e = [edges.SlottedEdge(self, self.sx, "f"), "f",
|
||||
edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * hi), "f"]
|
||||
self.rectangularWall(x, hi, e,
|
||||
move="up")
|
||||
self.rectangularWall(x, hi, e, move="up")
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
def main():
|
||||
b = TypeTray()
|
||||
b.parseArgs()
|
||||
b.render()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
from math import *
|
||||
|
||||
|
||||
def arcOnCircle(spanning_angle, outgoing_angle, r=1.0):
|
||||
angle = spanning_angle + 2 * outgoing_angle
|
||||
radius = r * sin(radians(0.5 * spanning_angle)) / sin(radians(180 - outgoing_angle - 0.5 * spanning_angle))
|
||||
return angle, abs(radius)
|
||||
|
||||
class Parts:
|
||||
|
||||
class Parts:
|
||||
def __init__(self, boxes):
|
||||
self.boxes = boxes
|
||||
|
||||
"""
|
||||
def roundKnob(self, diameter, n=20, callback=None, move=""):
|
||||
size = diameter+diameter/n
|
||||
|
@ -26,11 +28,15 @@ class Parts:
|
|||
def disc(self, diameter, hole=0, callback=None, move=""):
|
||||
size = diameter
|
||||
r = diameter / 2.0
|
||||
|
||||
if self.move(size, size, move, before=True):
|
||||
return
|
||||
|
||||
self.moveTo(size / 2, size / 2)
|
||||
|
||||
if hole:
|
||||
self.hole(0, 0, hole / 2)
|
||||
|
||||
self.cc(callback, None, 0, 0)
|
||||
self.moveTo(r + self.burn, 0, 90)
|
||||
self.corner(360, r)
|
||||
|
@ -38,33 +44,45 @@ class Parts:
|
|||
|
||||
def waivyKnob(self, diameter, n=20, angle=45, hole=0, callback=None, move=""):
|
||||
size = diameter + pi * diameter / n
|
||||
|
||||
if self.move(size, size, move, before=True):
|
||||
return
|
||||
|
||||
self.moveTo(size / 2, size / 2)
|
||||
self.cc(callback, None, 0, 0)
|
||||
|
||||
if hole:
|
||||
self.hole(0, 0, hole / 2)
|
||||
|
||||
self.moveTo(diameter / 2, 0, angle)
|
||||
a, r = arcOnCircle(360. / n, angle, diameter / 2)
|
||||
a2, r2 = arcOnCircle(360. / n, -angle, diameter / 2)
|
||||
|
||||
for i in range(n // 2):
|
||||
self.boxes.corner(a, r)
|
||||
self.boxes.corner(a2, r2)
|
||||
|
||||
self.move(size, size, move)
|
||||
|
||||
def concaveKnob(self, diameter, n=3, rounded=0.2, angle=70, hole=0,
|
||||
callback=None, move=""):
|
||||
size = diameter
|
||||
|
||||
if self.move(size, size, move, before=True):
|
||||
return
|
||||
|
||||
self.moveTo(size / 2, size / 2)
|
||||
|
||||
if hole:
|
||||
self.hole(0, 0, hole / 2)
|
||||
|
||||
self.cc(callback, None, 0, 0)
|
||||
self.moveTo(diameter / 2, 0, 90 + angle)
|
||||
a, r = arcOnCircle(360. / n * (1 - rounded), -angle, diameter / 2)
|
||||
|
||||
if abs(a) < 0.01: # avoid trying to make a straight line as an arc
|
||||
a, r = arcOnCircle(360. / n * (1 - rounded), -angle - 0.01, diameter / 2)
|
||||
|
||||
for i in range(n):
|
||||
self.boxes.corner(a, r)
|
||||
self.corner(angle)
|
||||
|
@ -72,5 +90,3 @@ class Parts:
|
|||
self.corner(angle)
|
||||
|
||||
self.move(size, size, move)
|
||||
|
||||
|
||||
|
|
|
@ -14,12 +14,15 @@
|
|||
from math import *
|
||||
from boxes.vectors import *
|
||||
|
||||
|
||||
def tooth_spaceing_curvefit(teeth, b, c, d):
|
||||
return ((c * teeth ** d) / (b + teeth ** d)) * teeth
|
||||
|
||||
|
||||
def tooth_spacing(teeth, tooth_pitch, pitch_line_offset):
|
||||
return (2 * ((teeth * tooth_pitch) / (3.14159265 * 2) - pitch_line_offset))
|
||||
|
||||
|
||||
def mirrorx(points):
|
||||
return [[-x, y] for x, y in points]
|
||||
|
||||
|
@ -41,6 +44,7 @@ class Pulley:
|
|||
"GT2_3mm": (False, 3, 0.381),
|
||||
"GT2_5mm": (False, 5, 0.5715),
|
||||
}
|
||||
|
||||
profile_data = {
|
||||
"MXL": (0.508, 1.321),
|
||||
"40DP": (0.457, 1.226),
|
||||
|
@ -86,16 +90,17 @@ class Pulley:
|
|||
lines = kerf(lines, self.boxes.burn * kerfdir)
|
||||
self.boxes.ctx.save()
|
||||
self.boxes.ctx.move_to(*lines[0])
|
||||
|
||||
for x, y in lines[1:]:
|
||||
self.boxes.ctx.line_to(x, y)
|
||||
|
||||
self.boxes.ctx.line_to(*lines[0])
|
||||
self.boxes.ctx.restore()
|
||||
|
||||
def diameter(self, teeth, profile):
|
||||
if self.spacing[profile][0]:
|
||||
return tooth_spaceing_curvefit(
|
||||
teeth, *self.spacing[profile][1:])
|
||||
else:
|
||||
return tooth_spaceing_curvefit(teeth, *self.spacing[profile][1:])
|
||||
|
||||
return tooth_spacing(teeth, *self.spacing[profile][1:])
|
||||
|
||||
def __call__(self, teeth, profile, move="", r_axle=None, callback=None):
|
||||
|
@ -118,18 +123,22 @@ class Pulley:
|
|||
tooth_depth_scale = ((tooth_depth + additional_tooth_depth) / tooth_depth)
|
||||
|
||||
total_width = pulley_OD
|
||||
|
||||
if self.boxes.move(total_width, total_width, move, before=True):
|
||||
return
|
||||
|
||||
self.boxes.moveTo(total_width / 2, total_width / 2)
|
||||
self.boxes.cc(callback, None, 0.0, 0.0)
|
||||
|
||||
if r_axle:
|
||||
self.boxes.hole(0, 0, r_axle)
|
||||
|
||||
points = []
|
||||
for i in range(teeth):
|
||||
m = [[tooth_width_scale, 0, 0],
|
||||
[0, tooth_depth_scale, -tooth_distance_from_centre]]
|
||||
m = mmul(m, rotm(i * 2 * pi / teeth))
|
||||
points.extend((vtransl(pt, m) for pt in self.teeth[profile][1:-1]))
|
||||
self.drawPoints(points)
|
||||
|
||||
self.drawPoints(points)
|
||||
self.boxes.move(total_width, total_width, move)
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
import xml.parsers.expat
|
||||
import re
|
||||
|
||||
class SVGFile(object):
|
||||
|
||||
class SVGFile(object):
|
||||
pathre = re.compile(r"[MCL]? *((-?\d+(\.\d+)?) (-?\d+(\.\d+)?) *)+")
|
||||
transformre = re.compile(r"matrix\(" + ",".join([r"(-?\d+(\.\d+)?)"] * 6) + "\)")
|
||||
|
||||
|
@ -31,12 +31,14 @@ class SVGFile(object):
|
|||
if name == "path" and "symbol" not in self.tags:
|
||||
minx = maxx = miny = maxy = None
|
||||
m = self.transformre.match(attrs.get("transform", ""))
|
||||
|
||||
if m:
|
||||
matrix = [float(m.group(i)) for i in range(1, 12, 2)]
|
||||
else:
|
||||
matrix = [1, 0,
|
||||
0, 1,
|
||||
0, 0]
|
||||
|
||||
for m in self.pathre.findall(attrs.get("d", "")):
|
||||
x = float(m[1])
|
||||
y = float(m[3])
|
||||
|
@ -45,15 +47,19 @@ class SVGFile(object):
|
|||
|
||||
if self.minx is None or self.minx > tx:
|
||||
self.minx = tx
|
||||
|
||||
if self.maxx is None or self.maxx < tx:
|
||||
self.maxx = tx
|
||||
|
||||
if self.miny is None or self.miny > ty:
|
||||
self.miny = ty
|
||||
|
||||
if self.maxy is None or self.maxy < ty:
|
||||
self.maxy = ty
|
||||
|
||||
def handleEndElement(self, name):
|
||||
last = self.tags.pop()
|
||||
|
||||
if last != name:
|
||||
raise ValueError("Got </%s> expected </%s>" % (name, last))
|
||||
|
||||
|
@ -85,8 +91,10 @@ class SVGFile(object):
|
|||
f.seek(m.start(1))
|
||||
s = ('width="%imm" height="%imm" viewBox="0 %i %i %i"' %
|
||||
(maxx - minx, maxy - miny, miny, maxx, maxy - miny))
|
||||
|
||||
if len(s) > len(m.group(1)):
|
||||
raise ValueError("Not enough space for size")
|
||||
|
||||
f.write(s + " " * (len(m.group(1)) - len(s)))
|
||||
else:
|
||||
raise ValueError("Could not understand SVG file")
|
||||
|
|
|
@ -14,51 +14,62 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import math
|
||||
|
||||
|
||||
def normalize(v):
|
||||
"set lenght of vector to one"
|
||||
l = (v[0] ** 2 + v[1] ** 2) ** 0.5
|
||||
return (v[0] / l, v[1] / l)
|
||||
|
||||
|
||||
def vlength(v):
|
||||
return (v[0] ** 2 + v[1] ** 2) ** 0.5
|
||||
|
||||
|
||||
def vclip(v, length):
|
||||
l = vlength(v)
|
||||
if l > length:
|
||||
return vscalmul(v, length / l)
|
||||
return v
|
||||
|
||||
|
||||
def vdiff(p1, p2):
|
||||
"vector from point1 to point2"
|
||||
return (p2[0] - p1[0], p2[1] - p1[1])
|
||||
|
||||
|
||||
def vadd(v1, v2):
|
||||
"Sum of two vectors"
|
||||
return (v1[0] + v2[0], v1[1] + v2[1])
|
||||
|
||||
|
||||
def vorthogonal(v):
|
||||
"orthogonal vector"
|
||||
"Orthogonal vector"
|
||||
return (-v[1], v[0])
|
||||
|
||||
|
||||
def vscalmul(v, a):
|
||||
"scale vector by a"
|
||||
return (a * v[0], a * v[1])
|
||||
|
||||
|
||||
def dotproduct(v1, v2):
|
||||
"Dot product"
|
||||
return v1[0] * v2[0] + v1[1] * v2[1]
|
||||
|
||||
|
||||
def rotm(angle):
|
||||
"Rotation matrix"
|
||||
return [[math.cos(angle), -math.sin(angle), 0],
|
||||
[math.sin(angle), math.cos(angle), 0]]
|
||||
|
||||
|
||||
def vtransl(v, m):
|
||||
m0, m1 = m
|
||||
return [m0[0] * v[0] + m0[1] * v[1] + m0[2],
|
||||
m1[0] * v[0] + m1[1] * v[1] + m1[2]]
|
||||
|
||||
|
||||
def mmul(m0, m1):
|
||||
result = [[0, ] * len(m0[0]) for i in range(len(m0))]
|
||||
for i in range(len(m0[0])):
|
||||
|
@ -67,12 +78,14 @@ def mmul(m0, m1):
|
|||
result[j][i] += m0[k][i] * m1[j][k]
|
||||
return result
|
||||
|
||||
|
||||
def kerf(points, k):
|
||||
"""Outset points by k
|
||||
Assumes a closed loop of points
|
||||
"""
|
||||
result = []
|
||||
lp = len(points)
|
||||
|
||||
for i in range(len(points)):
|
||||
# get normalized orthogonals of both segments
|
||||
v1 = vorthogonal(normalize(vdiff(points[i - 1], points[i])))
|
||||
|
@ -82,4 +95,5 @@ def kerf(points, k):
|
|||
# cos of the half the angle between the segments
|
||||
cos_alpha = dotproduct(v1, d)
|
||||
result.append(vadd(points[i], vscalmul(d, -k / cos_alpha)))
|
||||
|
||||
return result
|
||||
|
|
Loading…
Reference in New Issue