Code Reformat #1

This commit is contained in:
schinken 2016-08-17 15:07:41 +02:00
parent af167295b8
commit 93af56ff9c
33 changed files with 1405 additions and 1097 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@
build/ build/
dist/ dist/
boxes.py.egg-info/ boxes.py.egg-info/
.idea

View File

@ -16,6 +16,7 @@
try: try:
import cairocffi import cairocffi
cairocffi.install_as_pycairo() cairocffi.install_as_pycairo()
except ImportError: except ImportError:
pass pass
@ -31,6 +32,7 @@ from boxes import gears
from boxes import pulley from boxes import pulley
from boxes import parts from boxes import parts
### Helpers ### Helpers
def dist(dx, dy): def dist(dx, dy):
@ -40,7 +42,8 @@ def dist(dx, dy):
:param dx: delta x :param dx: delta x
:param dy: delat y :param dy: delat y
""" """
return (dx*dx+dy*dy)**0.5 return (dx * dx + dy * dy) ** 0.5
def restore(func): def restore(func):
""" """
@ -49,6 +52,7 @@ def restore(func):
:param func: function to wrap :param func: function to wrap
""" """
@wraps(func) @wraps(func)
def f(self, *args, **kw): def f(self, *args, **kw):
self.ctx.save() self.ctx.save()
@ -56,8 +60,10 @@ def restore(func):
func(self, *args, **kw) func(self, *args, **kw)
self.ctx.restore() self.ctx.restore()
self.ctx.move_to(*pt) self.ctx.move_to(*pt)
return f return f
def holeCol(func): def holeCol(func):
""" """
Wrapper: color holes differently Wrapper: color holes differently
@ -65,6 +71,7 @@ def holeCol(func):
:param func: function to wrap :param func: function to wrap
""" """
@wraps(func) @wraps(func)
def f(self, *args, **kw): def f(self, *args, **kw):
self.ctx.stroke() self.ctx.stroke()
@ -72,8 +79,8 @@ def holeCol(func):
func(self, *args, **kw) func(self, *args, **kw)
self.ctx.stroke() self.ctx.stroke()
self.ctx.set_source_rgb(0.0, 0.0, 0.0) self.ctx.set_source_rgb(0.0, 0.0, 0.0)
return f
return f
############################################################################# #############################################################################
@ -83,26 +90,26 @@ def holeCol(func):
class NutHole: class NutHole:
"""Draw a hex nut""" """Draw a hex nut"""
sizes = { sizes = {
"M1.6" : (3.2, 1.3), "M1.6": (3.2, 1.3),
"M2" : (4, 1.6), "M2": (4, 1.6),
"M2.5" : (5, 2.0), "M2.5": (5, 2.0),
"M3" : (5.5, 2.4), "M3": (5.5, 2.4),
"M4" : (7, 3.2), "M4": (7, 3.2),
"M5" : (8, 4.7), "M5": (8, 4.7),
"M6" : (10, 5.2), "M6": (10, 5.2),
"M8" : (13, 6.8), "M8": (13, 6.8),
"M10" : (16, 8.4), "M10": (16, 8.4),
"M12" : (18, 10.8), "M12": (18, 10.8),
"M14" : (21, 12.8), "M14": (21, 12.8),
"M16" : (24, 14.8), "M16": (24, 14.8),
"M20" : (30, 18.0), "M20": (30, 18.0),
"M24" : (36, 21.5), "M24": (36, 21.5),
"M30" : (46, 25.6), "M30": (46, 25.6),
"M36" : (55, 31), "M36": (55, 31),
"M42" : (65, 34), "M42": (65, 34),
"M48" : (75, 38), "M48": (75, 38),
"M56" : (85, 45), "M56": (85, 45),
"M64" : (95, 51), "M64": (95, 51),
} }
def __init__(self, boxes, settings): def __init__(self, boxes, settings):
@ -114,13 +121,14 @@ class NutHole:
@holeCol @holeCol
def __call__(self, size, x=0, y=0, angle=0): def __call__(self, size, x=0, y=0, angle=0):
size = self.sizes.get(size, (size,))[0] size = self.sizes.get(size, (size,))[0]
side = size / 3**0.5 side = size / 3 ** 0.5
self.boxes.moveTo(x, y, angle) self.boxes.moveTo(x, y, angle)
self.boxes.moveTo(-0.5*side, 0.5*size, angle) self.boxes.moveTo(-0.5 * side, 0.5 * size, angle)
for i in range(6): for i in range(6):
self.boxes.edge(side) self.boxes.edge(side)
self.boxes.corner(-60) self.boxes.corner(-60)
############################################################################## ##############################################################################
### Argument types ### Argument types
############################################################################## ##############################################################################
@ -135,17 +143,18 @@ def argparseSections(s):
m = re.match(r"(\d+(\.\d+)?)/(\d+)", s) m = re.match(r"(\d+(\.\d+)?)/(\d+)", s)
if m: if m:
n = int(m.group(3)) n = int(m.group(3))
print([ float(m.group(1)) ] * n) print([float(m.group(1))] * n)
return [ float(m.group(1))/n ] * n return [float(m.group(1)) / n] * n
m = re.match(r"(\d+(\.\d+)?)\*(\d+)", s) m = re.match(r"(\d+(\.\d+)?)\*(\d+)", s)
if m: if m:
n = int(m.group(3)) n = int(m.group(3))
return [ float(m.group(1)) ] * n return [float(m.group(1))] * n
try: try:
return [float(part) for part in s.split(":")] return [float(part) for part in s.split(":")]
except ValueError: except ValueError:
raise argparse.ArgumentTypeError("Don't understand sections string") raise argparse.ArgumentTypeError("Don't understand sections string")
class ArgparseEdgeType: class ArgparseEdgeType:
names = edges.getDescriptions() names = edges.getDescriptions()
edges = [] edges = []
@ -169,6 +178,7 @@ class ArgparseEdgeType:
e, self.names.get(e, "")) for e in self.edges)) e, self.names.get(e, "")) for e in self.edges))
return """<select name="%s" size="1">\n%s</select>\n""" % (name, options) return """<select name="%s" size="1">\n%s</select>\n""" % (name, options)
############################################################################## ##############################################################################
### Main class ### Main class
############################################################################## ##############################################################################
@ -216,21 +226,21 @@ class Boxes:
Call this function from your .render() method Call this function from your .render() method
""" """
self.spacing = 2*self.burn + 0.5 * self.thickness self.spacing = 2 * self.burn + 0.5 * self.thickness
self.bedBoltSettings = (3, 5.5, 2, 20, 15) #d, d_nut, h_nut, l, l1 self.bedBoltSettings = (3, 5.5, 2, 20, 15) # d, d_nut, h_nut, l, l1
self.hexHolesSettings = (5, 3, 'circle') # r, dist, style self.hexHolesSettings = (5, 3, 'circle') # r, dist, style
self.surface, self.ctx = self.formats.getSurface(self.format, self.output) self.surface, self.ctx = self.formats.getSurface(self.format, self.output)
self.ctx.set_line_width(2*self.burn) self.ctx.set_line_width(2 * self.burn)
self._buildObjects() self._buildObjects()
if self.reference: if self.reference:
self.move(10, 10, "up", before=True) self.move(10, 10, "up", before=True)
self.ctx.rectangle(0, 0, self.reference, 10) self.ctx.rectangle(0, 0, self.reference, 10)
if self.reference < 40: if self.reference < 40:
self.text("%.fmm" % self.reference, self.reference+5, 5, self.text("%.fmm" % self.reference, self.reference + 5, 5,
align="middle left") align="middle left")
else: else:
self.text("%.fmm" % self.reference, self.reference/2.0, 5, self.text("%.fmm" % self.reference, self.reference / 2.0, 5,
align="middle center") align="middle center")
self.move(10, 10, "up") self.move(10, 10, "up")
@ -280,7 +290,7 @@ class Boxes:
"--top_edge", action="store", "--top_edge", action="store",
type=ArgparseEdgeType("ecESik"), choices=list("ecESik"), type=ArgparseEdgeType("ecESik"), choices=list("ecESik"),
default="e", help="edge type for top edge") default="e", help="edge type for top edge")
elif arg=="outside": elif arg == "outside":
self.argparser.add_argument( self.argparser.add_argument(
"--outside", action="store", type=bool, default=False, "--outside", action="store", type=bool, default=False,
help="treat sizes as outside measurements that include the walls") help="treat sizes as outside measurements that include the walls")
@ -294,7 +304,7 @@ class Boxes:
:param args: (Default value = None) parameters, None for using sys.argv :param args: (Default value = None) parameters, None for using sys.argv
""" """
for key,value in vars(self.argparser.parse_args(args=args)).items(): for key, value in vars(self.argparser.parse_args(args=args)).items():
setattr(self, key, value) setattr(self, key, value)
# Change file ending to format if not given explicitly # Change file ending to format if not given explicitly
@ -312,7 +322,7 @@ class Boxes:
if name is None: if name is None:
name = part.__class__.__name__ name = part.__class__.__name__
name = name[0].lower() + name[1:] name = name[0].lower() + name[1:]
#if not hasattr(self, name): # if not hasattr(self, name):
if isinstance(part, edges.BaseEdge): if isinstance(part, edges.BaseEdge):
self.edges[part.char] = part self.edges[part.char] = part
else: else:
@ -354,9 +364,11 @@ class Boxes:
self.addPart(edges.ClickEdge(self, s)) self.addPart(edges.ClickEdge(self, s))
# Hinges # Hinges
s = edges.HingeSettings(self.thickness) s = edges.HingeSettings(self.thickness)
for i in range(1, 4): for i in range(1, 4):
self.addPart(edges.Hinge(self, s, i)) self.addPart(edges.Hinge(self, s, i))
self.addPart(edges.HingePin(self, s, i)) self.addPart(edges.HingePin(self, s, i))
# Nuts # Nuts
self.addPart(NutHole(self, None)) self.addPart(NutHole(self, None))
# Gears # Gears
@ -367,7 +379,7 @@ class Boxes:
def adjustSize(self, l, e1=True, e2=True): def adjustSize(self, l, e1=True, e2=True):
try: try:
total = sum(l) total = sum(l)
walls = (len(l)-1) * self.thickness walls = (len(l) - 1) * self.thickness
except TypeError: except TypeError:
total = l total = l
walls = 0 walls = 0
@ -376,14 +388,15 @@ class Boxes:
walls += e1.startwidth() + e1.margin() walls += e1.startwidth() + e1.margin()
elif e1: elif e1:
walls += self.thickness walls += self.thickness
if isinstance(e2, edges.BaseEdge): if isinstance(e2, edges.BaseEdge):
walls += e2.startwidth + e2.margin() walls += e2.startwidth + e2.margin()
elif e2: elif e2:
walls += self.thickness walls += self.thickness
try: try:
factor = (total-walls) / total factor = (total - walls) / total
return [s*factor for s in l] return [s * factor for s in l]
except TypeError: except TypeError:
return l - walls return l - walls
@ -414,6 +427,7 @@ class Boxes:
callback() callback()
else: else:
callback(number) callback(number)
elif hasattr(callback, '__getitem__'): elif hasattr(callback, '__getitem__'):
try: try:
callback = callback[number] callback = callback[number]
@ -424,6 +438,7 @@ class Boxes:
except: except:
self.ctx.restore() self.ctx.restore()
raise raise
self.ctx.restore() self.ctx.restore()
def getEntry(self, param, idx): def getEntry(self, param, idx):
@ -435,7 +450,7 @@ class Boxes:
""" """
if isinstance(param, list): if isinstance(param, list):
if len(param)>idx: if len(param) > idx:
return param[idx] return param[idx]
else: else:
return None return None
@ -466,16 +481,16 @@ class Boxes:
:param radius: (Default value = 0) :param radius: (Default value = 0)
""" """
rad = degrees*math.pi/180 rad = degrees * math.pi / 180
if degrees > 0: if degrees > 0:
self.ctx.arc(0, radius+self.burn, radius+self.burn, self.ctx.arc(0, radius + self.burn, radius + self.burn,
-0.5*math.pi, rad - 0.5*math.pi) -0.5 * math.pi, rad - 0.5 * math.pi)
elif radius > self.burn: elif radius > self.burn:
self.ctx.arc_negative(0, -(radius-self.burn), radius-self.burn, self.ctx.arc_negative(0, -(radius - self.burn), radius - self.burn,
0.5*math.pi, rad + 0.5*math.pi) 0.5 * math.pi, rad + 0.5 * math.pi)
else: # not rounded inner corner else: # not rounded inner corner
self.ctx.arc_negative(0, self.burn-radius, self.burn-radius, self.ctx.arc_negative(0, self.burn - radius, self.burn - radius,
-0.5*math.pi, -0.5*math.pi+rad) -0.5 * math.pi, -0.5 * math.pi + rad)
self.continueDirection(rad) self.continueDirection(rad)
@ -485,7 +500,7 @@ class Boxes:
:param length: length in mm :param length: length in mm
""" """
self.ctx.move_to(0,0) self.ctx.move_to(0, 0)
self.ctx.line_to(length, 0) self.ctx.line_to(length, 0)
self.ctx.translate(*self.ctx.get_current_point()) self.ctx.translate(*self.ctx.get_current_point())
@ -501,8 +516,8 @@ class Boxes:
""" """
self.ctx.curve_to(x1, y1, x2, y2, x3, y3) self.ctx.curve_to(x1, y1, x2, y2, x3, y3)
dx = x3-x2 dx = x3 - x2
dy = y3-y2 dy = y3 - y2
rad = math.atan2(dy, dx) rad = math.atan2(dy, dx)
self.continueDirection(rad) self.continueDirection(rad)
@ -532,37 +547,37 @@ class Boxes:
""" """
d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings
self.edge((length-d)/2.0) self.edge((length - d) / 2.0)
self.corner(90) self.corner(90)
self.edge(l1) self.edge(l1)
self.corner(90) self.corner(90)
self.edge((d_nut-d)/2.0) self.edge((d_nut - d) / 2.0)
self.corner(-90) self.corner(-90)
self.edge(h_nut) self.edge(h_nut)
self.corner(-90) self.corner(-90)
self.edge((d_nut-d)/2.0) self.edge((d_nut - d) / 2.0)
self.corner(90) self.corner(90)
self.edge(l-l1-h_nut) self.edge(l - l1 - h_nut)
self.corner(-90) self.corner(-90)
self.edge(d) self.edge(d)
self.corner(-90) self.corner(-90)
self.edge(l-l1-h_nut) self.edge(l - l1 - h_nut)
self.corner(90) self.corner(90)
self.edge((d_nut-d)/2.0) self.edge((d_nut - d) / 2.0)
self.corner(-90) self.corner(-90)
self.edge(h_nut) self.edge(h_nut)
self.corner(-90) self.corner(-90)
self.edge((d_nut-d)/2.0) self.edge((d_nut - d) / 2.0)
self.corner(90) self.corner(90)
self.edge(l1) self.edge(l1)
self.corner(90) self.corner(90)
self.edge((length-d)/2.0) self.edge((length - d) / 2.0)
def edgeCorner(self, edge1, edge2, angle=90): def edgeCorner(self, edge1, edge2, angle=90):
"""Make a corner between two Edges. Take width of edges into account""" """Make a corner between two Edges. Take width of edges into account"""
self.edge(edge2.startwidth()/math.sin(math.radians(180-angle))) self.edge(edge2.startwidth() / math.sin(math.radians(180 - angle)))
self.corner(angle) self.corner(angle)
self.edge(edge1.endwidth()/math.sin(math.radians(180-angle))) self.edge(edge1.endwidth() / math.sin(math.radians(180 - angle)))
def grip(self, length, depth): def grip(self, length, depth):
"""Corrugated edge useful as an gipping area """Corrugated edge useful as an gipping area
@ -571,7 +586,7 @@ class Boxes:
:param depth: depth of the grooves :param depth: depth of the grooves
""" """
grooves = int(length // (depth*2.0)) + 1 grooves = int(length // (depth * 2.0)) + 1
depth = length / grooves / 4.0 depth = length / grooves / 4.0
for groove in range(grooves): for groove in range(grooves):
self.corner(90, depth) self.corner(90, depth)
@ -584,11 +599,11 @@ class Boxes:
:param length: :param length:
""" """
self.edge(1.1*self.thickness) self.edge(1.1 * self.thickness)
self.corner(-90) self.corner(-90)
self.edge(length/2.0+0.2*self.thickness) self.edge(length / 2.0 + 0.2 * self.thickness)
self.corner(-90) self.corner(-90)
self.edge(1.1*self.thickness) self.edge(1.1 * self.thickness)
def _latchGrip(self, length): def _latchGrip(self, length):
""" """
@ -596,9 +611,9 @@ class Boxes:
:param length: :param length:
""" """
self.corner(90, self.thickness/4.0) self.corner(90, self.thickness / 4.0)
self.grip(length/2.0-self.thickness/2.0-0.2*self.thickness, self.thickness/2.0) self.grip(length / 2.0 - self.thickness / 2.0 - 0.2 * self.thickness, self.thickness / 2.0)
self.corner(90, self.thickness/4.0) self.corner(90, self.thickness / 4.0)
def latch(self, length, positive=True, reverse=False): def latch(self, length, positive=True, reverse=False):
"""Latch to fix a flex box door to the box """Latch to fix a flex box door to the box
@ -610,16 +625,16 @@ class Boxes:
""" """
if positive: if positive:
if reverse: if reverse:
self.edge(length/2.0-self.burn) self.edge(length / 2.0 - self.burn)
self.corner(-90) self.corner(-90)
self.edge(self.thickness) self.edge(self.thickness)
self.corner(90) self.corner(90)
self.edge(length/2.0) self.edge(length / 2.0)
self.corner(90) self.corner(90)
self.edge(self.thickness) self.edge(self.thickness)
self.corner(-90) self.corner(-90)
if not reverse: if not reverse:
self.edge(length/2.0-self.burn) self.edge(length / 2.0 - self.burn)
else: else:
if reverse: if reverse:
self._latchGrip(length) self._latchGrip(length)
@ -640,31 +655,31 @@ class Boxes:
:param r: (Default value = 30) radius of the corners :param r: (Default value = 30) radius of the corners
""" """
d = (x-hl-2*r)/2.0 d = (x - hl - 2 * r) / 2.0
if d < 0: if d < 0:
print("Handle too wide") print("Handle too wide")
self.ctx.save() self.ctx.save()
# Hole # Hole
self.moveTo(d+2*r, 0) self.moveTo(d + 2 * r, 0)
self.edge(hl-2*r) self.edge(hl - 2 * r)
self.corner(-90, r) self.corner(-90, r)
self.edge(h-3*r) self.edge(h - 3 * r)
self.corner(-90, r) self.corner(-90, r)
self.edge(hl-2*r) self.edge(hl - 2 * r)
self.corner(-90, r) self.corner(-90, r)
self.edge(h-3*r) self.edge(h - 3 * r)
self.corner(-90, r) self.corner(-90, r)
self.ctx.restore() self.ctx.restore()
self.moveTo(0,0) self.moveTo(0, 0)
self.curveTo(d, 0, d, 0, d, -h+r) self.curveTo(d, 0, d, 0, d, -h + r)
self.curveTo(r, 0, r, 0, r, r) self.curveTo(r, 0, r, 0, r, r)
self.edge(hl) self.edge(hl)
self.curveTo(r, 0, r, 0, r, r) self.curveTo(r, 0, r, 0, r, r)
self.curveTo(h-r, 0, h-r, 0, h-r, -d) self.curveTo(h - r, 0, h - r, 0, h - r, -d)
### Navigation ### Navigation
@ -679,7 +694,7 @@ class Boxes:
""" """
self.ctx.move_to(0, 0) self.ctx.move_to(0, 0)
self.ctx.translate(x, y) self.ctx.translate(x, y)
self.ctx.rotate(degrees*math.pi/180.0) self.ctx.rotate(degrees * math.pi / 180.0)
self.ctx.move_to(0, 0) self.ctx.move_to(0, 0)
def continueDirection(self, angle=0): def continueDirection(self, angle=0):
@ -715,10 +730,10 @@ class Boxes:
y += self.spacing y += self.spacing
moves = { moves = {
"up": (0, y, False), "up": (0, y, False),
"down" : (0, -y, True), "down": (0, -y, True),
"left" : (-x, 0, True), "left": (-x, 0, True),
"right" : (x, 0, False), "right": (x, 0, False),
"only" : (0, 0, None), "only": (0, 0, None),
} }
if not before: if not before:
@ -737,7 +752,7 @@ class Boxes:
if before: if before:
# save position # save position
self.ctx.save() self.ctx.save()
self.moveTo(self.spacing/2.0, self.spacing/2.0) self.moveTo(self.spacing / 2.0, self.spacing / 2.0)
return dontdraw return dontdraw
@restore @restore
@ -754,8 +769,8 @@ class Boxes:
r -= self.burn r -= self.burn
if r < 0: if r < 0:
r = 1E-9 r = 1E-9
self.moveTo(x+r, y) self.moveTo(x + r, y)
self.ctx.arc(-r, 0, r, 0, 2*math.pi) self.ctx.arc(-r, 0, r, 0, 2 * math.pi)
@restore @restore
@holeCol @holeCol
@ -770,10 +785,10 @@ class Boxes:
:param r: (Default value = 0) radius of the corners :param r: (Default value = 0) radius of the corners
""" """
self.moveTo(x+r-dx/2.0, y-dy/2.0, 180) self.moveTo(x + r - dx / 2.0, y - dy / 2.0, 180)
for d in (dy, dx, dy, dx): for d in (dy, dx, dy, dx):
self.corner(-90, r) self.corner(-90, r)
self.edge(d-2*r) self.edge(d - 2 * r)
@restore @restore
def text(self, text, x=0, y=0, angle=0, align=""): def text(self, text, x=0, y=0, angle=0, align=""):
@ -791,12 +806,12 @@ class Boxes:
(tx, ty, width, height, dx, dy) = self.ctx.text_extents(text) (tx, ty, width, height, dx, dy) = self.ctx.text_extents(text)
align = align.split() align = align.split()
moves = { moves = {
"top" : (0, -height), "top": (0, -height),
"middle" : (0, -0.5*height), "middle": (0, -0.5 * height),
"bottom" : (0, 0), "bottom": (0, 0),
"left" : (0, 0), "left": (0, 0),
"center" : (-0.5*width, 0), "center": (-0.5 * width, 0),
"right" : (-width, 0), "right": (-width, 0),
} }
for a in align: for a in align:
if a in moves: if a in moves:
@ -819,27 +834,26 @@ class Boxes:
""" """
nema = { nema = {
# motor,flange, holes, screws # motor,flange, holes, screws
8 : (20.3, 16, 15.4, 3), 8: (20.3, 16, 15.4, 3),
11 : (28.2, 22, 23, 4), 11: (28.2, 22, 23, 4),
14 : (35.2, 22, 26, 4), 14: (35.2, 22, 26, 4),
16 : (39.2, 22, 31, 4), 16: (39.2, 22, 31, 4),
17 : (42.2, 22, 31, 4), 17: (42.2, 22, 31, 4),
23 : (56.4, 38.1, 47.1, 5.2), 23: (56.4, 38.1, 47.1, 5.2),
24 : (60, 36, 49.8, 5.1), 24: (60, 36, 49.8, 5.1),
34 : (86.3, 73, 69.8, 6.6), 34: (86.3, 73, 69.8, 6.6),
42 : (110, 55.5, 89, 8.5), 42: (110, 55.5, 89, 8.5),
} }
width, flange, holedistance, diameter = nema[size] width, flange, holedistance, diameter = nema[size]
self.moveTo(x, y, angle) self.moveTo(x, y, angle)
if self.debug: if self.debug:
self.rectangularHole(0, 0, width, width) self.rectangularHole(0, 0, width, width)
self.hole(0,0, 0.5*flange) self.hole(0, 0, 0.5 * flange)
for x in (-1, 1): for x in (-1, 1):
for y in (-1, 1): for y in (-1, 1):
self.hole(x*0.5*holedistance, self.hole(x * 0.5 * holedistance,
y*0.5*holedistance, y * 0.5 * holedistance,
0.5*diameter) 0.5 * diameter)
# hexHoles # hexHoles
@ -863,21 +877,21 @@ class Boxes:
settings = self.hexHolesSettings settings = self.hexHolesSettings
r, b, style = settings r, b, style = settings
w = r+b/2.0 w = r + b / 2.0
dist = w * math.cos(math.pi/6.0) dist = w * math.cos(math.pi / 6.0)
# how many half circles do fit # how many half circles do fit
cx = int((x-2*r) // (w)) + 2 cx = int((x - 2 * r) // (w)) + 2
cy = int((y-2*r) // (dist)) + 2 cy = int((y - 2 * r) // (dist)) + 2
# what's left on the sides # what's left on the sides
lx = (x - (2*r+(cx-2)*w))/2.0 lx = (x - (2 * r + (cx - 2) * w)) / 2.0
ly = (y - (2*r+((cy//2)*2)*dist-2*dist))/2.0 ly = (y - (2 * r + ((cy // 2) * 2) * dist - 2 * dist)) / 2.0
for i in range(cy//2): for i in range(cy // 2):
for j in range((cx-(i%2))//2): for j in range((cx - (i % 2)) // 2):
px = 2*j*w + r + lx px = 2 * j * w + r + lx
py = i*2*dist + r + ly py = i * 2 * dist + r + ly
if i % 2: if i % 2:
px += w px += w
if skip and skip(x, y, r, b, px, py): if skip and skip(x, y, r, b, px, py):
@ -885,8 +899,8 @@ class Boxes:
self.hole(px, py, r) self.hole(px, py, r)
def __skipcircle(self, x, y, r, b, posx, posy): def __skipcircle(self, x, y, r, b, posx, posy):
cx, cy = x/2.0, y/2.0 cx, cy = x / 2.0, y / 2.0
return (dist(posx-cx, posy-cy) > (cx-r)) return (dist(posx - cx, posy - cy) > (cx - r))
def hexHolesCircle(self, d, settings=None): def hexHolesCircle(self, d, settings=None):
""" """
@ -896,7 +910,7 @@ class Boxes:
:param settings: (Default value = None) :param settings: (Default value = None)
""" """
d2 = d/2.0 d2 = d / 2.0
self.hexHolesRectangle(d, d, settings=settings, skip=self.__skipcircle) self.hexHolesRectangle(d, d, settings=settings, skip=self.__skipcircle)
def hexHolesPlate(self, x, y, rc, settings=None): def hexHolesPlate(self, x, y, rc, settings=None):
@ -909,6 +923,7 @@ class Boxes:
:param settings: (Default value = None) :param settings: (Default value = None)
""" """
def skip(x, y, r, b, posx, posy): def skip(x, y, r, b, posx, posy):
""" """
@ -920,15 +935,15 @@ class Boxes:
:param posy: :param posy:
""" """
posx = abs(posx-(x/2.0)) posx = abs(posx - (x / 2.0))
posy = abs(posy-(y/2.0)) posy = abs(posy - (y / 2.0))
wx = 0.5*x-rc-r wx = 0.5 * x - rc - r
wy = 0.5*y-rc-r wy = 0.5 * y - rc - r
if (posx <= wx) or (posy <= wx): if (posx <= wx) or (posy <= wx):
return 0 return 0
return dist(posx-wx, posy-wy) > rc return dist(posx - wx, posy - wy) > rc
self.hexHolesRectangle(x, y, settings, skip=skip) self.hexHolesRectangle(x, y, settings, skip=skip)
@ -946,53 +961,53 @@ class Boxes:
r, b, style = settings r, b, style = settings
self.ctx.rectangle(0, 0, h, h) self.ctx.rectangle(0, 0, h, h)
w = r+b/2.0 w = r + b / 2.0
dist = w * math.cos(math.pi/6.0) dist = w * math.cos(math.pi / 6.0)
cy = 2 * int((h-4*dist)// (4*w)) + 1 cy = 2 * int((h - 4 * dist) // (4 * w)) + 1
leftover = h-2*r-(cy-1)*2*r leftover = h - 2 * r - (cy - 1) * 2 * r
if grow=='space ': if grow == 'space ':
b += leftover / (cy-1) / 2 b += leftover / (cy - 1) / 2
# recalulate with adjusted values # recalulate with adjusted values
w = r+b/2.0 w = r + b / 2.0
dist = w * math.cos(math.pi/6.0) dist = w * math.cos(math.pi / 6.0)
self.moveTo(h/2.0-(cy//2)*2*w, h/2.0) self.moveTo(h / 2.0 - (cy // 2) * 2 * w, h / 2.0)
for j in range(cy): for j in range(cy):
self.hole(2*j*w, 0, r) self.hole(2 * j * w, 0, r)
for i in range(1, cy/2+1): for i in range(1, cy / 2 + 1):
for j in range(cy-i): for j in range(cy - i):
self.hole(j*2*w+i*w, i*2*dist, r) self.hole(j * 2 * w + i * w, i * 2 * dist, r)
self.hole(j*2*w+i*w, -i*2*dist, r) self.hole(j * 2 * w + i * w, -i * 2 * dist, r)
def flex2D(self, x, y, width=1): def flex2D(self, x, y, width=1):
width *= self.thickness width *= self.thickness
cx = int(x // (5*width)) cx = int(x // (5 * width))
wx = x / 5. / cx wx = x / 5. / cx
cy = int(y // (5*width)) cy = int(y // (5 * width))
wy = y / 5. / cy wy = y / 5. / cy
armx = (4*wx, 90, 4*wy, 90, 2*wx, 90, 2*wy) armx = (4 * wx, 90, 4 * wy, 90, 2 * wx, 90, 2 * wy)
army = (4*wy, 90, 4*wx, 90, 2*wy, 90, 2*wx) army = (4 * wy, 90, 4 * wx, 90, 2 * wy, 90, 2 * wx)
for i in range(cx): for i in range(cx):
for j in range(cy): for j in range(cy):
if (i+j) % 2: if (i + j) % 2:
self.ctx.save() self.ctx.save()
self.moveTo((5*i)*wx, (5*j)*wy) self.moveTo((5 * i) * wx, (5 * j) * wy)
self.polyline(*armx) self.polyline(*armx)
self.ctx.restore() self.ctx.restore()
self.ctx.save() self.ctx.save()
self.moveTo((5*i+5)*wx, (5*j+5)*wy, -180) self.moveTo((5 * i + 5) * wx, (5 * j + 5) * wy, -180)
self.polyline(*armx) self.polyline(*armx)
self.ctx.restore() self.ctx.restore()
else: else:
self.ctx.save() self.ctx.save()
self.moveTo((5*i+5)*wx, (5*j)*wy, 90) self.moveTo((5 * i + 5) * wx, (5 * j) * wy, 90)
self.polyline(*army) self.polyline(*army)
self.ctx.restore() self.ctx.restore()
self.ctx.save() self.ctx.save()
self.moveTo((5*i)*wx, (5*j+5)*wy, -90) self.moveTo((5 * i) * wx, (5 * j + 5) * wy, -90)
self.polyline(*army) self.polyline(*army)
self.ctx.restore() self.ctx.restore()
self.ctx.stroke() self.ctx.stroke()
@ -1023,8 +1038,8 @@ class Boxes:
""" """
overallwidth = x+2*self.edges["f"].spacing() overallwidth = x + 2 * self.edges["f"].spacing()
overallheight = y+2*self.edges["f"].spacing() overallheight = y + 2 * self.edges["f"].spacing()
if self.move(overallwidth, overallheight, move, before=True): if self.move(overallwidth, overallheight, move, before=True):
return return
@ -1034,16 +1049,16 @@ class Boxes:
self.moveTo(r, 0) self.moveTo(r, 0)
self.cc(callback, 0) self.cc(callback, 0)
self.edges["f"](x/2.0-r, bedBolts=self.getEntry(bedBolts, 0), self.edges["f"](x / 2.0 - r, bedBolts=self.getEntry(bedBolts, 0),
bedBoltSettings=self.getEntry(bedBoltSettings, 0)) bedBoltSettings=self.getEntry(bedBoltSettings, 0))
self.cc(callback, 1) self.cc(callback, 1)
self.edges["f"](x/2.0-r, bedBolts=self.getEntry(bedBolts, 1), self.edges["f"](x / 2.0 - r, bedBolts=self.getEntry(bedBolts, 1),
bedBoltSettings=self.getEntry(bedBoltSettings, 1)) bedBoltSettings=self.getEntry(bedBoltSettings, 1))
for i, l in zip(range(3), (y, x, y)): for i, l in zip(range(3), (y, x, y)):
self.corner(90, r) self.corner(90, r)
self.cc(callback, i+2) self.cc(callback, i + 2)
self.edges["f"](l-2*r, bedBolts=self.getEntry(bedBolts, i+2), self.edges["f"](l - 2 * r, bedBolts=self.getEntry(bedBolts, i + 2),
bedBoltSettings=self.getEntry(bedBoltSettings, i+2)) bedBoltSettings=self.getEntry(bedBoltSettings, i + 2))
self.corner(90, r) self.corner(90, r)
self.ctx.restore() self.ctx.restore()
@ -1058,7 +1073,7 @@ class Boxes:
r -= holesMargin r -= holesMargin
else: else:
r = 0 r = 0
self.hexHolesPlate(x-2*holesMargin, y-2*holesMargin, r, self.hexHolesPlate(x - 2 * holesMargin, y - 2 * holesMargin, r,
settings=holesSettings) settings=holesSettings)
self.ctx.stroke() self.ctx.stroke()
self.move(overallwidth, overallheight, move) self.move(overallwidth, overallheight, move)
@ -1086,7 +1101,7 @@ class Boxes:
:param move: (Default value = None) :param move: (Default value = None)
""" """
c4 = (r+self.burn)*math.pi*0.5 # circumference of quarter circle c4 = (r + self.burn) * math.pi * 0.5 # circumference of quarter circle
c4 = c4 / self.edges["X"].settings.stretch c4 = c4 / self.edges["X"].settings.stretch
top = self.edges.get(top, top) top = self.edges.get(top, top)
@ -1098,42 +1113,41 @@ class Boxes:
topwidth = top.startwidth() topwidth = top.startwidth()
bottomwidth = bottom.startwidth() bottomwidth = bottom.startwidth()
overallwidth = 2*x + 2*y - 8*r + 4*c4 + \ overallwidth = 2 * x + 2 * y - 8 * r + 4 * c4 + \
self.edges["d"].spacing() + self.edges["D"].spacing() self.edges["d"].spacing() + self.edges["D"].spacing()
overallheight = h + top.spacing() + bottom.spacing() overallheight = h + top.spacing() + bottom.spacing()
if self.move(overallwidth, overallheight, move, before=True): if self.move(overallwidth, overallheight, move, before=True):
return return
self.moveTo(left.spacing(), bottom.margin()) self.moveTo(left.spacing(), bottom.margin())
self.cc(callback, 0, y=bottomwidth+self.burn) self.cc(callback, 0, y=bottomwidth + self.burn)
bottom(x/2.0-r) bottom(x / 2.0 - r)
if (y-2*r) < 1E-3: if (y - 2 * r) < 1E-3:
self.edges["X"](2*c4, h+topwidth+bottomwidth) self.edges["X"](2 * c4, h + topwidth + bottomwidth)
self.cc(callback, 2, y=bottomwidth+self.burn) self.cc(callback, 2, y=bottomwidth + self.burn)
bottom(x-2*r) bottom(x - 2 * r)
self.edges["X"](2*c4, h+topwidth+bottomwidth) self.edges["X"](2 * c4, h + topwidth + bottomwidth)
self.cc(callback, 4, y=bottomwidth+self.burn) self.cc(callback, 4, y=bottomwidth + self.burn)
else: else:
for i, l in zip(range(4), (y, x, y, 0)): for i, l in zip(range(4), (y, x, y, 0)):
self.edges["X"](c4, h+topwidth+bottomwidth) self.edges["X"](c4, h + topwidth + bottomwidth)
self.cc(callback, i+1, y=bottomwidth+self.burn) self.cc(callback, i + 1, y=bottomwidth + self.burn)
if i < 3: if i < 3:
bottom(l-2*r) bottom(l - 2 * r)
bottom(x/2.0-r) bottom(x / 2.0 - r)
self.edgeCorner(bottom, right, 90) self.edgeCorner(bottom, right, 90)
right(h) right(h)
self.edgeCorner(right, top, 90) self.edgeCorner(right, top, 90)
top(x/2.0-r) top(x / 2.0 - r)
for i, l in zip(range(4), (y, x, y, 0)): for i, l in zip(range(4), (y, x, y, 0)):
self.edge(c4) self.edge(c4)
if i < 3: if i < 3:
top(l - 2*r) top(l - 2 * r)
top(x/2.0-r) top(x / 2.0 - r)
self.edgeCorner(top, left, 90) self.edgeCorner(top, left, 90)
left(h) left(h)
@ -1174,16 +1188,16 @@ class Boxes:
self.moveTo(edges[-1].spacing(), edges[0].margin()) self.moveTo(edges[-1].spacing(), edges[0].margin())
for i, l in enumerate((x, y, x, y)): for i, l in enumerate((x, y, x, y)):
self.cc(callback, i, y=edges[i].startwidth()+self.burn) self.cc(callback, i, y=edges[i].startwidth() + self.burn)
edges[i](l, edges[i](l,
bedBolts=self.getEntry(bedBolts, i), bedBolts=self.getEntry(bedBolts, i),
bedBoltSettings=self.getEntry(bedBoltSettings, i)) bedBoltSettings=self.getEntry(bedBoltSettings, i))
self.edgeCorner(edges[i], edges[i+1], 90) self.edgeCorner(edges[i], edges[i + 1], 90)
if holesMargin is not None: if holesMargin is not None:
self.moveTo(holesMargin+edges[-1].endwidth(), self.moveTo(holesMargin + edges[-1].endwidth(),
holesMargin+edges[0].startwidth()) holesMargin + edges[0].startwidth())
self.hexHolesRectangle(x-2*holesMargin, y-2*holesMargin) self.hexHolesRectangle(x - 2 * holesMargin, y - 2 * holesMargin)
self.ctx.stroke() self.ctx.stroke()

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
import subprocess import subprocess
import tempfile import tempfile
import os import os
@ -6,8 +5,8 @@ import cairo
import re import re
from boxes import svgutil from boxes import svgutil
class PSFile:
class PSFile:
def __init__(self, filename): def __init__(self, filename):
self.filename = filename self.filename = filename
@ -15,34 +14,36 @@ class PSFile:
with open(self.filename, "r+") as f: with open(self.filename, "r+") as f:
s = f.read(1024) s = f.read(1024)
m = re.search(r"%%BoundingBox: (\d+) (\d+) (\d+) (\d+)", s) m = re.search(r"%%BoundingBox: (\d+) (\d+) (\d+) (\d+)", s)
if not m: if not m:
raise ValueError("%%BoundingBox in Postscript file not found") raise ValueError("%%BoundingBox in Postscript file not found")
x1, y1, x2, y2 = m.groups() x1, y1, x2, y2 = m.groups()
m = re.search(r"%%DocumentMedia: \d+x\d+mm ((\d+) (\d+)) 0 \(", s) m = re.search(r"%%DocumentMedia: \d+x\d+mm ((\d+) (\d+)) 0 \(", s)
f.seek(m.start(1)) f.seek(m.start(1))
media = "%i %i" % (int(x1)+int(x2), int(y1)+int(y2)) media = "%i %i" % (int(x1) + int(x2), int(y1) + int(y2))
f.write(media + " " * (len(m.group(1))-len(media))) f.write(media + " " * (len(m.group(1)) - len(media)))
class Formats: class Formats:
pstoedit = "/usr/bin/pstoedit" pstoedit = "/usr/bin/pstoedit"
formats = { formats = {
"svg" : None, "svg": None,
"ps" : None, "ps": None,
"dxf" : "-flat 0.1 -f dxf:-mm".split(), "dxf": "-flat 0.1 -f dxf:-mm".split(),
"gcode" : "-f gcode".split(), "gcode": "-f gcode".split(),
"plt" : "-f plot-hpgl".split(), "plt": "-f plot-hpgl".split(),
"ai" : "-f ps2ai".split(), "ai": "-f ps2ai".split(),
"pdf" : "-f pdf".split(), "pdf": "-f pdf".split(),
} }
http_headers = { http_headers = {
"svg" : [('Content-type', 'image/svg+xml; charset=utf-8')], "svg": [('Content-type', 'image/svg+xml; charset=utf-8')],
"ps" : [('Content-type', 'application/postscript')], "ps": [('Content-type', 'application/postscript')],
"dxf" : [('Content-type', 'image/vnd.dxf')], "dxf": [('Content-type', 'image/vnd.dxf')],
"plt" : [('Content-type', ' application/vnd.hp-hpgl')], "plt": [('Content-type', ' application/vnd.hp-hpgl')],
"gcode" : [('Content-type', 'text/plain; charset=utf-8')], "gcode": [('Content-type', 'text/plain; charset=utf-8')],
# "" : [('Content-type', '')], # "" : [('Content-type', '')],
} }
@ -66,7 +67,7 @@ class Formats:
else: else:
mm2pt = 72 / 25.4 mm2pt = 72 / 25.4
width *= mm2pt width *= mm2pt
height *= mm2pt #3.543307 height *= mm2pt # 3.543307
surface = cairo.PSSurface(filename, width, height) surface = cairo.PSSurface(filename, width, height)
ctx = cairo.Context(surface) ctx = cairo.Context(surface)
@ -86,11 +87,14 @@ class Formats:
else: else:
ps = PSFile(filename) ps = PSFile(filename)
ps.adjustDocumentMedia() ps.adjustDocumentMedia()
if fmt not in ("svg", "ps"): if fmt not in ("svg", "ps"):
fd, tmpfile = tempfile.mkstemp() fd, tmpfile = tempfile.mkstemp()
cmd = [self.pstoedit] + self.formats[fmt] + [filename, tmpfile] cmd = [self.pstoedit] + self.formats[fmt] + [filename, tmpfile]
err = subprocess.call(cmd) err = subprocess.call(cmd)
if err: if err:
# XXX show stderr output # XXX show stderr output
raise ValueError("Conversion failed. pstoedit returned %i" % err) raise ValueError("Conversion failed. pstoedit returned %i" % err)
os.rename(tmpfile, filename) os.rename(tmpfile, filename)

View File

@ -107,26 +107,22 @@ def gear_calculations(num_teeth, circular_pitch, pressure_angle, clearance=0, ri
pitch_diameter = num_teeth / diametral_pitch pitch_diameter = num_teeth / diametral_pitch
pitch_radius = pitch_diameter / 2.0 pitch_radius = pitch_diameter / 2.0
addendum = 1 / diametral_pitch addendum = 1 / diametral_pitch
#dedendum = 1.157 / diametral_pitch # auto calc clearance
dedendum = addendum dedendum = addendum
dedendum *= 1+profile_shift dedendum *= 1+profile_shift
addendum *= 1-profile_shift addendum *= 1-profile_shift
if ring_gear: if ring_gear:
addendum = addendum + clearance # our method addendum = addendum + clearance # our method
else: else:
dedendum = dedendum + clearance # our method dedendum = dedendum + clearance # our method
#
#
base_radius = pitch_diameter * cos(radians(pressure_angle)) / 2.0 base_radius = pitch_diameter * cos(radians(pressure_angle)) / 2.0
outer_radius = pitch_radius + addendum outer_radius = pitch_radius + addendum
root_radius = pitch_radius - dedendum root_radius = pitch_radius - dedendum
# Tooth thickness: Tooth width along pitch circle. # Tooth thickness: Tooth width along pitch circle.
tooth_thickness = ( pi * pitch_diameter ) / ( 2.0 * num_teeth ) 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, return (pitch_radius, base_radius,
addendum, dedendum, outer_radius, root_radius, addendum, dedendum, outer_radius, root_radius,
tooth_thickness 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) (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. 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 # roughly center rack in drawing, exact position is so that it meshes
# nicely with the spur gear. # nicely with the spur gear.
# -0.5*spacing has a gap in the center. # -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 base_bot = addendum+clearance+base_height
x_lhs = -pitch * int(0.5*tooth_count-.5) - spacing - tab_length - tasc + fudge 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 # Start with base tab on LHS
points = [] # make list of points points = [] # make list of points
points.append((x_lhs, base_bot)) 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-tas, -addendum))
points.append((x+spacing+tasc, base_top)) points.append((x+spacing+tasc, base_top))
x += pitch x += pitch
x -= spacing # remove last adjustment x -= spacing # remove last adjustment
# add base on RHS # add base on RHS
x_rhs = x+tasc+tab_length x_rhs = x+tasc+tab_length
@ -189,7 +187,7 @@ def generate_rack_points(tooth_count, pitch, addendum, pressure_angle,
p = [] p = []
p.append( (x_lhs + 0.5 * tab_length, 0) ) p.append( (x_lhs + 0.5 * tab_length, 0) )
p.append( (x_rhs - 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) 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 p_tmp = points1 + points_on_outer_radius[1:-1] + points2[::-1] + points_on_root # [::-1] reverses list
points.extend( p_tmp ) points.extend( p_tmp )
return (points) return (points)
def inkbool(val): def inkbool(val):
@ -257,6 +256,7 @@ class OptionParser(argparse.ArgumentParser):
self.add_argument(*names, **kw) self.add_argument(*names, **kw)
class Gears(): class Gears():
def __init__(self, boxes, **kw): def __init__(self, boxes, **kw):
# an alternate way to get debug info: # an alternate way to get debug info:
# could use inkex.debug(string) instead... # 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") 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): def drawPoints(self, lines, kerfdir=1):
if kerfdir != 0: if kerfdir != 0:
lines = kerf(lines, self.boxes.burn*kerfdir) lines = kerf(lines, self.boxes.burn*kerfdir)
self.boxes.ctx.save() self.boxes.ctx.save()
self.boxes.ctx.move_to(*lines[0]) self.boxes.ctx.move_to(*lines[0])
for x, y in lines[1:]: for x, y in lines[1:]:
self.boxes.ctx.line_to(x, y) self.boxes.ctx.line_to(x, y)
self.boxes.ctx.line_to(*lines[0]) self.boxes.ctx.line_to(*lines[0])
self.boxes.ctx.restore() self.boxes.ctx.restore()
@ -406,6 +410,7 @@ class Gears():
circular_pitch = dimension circular_pitch = dimension
else: else:
raise ValueError("unknown system '%s', try CP, DP, MM" % self.options.system) raise ValueError("unknown system '%s', try CP, DP, MM" % self.options.system)
# circular_pitch defines the size in mm # circular_pitch defines the size in mm
return circular_pitch return circular_pitch
@ -436,6 +441,7 @@ class Gears():
# check for mount hole collision with inner spokes # check for mount hole collision with inner spokes
if mount_radius <= mount_hole/2: if mount_radius <= mount_hole/2:
adj_factor = (r_outer - mount_hole/2) / 5 adj_factor = (r_outer - mount_hole/2) / 5
if adj_factor < 0.1: if adj_factor < 0.1:
# not enough reasonable room # not enough reasonable room
collision = True collision = True
@ -446,6 +452,7 @@ class Gears():
# then check to see if cross-over on spoke width # then check to see if cross-over on spoke width
for i in range(spoke_count): for i in range(spoke_count):
angle = spokes[i]-spokes[i-1] angle = spokes[i]-spokes[i-1]
if spoke_width >= angle * mount_radius: if spoke_width >= angle * mount_radius:
adj_factor = 1.2 # wrong value. its probably one of the points distances calculated below adj_factor = 1.2 # wrong value. its probably one of the points distances calculated below
mount_radius += adj_factor mount_radius += adj_factor
@ -458,6 +465,7 @@ class Gears():
if collision: # don't draw spokes if no room. if collision: # don't draw spokes if no room.
messages.append("Not enough room for Spokes. Decrease Spoke width.") messages.append("Not enough room for Spokes. Decrease Spoke width.")
else: # draw spokes else: # draw spokes
for i in range(spoke_count): for i in range(spoke_count):
self.boxes.ctx.save() self.boxes.ctx.save()
start_a, end_a = spokes[i], spokes[i+1] start_a, end_a = spokes[i], spokes[i+1]
@ -486,6 +494,7 @@ class Gears():
) )
self.boxes.ctx.restore() self.boxes.ctx.restore()
return messages return messages
def sizes(self, **kw): 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): def gearCarrier(self, r, spoke_width, positions, mount_radius, mount_hole, circle=True, move=None):
width = (r+spoke_width)*2 width = (r+spoke_width)*2
if self.boxes.move(width, width, move, before=True): if self.boxes.move(width, width, move, before=True):
return return
try: try:
positions = [i*360/positions for i in range(positions)] positions = [i*360/positions for i in range(positions)]
except TypeError: except TypeError:
@ -528,11 +539,13 @@ class Gears():
self.boxes.moveTo(width/2.0, width/2.0) 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.generate_spokes(r+0.5*spoke_width, spoke_width, positions, mount_radius, mount_hole, 1, "")
self.boxes.hole(0, 0, mount_hole) self.boxes.hole(0, 0, mount_hole)
for angle in positions: for angle in positions:
self.boxes.ctx.save() self.boxes.ctx.save()
self.boxes.moveTo(0, 0, angle) self.boxes.moveTo(0, 0, angle)
self.boxes.hole(r, 0, mount_hole) self.boxes.hole(r, 0, mount_hole)
self.boxes.ctx.restore() self.boxes.ctx.restore()
self.boxes.moveTo(r+0.5*spoke_width+self.boxes.burn, 0, 90) self.boxes.moveTo(r+0.5*spoke_width+self.boxes.burn, 0, 90)
self.boxes.corner(360, r+0.5*spoke_width) self.boxes.corner(360, r+0.5*spoke_width)
@ -578,6 +591,7 @@ class Gears():
else: accuracy_involute = 6 else: accuracy_involute = 6
else: else:
accuracy_involute = self.options.accuracy accuracy_involute = self.options.accuracy
accuracy_circular = max(3, int(accuracy_involute/2) - 1) # never less than three 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) # 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) # Pitch (circular pitch): Length of the arc from one tooth to the next)
@ -599,17 +613,20 @@ class Gears():
height = base_height+ 2* addendum height = base_height+ 2* addendum
if self.boxes.move(width, height, move, before=True): if self.boxes.move(width, height, move, before=True):
return return
self.boxes.cc(callback, None, s+b, s+b) self.boxes.cc(callback, None, s+b, s+b)
self.boxes.moveTo(width/2.0, base_height+addendum, -180) self.boxes.moveTo(width/2.0, base_height+addendum, -180)
self.drawPoints(points) self.drawPoints(points)
self.drawPoints(guide_points, kerfdir=0) self.drawPoints(guide_points, kerfdir=0)
self.boxes.move(width, height, move) self.boxes.move(width, height, move)
return return
# Move only # Move only
width = height = 2 * outer_radius width = height = 2 * outer_radius
if self.options.internal_ring: if self.options.internal_ring:
width = height = width + 2 * self.options.spoke_width width = height = width + 2 * self.options.spoke_width
if self.boxes.move(width, height, move, before=True): if self.boxes.move(width, height, move, before=True):
return return
@ -624,6 +641,7 @@ class Gears():
# alas annotation cannot handle the degree symbol. Also it ignore newlines. # alas annotation cannot handle the degree symbol. Also it ignore newlines.
# so split and make a list # so split and make a list
warnings.extend(msg.split("\n")) warnings.extend(msg.split("\n"))
if self.options.undercut_alert: if self.options.undercut_alert:
inkex.debug(msg) inkex.debug(msg)
else: else:
@ -653,6 +671,7 @@ class Gears():
self.boxes.moveTo(r, 0) self.boxes.moveTo(r, 0)
self.boxes.ctx.arc(-r, 0, r, 0, 2*pi) self.boxes.ctx.arc(-r, 0, r, 0, 2*pi)
self.boxes.ctx.restore() self.boxes.ctx.restore()
# Add center # Add center
if centercross: if centercross:
cs = pitch / 3.0 # centercross length cs = pitch / 3.0 # centercross length
@ -667,12 +686,13 @@ class Gears():
if pitchcircle: if pitchcircle:
self.boxes.hole(0, 0, pitch_radius) self.boxes.hole(0, 0, pitch_radius)
# Add Annotations (above) # Add Annotations (above)
if self.options.annotation: if self.options.annotation:
outer_dia = outer_radius * 2 outer_dia = outer_radius * 2
if self.options.internal_ring: if self.options.internal_ring:
outer_dia += 2 * spoke_width outer_dia += 2 * spoke_width
notes = [] notes = []
notes.extend(warnings) 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)) #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)) text_height = max(10, min(10+(outer_dia-60)/24, 22))
# position above # position above
y = - outer_radius - (len(notes)+1) * text_height * 1.2 y = - outer_radius - (len(notes)+1) * text_height * 1.2
for note in notes: for note in notes:
self.boxes.text(note, -outer_radius, y) self.boxes.text(note, -outer_radius, y)
y += text_height * 1.2 y += text_height * 1.2

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class Box(Boxes): class Box(Boxes):
"""Fully closed box""" """Fully closed box"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "outside") self.buildArgParser("x", "y", "h", "outside")
@ -53,10 +55,12 @@ class Box(Boxes):
self.close() self.close()
def main(): def main():
b = Box() b = Box()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -120,6 +120,7 @@ class Box2(Boxes):
bedBolts=[d2], move="up only") bedBolts=[d2], move="up only")
self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right") self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right")
if self.top_edge == "c": if self.top_edge == "c":
self.rectangularWall(x, y, "CCCC", bedBolts=[d2, d3, d2, d3], move="up") self.rectangularWall(x, y, "CCCC", bedBolts=[d2, d3, d2, d3], move="up")
elif self.top_edge == "i": elif self.top_edge == "i":

View File

@ -18,6 +18,7 @@ from boxes import *
class Box3(Boxes): class Box3(Boxes):
"""Box with just 3 walls""" """Box with just 3 walls"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "outside") self.buildArgParser("x", "y", "h", "outside")

View File

@ -16,8 +16,8 @@
from boxes import * from boxes import *
class Castle(Boxes):
class Castle(Boxes):
webinterface = False webinterface = False
def __init__(self): def __init__(self):
@ -26,21 +26,21 @@ class Castle(Boxes):
def render(self, t_x=70, t_h=250, w1_x=300, w1_h=120, w2_x=100, w2_h=120): def render(self, t_x=70, t_h=250, w1_x=300, w1_h=120, w2_x=100, w2_h=120):
self.open() self.open()
s = edges.FingerJointSettings(self.thickness, relative=False, s = edges.FingerJointSettings(self.thickness, relative=False,
space = 10, finger=10, height=10, space=10, finger=10, height=10,
width=self.thickness) width=self.thickness)
p = edges.FingerJointEdge(self, s) p = edges.FingerJointEdge(self, s)
p.char = "p" p.char = "p"
self.addPart(p) self.addPart(p)
P = edges.FingerJointEdgeCounterPart(self, s) P = edges.FingerJointEdgeCounterPart(self, s)
P.char = "P" P.char = "P"
self.addPart(P) self.addPart(P)
self.moveTo(0,0) self.moveTo(0, 0)
self.rectangularWall(t_x, t_h, edges="efPf", move="right", callback= self.rectangularWall(t_x, t_h, edges="efPf", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w1_h, 90), ])
[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")
self.rectangularWall(t_x, t_h, edges="eFPF", move="right", callback= self.rectangularWall(t_x, t_h, edges="eFPF", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w2_h, 90), ])
[lambda: self.fingerHolesAt(t_x*0.5, 0, w2_h, 90),])
self.rectangularWall(t_x, t_h, edges="eFPF", move="right") self.rectangularWall(t_x, t_h, edges="eFPF", move="right")
self.rectangularWall(w1_x, w1_h, "efpe", move="right") self.rectangularWall(w1_x, w1_h, "efpe", move="right")
@ -48,10 +48,12 @@ class Castle(Boxes):
self.close() self.close()
def main(): def main():
c = Castle() c = Castle()
c.parseArgs() c.parseArgs()
c.render() c.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,9 +16,11 @@
from boxes import * from boxes import *
class DrillBox(Boxes): class DrillBox(Boxes):
"""Not yet parametrized box for drills from 1 to 12.5mm """Not yet parametrized box for drills from 1 to 12.5mm
in 0.5mm steps, 3 holes each size""" in 0.5mm steps, 3 holes each size"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.x, self.y, self.h = 120, 240, 60 self.x, self.y, self.h = 120, 240, 60
@ -31,51 +33,46 @@ in 0.5mm steps, 3 holes each size"""
self.fingerHolesAt(0, 5, self.y, angle=0) self.fingerHolesAt(0, 5, self.y, angle=0)
self.fingerHolesAt(0, 25, self.y, angle=0) self.fingerHolesAt(0, 25, self.y, angle=0)
def drillholes(self): def drillholes(self):
for i in range(6): for i in range(6):
for j in range(4): for j in range(4):
for k in range(3): for k in range(3):
r = (12.5-2*i-0.5*j) * 0.5 r = (12.5 - 2 * i - 0.5 * j) * 0.5
self.hole(i*20+10, j*60+k*20+10, r+0.05) self.hole(i * 20 + 10, j * 60 + k * 20 + 10, r + 0.05)
def description(self): def description(self):
self.ctx.set_font_size(6) self.ctx.set_font_size(6)
for i in range(4): for i in range(4):
for j in range(6): for j in range(6):
self.rectangularHole(i*60+30, 20*j+10, 58, 14+1*j) self.rectangularHole(i * 60 + 30, 20 * j + 10, 58, 14 + 1 * j)
d = 2.5-0.5*i+2*j d = 2.5 - 0.5 * i + 2 * j
self.text("%.1f" % d, i*60+20, 19*j+6, self.text("%.1f" % d, i * 60 + 20, 19 * j + 6,
align="center") align="center")
def render(self): def render(self):
x, y, h = self.x, self.y, self.h x, y, h = self.x, self.y, self.h
t = self.thickness t = self.thickness
self.open() self.open()
self.edges["f"].settings.setValues(self.thickness, space=3, finger=3, self.edges["f"].settings.setValues(self.thickness, space=3, finger=3, surroundingspaces=1)
surroundingspaces=1)
self.rectangularWall(x, h, "FfeF", callback=[self.holesx],move="right") 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], move="up")
self.rectangularWall(y, h, "FfeF", callback=[self.holesy]) self.rectangularWall(y, h, "FfeF", callback=[self.holesy])
self.rectangularWall(x, h, "FfeF", callback=[self.holesx], self.rectangularWall(x, h, "FfeF", callback=[self.holesx], move="left up")
move="left up")
self.rectangularWall(x, y, "ffff", move="up") self.rectangularWall(x, y, "ffff", move="up")
self.rectangularWall(x, y, "ffff", callback=[self.drillholes], self.rectangularWall(x, y, "ffff", callback=[self.drillholes], move="up")
move="up") self.rectangularWall(x, y, "ffff", callback=[self.drillholes, self.description], move="up")
self.rectangularWall(x, y, "ffff", callback=[self.drillholes,
self.description],
move="up")
self.close() self.close()
def main(): def main():
b = DrillBox() b = DrillBox()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -17,8 +17,10 @@
import boxes import boxes
import math import math
class FlexBox(boxes.Boxes): class FlexBox(boxes.Boxes):
"""Box with living hinge and round corners""" """Box with living hinge and round corners"""
def __init__(self): def __init__(self):
boxes.Boxes.__init__(self) boxes.Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "outside") self.buildArgParser("x", "y", "h", "outside")
@ -29,17 +31,19 @@ class FlexBox(boxes.Boxes):
@boxes.restore @boxes.restore
def flexBoxSide(self, x, y, r, callback=None): def flexBoxSide(self, x, y, r, callback=None):
self.moveTo(r, 0) self.moveTo(r, 0)
for i, l in zip(range(2), (x, y)): for i, l in zip(range(2), (x, y)):
self.cc(callback, i) self.cc(callback, i)
self.edges["f"](l-2*r) self.edges["f"](l - 2 * r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 2) self.cc(callback, 2)
self.edge(x-2*r) self.edge(x - 2 * r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 3) self.cc(callback, 3)
self.latch(self.latchsize) self.latch(self.latchsize)
self.cc(callback, 4) self.cc(callback, 4)
self.edges["f"](y-2*r-self.latchsize) self.edges["f"](y - 2 * r - self.latchsize)
self.corner(90, r) self.corner(90, r)
def surroundingWall(self): def surroundingWall(self):
@ -47,33 +51,33 @@ class FlexBox(boxes.Boxes):
c4 = math.pi * r * 0.5 c4 = math.pi * r * 0.5
self.edges["F"](y-2*r-self.latchsize, False) self.edges["F"](y - 2 * r - self.latchsize, False)
if x-2*r < self.thickness: if x - 2 * r < self.thickness:
self.edges["X"](2*c4+x-2*r, h+2*self.thickness) self.edges["X"](2 * c4 + x - 2 * r, h + 2 * self.thickness)
else: else:
self.edges["X"](c4, h+2*self.thickness) self.edges["X"](c4, h + 2 * self.thickness)
self.edges["F"](x-2*r, False) self.edges["F"](x - 2 * r, False)
self.edges["X"](c4, h+2*self.thickness) self.edges["X"](c4, h + 2 * self.thickness)
self.edges["F"](y-2*r, False) self.edges["F"](y - 2 * r, False)
if x-2*r < self.thickness: if x - 2 * r < self.thickness:
self.edges["X"](2*c4+x-2*r, h+2*self.thickness) self.edges["X"](2 * c4 + x - 2 * r, h + 2 * self.thickness)
else: else:
self.edges["X"](c4, h+2*self.thickness) self.edges["X"](c4, h + 2 * self.thickness)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edges["X"](c4, h+2*self.thickness) self.edges["X"](c4, h + 2 * self.thickness)
self.latch(self.latchsize, False) self.latch(self.latchsize, False)
self.edge(h+2*self.thickness) self.edge(h + 2 * self.thickness)
self.latch(self.latchsize, False, True) self.latch(self.latchsize, False, True)
self.edge(c4) self.edge(c4)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edge(c4) self.edge(c4)
self.edges["F"](y-2*r, False) self.edges["F"](y - 2 * r, False)
self.edge(c4) self.edge(c4)
self.edges["F"](x-2*r, False) self.edges["F"](x - 2 * r, False)
self.edge(c4) self.edge(c4)
self.edges["F"](y-2*r-self.latchsize, False) self.edges["F"](y - 2 * r - self.latchsize, False)
self.corner(90) self.corner(90)
self.edge(h+2*self.thickness) self.edge(h + 2 * self.thickness)
self.corner(90) self.corner(90)
def render(self): def render(self):
@ -85,27 +89,29 @@ class FlexBox(boxes.Boxes):
x, y, h = self.x, self.y, self.h x, y, h = self.x, self.y, self.h
self.latchsize = 8 * self.thickness self.latchsize = 8 * self.thickness
r = self.radius or min(x, y-self.latchsize)/2.0 r = self.radius or min(x, y - self.latchsize) / 2.0
r = min(r, x/2.0) r = min(r, x / 2.0)
self.radius = r = min(r, max(0, (y-self.latchsize)/2.0)) self.radius = r = min(r, max(0, (y - self.latchsize) / 2.0))
c4 = math.pi * r * 0.5 c4 = math.pi * r * 0.5
self.open() self.open()
self.moveTo(self.thickness, self.thickness) self.moveTo(self.thickness, self.thickness)
self.surroundingWall() self.surroundingWall()
self.moveTo(self.thickness, self.h+5*self.thickness) self.moveTo(self.thickness, self.h + 5 * self.thickness)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.moveTo(2*self.x+3*self.thickness, 0) self.moveTo(2 * self.x + 3 * self.thickness, 0)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.close() self.close()
def main(): def main():
b = FlexBox() b = FlexBox()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__=="__main__":
if __name__ == "__main__":
main() main()

View File

@ -17,8 +17,10 @@
from boxes import * from boxes import *
import math import math
class FlexBox2(Boxes): class FlexBox2(Boxes):
"""Box with living hinge and top corners rounded""" """Box with living hinge and top corners rounded"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "outside") self.buildArgParser("x", "y", "h", "outside")
@ -32,34 +34,36 @@ class FlexBox2(Boxes):
self.edges["f"](x) self.edges["f"](x)
self.corner(90, 0) self.corner(90, 0)
self.cc(callback, 1) self.cc(callback, 1)
self.edges["f"](y-r) self.edges["f"](y - r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 2) self.cc(callback, 2)
self.edge(x-2*r) self.edge(x - 2 * r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 3) self.cc(callback, 3)
self.latch(self.latchsize) self.latch(self.latchsize)
self.cc(callback, 4) self.cc(callback, 4)
self.edges["f"](y-r-self.latchsize) self.edges["f"](y - r - self.latchsize)
self.corner(90) self.corner(90)
def surroundingWall(self): def surroundingWall(self):
x, y, h, r = self.x, self.y, self.h, self.radius x, y, h, r = self.x, self.y, self.h, self.radius
self.edges["F"](y-r, False) 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) if (x - 2 * r < self.thickness):
self.edges["X"](2 * self.c4 + x - 2 * r, h + 2 * self.thickness)
else: else:
self.edges["X"](self.c4, h+2*self.thickness) self.edges["X"](self.c4, h + 2 * self.thickness)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edges["X"](self.c4, h+2*self.thickness) self.edges["X"](self.c4, h + 2 * self.thickness)
self.latch(self.latchsize, False) self.latch(self.latchsize, False)
self.edge(h+2*self.thickness) self.edge(h + 2 * self.thickness)
self.latch(self.latchsize, False, True) self.latch(self.latchsize, False, True)
self.edge(self.c4) self.edge(self.c4)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edge(self.c4) self.edge(self.c4)
self.edges["F"](y-r) self.edges["F"](y - r)
self.corner(90) self.corner(90)
self.edge(self.thickness) self.edge(self.thickness)
self.edges["f"](h) self.edges["f"](h)
@ -67,41 +71,48 @@ class FlexBox2(Boxes):
self.corner(90) self.corner(90)
def render(self): def render(self):
if self.outside: if self.outside:
self.x = self.adjustSize(self.x) self.x = self.adjustSize(self.x)
self.y = self.adjustSize(self.y) self.y = self.adjustSize(self.y)
self.h = self.adjustSize(self.h) self.h = self.adjustSize(self.h)
self.latchsize = 8*self.thickness self.latchsize = 8 * self.thickness
self.radius = self.radius or min(self.x/2.0, self.y-self.latchsize) self.radius = self.radius or min(self.x / 2.0, self.y - self.latchsize)
self.radius = min(self.radius, self.x/2.0) self.radius = min(self.radius, self.x / 2.0)
self.radius = min(self.radius, max(0, self.y-self.latchsize)) self.radius = min(self.radius, max(0, self.y - self.latchsize))
self.c4 = c4 = math.pi * self.radius * 0.5 self.c4 = c4 = math.pi * self.radius * 0.5
self.open() self.open()
self.fingerJointSettings = (4, 4) self.fingerJointSettings = (4, 4)
self.moveTo(2*self.thickness, self.thickness) self.moveTo(2 * self.thickness, self.thickness)
self.ctx.save() self.ctx.save()
self.surroundingWall() self.surroundingWall()
self.moveTo(self.x+self.y-3*self.radius+2*self.c4+self.latchsize+1*self.thickness, 0)
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.rectangularWall(self.x, self.h, edges="FFFF")
self.ctx.restore() self.ctx.restore()
self.moveTo(0, self.h+4*self.thickness)
self.moveTo(0, self.h + 4 * self.thickness)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.moveTo(2*self.x+3*self.thickness, 0)
self.moveTo(2 * self.x + 3 * self.thickness, 0)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.moveTo(2*self.thickness, 0)
self.rectangularWall(self.h, self.y-self.radius-self.latchsize, edges="fFeF") self.moveTo(2 * self.thickness, 0)
self.rectangularWall(self.h, self.y - self.radius - self.latchsize, edges="fFeF")
self.close() self.close()
def main(): def main():
b = FlexBox2() b = FlexBox2()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__=="__main__":
if __name__ == "__main__":
main() main()

View File

@ -17,8 +17,10 @@
from boxes import * from boxes import *
import math import math
class FlexBox3(Boxes): class FlexBox3(Boxes):
"""Box with living hinge""" """Box with living hinge"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "outside") self.buildArgParser("x", "y", "outside")
@ -50,10 +52,10 @@ class FlexBox3(Boxes):
self.edges["f"](x) self.edges["f"](x)
self.corner(90, 0) self.corner(90, 0)
self.cc(callback, 1) self.cc(callback, 1)
self.edges["f"](y-r) self.edges["f"](y - r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 2) self.cc(callback, 2)
self.edge(x-r) self.edge(x - r)
self.corner(90, 0) self.corner(90, 0)
self.cc(callback, 3) self.cc(callback, 3)
self.edges["f"](y) self.edges["f"](y)
@ -62,21 +64,21 @@ class FlexBox3(Boxes):
def surroundingWall(self): def surroundingWall(self):
x, y, z, r, d = self.x, self.y, self.z, self.radius, self.d x, y, z, r, d = self.x, self.y, self.z, self.radius, self.d
self.edges["F"](y-r, False) self.edges["F"](y - r, False)
self.edges["X"](self.c4, z+2*self.thickness) self.edges["X"](self.c4, z + 2 * self.thickness)
self.corner(-90) self.corner(-90)
self.edge(d) self.edge(d)
self.corner(90) self.corner(90)
self.edges["f"](x-r+d) self.edges["f"](x - r + d)
self.corner(90) self.corner(90)
self.edges["f"](z+2*self.thickness+2*d) self.edges["f"](z + 2 * self.thickness + 2 * d)
self.corner(90) self.corner(90)
self.edges["f"](x-r+d) self.edges["f"](x - r + d)
self.corner(90) self.corner(90)
self.edge(d) self.edge(d)
self.corner(-90) self.corner(-90)
self.edge(self.c4) self.edge(self.c4)
self.edges["F"](y-r) self.edges["F"](y - r)
self.corner(90) self.corner(90)
self.edge(self.thickness) self.edge(self.thickness)
self.edges["f"](z) self.edges["f"](z)
@ -87,16 +89,16 @@ class FlexBox3(Boxes):
def lidSide(self): def lidSide(self):
x, y, z, r, d, h = self.x, self.y, self.z, self.radius, self.d, self.h x, y, z, r, d, h = self.x, self.y, self.z, self.radius, self.d, self.h
t = self.thickness t = self.thickness
r2 = r+t if r+t <=h+t else h+t r2 = r + t if r + t <= h + t else h + t
self.moveTo(self.thickness, self.thickness) self.moveTo(self.thickness, self.thickness)
self.edge(h+self.thickness-r2) self.edge(h + self.thickness - r2)
self.corner(90, r2) self.corner(90, r2)
self.edge(r-r2+2*t) self.edge(r - r2 + 2 * t)
self.edges["F"](x-r) self.edges["F"](x - r)
self.rectangleCorner("F", "f") self.rectangleCorner("F", "f")
self.edges["g"](h) self.edges["g"](h)
self.rectangleCorner("f", "e") self.rectangleCorner("f", "e")
self.edge(x+2*t) self.edge(x + 2 * t)
def render(self): def render(self):
if self.outside: if self.outside:
@ -105,56 +107,57 @@ class FlexBox3(Boxes):
self.z = self.adjustSize(self.z) self.z = self.adjustSize(self.z)
x, y, z, d, h = self.x, self.y, self.z, self.d, self.h x, y, z, d, h = self.x, self.y, self.z, self.d, self.h
r = self.radius = self.radius or min(x, y)/2.0 r = self.radius = self.radius or min(x, y) / 2.0
thickness = self.thickness thickness = self.thickness
self.c4 = c4 = math.pi * r * 0.5 * 0.95 self.c4 = c4 = math.pi * r * 0.5 * 0.95
self.latchsize = 8*thickness self.latchsize = 8 * thickness
width = 2*x + y - 2*r + c4 + 14*thickness + 3*h # lock width = 2 * x + y - 2 * r + c4 + 14 * thickness + 3 * h # lock
height = y + z + 8*thickness height = y + z + 8 * thickness
self.open() self.open()
self.edges["f"].settings.setValues( self.edges["f"].settings.setValues(self.thickness, finger=2, space=2, surroundingspaces=1)
self.thickness, finger=2, space=2, surroundingspaces=1)
s = edges.FingerJointSettings(self.thickness, surroundingspaces=1) s = edges.FingerJointSettings(self.thickness, surroundingspaces=1)
g = edges.FingerJointEdge(self, s) g = edges.FingerJointEdge(self, s)
g.char = "g" g.char = "g"
self.addPart(g) self.addPart(g)
G = edges.FingerJointEdgeCounterPart(self, s) G = edges.FingerJointEdgeCounterPart(self, s)
G.char = "G" G.char = "G"
self.addPart(G) self.addPart(G)
self.moveTo(2*self.thickness, self.thickness+2*d) self.moveTo(2 * self.thickness, self.thickness + 2 * d)
self.ctx.save() self.ctx.save()
self.surroundingWall() self.surroundingWall()
self.moveTo(x+y-2*r+self.c4+2*self.thickness, -2*d-self.thickness) 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(x, z, edges="FFFF", move="right")
self.rectangularWall(h, z+2*(d+self.thickness), self.rectangularWall(h, z + 2 * (d + self.thickness), edges="GeGF", move="right")
edges="GeGF", move="right")
self.lidSide() self.lidSide()
self.moveTo(2*h+5*self.thickness, 0) self.moveTo(2 * h + 5 * self.thickness, 0)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.lidSide() self.lidSide()
self.ctx.restore() self.ctx.restore()
self.moveTo(0, z+4*self.thickness+2*d) self.moveTo(0, z + 4 * self.thickness + 2 * d)
self.flexBoxSide(x, y, r) self.flexBoxSide(x, y, r)
self.moveTo(2*x+3*self.thickness, 2*d) self.moveTo(2 * x + 3 * self.thickness, 2 * d)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.flexBoxSide(x, y, r) self.flexBoxSide(x, y, r)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.moveTo(2*self.thickness, -self.thickness) self.moveTo(2 * self.thickness, -self.thickness)
self.rectangularWall(z, y, edges="fFeF") self.rectangularWall(z, y, edges="fFeF")
self.close() self.close()
def main(): def main():
b = FlexBox3() #100, 40, 100, r=20, h=10, thickness=4.0) b = FlexBox3() # 100, 40, 100, r=20, h=10, thickness=4.0)
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__=="__main__":
if __name__ == "__main__":
main() main()

View File

@ -17,8 +17,10 @@
from boxes import * from boxes import *
import math import math
class FlexBox4(Boxes): class FlexBox4(Boxes):
"""Box with living hinge and left corners rounded""" """Box with living hinge and left corners rounded"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "outside") self.buildArgParser("x", "y", "h", "outside")
@ -32,13 +34,13 @@ class FlexBox4(Boxes):
self.edges["f"](x) self.edges["f"](x)
self.corner(90, 0) self.corner(90, 0)
self.cc(callback, 1) self.cc(callback, 1)
self.edges["f"](y-r) self.edges["f"](y - r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 2) self.cc(callback, 2)
self.edge(x-2*r) self.edge(x - 2 * r)
self.corner(90, r) self.corner(90, r)
self.cc(callback, 3) self.cc(callback, 3)
self.edges["e"](y-r-self.latchsize) self.edges["e"](y - r - self.latchsize)
self.cc(callback, 4) self.cc(callback, 4)
self.latch(self.latchsize) self.latch(self.latchsize)
self.corner(90) self.corner(90)
@ -46,22 +48,23 @@ class FlexBox4(Boxes):
def surroundingWall(self): def surroundingWall(self):
x, y, h, r = self.x, self.y, self.h, self.radius x, y, h, r = self.x, self.y, self.h, self.radius
self.edges["F"](y-r, False) self.edges["F"](y - r, False)
if (x-2*r < self.thickness): if (x - 2 * r < self.thickness):
self.edges["X"](2*self.c4+x-2*r, h+2*self.thickness) self.edges["X"](2 * self.c4 + x - 2 * r, h + 2 * self.thickness)
else: else:
self.edges["X"](self.c4, h+2*self.thickness) self.edges["X"](self.c4, h + 2 * self.thickness)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edges["X"](self.c4, h+2*self.thickness) self.edges["X"](self.c4, h + 2 * self.thickness)
self.edge(y-r-self.latchsize)
self.edge(y - r - self.latchsize)
self.latch(self.latchsize, False) self.latch(self.latchsize, False)
self.edge(h+2*self.thickness) self.edge(h + 2 * self.thickness)
self.latch(self.latchsize, False, True) self.latch(self.latchsize, False, True)
self.edge(y-r-self.latchsize) self.edge(y - r - self.latchsize)
self.edge(self.c4) self.edge(self.c4)
self.edge(x-2*r) self.edge(x - 2 * r)
self.edge(self.c4) self.edge(self.c4)
self.edges["F"](y-r) self.edges["F"](y - r)
self.corner(90) self.corner(90)
self.edge(self.thickness) self.edge(self.thickness)
self.edges["f"](h) self.edges["f"](h)
@ -75,33 +78,35 @@ class FlexBox4(Boxes):
self.h = self.adjustSize(self.h) self.h = self.adjustSize(self.h)
self.c4 = c4 = math.pi * self.radius * 0.5 self.c4 = c4 = math.pi * self.radius * 0.5
self.latchsize = 8*self.thickness self.latchsize = 8 * self.thickness
self.radius = self.radius or min(self.x/2.0, self.y-self.latchsize) self.radius = self.radius or min(self.x / 2.0, self.y - self.latchsize)
self.radius = min(self.radius, self.x/2.0) self.radius = min(self.radius, self.x / 2.0)
self.radius = min(self.radius, max(0, self.y-self.latchsize)) self.radius = min(self.radius, max(0, self.y - self.latchsize))
self.open() self.open()
self.fingerJointSettings = (4, 4) self.fingerJointSettings = (4, 4)
self.moveTo(2*self.thickness, self.thickness) self.moveTo(2 * self.thickness, self.thickness)
self.ctx.save() self.ctx.save()
self.surroundingWall() self.surroundingWall()
self.ctx.restore() self.ctx.restore()
self.moveTo(0, self.h+4*self.thickness) self.moveTo(0, self.h + 4 * self.thickness)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.moveTo(2*self.x+3*self.thickness, 0) self.moveTo(2 * self.x + 3 * self.thickness, 0)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.flexBoxSide(self.x, self.y, self.radius) self.flexBoxSide(self.x, self.y, self.radius)
self.ctx.scale(-1, 1) self.ctx.scale(-1, 1)
self.moveTo(2*self.thickness,-self.thickness) self.moveTo(2 * self.thickness, -self.thickness)
self.rectangularWall(self.x, self.h, edges="FeFF") self.rectangularWall(self.x, self.h, edges="FeFF")
self.close() self.close()
def main(): def main():
b = FlexBox4() b = FlexBox4()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__=="__main__":
if __name__ == "__main__":
main() main()

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class FlexTest(Boxes): class FlexTest(Boxes):
"Piece for testing different flex settings" "Piece for testing different flex settings"
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y") self.buildArgParser("x", "y")
@ -46,17 +48,19 @@ class FlexTest(Boxes):
self.corner(90) self.corner(90)
self.edge(y) self.edge(y)
self.corner(90) self.corner(90)
self.edge(x+20) self.edge(x + 20)
self.corner(90) self.corner(90)
self.edge(y) self.edge(y)
self.corner(90) self.corner(90)
self.close() self.close()
def main(): def main():
f = FlexTest() f = FlexTest()
f.parseArgs() f.parseArgs()
f.render() f.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class FlexTest2(Boxes): class FlexTest2(Boxes):
"Piece for testing 2D flex settings" "Piece for testing 2D flex settings"
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y") self.buildArgParser("x", "y")
@ -27,15 +29,17 @@ class FlexTest2(Boxes):
def render(self): def render(self):
x, y = self.x, self.y x, y = self.x, self.y
t = self.thickness
self.open() self.open()
self.rectangularWall(x, y, callback=[lambda:self.flex2D(x, y, self.fw)]) self.rectangularWall(x, y, callback=[lambda: self.flex2D(x, y, self.fw)])
self.close() self.close()
def main(): def main():
f = FlexTest() f = FlexTest()
f.parseArgs() f.parseArgs()
f.render() f.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -17,6 +17,7 @@
from boxes import * from boxes import *
import math import math
class Folder(Boxes): class Folder(Boxes):
"""Book cover with flex for the spine""" """Book cover with flex for the spine"""
@ -32,16 +33,16 @@ class Folder(Boxes):
x, y, r, h = self.x, self.y, self.r, self.h x, y, r, h = self.x, self.y, self.r, self.h
c2 = math.pi * h c2 = math.pi * h
self.open() self.open()
self.moveTo(r+self.thickness, self.thickness) self.moveTo(r + self.thickness, self.thickness)
self.edge(x-r) self.edge(x - r)
self.edges["X"](c2, y) self.edges["X"](c2, y)
self.edge(x-r) self.edge(x - r)
self.corner(90, r) self.corner(90, r)
self.edge(y-2*r) self.edge(y - 2 * r)
self.corner(90, r) self.corner(90, r)
self.edge(2*x-2*r+c2) self.edge(2 * x - 2 * r + c2)
self.corner(90, r) self.corner(90, r)
self.edge(y-2*r) self.edge(y - 2 * r)
self.corner(90, r) self.corner(90, r)
self.close() self.close()
@ -52,5 +53,6 @@ def main():
f.parseArgs() f.parseArgs()
f.render() f.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class GearBox(Boxes): class GearBox(Boxes):
"""Gearbox with multiple identical stages""" """Gearbox with multiple identical stages"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.argparser.add_argument( self.argparser.add_argument(
@ -43,21 +45,20 @@ class GearBox(Boxes):
if self.teeth2 < self.teeth1: if self.teeth2 < self.teeth1:
self.teeth2, self.teeth1 = self.teeth1, self.teeth2 self.teeth2, self.teeth1 = self.teeth1, self.teeth2
pitch1, size1, xxx = self.gears.sizes(teeth=self.teeth1, pitch1, size1, xxx = self.gears.sizes(teeth=self.teeth1, dimension=self.modulus)
dimension=self.modulus) pitch2, size2, xxx = self.gears.sizes(teeth=self.teeth2, dimension=self.modulus)
pitch2, size2, xxx = self.gears.sizes(teeth=self.teeth2,
dimension=self.modulus)
t = self.thickness t = self.thickness
x = 1.1*t*self.stages x = 1.1 * t * self.stages
if self.stages == 1: if self.stages == 1:
y = size1 + size2 y = size1 + size2
y1 = y/2-(pitch1+pitch2)+pitch1 y1 = y / 2 - (pitch1 + pitch2) + pitch1
y2 = y/2+(pitch1+pitch2)-pitch2 y2 = y / 2 + (pitch1 + pitch2) - pitch2
else: else:
y = 2 * size2 y = 2 * size2
y1 = y/2 - (pitch1+pitch2)/2 y1 = y / 2 - (pitch1 + pitch2) / 2
y2 = y/2 + (pitch1+pitch2)/2 y2 = y / 2 + (pitch1 + pitch2) / 2
h = max(size1, size2) + t h = max(size1, size2) + t
@ -65,10 +66,9 @@ class GearBox(Boxes):
t = "e" # prepare for close box t = "e" # prepare for close box
mh = self.shaft mh = self.shaft
def sideCB(): def sideCB():
self.hole(y1, h/2, mh/2) self.hole(y1, h / 2, mh / 2)
self.hole(y2, h/2, mh/2) self.hole(y2, h / 2, mh / 2)
self.moveTo(self.thickness, self.thickness) self.moveTo(self.thickness, self.thickness)
self.rectangularWall(y, h, [b, "f", t, "f"], callback=[sideCB], move="right") self.rectangularWall(y, h, [b, "f", t, "f"], callback=[sideCB], move="right")
@ -81,24 +81,26 @@ class GearBox(Boxes):
profile_shift = 20 profile_shift = 20
pressure_angle = 20 pressure_angle = 20
for i in range(self.stages-1):
self.gears(teeth=self.teeth2, dimension=self.modulus, for i in range(self.stages - 1):
angle=pressure_angle, self.gears(teeth=self.teeth2, dimension=self.modulus, angle=pressure_angle,
mount_hole=mh, profile_shift=profile_shift, move="up") 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") mount_hole=mh, profile_shift=profile_shift, move="right")
for i in range(self.stages): for i in range(self.stages):
self.gears(teeth=self.teeth1, dimension=self.modulus, self.gears(teeth=self.teeth1, dimension=self.modulus, angle=pressure_angle,
angle=pressure_angle,
mount_hole=mh, profile_shift=profile_shift, move="down") mount_hole=mh, profile_shift=profile_shift, move="down")
self.close() self.close()
def main(): def main():
b = Box() b = GearBox()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -17,6 +17,7 @@
from boxes import * from boxes import *
import random import random
class JigsawPuzzle(Boxes): # change class name here and below class JigsawPuzzle(Boxes): # change class name here and below
"""Fractal jigsaw puzzle. Still aplha""" """Fractal jigsaw puzzle. Still aplha"""
@ -32,19 +33,18 @@ class JigsawPuzzle(Boxes): # change class name here and below
"--depth", action="store", type=int, default=5, "--depth", action="store", type=int, default=5,
help="depth of the recursion/level of detail") help="depth of the recursion/level of detail")
def peano(self, level): def peano(self, level):
if level == 0: if level == 0:
self.edge(self.size/self.depth) self.edge(self.size / self.depth)
return return
self.peano(self, level-1)
self.corner()
self.peano(self, level - 1)
self.corner()
def edge(self, l): def edge(self, l):
self.count += 1 self.count += 1
Boxes.edge(self, l) Boxes.edge(self, l)
#if (self.count % 2**5) == 0: #level == 3 and parity>0: # if (self.count % 2**5) == 0: #level == 3 and parity>0:
# self.corner(-360, 0.25*self.size/2**self.depth) # self.corner(-360, 0.25*self.size/2**self.depth)
def hilbert(self, level, parity=1): def hilbert(self, level, parity=1):
@ -53,27 +53,30 @@ class JigsawPuzzle(Boxes): # change class name here and below
# rotate and draw first subcurve with opposite parity to big curve # rotate and draw first subcurve with opposite parity to big curve
self.corner(parity * 90) self.corner(parity * 90)
self.hilbert(level - 1, -parity) self.hilbert(level - 1, -parity)
# interface to and draw second subcurve with same parity as big curve # interface to and draw second subcurve with same parity as big curve
self.edge(self.size/2**self.depth) self.edge(self.size / 2 ** self.depth)
self.corner(parity * -90) self.corner(parity * -90)
self.hilbert(level - 1, parity) self.hilbert(level - 1, parity)
# third subcurve # third subcurve
self.edge(self.size/2**self.depth) self.edge(self.size / 2 ** self.depth)
self.hilbert(level - 1, parity) self.hilbert(level - 1, parity)
#if level == 3: self.corner(-360, 0.4*self.size/2**self.depth)
# if level == 3: self.corner(-360, 0.4*self.size/2**self.depth)
# fourth subcurve # fourth subcurve
self.corner(parity * -90) self.corner(parity * -90)
self.edge(self.size/2**self.depth) self.edge(self.size / 2 ** self.depth)
self.hilbert(level - 1, -parity) self.hilbert(level - 1, -parity)
# a final turn is needed to make the turtle # a final turn is needed to make the turtle
# end up facing outward from the large square # end up facing outward from the large square
self.corner(parity * 90) self.corner(parity * 90)
#if level == 3 and parity>0: # and random.random() < 100*0.5**(self.depth-2): # if level == 3 and parity>0: # and random.random() < 100*0.5**(self.depth-2):
# self.corner(-360, 0.4*self.size/2**self.depth) # self.corner(-360, 0.4*self.size/2**self.depth)
#self.ctx.save() # self.ctx.save()
#self.corner(parity*-90) # self.corner(parity*-90)
#self.edge(self.size/2**self.depth) # self.edge(self.size/2**self.depth)
#self.ctx.restore() # self.ctx.restore()
def render(self): def render(self):
size = self.size size = self.size
@ -85,10 +88,12 @@ class JigsawPuzzle(Boxes): # change class name here and below
self.hilbert(self.depth) self.hilbert(self.depth)
self.close() self.close()
def main(): def main():
b = JigsawPuzzle() b = JigsawPuzzle()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -17,37 +17,39 @@
from boxes import * from boxes import *
import math import math
""" """
22x7.5x7cm 22x7.5x7cm
D=23cm, d=21cm D=23cm, d=21cm
d = 8" D = 9" d = 8" D = 9"
""" """
class RoundedTriangleSettings(edges.Settings): class RoundedTriangleSettings(edges.Settings):
absolute_params = { absolute_params = {
"angle" : 60, "angle": 60,
"radius" : 30, "radius": 30,
"r_hole" : None, "r_hole": None,
} }
class RoundedTriangle(edges.Edge): class RoundedTriangle(edges.Edge):
char = "t" char = "t"
def __call__(self, length, **kw): def __call__(self, length, **kw):
angle = self.settings.angle angle = self.settings.angle
r = self.settings.radius r = self.settings.radius
if self.settings.r_hole: if self.settings.r_hole:
x = 0.5*(length-2*r)*math.tan(math.radians(angle)) x = 0.5 * (length - 2 * r) * math.tan(math.radians(angle))
y = 0.5*(length) y = 0.5 * (length)
self.hole(x, y, self.settings.r_hole) self.hole(x, y, self.settings.r_hole)
l = 0.5 * (length-2*r) / math.cos(math.radians(angle)) l = 0.5 * (length - 2 * r) / math.cos(math.radians(angle))
self.corner(90-angle, r) self.corner(90 - angle, r)
self.edge(l) self.edge(l)
self.corner(2*angle, r) self.corner(2 * angle, r)
self.edge(l) self.edge(l)
self.corner(90-angle, r) self.corner(90 - angle, r)
def startAngle(self): def startAngle(self):
return 90 return 90
@ -55,8 +57,8 @@ class RoundedTriangle(edges.Edge):
def endAngle(self): def endAngle(self):
return 90 return 90
class Lamp(Boxes):
class Lamp(Boxes):
webinterface = False webinterface = False
def __init__(self): def __init__(self):
@ -82,7 +84,7 @@ class Lamp(Boxes):
self.open() self.open()
#self.edges["f"].settings = (5, 5) # XXX # self.edges["f"].settings = (5, 5) # XXX
s = RoundedTriangleSettings(self.thickness, angle=72, r_hole=2) s = RoundedTriangleSettings(self.thickness, angle=72, r_hole=2)
self.addPart(RoundedTriangle(self, s)) self.addPart(RoundedTriangle(self, s))
@ -90,13 +92,14 @@ class Lamp(Boxes):
self.flexSettings = (3, 5.0, 20.0) self.flexSettings = (3, 5.0, 20.0)
self.edges["f"].settings.setValues(self.thickness, finger=5, space=5, relative=False) self.edges["f"].settings.setValues(self.thickness, finger=5, space=5, relative=False)
d = 2*(r+w) d = 2 * (r + w)
self.roundedPlate(d, d, r, move="right", callback=[ self.roundedPlate(d, d, r, move="right", callback=[
lambda: self.hole(w, r+w, r),]) lambda: self.hole(w, r + w, r), ])
#dist = ((2**0.5)*r-r) / (2**0.5) + 4
#pos = (w-dist, dist) # dist = ((2**0.5)*r-r) / (2**0.5) + 4
self.roundedPlate(d, d, r, holesMargin=w/2.0) #, callback=[ # pos = (w-dist, dist)
self.roundedPlate(d, d, r, holesMargin=w / 2.0) # , callback=[
# lambda: self.hole(pos[0], pos[1], 7),]) # lambda: self.hole(pos[0], pos[1], 7),])
self.roundedPlate(d, d, r, move="only left up") self.roundedPlate(d, d, r, move="only left up")
@ -119,10 +122,12 @@ class Lamp(Boxes):
self.close() self.close()
def main(): def main():
l = Lamp() l = Lamp()
l.parseArgs() l.parseArgs()
l.render(r=4*25.4, w=20, x=270, y=150, h=100) l.render(r=4 * 25.4, w=20, x=270, y=150, h=100)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class MagazinFile(Boxes): class MagazinFile(Boxes):
"""Open magazine file""" """Open magazine file"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("x", "y", "h", "hi", "outside") self.buildArgParser("x", "y", "h", "hi", "outside")
@ -27,14 +29,15 @@ class MagazinFile(Boxes):
) )
def side(self, w, h, hi): def side(self, w, h, hi):
r = min(h-hi, w) / 2.0 r = min(h - hi, w) / 2.0
if (h-hi) > w:
if (h - hi) > w:
r = w / 2.0 r = w / 2.0
lx = 0 lx = 0
ly = (h-hi) - w ly = (h - hi) - w
else: else:
r = (h - hi) / 2.0 r = (h - hi) / 2.0
lx = (w - 2*r) / 2.0 lx = (w - 2 * r) / 2.0
ly = 0 ly = 0
e_w = self.edges["F"].startwidth() e_w = self.edges["F"].startwidth()
@ -58,8 +61,8 @@ class MagazinFile(Boxes):
self.edge(e_w) self.edge(e_w)
self.corner(90) self.corner(90)
def render(self): def render(self):
if self.outside: if self.outside:
self.x = self.adjustSize(self.x) self.x = self.adjustSize(self.x)
self.y = self.adjustSize(self.y) self.y = self.adjustSize(self.y)
@ -80,15 +83,17 @@ class MagazinFile(Boxes):
self.rectangularWall(x, h, "Ffef", move="right only") self.rectangularWall(x, h, "Ffef", move="right only")
self.side(y, h, hi) self.side(y, h, hi)
self.moveTo(y+15, h+hi+15, 180) self.moveTo(y + 15, h + hi + 15, 180)
self.side(y, h, hi) self.side(y, h, hi)
self.close() self.close()
def main(): def main():
b = MagazinFile() b = MagazinFile()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -17,8 +17,10 @@
from boxes import * from boxes import *
import math import math
class Planetary(Boxes): class Planetary(Boxes):
"""Gearbox with multiple identical stages""" """Gearbox with multiple identical stages"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.argparser.add_argument( self.argparser.add_argument(
@ -39,7 +41,7 @@ class Planetary(Boxes):
self.argparser.add_argument( self.argparser.add_argument(
"--shaft", action="store", type=float, default=6., "--shaft", action="store", type=float, default=6.,
help="diameter of the shaft") help="diameter of the shaft")
#self.argparser.add_argument( # self.argparser.add_argument(
# "--stages", action="store", type=int, default=4, # "--stages", action="store", type=int, default=4,
# help="number of stages in the gear reduction") # help="number of stages in the gear reduction")
@ -47,8 +49,8 @@ class Planetary(Boxes):
# Initialize canvas # Initialize canvas
self.open() self.open()
ringteeth = self.sunteeth+2*self.planetteeth ringteeth = self.sunteeth + 2 * self.planetteeth
spoke_width = 3*self.shaft spoke_width = 3 * self.shaft
pitch1, size1, xxx = self.gears.sizes(teeth=self.sunteeth, pitch1, size1, xxx = self.gears.sizes(teeth=self.sunteeth,
dimension=self.modulus) dimension=self.modulus)
@ -59,36 +61,38 @@ class Planetary(Boxes):
dimension=self.modulus) dimension=self.modulus)
t = self.thickness t = self.thickness
planets = int(math.pi//math.asin((self.planetteeth+2)/(self.planetteeth+self.sunteeth))) planets = int(math.pi // math.asin((self.planetteeth + 2) / (self.planetteeth + self.sunteeth)))
if self.maxplanets: if self.maxplanets:
planets = min(self.maxplanets, planets) planets = min(self.maxplanets, planets)
# Make sure the teeth mash # Make sure the teeth mash
ta = self.sunteeth+ringteeth ta = self.sunteeth + ringteeth
# There are sunteeth+ringteeth mashing positions for the planets # There are sunteeth+ringteeth mashing positions for the planets
if ta % planets: if ta % planets:
planetpositions = [round(i*ta/planets)*360/ta for i in range(planets)] planetpositions = [round(i * ta / planets) * 360 / ta for i in range(planets)]
else: else:
planetpositions = planets planetpositions = planets
# XXX make configurable? # XXX make configurable?
profile_shift = 20 profile_shift = 20
pressure_angle = 20 pressure_angle = 20
self.parts.disc(size3, callback=lambda:self.hole(0,0,self.shaft/2), move="up") self.parts.disc(size3, callback=lambda: self.hole(0, 0, self.shaft / 2), move="up")
self.gears(teeth=ringteeth, dimension=self.modulus, self.gears(teeth=ringteeth, dimension=self.modulus,
angle=pressure_angle, internal_ring=True, angle=pressure_angle, internal_ring=True,
spoke_width=spoke_width, mount_hole=self.shaft, spoke_width=spoke_width, mount_hole=self.shaft,
profile_shift=profile_shift, move="up") profile_shift=profile_shift, move="up")
self.gears.gearCarrier(pitch1+pitch2, spoke_width, planetpositions, self.gears.gearCarrier(pitch1 + pitch2, spoke_width, planetpositions,
2*spoke_width, self.shaft/2, move="up") 2 * spoke_width, self.shaft / 2, move="up")
self.gears(teeth=self.sunteeth, dimension=self.modulus, self.gears(teeth=self.sunteeth, dimension=self.modulus,
angle=pressure_angle, angle=pressure_angle,
mount_hole=self.shaft, profile_shift=profile_shift, move="up") mount_hole=self.shaft, profile_shift=profile_shift, move="up")
numplanets = planets numplanets = planets
if self.deltateeth: if self.deltateeth:
numplanets += planets numplanets += planets
deltamodulus = self.modulus*ringteeth/(ringteeth-self.deltateeth) deltamodulus = self.modulus * ringteeth / (ringteeth - self.deltateeth)
self.gears(teeth=ringteeth-self.deltateeth, dimension=deltamodulus, self.gears(teeth=ringteeth - self.deltateeth, dimension=deltamodulus,
angle=pressure_angle, internal_ring=True, angle=pressure_angle, internal_ring=True,
spoke_width=spoke_width, mount_hole=self.shaft, spoke_width=spoke_width, mount_hole=self.shaft,
profile_shift=profile_shift, move="up") profile_shift=profile_shift, move="up")
@ -100,10 +104,12 @@ class Planetary(Boxes):
self.close() self.close()
def main(): def main():
b = Box() b = Box()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,8 +16,8 @@
from boxes import * from boxes import *
class Printer(Boxes):
class Printer(Boxes):
"""Work in progress""" """Work in progress"""
webinterface = False webinterface = False
@ -32,44 +32,46 @@ class Printer(Boxes):
self.d_i = 5.0 self.d_i = 5.0
self.w_i = 7.0 # includes washers self.w_i = 7.0 # includes washers
def mainPlate(self, nr): def mainPlate(self, nr):
r = self.r r = self.r
t2 = 0.5 * self.thickness t2 = 0.5 * self.thickness
if nr: if nr:
return return
self.moveTo(r-5, r, -90) self.moveTo(r - 5, r, -90)
self.hole(0, 0, r-80) self.hole(0, 0, r - 80)
D_i2 = self.D_i / 2 D_i2 = self.D_i / 2
w_i2 = self.w_i / 2 w_i2 = self.w_i / 2
d_c2 = self.d_c/2 d_c2 = self.d_c / 2
for i in range(6): for i in range(6):
self.ctx.save() self.ctx.save()
self.moveTo(0, 0, i*60) self.moveTo(0, 0, i * 60)
# winches # winches
if i % 2: if i % 2:
self.fingerHolesAt(r-80, (d_c2+20), 70, angle=0) self.fingerHolesAt(r - 80, (d_c2 + 20), 70, angle=0)
self.fingerHolesAt(r-80, -(d_c2+20), 70, angle=0) self.fingerHolesAt(r - 80, -(d_c2 + 20), 70, angle=0)
if i==5: if i == 5:
self.fingerHolesAt(r-70+t2, -(d_c2+20+t2), 40, angle=-90) self.fingerHolesAt(r - 70 + t2, -(d_c2 + 20 + t2), 40, angle=-90)
else: else:
self.fingerHolesAt(r-70+t2, (d_c2+20+t2), 40, angle=90) self.fingerHolesAt(r - 70 + t2, (d_c2 + 20 + t2), 40, angle=90)
# idler buck # idler buck
else: else:
d = 0.5*(self.thickness)+w_i2 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()
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): def head(self):
d_c = self.d_c d_c = self.d_c
self.moveTo(self.spacing+10, self.spacing) self.moveTo(self.spacing + 10, self.spacing)
for i in range(3): for i in range(3):
self.hole(0, 5, 0.3) self.hole(0, 5, 0.3)
self.fingerHolesAt(25, 0, 20) self.fingerHolesAt(25, 0, 20)
@ -78,20 +80,20 @@ class Printer(Boxes):
self.hole(0, 5, 0.3) self.hole(0, 5, 0.3)
self.corner(120, 10) self.corner(120, 10)
def support(self, x, y, edges="ff", pair=False, callback=None, move=None): def support(self, x, y, edges="ff", pair=False, callback=None, move=None):
if len(edges) != 2: if len(edges) != 2:
raise ValueError("Two edges required") raise ValueError("Two edges required")
edges = [self.edges.get(e, e,) for e in edges]
edges = [self.edges.get(e, e, ) for e in edges]
overallwidth = x + edges[0].spacing() + self.edges["e"].spacing() overallwidth = x + edges[0].spacing() + self.edges["e"].spacing()
overallheight = y + edges[1].spacing() + self.edges["e"].spacing() overallheight = y + edges[1].spacing() + self.edges["e"].spacing()
r = 2*self.thickness r = 2 * self.thickness
if pair: if pair:
overallwidth+= edges[0].spacing() + r - self.edges["e"].spacing() overallwidth += edges[0].spacing() + r - self.edges["e"].spacing()
overallheight+= edges[1].spacing() + r - self.edges["e"].spacing() overallheight += edges[1].spacing() + r - self.edges["e"].spacing()
if self.move(overallwidth, overallheight, move, before=True): if self.move(overallwidth, overallheight, move, before=True):
return return
@ -99,16 +101,16 @@ class Printer(Boxes):
self.ctx.save() self.ctx.save()
self.moveTo(edges[0].margin(), edges[1].margin()) self.moveTo(edges[0].margin(), edges[1].margin())
angle = math.degrees(math.atan((y-r)/float(x-r))) angle = math.degrees(math.atan((y - r) / float(x - r)))
self.cc(callback, 0) self.cc(callback, 0)
edges[1](x) edges[1](x)
self.corner(90) self.corner(90)
#self.edge(self.thickness) # self.edge(self.thickness)
self.corner(90-angle, r) self.corner(90 - angle, r)
self.edge(((x-r)**2+(y-r)**2)**0.5) self.edge(((x - r) ** 2 + (y - r) ** 2) ** 0.5)
self.corner(angle, r) self.corner(angle, r)
#self.edge(self.thickness) # self.edge(self.thickness)
self.corner(90) self.corner(90)
self.cc(callback, 0) self.cc(callback, 0)
edges[0](y) edges[0](y)
@ -127,10 +129,11 @@ class Printer(Boxes):
self.open() self.open()
self.edges["f"].settings.setValues(self.thickness, surroundingspaces=0) self.edges["f"].settings.setValues(self.thickness, surroundingspaces=0)
self.ctx.save() self.ctx.save()
for i in range(3): for i in range(3):
# motor mounts # motor mounts
self.rectangularWall(70, 70, edges="feee", callback=[ self.rectangularWall(70, 70, edges="feee", callback=[
lambda: self.NEMA(23, 35, 35),], lambda: self.NEMA(23, 35, 35), ],
move="right") move="right")
# winch bucks # winch bucks
self.rectangularWall(50, 70, edges="efee", callback=[ self.rectangularWall(50, 70, edges="efee", callback=[
@ -138,25 +141,30 @@ class Printer(Boxes):
lambda: self.hole(35, 35, 8.5), lambda: self.hole(35, 35, 8.5),
None, None,
lambda: self.fingerHolesAt(10, 0, 50)], move="right") lambda: self.fingerHolesAt(10, 0, 50)], move="right")
self.support(40, 50, move="right", pair=True) self.support(40, 50, move="right", pair=True)
self.support(40, 50, move="right") self.support(40, 50, move="right")
self.ctx.restore() self.ctx.restore()
self.moveTo(0, 80) self.moveTo(0, 80)
self.ctx.save() self.ctx.save()
# idler bucks # idler bucks
for i in range(12): for i in range(12):
self.rectangularWall(30, 30, edges="feee", callback=[ self.rectangularWall(30, 30, edges="feee", callback=[
lambda: self.hole(15, 15, 3),], move="right") lambda: self.hole(15, 15, 3), ], move="right")
# Cable adjustment blocks # Cable adjustment blocks
self.ctx.save() self.ctx.save()
for i in range(6): for i in range(6):
def holes(): def holes():
self.hole(5, 4, 1.5) self.hole(5, 4, 1.5)
self.hole(15, 4, 1.5) self.hole(15, 4, 1.5)
self.rectangularWall(20, 8, edges="feee", callback=[holes,],
self.rectangularWall(20, 8, edges="feee", callback=[holes, ],
move="right") move="right")
self.ctx.restore() self.ctx.restore()
self.moveTo(0, 20) self.moveTo(0, 20)
# Cable adjustment glyders # Cable adjustment glyders
for i in range(6): for i in range(6):
self.rectangularWall(8, 10, move="right", callback=[ self.rectangularWall(8, 10, move="right", callback=[
@ -172,16 +180,18 @@ class Printer(Boxes):
self.moveTo(0, 40) self.moveTo(0, 40)
# mainPlate # mainPlate
self.rectangularWall(2*self.r-10, 2*self.r-10, edges="ffff", self.rectangularWall(2 * self.r - 10, 2 * self.r - 10, edges="ffff",
callback=self.mainPlate, move="right") callback=self.mainPlate, move="right")
self.head() self.head()
self.close() self.close()
def main(): def main():
p = Printer() p = Printer()
p.parseArgs() p.parseArgs()
p.render() p.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -18,8 +18,10 @@ from boxes import *
from boxes import pulley from boxes import pulley
import math import math
class Pulley(Boxes): class Pulley(Boxes):
"""Timing belt pulleys for different profiles""" """Timing belt pulleys for different profiles"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
# remove cli params you do not need # remove cli params you do not need
@ -39,22 +41,25 @@ class Pulley(Boxes):
help="overlap of top rim (zero for none)") help="overlap of top rim (zero for none)")
# Add non default cli params if needed (see argparse std lib) # Add non default cli params if needed (see argparse std lib)
#self.argparser.add_argument( # self.argparser.add_argument(
# "--XX", action="store", type=float, default=0.5, # "--XX", action="store", type=float, default=0.5,
# help="DESCRIPTION") # help="DESCRIPTION")
def disk(self, diameter, hole, callback=None, move=""): def disk(self, diameter, hole, callback=None, move=""):
w = diameter + 2*self.spacing w = diameter + 2 * self.spacing
if self.move(w, w, move, before=True): if self.move(w, w, move, before=True):
return return
self.ctx.save() self.ctx.save()
self.moveTo(w/2, w/2) self.moveTo(w / 2, w / 2)
self.cc(callback, None, 0.0, 0.0) self.cc(callback, None, 0.0, 0.0)
if hole: if hole:
self.hole(0, 0, hole/2.0) self.hole(0, 0, hole / 2.0)
self.moveTo(diameter/2+self.burn, 0, 90)
self.corner(360, diameter/2) self.moveTo(diameter / 2 + self.burn, 0, 90)
self.corner(360, diameter / 2)
self.ctx.restore() self.ctx.restore()
self.move(w, w, move) self.move(w, w, move)
@ -63,19 +68,23 @@ class Pulley(Boxes):
t = self.thickness t = self.thickness
# Initialize canvas # Initialize canvas
self.open() self.open()
if self.top: if self.top:
self.disk( self.disk(
self.pulley.diameter(self.teeth, self.profile)+2*self.top, self.pulley.diameter(self.teeth, self.profile) + 2 * self.top,
self.axle, move="right") 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") 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() self.close()
def main(): def main():
b = Box() b = Box()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,49 +16,56 @@
from boxes import * from boxes import *
class MotorEdge(edges.BaseEdge): class MotorEdge(edges.BaseEdge):
#def margin(self): # def margin(self):
# return 30 # return 30
def __call__(self, l, **kw): def __call__(self, l, **kw):
self.polyline( self.polyline(
l-165, 45, l - 165, 45,
25*2**0.5, -45, 25 * 2 ** 0.5, -45,
60, -45, 60, -45,
25*2**0.5, 45, 25 * 2 ** 0.5, 45,
55) 55)
class OutsetEdge(edges.OutSetEdge): class OutsetEdge(edges.OutSetEdge):
def startwidth(self): def startwidth(self):
return 20 return 20
class HangerEdge(edges.BaseEdge): class HangerEdge(edges.BaseEdge):
char = "H" char = "H"
def margin(self): def margin(self):
return 40 return 40
def __call__(self, l, **kw): def __call__(self, l, **kw):
self.fingerHolesAt(0, -0.5*self.thickness, l, angle=0) self.fingerHolesAt(0, -0.5 * self.thickness, l, angle=0)
w = self.settings w = self.settings
self.polyline(0, -90, self.polyline(0, -90,
22+w, 90, 22 + w, 90,
70, 135, 70, 135,
2**0.5*12, 45, 2 ** 0.5 * 12, 45,
35, -45, 35, -45,
2**0.5*0.5*w, -90, 2 ** 0.5 * 0.5 * w, -90,
2**0.5*0.5*w, -45, 2 ** 0.5 * 0.5 * w, -45,
l -28, 45, l - 28, 45,
2**0.5*5, 45, 5, -90) 2 ** 0.5 * 5, 45, 5, -90)
class RollerEdge(edges.BaseEdge): class RollerEdge(edges.BaseEdge):
def margin(self): def margin(self):
return 20 return 20
def __call__(self, l, **kw): def __call__(self, l, **kw):
m = 40+100 m = 40 + 100
self.polyline((l-m)/2.0, -45, self.polyline((l - m) / 2.0, -45,
2**0.5*20, 45, 2 ** 0.5 * 20, 45,
100, 45, 100, 45,
2**0.5*20, -45, 2 ** 0.5 * 20, -45,
(l-m)/2.0) (l - m) / 2.0)
class RollerEdge2(edges.BaseEdge): class RollerEdge2(edges.BaseEdge):
def margin(self): def margin(self):
@ -66,17 +73,19 @@ class RollerEdge2(edges.BaseEdge):
def __call__(self, l, **kw): def __call__(self, l, **kw):
a = 30 a = 30
f = 1/math.cos(math.radians(a)) f = 1 / math.cos(math.radians(a))
self.edges["f"](70) self.edges["f"](70)
self.polyline(0, a, f*25, -a, l-190, -a, f*25, a, 0) self.polyline(0, a, f * 25, -a, l - 190, -a, f * 25, a, 0)
self.edges["f"](70) self.edges["f"](70)
class Rotary(Boxes): class Rotary(Boxes):
"""Rotary Attachment for engraving cylindrical objects in a laser cutter""" """Rotary Attachment for engraving cylindrical objects in a laser cutter"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
# remove cli params you do not need # remove cli params you do not need
#self.buildArgParser("x", "sx", "y", "sy", "h", "hi") # self.buildArgParser("x", "sx", "y", "sy", "h", "hi")
# Add non default cli params if needed (see argparse std lib) # Add non default cli params if needed (see argparse std lib)
self.argparser.add_argument( self.argparser.add_argument(
"--diameter", action="store", type=float, default=72., "--diameter", action="store", type=float, default=72.,
@ -91,73 +100,75 @@ class Rotary(Boxes):
"--knifethickness", action="store", type=float, default=8., "--knifethickness", action="store", type=float, default=8.,
help="thickness of the knifes in mm. Use 0 for use with honey comb table.") help="thickness of the knifes in mm. Use 0 for use with honey comb table.")
def mainPlate(self): def mainPlate(self):
# Motor block outer side # Motor block outer side
t = self.thickness t = self.thickness
d = self.diameter d = self.diameter
a = self.axle a = self.axle
self.hole(1.0*d, 0.6*d, a/2.) self.hole(1.0 * d, 0.6 * d, a / 2.)
#self.hole(1.0*d, 0.6*d, d/2.) # self.hole(1.0*d, 0.6*d, d/2.)
self.hole(2.0*d+5, 0.6*d, a/2.) self.hole(2.0 * d + 5, 0.6 * d, a / 2.)
#self.hole(2.0*d+5, 0.6*d, d/2.) # self.hole(2.0*d+5, 0.6*d, d/2.)
# Main beam # Main beam
self.rectangularHole(1.5*d+2.5, 3.6, 32, 7.1) self.rectangularHole(1.5 * d + 2.5, 3.6, 32, 7.1)
def frontPlate(self): def frontPlate(self):
# Motor block inner side with motor mount # Motor block inner side with motor mount
t = self.thickness t = self.thickness
d = self.diameter d = self.diameter
a = self.axle a = self.axle
self.hole(1.0*d, 0.6*d, a/2.) self.hole(1.0 * d, 0.6 * d, a / 2.)
#self.hole(1.0*d, 0.6*d, d/2.) # self.hole(1.0*d, 0.6*d, d/2.)
self.hole(2.0*d+5, 0.6*d, a/2.) self.hole(2.0 * d + 5, 0.6 * d, a / 2.)
#self.hole(2.0*d+5, 0.6*d, d/2.) # self.hole(2.0*d+5, 0.6*d, d/2.)
# Main beam # Main beam
self.rectangularHole(1.5*d+2.5, 3.6, 32, 7.1) self.rectangularHole(1.5 * d + 2.5, 3.6, 32, 7.1)
# Motor # Motor
mx = 2.7*d+20 mx = 2.7 * d + 20
self.rectangularHole(mx, 0.6*d, 36+20, 36, r=36/2.0) self.rectangularHole(mx, 0.6 * d, 36 + 20, 36, r=36 / 2.0)
for x in (-1, 1): for x in (-1, 1):
for y in (-1,1): for y in (-1, 1):
self.rectangularHole(mx+x*25, 0.6*d+y*25, 20, 4, r=2) self.rectangularHole(mx + x * 25, 0.6 * d + y * 25, 20, 4, r=2)
def link(self, x, y, a, middleHole=False, move=None): def link(self, x, y, a, middleHole=False, move=None):
t = self. thickness t = self.thickness
overallwidth = x + y overallwidth = x + y
overallheight = y overallheight = y
ra = a/2.0 ra = a / 2.0
if self.move(overallwidth, overallheight, move, before=True): if self.move(overallwidth, overallheight, move, before=True):
return return
self.moveTo(y/2.0, 0) self.moveTo(y / 2.0, 0)
self.hole(0, y/2., ra) self.hole(0, y / 2., ra)
self.hole(x, y/2., ra) self.hole(x, y / 2., ra)
if middleHole: if middleHole:
self.hole(x/2., y/2., ra) self.hole(x / 2., y / 2., ra)
self.edge(10) self.edge(10)
self.edges["F"](60) self.edges["F"](60)
self.polyline(x-70, (180, y/2.), x, (180, y/2.)) self.polyline(x - 70, (180, y / 2.), x, (180, y / 2.))
self.ctx.stroke() self.ctx.stroke()
self.move(overallwidth, overallheight, move) self.move(overallwidth, overallheight, move)
def holderBaseCB(self): def holderBaseCB(self):
self.hole(20, 30, self.a/2) self.hole(20, 30, self.a / 2)
self.rectangularHole(self.hl-70, self.hh-10, 110, self.a, r=self.a/2) self.rectangularHole(self.hl - 70, self.hh - 10, 110, self.a, r=self.a / 2)
self.rectangularHole(self.hl/2, 3.6, 32, 7.1) self.rectangularHole(self.hl / 2, 3.6, 32, 7.1)
def holderTopCB(self): def holderTopCB(self):
self.fingerHolesAt(0, 30-0.5*self.thickness, self.hl, 0) self.fingerHolesAt(0, 30 - 0.5 * self.thickness, self.hl, 0)
d = self.diameter/2.0 + 1 d = self.diameter / 2.0 + 1
y = -0.6*self.diameter + 2*self.hh y = -0.6 * self.diameter + 2 * self.hh
print(y) 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.axle / 2.0)
self.hole(self.hl/2+d, y, self.diameter/2.0) self.hole(self.hl / 2 - d, y, self.axle / 2.0)
self.hole(self.hl/2-d, y, self.diameter/2.0) self.hole(self.hl / 2 + d, y, self.diameter / 2.0)
self.hole(self.hl / 2 - d, y, self.diameter / 2.0)
def render(self): def render(self):
# adjust to the variables you want in the local scope # adjust to the variables you want in the local scope
@ -166,7 +177,7 @@ class Rotary(Boxes):
a = self.a = self.axle a = self.a = self.axle
# Initialize canvas # Initialize canvas
self.open() self.open()
#self.spacing = 0.1 * t # self.spacing = 0.1 * t
# Change settings of default edges if needed. E.g.: # Change settings of default edges if needed. E.g.:
self.edges["f"].settings.setValues(self.thickness, space=2, finger=2, self.edges["f"].settings.setValues(self.thickness, space=2, finger=2,
@ -181,124 +192,137 @@ class Rotary(Boxes):
hh = self.hh = 40. hh = self.hh = 40.
hl = self.hl = 240 hl = self.hl = 240
# Base # 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, hh, edges="hfef", callback=[self.holderBaseCB], move="up")
self.rectangularWall(hl, hw, edges="ffff", callback=[ self.rectangularWall(hl, hw, edges="ffff", callback=[lambda: self.hole(hl / 2 - 16 - 20, 25, 5)], move="up")
lambda: self.hole(hl/2-16-20, 25, 5)], move="up")
self.ctx.save() 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") self.rectangularWall(hw, hh, edges="hFeF", move="right")
# Top # Top
th = 30 th = 30
# sides # 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",
self.rectangularWall(hw+20, th, edges="fFeF", move="right", callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)])
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.ctx.restore()
self.rectangularWall(hw, hh, edges="hFeF", move="up only") self.rectangularWall(hw, hh, edges="hFeF", move="up only")
outset = OutsetEdge(self, None) outset = OutsetEdge(self, None)
roller2 = RollerEdge2(self, None) roller2 = RollerEdge2(self, None)
self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[ 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=[ 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.rectangularWall(hl, th, edges=[roller2, "f", RollerEdge(self, None), "f"], callback=[
self.holderTopCB], move="up") self.holderTopCB], move="up")
self.rectangularWall(hl, 20-t, edges="feee", move="up") self.rectangularWall(hl, 20 - t, edges="feee", move="up")
tl = 70 tl = 70
self.rectangularWall(tl, hw+20, edges="FeFF", move="right", self.rectangularWall(tl, hw + 20, edges="FeFF", move="right",
callback=[None, lambda:self.fingerHolesAt(20-0.5*t,0, tl)]) callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])
self.rectangularWall(tl, hw+20, edges="FeFF", move="", self.rectangularWall(tl, hw + 20, edges="FeFF", move="",
callback=[None, lambda:self.fingerHolesAt(20-0.5*t,0, tl)]) callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])
self.rectangularWall(tl, hw+20, edges="FeFF", move="left up only", self.rectangularWall(tl, hw + 20, edges="FeFF", move="left up only",
callback=[None, lambda:self.fingerHolesAt(20-0.5*t,0, tl)]) callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])
# Links # Links
self.link(hl-40, 25, a, True, move="up") self.link(hl - 40, 25, a, True, move="up")
self.link(hl-40, 25, a, True, move="up") self.link(hl - 40, 25, a, True, move="up")
self.link(hl-40, 25, a, True, move="up") self.link(hl - 40, 25, a, True, move="up")
self.link(hl-40, 25, a, True, move="up") self.link(hl - 40, 25, a, True, move="up")
self.ctx.save() self.ctx.save()
self.rectangularWall(hw-2*t-2, 60, edges="efef",move="right") self.rectangularWall(hw - 2 * t - 2, 60, edges="efef", move="right")
self.rectangularWall(hw-4*t-4, 60, edges="efef",move="right") self.rectangularWall(hw - 4 * t - 4, 60, edges="efef", move="right")
# Spindel auxiliaries # Spindel auxiliaries
self.parts.waivyKnob(50, callback=lambda:self.nutHole("M8"), move="right") self.parts.waivyKnob(50, callback=lambda: self.nutHole("M8"), move="right")
self.parts.waivyKnob(50, callback=lambda:self.nutHole("M8"), move="right") self.parts.waivyKnob(50, callback=lambda: self.nutHole("M8"), move="right")
self.ctx.restore() self.ctx.restore()
self.rectangularWall(hw-2*t-4, 60, edges="efef",move="up only") self.rectangularWall(hw - 2 * t - 4, 60, edges="efef", move="up only")
self.ctx.save() self.ctx.save()
slot = edges.SlottedEdge(self, [(30-t)/2, (30-t)/2], slots=15) slot = edges.SlottedEdge(self, [(30 - t) / 2, (30 - t) / 2], slots=15)
self.rectangularWall(30, 30, edges=["e", "e", slot, "e"], self.rectangularWall(30, 30, edges=["e", "e", slot, "e"],
callback=[lambda:self.hole(7, 23, self.axle/2)], move="right") callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right")
self.rectangularWall(30, 30, edges=["e", "e", slot, "e"], self.rectangularWall(30, 30, edges=["e", "e", slot, "e"],
callback=[lambda:self.hole(7, 23, self.axle/2)], move="right") callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right")
leftover = (hw-6*t-6-20) / 2.0 leftover = (hw - 6 * t - 6 - 20) / 2.0
slot = edges.SlottedEdge(self, [leftover, 20, leftover], slots=15) slot = edges.SlottedEdge(self, [leftover, 20, leftover], slots=15)
self.rectangularWall(hw-4*t-6, 30, edges=[slot, "e", "e", "e"], self.rectangularWall(hw - 4 * t - 6, 30, edges=[slot, "e", "e", "e"],
callback=[lambda:self.hole((hw-4*t-6)/2., 15, 4)], move="right") callback=[lambda: self.hole((hw - 4 * t - 6) / 2., 15, 4)], move="right")
for i in range(3): for i in range(3):
self.rectangularWall(20, 30, self.rectangularWall(20, 30,
callback=[lambda:self.nutHole("M8", 10, 15)], move="right") callback=[lambda: self.nutHole("M8", 10, 15)], move="right")
self.rectangularWall(20, 30, self.rectangularWall(20, 30,
callback=[lambda:self.hole(10, 15, 4)], move="right") callback=[lambda: self.hole(10, 15, 4)], move="right")
self.ctx.restore() self.ctx.restore()
self.rectangularWall(30, 30, move="up only") self.rectangularWall(30, 30, move="up only")
# Other side # Other side
if self.knifethickness: if self.knifethickness:
ow = 10 ow = 10
self.rectangularWall(3.6*d, 1.1*d, edges="hfFf", callback=[ self.rectangularWall(3.6 * d, 1.1 * d, edges="hfFf", callback=[
lambda:self.rectangularHole(1.8*d, 3.6, 32, 7.1)], move="up") lambda: self.rectangularHole(1.8 * d, 3.6, 32, 7.1)], move="up")
self.rectangularWall(3.6*d, 1.1*d, edges="hfFf", callback=[ self.rectangularWall(3.6 * d, 1.1 * d, edges="hfFf", callback=[
lambda:self.rectangularHole(1.8*d, 3.6, 32, 7.1)], move="up") lambda: self.rectangularHole(1.8 * d, 3.6, 32, 7.1)], move="up")
self.rectangularWall(3.6*d, ow, edges="ffff", move="up") self.rectangularWall(3.6 * d, ow, edges="ffff", move="up")
self.rectangularWall(3.6*d, ow, edges="ffff", move="up") self.rectangularWall(3.6 * d, ow, edges="ffff", move="up")
self.ctx.save() self.ctx.save()
self.rectangularWall(ow, 1.1*d, edges="hFFH", move="right") self.rectangularWall(ow, 1.1 * d, edges="hFFH", move="right")
self.rectangularWall(ow, 1.1*d, edges="hFFH", move="right") self.rectangularWall(ow, 1.1 * d, edges="hFFH", move="right")
self.ctx.restore() self.ctx.restore()
self.rectangularWall(ow, 1.1*d, edges="hFFH", move="up only") self.rectangularWall(ow, 1.1 * d, edges="hFFH", move="up only")
# Motor block # Motor block
mw = 40 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.mainPlate],
self.rectangularWall(3.6*d, 1.1*d, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.frontPlate], move="up") move="up")
self.rectangularWall(3.6*d, mw, edges="ffff", 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.ctx.save()
self.rectangularWall(mw, 1.1*d, edges="hFeH", move="right") self.rectangularWall(mw, 1.1 * d, edges="hFeH", move="right")
self.rectangularWall(mw, 1.1*d, edges="hFeH", move="right") self.rectangularWall(mw, 1.1 * d, edges="hFeH", move="right")
self.pulley(88, "GT2_2mm", r_axle=a/2.0,move="right") self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right")
self.pulley(88, "GT2_2mm", r_axle=a/2.0,move="right") self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right")
self.ctx.restore() self.ctx.restore()
self.rectangularWall(mw, 1.1*d, edges="hFeH", move="up only") self.rectangularWall(mw, 1.1 * d, edges="hFeH", move="up only")
self.axle = 19 self.axle = 19
for i in range(3): for i in range(3):
self.parts.disc(self.diameter-2*self.rubberthickness, self.parts.disc(self.diameter - 2 * self.rubberthickness,
hole=self.axle, move="right") hole=self.axle, move="right")
self.parts.disc(self.diameter-2*self.rubberthickness, self.parts.disc(self.diameter - 2 * self.rubberthickness,
hole=self.axle, move="up right") hole=self.axle, move="up right")
for i in range(3): for i in range(3):
self.parts.disc(self.diameter-2*self.rubberthickness, self.parts.disc(self.diameter - 2 * self.rubberthickness,
hole=self.axle, move="left") hole=self.axle, move="left")
self.parts.disc(self.diameter-2*self.rubberthickness, self.parts.disc(self.diameter - 2 * self.rubberthickness,
hole=self.axle, move="left up") hole=self.axle, move="left up")
for i in range(3): for i in range(3):
self.parts.disc(self.diameter-2*self.rubberthickness+4, self.parts.disc(self.diameter - 2 * self.rubberthickness + 4,
hole=self.axle, move="right") hole=self.axle, move="right")
self.parts.disc(self.diameter-2*self.rubberthickness+4, self.parts.disc(self.diameter - 2 * self.rubberthickness + 4,
hole=self.axle, move="right up") hole=self.axle, move="right up")
self.close() self.close()
def main(): def main():
b = Box() b = Box()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,6 +16,7 @@
from boxes import Boxes from boxes import Boxes
class Silverware(Boxes): class Silverware(Boxes):
"""Not yet parametrized cuttlery stand with carrying grip """Not yet parametrized cuttlery stand with carrying grip
using flex for rounded corners""" using flex for rounded corners"""
@ -26,19 +27,19 @@ using flex for rounded corners"""
def basePlate(self, x, y, r): def basePlate(self, x, y, r):
self.roundedPlate(x, y, r, callback=[ self.roundedPlate(x, y, r, callback=[
lambda: self.fingerHolesAt(x/3.0-r, 0, 0.5*(y-self.thickness)), lambda: self.fingerHolesAt(x / 3.0 - r, 0, 0.5 * (y - self.thickness)),
lambda: self.fingerHolesAt(x/6.0, 0, 0.5*(y-self.thickness)), lambda: self.fingerHolesAt(x / 6.0, 0, 0.5 * (y - self.thickness)),
lambda: self.fingerHolesAt(y/2.0-r, 0, x), lambda: self.fingerHolesAt(y / 2.0 - r, 0, x),
lambda: self.fingerHolesAt(x/2.0-r, 0, 0.5*(y-self.thickness)) lambda: self.fingerHolesAt(x / 2.0 - r, 0, 0.5 * (y - self.thickness))
]) ])
def wall(self, x=100, y=100, h=100, r=0): def wall(self, x=100, y=100, h=100, r=0):
self.surroundingWall(x,y,r,h, bottom='h', callback={ self.surroundingWall(x, y, r, h, bottom='h', callback={
0 : lambda: self.fingerHolesAt(x/6.0, 0, h-10), 0: lambda: self.fingerHolesAt(x / 6.0, 0, h - 10),
4 : lambda: self.fingerHolesAt(x/3.0-r, 0, h-10), 4: lambda: self.fingerHolesAt(x / 3.0 - r, 0, h - 10),
1 : lambda: self.fingerHolesAt(y/2.0-r, 0, h-10), 1: lambda: self.fingerHolesAt(y / 2.0 - r, 0, h - 10),
3 : 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), 2: lambda: self.fingerHolesAt(x / 2.0 - r, 0, h - 10),
}, },
move="up") move="up")
@ -47,49 +48,52 @@ using flex for rounded corners"""
self.moveTo(self.edges["f"].spacing(), self.edges["f"].spacing()) self.moveTo(self.edges["f"].spacing(), self.edges["f"].spacing())
for i in range(2, 5): for i in range(2, 5):
self.fingerHolesAt(i*x/6.0, 0, h-10) self.fingerHolesAt(i * x / 6.0, 0, h - 10)
self.edges["f"](x) self.edges["f"](x)
self.corner(90) self.corner(90)
self.edges["f"](h-10) self.edges["f"](h - 10)
self.corner(90) self.corner(90)
self.handle(x, 150, 120) self.handle(x, 150, 120)
#self.handle(x, 40, 30, r=2) # self.handle(x, 40, 30, r=2)
self.corner(90) self.corner(90)
self.edges["f"](h-10) self.edges["f"](h - 10)
self.corner(90) self.corner(90)
self.ctx.restore() self.ctx.restore()
self.moveTo(x+2*self.edges["f"].spacing()) self.moveTo(x + 2 * self.edges["f"].spacing())
################################################## ##################################################
### main ### main
################################################## ##################################################
def render(self): def render(self):
x, y, h, r = 250, 250/1.618, 120, 30 x, y, h, r = 250, 250 / 1.618, 120, 30
self.open() self.open()
t = self.thickness t = self.thickness
b = self.burn b = self.burn
self.wall(x, y, h, r) self.wall(x, y, h, r)
self.centerWall(x,h) self.centerWall(x, h)
l = (y - t) / 2.0
l = (y-t)/2.0
for i in range(3): for i in range(3):
self.rectangularWall(l, h-10, edges="ffef", move="right") self.rectangularWall(l, h - 10, edges="ffef", move="right")
self.moveTo(-3.0*(l+2*t+8*b), h-10+2*t+8*b) self.moveTo(-3.0 * (l + 2 * t + 8 * b), h - 10 + 2 * t + 8 * b)
self.basePlate(x, y, r) self.basePlate(x, y, r)
self.close() self.close()
def main(): def main():
b = Silverware() b = Silverware()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,40 +16,44 @@
from boxes import * from boxes import *
class TrayInsert(Boxes): class TrayInsert(Boxes):
"""Tray insert without floor and outer walls - allows only continuous walls""" """Tray insert without floor and outer walls - allows only continuous walls"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("sx", "sy", "h", "outside") self.buildArgParser("sx", "sy", "h", "outside")
def render(self): def render(self):
if self.outside: if self.outside:
self.sx = self.adjustSize(self.sx, False, False) self.sx = self.adjustSize(self.sx, False, False)
self.sy = self.adjustSize(self.sy, False, False) self.sy = self.adjustSize(self.sy, False, False)
x = sum(self.sx) + self.thickness * (len(self.sx)-1) x = sum(self.sx) + self.thickness * (len(self.sx) - 1)
y = sum(self.sy) + self.thickness * (len(self.sy)-1) y = sum(self.sy) + self.thickness * (len(self.sy) - 1)
h = self.h h = self.h
t = self.thickness t = self.thickness
self.open() self.open()
# Inner walls # Inner walls
for i in range(len(self.sx)-1): for i in range(len(self.sx) - 1):
e = [edges.SlottedEdge(self, self.sy, slots=0.5*h), "e", "e", "e"] e = [edges.SlottedEdge(self, self.sy, slots=0.5 * h), "e", "e", "e"]
self.rectangularWall(y, h, e, self.rectangularWall(y, h, e, move="up")
move="up")
for i in range(len(self.sy)-1): for i in range(len(self.sy) - 1):
e = ["e", "e", e = ["e", "e", edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * h), "e"]
edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5*h), "e"] self.rectangularWall(x, h, e, move="up")
self.rectangularWall(x, h, e,
move="up")
self.close() self.close()
def main(): def main():
b = TrayInsert() b = TrayInsert()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -18,8 +18,8 @@ import sys, re
from boxes import * from boxes import *
import boxes import boxes
class Layout(Boxes):
class Layout(Boxes):
"""Generate a typetray from a layout file""" """Generate a typetray from a layout file"""
webinterface = False webinterface = False
@ -44,49 +44,54 @@ class Layout(Boxes):
def fillDefault(self, x, y): def fillDefault(self, x, y):
self.x = [0.0] * x self.x = [0.0] * x
self.y = [0.0] * y self.y = [0.0] * y
self.hwalls = [[True for i in range(x)] for j in range(y+1)] self.hwalls = [[True for i in range(x)] for j in range(y + 1)]
self.vwalls = [[True for i in range(x+1)] for j in range(y)] self.vwalls = [[True for i in range(x + 1)] for j in range(y)]
self.floors = [[True for i in range(x)] for j in range(y)] self.floors = [[True for i in range(x)] for j in range(y)]
def __str__(self): def __str__(self):
r = [] r = []
for i, x in enumerate(self.x): for i, x in enumerate(self.x):
r.append(" |" * (i) + " ,> %.1fmm\n" % x) r.append(" |" * (i) + " ,> %.1fmm\n" % x)
for hwalls, vwalls, floors, y in zip( for hwalls, vwalls, floors, y in zip(
self.hwalls, self.vwalls, self.floors, self.y): self.hwalls, self.vwalls, self.floors, self.y):
r.append("".join(("+" + " -"[h] for h in hwalls)) + "+\n") r.append("".join(("+" + " -"[h] for h in hwalls)) + "+\n")
r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors))) r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors)))
+ " |"[vwalls[-1]] + " %.1fmm\n" % y) + " |"[vwalls[-1]] + " %.1fmm\n" % y)
r.append("".join(("+" + " -"[h] for h in self.hwalls[-1])) + "+\n") r.append("".join(("+" + " -"[h] for h in self.hwalls[-1])) + "+\n")
return "".join(r) return "".join(r)
def vWalls(self, x, y): def vWalls(self, x, y):
"Number of vertical walls at a crossing" "Number of vertical walls at a crossing"
result = 0 result = 0
if y>0 and self.vwalls[y-1][x]: if y > 0 and self.vwalls[y - 1][x]:
result += 1 result += 1
if y < len(self.y) and self.vwalls[y][x]: if y < len(self.y) and self.vwalls[y][x]:
result += 1 result += 1
return result return result
def hWalls(self, x, y): def hWalls(self, x, y):
"Number of horizontal walls at a crossing" "Number of horizontal walls at a crossing"
result = 0 result = 0
if x>0 and self.hwalls[y][x-1]: if x > 0 and self.hwalls[y][x - 1]:
result += 1 result += 1
if x<len(self.x) and self.hwalls[y][x]: if x < len(self.x) and self.hwalls[y][x]:
result += 1 result += 1
return result return result
def vFloor(self, x, y): def vFloor(self, x, y):
"Is there floor under vertical wall" "Is there floor under vertical wall"
return ((x>0 and self.floors[y][x-1]) or return ((x > 0 and self.floors[y][x - 1]) or
(x<len(self.x) and self.floors[y][x])) (x < len(self.x) and self.floors[y][x]))
def hFloor(self, x, y): def hFloor(self, x, y):
"Is there foor under horizontal wall" "Is there foor under horizontal wall"
return ((y>0 and self.floors[y-1][x]) or return ((y > 0 and self.floors[y - 1][x]) or
(y<len(self.y) and self.floors[y][x])) (y < len(self.y) and self.floors[y][x]))
@restore @restore
def edgeAt(self, edge, x, y, length, angle=0): def edgeAt(self, edge, x, y, length, angle=0):
@ -99,6 +104,7 @@ class Layout(Boxes):
self.x = self.adjustSize(self.x) self.x = self.adjustSize(self.x)
self.y = self.adjustSize(self.y) self.y = self.adjustSize(self.y)
self.h = self.adjustSize(self.h, e2=False) self.h = self.adjustSize(self.h, e2=False)
if self.hi: if self.hi:
self.hi = self.adjustSize(self.hi, e2=False) self.hi = self.adjustSize(self.hi, e2=False)
@ -117,7 +123,7 @@ class Layout(Boxes):
self.open() self.open()
self.edges["s"] = boxes.edges.Slot(self, self.hi/2.0) self.edges["s"] = boxes.edges.Slot(self, self.hi / 2.0)
self.edges["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi) self.edges["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi)
self.ctx.save() self.ctx.save()
@ -128,22 +134,30 @@ class Layout(Boxes):
h = self.h h = self.h
else: else:
h = self.hi h = self.hi
start = 0 start = 0
end = 0 end = 0
while end < lx: while end < lx:
lengths = [] lengths = []
edges = [] 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: if start == lx:
break break
end = start end = start
while end < lx and self.hwalls[y][end]: while end < lx and self.hwalls[y][end]:
if self.hFloor(end, y): if self.hFloor(end, y):
edges.append("f") edges.append("f")
else: else:
edges.append("e") # XXX E? edges.append("e") # XXX E?
lengths.append(self.x[end]) lengths.append(self.x[end])
edges.append("eCs"[self.vWalls(end+1, y)]) edges.append("eCs"[self.vWalls(end + 1, y)])
lengths.append(self.thickness) lengths.append(self.thickness)
end += 1 end += 1
@ -170,20 +184,26 @@ class Layout(Boxes):
h = self.hi h = self.hi
start = 0 start = 0
end = 0 end = 0
while end < ly: while end < ly:
lengths = [] lengths = []
edges = [] 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: if start == ly:
break break
end = start end = start
while end < ly and self.vwalls[end][x]: while end < ly and self.vwalls[end][x]:
if self.vFloor(x, end): if self.vFloor(x, end):
edges.append("f") edges.append("f")
else: else:
edges.append("e") # XXX E? edges.append("e") # XXX E?
lengths.append(self.y[end]) lengths.append(self.y[end])
edges.append("eCs"[self.hWalls(x, end+1)]) edges.append("eCs"[self.hWalls(x, end + 1)])
lengths.append(self.thickness) lengths.append(self.thickness)
end += 1 end += 1
# remove last "slot" # remove last "slot"
@ -191,23 +211,23 @@ class Layout(Boxes):
edges.pop() edges.pop()
upper = [{ upper = [{
"f" : "e", "f": "e",
"s" : "s", "s": "s",
"e" : "e", "e": "e",
"E" : "e", "E": "e",
"C" : "e"}[e] for e in reversed(edges)] "C": "e"}[e] for e in reversed(edges)]
edges = ["e" if e == "s" else e for e in edges] edges = ["e" if e == "s" else e for e in edges]
self.rectangularWall(sum(lengths), h, [ self.rectangularWall(sum(lengths), h, [
boxes.edges.CompoundEdge(self, edges, lengths), boxes.edges.CompoundEdge(self, edges, lengths),
"eFf"[self.hWalls(x, end)], "eFf"[self.hWalls(x, end)],
boxes.edges.CompoundEdge(self, upper, list(reversed(lengths))), boxes.edges.CompoundEdge(self, upper, list(reversed(lengths))),
"eFf"[self.hWalls(x, start)] ], "eFf"[self.hWalls(x, start)]],
move="right") move="right")
start = end start = end
self.ctx.restore() self.ctx.restore()
self.rectangularWall(10, h, "ffef", move="up only") self.rectangularWall(10, h, "ffef", move="up only")
self.moveTo(2*self.thickness, 2*self.thickness) self.moveTo(2 * self.thickness, 2 * self.thickness)
self.ctx.save() self.ctx.save()
########################################################## ##########################################################
@ -224,54 +244,54 @@ class Layout(Boxes):
else: else:
e = "e" e = "e"
if y < ly and self.floors[y][x]: if y < ly and self.floors[y][x]:
if y>0 and self.floors[y-1][x]: if y > 0 and self.floors[y - 1][x]:
# Inside Wall # Inside Wall
if self.hwalls[y][x]: if self.hwalls[y][x]:
self.fingerHolesAt(posx, posy+t2, self.x[x], angle=0) self.fingerHolesAt(posx, posy + t2, self.x[x], angle=0)
else: else:
# Top edge # Top edge
self.edgeAt(e, posx+self.x[x], posy+t, self.x[x], self.edgeAt(e, posx + self.x[x], posy + t, self.x[x],
-180) -180)
if x==0 or y==0 or not self.floors[y-1][x-1]: if x == 0 or y == 0 or not self.floors[y - 1][x - 1]:
self.edgeAt("e", posx, posy+t, t, -180) self.edgeAt("e", posx, posy + t, t, -180)
if x==lx-1 or y==0 or not self.floors[y-1][x+1]: if x == lx - 1 or y == 0 or not self.floors[y - 1][x + 1]:
self.edgeAt("e", posx+self.x[x]+t, posy+t, t, -180) self.edgeAt("e", posx + self.x[x] + t, posy + t, t, -180)
elif y>0 and self.floors[y-1][x]: elif y > 0 and self.floors[y - 1][x]:
# Bottom Edge # Bottom Edge
self.edgeAt(e, posx, posy, self.x[x]) self.edgeAt(e, posx, posy, self.x[x])
if x==0 or y==ly or not self.floors[y][x-1]: if x == 0 or y == ly or not self.floors[y][x - 1]:
self.edgeAt("e", posx-t, posy, t) self.edgeAt("e", posx - t, posy, t)
if x==lx-1 or y==ly or not self.floors[y][x+1]: if x == lx - 1 or y == ly or not self.floors[y][x + 1]:
self.edgeAt("e", posx+self.x[x], posy, t) self.edgeAt("e", posx + self.x[x], posy, t)
posx += self.x[x] + self. thickness posx += self.x[x] + self.thickness
posy += self.y[y-1] + self.thickness posy += self.y[y - 1] + self.thickness
posx = 0 posx = 0
for x in range(lx+1): for x in range(lx + 1):
posy = self.thickness posy = self.thickness
for y in range(ly-1, -1, -1): for y in range(ly - 1, -1, -1):
if self.vwalls[y][x]: if self.vwalls[y][x]:
e = "F" e = "F"
else: else:
e = "e" e = "e"
if x>0 and self.floors[y][x-1]: if x > 0 and self.floors[y][x - 1]:
if x < lx and self.floors[y][x]: if x < lx and self.floors[y][x]:
# Inside wall # Inside wall
if self.vwalls[y][x]: if self.vwalls[y][x]:
self.fingerHolesAt(posx+t2, posy, self.y[y]) self.fingerHolesAt(posx + t2, posy, self.y[y])
else: else:
# Right edge # Right edge
self.edgeAt(e, posx+t, posy, self.y[y], 90) self.edgeAt(e, posx + t, posy, self.y[y], 90)
if x==lx or y==0 or not self.floors[y-1][x]: if x == lx or y == 0 or not self.floors[y - 1][x]:
self.edgeAt("e", posx+t, posy+self.y[y], t, 90) self.edgeAt("e", posx + t, posy + self.y[y], t, 90)
if x==lx or y==ly-1 or not self.floors[y+1][x]: if x == lx or y == ly - 1 or not self.floors[y + 1][x]:
self.edgeAt("e", posx+t, posy-t, t, 90) self.edgeAt("e", posx + t, posy - t, t, 90)
elif x < lx and self.floors[y][x]: elif x < lx and self.floors[y][x]:
# Left edge # Left edge
self.edgeAt(e, posx, posy+self.y[y], self.y[y], -90) self.edgeAt(e, posx, posy + self.y[y], self.y[y], -90)
if x==0 or y==0 or not self.floors[y-1][x-1]: if x == 0 or y == 0 or not self.floors[y - 1][x - 1]:
self.edgeAt("e", posx, posy+self.y[y]+t, t, -90) self.edgeAt("e", posx, posy + self.y[y] + t, t, -90)
if x==0 or y==ly-1 or not self.floors[y+1][x-1]: if x == 0 or y == ly - 1 or not self.floors[y + 1][x - 1]:
self.edgeAt("e", posx, posy, t, -90) self.edgeAt("e", posx, posy, t, -90)
posy += self.y[y] + self.thickness posy += self.y[y] + self.thickness
if x < lx: if x < lx:
@ -302,18 +322,17 @@ class Layout(Boxes):
w.append(True) w.append(True)
else: else:
pass pass
#raise ValueError(line) # raise ValueError(line)
else: else:
if c != '+': if c != '+':
pass pass
#raise ValueError(line) # raise ValueError(line)
hwalls.append(w) hwalls.append(w)
if line[0] in " |": if line[0] in " |":
w = [] w = []
f = [] f = []
for n, c in enumerate(line[:len(x)*2+1]): for n, c in enumerate(line[:len(x) * 2 + 1]):
if n % 2: if n % 2:
if c == 'X': if c == 'X':
f.append(False) f.append(False)
@ -340,16 +359,17 @@ class Layout(Boxes):
# check sizes # check sizes
lx = len(x) lx = len(x)
ly = len(y) ly = len(y)
if len(hwalls) != ly+1: if len(hwalls) != ly + 1:
raise ValueError("Wrong number of horizontal wall lines: %i (%i expected)" % (len(hwalls), ly+1)) raise ValueError("Wrong number of horizontal wall lines: %i (%i expected)" % (len(hwalls), ly + 1))
for nr, walls in enumerate(hwalls): for nr, walls in enumerate(hwalls):
if len(walls)!= lx: if len(walls) != lx:
raise ValueError("Wrong number of horizontal walls in line %i: %i (%i expected)" % (nr, len(walls), lx)) raise ValueError("Wrong number of horizontal walls in line %i: %i (%i expected)" % (nr, len(walls), lx))
if len(vwalls) != ly: if len(vwalls) != ly:
raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly)) raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly))
for nr, walls in enumerate(vwalls): for nr, walls in enumerate(vwalls):
if len(walls) != lx+1: 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.x = x
self.y = y self.y = y
@ -357,8 +377,8 @@ class Layout(Boxes):
self.vwalls = vwalls self.vwalls = vwalls
self.floors = floors self.floors = floors
class TrayLayout(Layout):
class TrayLayout(Layout):
"""Type tray with each wall and floor tile being optional""" """Type tray with each wall and floor tile being optional"""
webinterface = True webinterface = True
@ -376,8 +396,8 @@ class TrayLayout(Layout):
def render(self): def render(self):
return return
class TrayLayout2(Layout):
class TrayLayout2(Layout):
"""Generate a typetray from a layout file""" """Generate a typetray from a layout file"""
webinterface = True webinterface = True
@ -388,6 +408,7 @@ class TrayLayout2(Layout):
self.argparser.add_argument( self.argparser.add_argument(
"--layout", action="store", type=str) "--layout", action="store", type=str)
def main(): def main():
l = Layout() l = Layout()
l.parseArgs() l.parseArgs()
@ -404,5 +425,6 @@ def main():
else: else:
l.argparser.print_usage() l.argparser.print_usage()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -16,8 +16,10 @@
from boxes import * from boxes import *
class TypeTray(Boxes): class TypeTray(Boxes):
"""Type tray - allows only continuous walls""" """Type tray - allows only continuous walls"""
def __init__(self): def __init__(self):
Boxes.__init__(self) Boxes.__init__(self)
self.buildArgParser("sx", "sy", "h", "hi", "outside") self.buildArgParser("sx", "sy", "h", "hi", "outside")
@ -67,9 +69,9 @@ class TypeTray(Boxes):
if not self.gw: if not self.gw:
return return
x = sum(self.sx) + self.thickness * (len(self.sx)-1) x = sum(self.sx) + self.thickness * (len(self.sx) - 1)
r = min(self.gw, self.gh) / 2.0 r = min(self.gw, self.gh) / 2.0
self.rectangularHole(x/2.0, self.gh*1.5, self.gw, self.gh, r) self.rectangularHole(x / 2.0, self.gh * 1.5, self.gw, self.gh, r)
def render(self): def render(self):
if self.outside: if self.outside:
@ -79,8 +81,8 @@ class TypeTray(Boxes):
if self.hi: if self.hi:
self.hi = self.adjustSize(self.hi, e2=False) self.hi = self.adjustSize(self.hi, e2=False)
x = sum(self.sx) + self.thickness * (len(self.sx)-1) x = sum(self.sx) + self.thickness * (len(self.sx) - 1)
y = sum(self.sy) + self.thickness * (len(self.sy)-1) y = sum(self.sy) + self.thickness * (len(self.sy) - 1)
h = self.h h = self.h
hi = self.hi = self.hi or h hi = self.hi = self.hi or h
t = self.thickness t = self.thickness
@ -88,35 +90,31 @@ class TypeTray(Boxes):
self.open() self.open()
# outer walls # outer walls
self.rectangularWall(x, h, "Ffef", callback=[ self.rectangularWall(x, h, "Ffef", callback=[self.xHoles, None, self.gripHole], move="right")
self.xHoles, None, self.gripHole], self.rectangularWall(y, h, "FFeF", callback=[self.yHoles, ], move="up")
move="right") self.rectangularWall(y, h, "FFeF", callback=[self.yHoles, ])
self.rectangularWall(y, h, "FFeF", callback=[self.yHoles,], self.rectangularWall(x, h, "Ffef", callback=[self.xHoles, ], move="left up")
move="up")
self.rectangularWall(y, h, "FFeF", callback=[self.yHoles,])
self.rectangularWall(x, h, "Ffef", callback=[self.xHoles,],
move="left up")
# floor # floor
self.rectangularWall(x, y, "ffff", self.rectangularWall(x, y, "ffff", callback=[self.xSlots, self.ySlots],move="right")
callback=[self.xSlots, self.ySlots],
move="right")
# Inner walls # Inner walls
for i in range(len(self.sx)-1): for i in range(len(self.sx) - 1):
e = [edges.SlottedEdge(self, self.sy, "f", slots=0.5*hi), "f", "e", "f"] e = [edges.SlottedEdge(self, self.sy, "f", slots=0.5 * hi), "f", "e", "f"]
self.rectangularWall(y, hi, e, self.rectangularWall(y, hi, e, move="up")
move="up")
for i in range(len(self.sy)-1): for i in range(len(self.sy) - 1):
e = [edges.SlottedEdge(self, self.sx, "f"), "f", e = [edges.SlottedEdge(self, self.sx, "f"), "f",
edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5*hi), "f"] edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * hi), "f"]
self.rectangularWall(x, hi, e, self.rectangularWall(x, hi, e, move="up")
move="up")
self.close() self.close()
def main(): def main():
b = TypeTray() b = TypeTray()
b.parseArgs() b.parseArgs()
b.render() b.render()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -1,14 +1,16 @@
from math import * from math import *
def arcOnCircle(spanning_angle, outgoing_angle, r=1.0): def arcOnCircle(spanning_angle, outgoing_angle, r=1.0):
angle = spanning_angle+2*outgoing_angle angle = spanning_angle + 2 * outgoing_angle
radius = r * sin(radians(0.5*spanning_angle))/sin(radians(180-outgoing_angle-0.5*spanning_angle)) radius = r * sin(radians(0.5 * spanning_angle)) / sin(radians(180 - outgoing_angle - 0.5 * spanning_angle))
return angle, abs(radius) return angle, abs(radius)
class Parts:
class Parts:
def __init__(self, boxes): def __init__(self, boxes):
self.boxes = boxes self.boxes = boxes
""" """
def roundKnob(self, diameter, n=20, callback=None, move=""): def roundKnob(self, diameter, n=20, callback=None, move=""):
size = diameter+diameter/n size = diameter+diameter/n
@ -25,52 +27,66 @@ class Parts:
def disc(self, diameter, hole=0, callback=None, move=""): def disc(self, diameter, hole=0, callback=None, move=""):
size = diameter size = diameter
r = diameter/2.0 r = diameter / 2.0
if self.move(size, size, move, before=True): if self.move(size, size, move, before=True):
return return
self.moveTo(size/2, size/2)
self.moveTo(size / 2, size / 2)
if hole: if hole:
self.hole(0, 0, hole/2) self.hole(0, 0, hole / 2)
self.cc(callback, None, 0, 0) self.cc(callback, None, 0, 0)
self.moveTo(r+self.burn,0, 90) self.moveTo(r + self.burn, 0, 90)
self.corner(360, r) self.corner(360, r)
self.move(size, size, move) self.move(size, size, move)
def waivyKnob(self, diameter, n=20, angle=45, hole=0, callback=None, move=""): def waivyKnob(self, diameter, n=20, angle=45, hole=0, callback=None, move=""):
size = diameter+pi*diameter/n size = diameter + pi * diameter / n
if self.move(size, size, move, before=True): if self.move(size, size, move, before=True):
return return
self.moveTo(size/2, size/2)
self.moveTo(size / 2, size / 2)
self.cc(callback, None, 0, 0) self.cc(callback, None, 0, 0)
if hole: if hole:
self.hole(0, 0, hole/2) self.hole(0, 0, hole / 2)
self.moveTo(diameter/2, 0, angle)
a, r = arcOnCircle(360./n, angle, diameter/2) self.moveTo(diameter / 2, 0, angle)
a2, r2 = arcOnCircle(360./n, -angle, diameter/2) a, r = arcOnCircle(360. / n, angle, diameter / 2)
for i in range(n//2): a2, r2 = arcOnCircle(360. / n, -angle, diameter / 2)
for i in range(n // 2):
self.boxes.corner(a, r) self.boxes.corner(a, r)
self.boxes.corner(a2, r2) self.boxes.corner(a2, r2)
self.move(size, size, move) self.move(size, size, move)
def concaveKnob(self, diameter, n=3, rounded=0.2, angle=70, hole=0, def concaveKnob(self, diameter, n=3, rounded=0.2, angle=70, hole=0,
callback=None, move=""): callback=None, move=""):
size = diameter size = diameter
if self.move(size, size, move, before=True): if self.move(size, size, move, before=True):
return return
self.moveTo(size/2, size/2)
self.moveTo(size / 2, size / 2)
if hole: if hole:
self.hole(0, 0, hole/2) self.hole(0, 0, hole / 2)
self.cc(callback, None, 0, 0) self.cc(callback, None, 0, 0)
self.moveTo(diameter/2, 0, 90+angle) self.moveTo(diameter / 2, 0, 90 + angle)
a, r = arcOnCircle(360./n*(1-rounded), -angle, diameter/2) 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 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) a, r = arcOnCircle(360. / n * (1 - rounded), -angle - 0.01, diameter / 2)
for i in range(n): for i in range(n):
self.boxes.corner(a, r) self.boxes.corner(a, r)
self.corner(angle) self.corner(angle)
self.corner(360./n*rounded, diameter/2) self.corner(360. / n * rounded, diameter / 2)
self.corner(angle) self.corner(angle)
self.move(size, size, move) self.move(size, size, move)

View File

@ -14,11 +14,14 @@
from math import * from math import *
from boxes.vectors import * from boxes.vectors import *
def tooth_spaceing_curvefit(teeth, b, c, d): def tooth_spaceing_curvefit(teeth, b, c, d):
return ((c * teeth**d) / (b + teeth**d)) * teeth return ((c * teeth ** d) / (b + teeth ** d)) * teeth
def tooth_spacing(teeth, tooth_pitch, pitch_line_offset): def tooth_spacing(teeth, tooth_pitch, pitch_line_offset):
return (2*((teeth*tooth_pitch)/(3.14159265*2)-pitch_line_offset)) return (2 * ((teeth * tooth_pitch) / (3.14159265 * 2) - pitch_line_offset))
def mirrorx(points): def mirrorx(points):
return [[-x, y] for x, y in points] return [[-x, y] for x, y in points]
@ -26,36 +29,37 @@ def mirrorx(points):
class Pulley: class Pulley:
spacing = { spacing = {
"MXL" : (False, 2.032,0.254), "MXL": (False, 2.032, 0.254),
"40DP" : (False, 2.07264,0.1778), "40DP": (False, 2.07264, 0.1778),
"XL" : (False, 5.08,0.254), "XL": (False, 5.08, 0.254),
"H" : (False, 9.525,0.381), "H": (False, 9.525, 0.381),
"T2_5" : (True, 0.7467,0.796,1.026), "T2_5": (True, 0.7467, 0.796, 1.026),
"T5" : (True, 0.6523,1.591,1.064), "T5": (True, 0.6523, 1.591, 1.064),
"T10" : (False, 10,0.93), "T10": (False, 10, 0.93),
"AT5" : (True, 0.6523,1.591,1.064), "AT5": (True, 0.6523, 1.591, 1.064),
"HTD_3mm" : (False, 3,0.381), "HTD_3mm": (False, 3, 0.381),
"HTD_5mm" : (False, 5,0.5715), "HTD_5mm": (False, 5, 0.5715),
"HTD_8mm" : (False, 8,0.6858), "HTD_8mm": (False, 8, 0.6858),
"GT2_2mm" : (False, 2,0.254), "GT2_2mm": (False, 2, 0.254),
"GT2_3mm" : (False, 3,0.381), "GT2_3mm": (False, 3, 0.381),
"GT2_5mm" : (False, 5,0.5715), "GT2_5mm": (False, 5, 0.5715),
} }
profile_data = { profile_data = {
"MXL" : (0.508 , 1.321 ), "MXL": (0.508, 1.321),
"40DP" : (0.457 , 1.226 ), "40DP": (0.457, 1.226),
"XL" : (1.27, 3.051 ), "XL": (1.27, 3.051),
"H" : (1.905 , 5.359 ), "H": (1.905, 5.359),
"T2_5" : (0.7 , 1.678 ), "T2_5": (0.7, 1.678),
"T5" : (1.19 , 3.264 ), "T5": (1.19, 3.264),
"T10" : (2.5 , 6.13 ), "T10": (2.5, 6.13),
"AT5" : (1.19 , 4.268 ), "AT5": (1.19, 4.268),
"HTD_3mm" : (1.289 , 2.27 ), "HTD_3mm": (1.289, 2.27),
"HTD_5mm" : (2.199 , 3.781 ), "HTD_5mm": (2.199, 3.781),
"HTD_8mm" : (3.607 , 6.603 ), "HTD_8mm": (3.607, 6.603),
"GT2_2mm" : (0.764 , 1.494 ), "GT2_2mm": (0.764, 1.494),
"GT2_3mm" : (1.169 , 2.31 ), "GT2_3mm": (1.169, 2.31),
"GT2_5mm" : (1.969 , 3.952 ), "GT2_5mm": (1.969, 3.952),
} }
teeth = { "MXL" : [[-0.660421,-0.5],[-0.660421,0],[-0.621898,0.006033],[-0.587714,0.023037],[-0.560056,0.049424],[-0.541182,0.083609],[-0.417357,0.424392],[-0.398413,0.458752],[-0.370649,0.48514],[-0.336324,0.502074],[-0.297744,0.508035],[0.297744,0.508035],[0.336268,0.502074],[0.370452,0.48514],[0.39811,0.458752],[0.416983,0.424392],[0.540808,0.083609],[0.559752,0.049424],[0.587516,0.023037],[0.621841,0.006033],[0.660421,0],[0.660421,-0.5]], teeth = { "MXL" : [[-0.660421,-0.5],[-0.660421,0],[-0.621898,0.006033],[-0.587714,0.023037],[-0.560056,0.049424],[-0.541182,0.083609],[-0.417357,0.424392],[-0.398413,0.458752],[-0.370649,0.48514],[-0.336324,0.502074],[-0.297744,0.508035],[0.297744,0.508035],[0.336268,0.502074],[0.370452,0.48514],[0.39811,0.458752],[0.416983,0.424392],[0.540808,0.083609],[0.559752,0.049424],[0.587516,0.023037],[0.621841,0.006033],[0.660421,0],[0.660421,-0.5]],
@ -83,19 +87,20 @@ class Pulley:
def drawPoints(self, lines, kerfdir=1): def drawPoints(self, lines, kerfdir=1):
if kerfdir != 0: if kerfdir != 0:
lines = kerf(lines, self.boxes.burn*kerfdir) lines = kerf(lines, self.boxes.burn * kerfdir)
self.boxes.ctx.save() self.boxes.ctx.save()
self.boxes.ctx.move_to(*lines[0]) self.boxes.ctx.move_to(*lines[0])
for x, y in lines[1:]: for x, y in lines[1:]:
self.boxes.ctx.line_to(x, y) self.boxes.ctx.line_to(x, y)
self.boxes.ctx.line_to(*lines[0]) self.boxes.ctx.line_to(*lines[0])
self.boxes.ctx.restore() self.boxes.ctx.restore()
def diameter(self, teeth, profile): def diameter(self, teeth, profile):
if self.spacing[profile][0]: if self.spacing[profile][0]:
return tooth_spaceing_curvefit( return tooth_spaceing_curvefit(teeth, *self.spacing[profile][1:])
teeth, *self.spacing[profile][1:])
else:
return tooth_spacing(teeth, *self.spacing[profile][1:]) return tooth_spacing(teeth, *self.spacing[profile][1:])
def __call__(self, teeth, profile, move="", r_axle=None, callback=None): def __call__(self, teeth, profile, move="", r_axle=None, callback=None):
@ -105,31 +110,35 @@ class Pulley:
# ******************************** # ********************************
# To improve fit of belt to pulley, set the following constant. Decrease or increase by 0.1mm at a time. We are modelling the *BELT* tooth here, not the tooth on the pulley. Increasing the number will *decrease* the pulley tooth size. Increasing the tooth width will also scale proportionately the tooth depth, to maintain the shape of the tooth, and increase how far into the pulley the tooth is indented. Can be negative # To improve fit of belt to pulley, set the following constant. Decrease or increase by 0.1mm at a time. We are modelling the *BELT* tooth here, not the tooth on the pulley. Increasing the number will *decrease* the pulley tooth size. Increasing the tooth width will also scale proportionately the tooth depth, to maintain the shape of the tooth, and increase how far into the pulley the tooth is indented. Can be negative
additional_tooth_width = 0.2 #mm additional_tooth_width = 0.2 # mm
# If you need more tooth depth than this provides, adjust the following constant. However, this will cause the shape of the tooth to change. # If you need more tooth depth than this provides, adjust the following constant. However, this will cause the shape of the tooth to change.
additional_tooth_depth = 0 #mm additional_tooth_depth = 0 # mm
pulley_OD = self.diameter(teeth, profile) pulley_OD = self.diameter(teeth, profile)
tooth_depth, tooth_width = self.profile_data[profile] tooth_depth, tooth_width = self.profile_data[profile]
tooth_distance_from_centre = ((pulley_OD/2)**2 - ((tooth_width+additional_tooth_width)/2)**2)**0.5 tooth_distance_from_centre = ((pulley_OD / 2) ** 2 - ((tooth_width + additional_tooth_width) / 2) ** 2) ** 0.5
tooth_width_scale = (tooth_width + additional_tooth_width ) / tooth_width tooth_width_scale = (tooth_width + additional_tooth_width) / tooth_width
tooth_depth_scale = ((tooth_depth + additional_tooth_depth ) / tooth_depth) tooth_depth_scale = ((tooth_depth + additional_tooth_depth) / tooth_depth)
total_width = pulley_OD total_width = pulley_OD
if self.boxes.move(total_width, total_width, move, before=True): if self.boxes.move(total_width, total_width, move, before=True):
return return
self.boxes.moveTo(total_width/2, total_width/2)
self.boxes.moveTo(total_width / 2, total_width / 2)
self.boxes.cc(callback, None, 0.0, 0.0) self.boxes.cc(callback, None, 0.0, 0.0)
if r_axle: if r_axle:
self.boxes.hole(0, 0, r_axle) self.boxes.hole(0, 0, r_axle)
points = [] points = []
for i in range(teeth): for i in range(teeth):
m = [[tooth_width_scale, 0, 0], m = [[tooth_width_scale, 0, 0],
[0, tooth_depth_scale, -tooth_distance_from_centre]] [0, tooth_depth_scale, -tooth_distance_from_centre]]
m = mmul(m, rotm(i*2*pi/teeth)) m = mmul(m, rotm(i * 2 * pi / teeth))
points.extend((vtransl(pt, m) for pt in self.teeth[profile][1:-1])) 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) self.boxes.move(total_width, total_width, move)

View File

@ -17,8 +17,8 @@
import xml.parsers.expat import xml.parsers.expat
import re import re
class SVGFile(object):
class SVGFile(object):
pathre = re.compile(r"[MCL]? *((-?\d+(\.\d+)?) (-?\d+(\.\d+)?) *)+") pathre = re.compile(r"[MCL]? *((-?\d+(\.\d+)?) (-?\d+(\.\d+)?) *)+")
transformre = re.compile(r"matrix\(" + ",".join([r"(-?\d+(\.\d+)?)"] * 6) + "\)") transformre = re.compile(r"matrix\(" + ",".join([r"(-?\d+(\.\d+)?)"] * 6) + "\)")
@ -31,29 +31,35 @@ class SVGFile(object):
if name == "path" and "symbol" not in self.tags: if name == "path" and "symbol" not in self.tags:
minx = maxx = miny = maxy = None minx = maxx = miny = maxy = None
m = self.transformre.match(attrs.get("transform", "")) m = self.transformre.match(attrs.get("transform", ""))
if m: if m:
matrix = [float(m.group(i)) for i in range(1, 12, 2)] matrix = [float(m.group(i)) for i in range(1, 12, 2)]
else: else:
matrix = [1, 0, matrix = [1, 0,
0, 1, 0, 1,
0, 0] 0, 0]
for m in self.pathre.findall(attrs.get("d", "")): for m in self.pathre.findall(attrs.get("d", "")):
x = float(m[1]) x = float(m[1])
y = float(m[3]) y = float(m[3])
tx = matrix[0]*x+matrix[2]*y+matrix[4] tx = matrix[0] * x + matrix[2] * y + matrix[4]
ty = matrix[1]*x+matrix[3]*y+matrix[5] ty = matrix[1] * x + matrix[3] * y + matrix[5]
if self.minx is None or self.minx > tx: if self.minx is None or self.minx > tx:
self.minx = tx self.minx = tx
if self.maxx is None or self.maxx < tx: if self.maxx is None or self.maxx < tx:
self.maxx = tx self.maxx = tx
if self.miny is None or self.miny > ty: if self.miny is None or self.miny > ty:
self.miny = ty self.miny = ty
if self.maxy is None or self.maxy < ty: if self.maxy is None or self.maxy < ty:
self.maxy = ty self.maxy = ty
def handleEndElement(self, name): def handleEndElement(self, name):
last = self.tags.pop() last = self.tags.pop()
if last != name: if last != name:
raise ValueError("Got </%s> expected </%s>" % (name, last)) raise ValueError("Got </%s> expected </%s>" % (name, last))
@ -70,26 +76,28 @@ class SVGFile(object):
m = re.search(r"""<svg[^>]*(width="(\d+pt)" height="(\d+pt)" viewBox="0 (0 (\d+) (\d+))") version="1.1">""", s) m = re.search(r"""<svg[^>]*(width="(\d+pt)" height="(\d+pt)" viewBox="0 (0 (\d+) (\d+))") version="1.1">""", s)
#minx = 10*int(self.minx//10)-10 # minx = 10*int(self.minx//10)-10
# as we don't rewrite the left border keep it as 0 # as we don't rewrite the left border keep it as 0
if 0 <= self.minx <= 50: if 0 <= self.minx <= 50:
minx = 0 minx = 0
else: else:
minx = 10*int(self.minx//10)-10 minx = 10 * int(self.minx // 10) - 10
#raise ValueError("Left end of drawing at wrong place: %imm (0-50mm expected)" % self.minx) # raise ValueError("Left end of drawing at wrong place: %imm (0-50mm expected)" % self.minx)
maxx = 10*int(self.maxx//10)+10 maxx = 10 * int(self.maxx // 10) + 10
miny = 10*int(self.miny//10)-10 miny = 10 * int(self.miny // 10) - 10
maxy = 10*int(self.maxy//10)+10 maxy = 10 * int(self.maxy // 10) + 10
if m: if m:
f.seek(m.start(1)) f.seek(m.start(1))
s = ('width="%imm" height="%imm" viewBox="0 %i %i %i"' % s = ('width="%imm" height="%imm" viewBox="0 %i %i %i"' %
(maxx-minx, maxy-miny, miny, maxx, maxy-miny)) (maxx - minx, maxy - miny, miny, maxx, maxy - miny))
if len(s) > len(m.group(1)): if len(s) > len(m.group(1)):
raise ValueError("Not enough space for size") raise ValueError("Not enough space for size")
f.write(s + " " * (len(m.group(1))- len(s)))
f.write(s + " " * (len(m.group(1)) - len(s)))
else: else:
raiseValueError("Could not understand SVG file") raise ValueError("Could not understand SVG file")
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -14,72 +14,86 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import math import math
def normalize(v): def normalize(v):
"set lenght of vector to one" "set lenght of vector to one"
l = (v[0]**2+v[1]**2)**0.5 l = (v[0] ** 2 + v[1] ** 2) ** 0.5
return (v[0]/l, v[1]/l) return (v[0] / l, v[1] / l)
def vlength(v): def vlength(v):
return (v[0]**2+v[1]**2)**0.5 return (v[0] ** 2 + v[1] ** 2) ** 0.5
def vclip(v, length): def vclip(v, length):
l = vlength(v) l = vlength(v)
if l > length: if l > length:
return vscalmul(v, length/l) return vscalmul(v, length / l)
return v return v
def vdiff(p1, p2): def vdiff(p1, p2):
"vector from point1 to point2" "vector from point1 to point2"
return (p2[0]-p1[0], p2[1]-p1[1]) return (p2[0] - p1[0], p2[1] - p1[1])
def vadd(v1, v2): def vadd(v1, v2):
"Sum of two vectors" "Sum of two vectors"
return (v1[0]+ v2[0], v1[1]+v2[1]) return (v1[0] + v2[0], v1[1] + v2[1])
def vorthogonal(v): def vorthogonal(v):
"orthogonal vector" "orthogonal vector"
"Orthogonal vector" "Orthogonal vector"
return (-v[1], v[0]) return (-v[1], v[0])
def vscalmul(v, a): def vscalmul(v, a):
"scale vector by a" "scale vector by a"
return (a*v[0], a*v[1]) return (a * v[0], a * v[1])
def dotproduct(v1, v2): def dotproduct(v1, v2):
"Dot product" "Dot product"
return v1[0]*v2[0]+v1[1]*v2[1] return v1[0] * v2[0] + v1[1] * v2[1]
def rotm(angle): def rotm(angle):
"Rotation matrix" "Rotation matrix"
return [[math.cos(angle), -math.sin(angle), 0], return [[math.cos(angle), -math.sin(angle), 0],
[math.sin(angle), math.cos(angle), 0]] [math.sin(angle), math.cos(angle), 0]]
def vtransl(v, m): def vtransl(v, m):
m0, m1 = m m0, m1 = m
return [m0[0]*v[0]+m0[1]*v[1]+m0[2], return [m0[0] * v[0] + m0[1] * v[1] + m0[2],
m1[0]*v[0]+m1[1]*v[1]+m1[2]] m1[0] * v[0] + m1[1] * v[1] + m1[2]]
def mmul(m0, m1): def mmul(m0, m1):
result = [[0,]*len(m0[0]) for i in range(len(m0))] result = [[0, ] * len(m0[0]) for i in range(len(m0))]
for i in range(len(m0[0])): for i in range(len(m0[0])):
for j in range(len(m0)): for j in range(len(m0)):
for k in range(len(m0)): for k in range(len(m0)):
result[j][i] += m0[k][i] * m1[j][k] result[j][i] += m0[k][i] * m1[j][k]
return result return result
def kerf(points, k): def kerf(points, k):
"""Outset points by k """Outset points by k
Assumes a closed loop of points Assumes a closed loop of points
""" """
result = [] result = []
lp = len(points) lp = len(points)
for i in range(len(points)): for i in range(len(points)):
# get normalized orthogonals of both segments # get normalized orthogonals of both segments
v1 = vorthogonal(normalize(vdiff(points[i-1], points[i]))) v1 = vorthogonal(normalize(vdiff(points[i - 1], points[i])))
v2 = vorthogonal(normalize(vdiff(points[i], points[(i+1) % lp]))) v2 = vorthogonal(normalize(vdiff(points[i], points[(i + 1) % lp])))
# direction the point has to move # direction the point has to move
d = normalize(vadd(v1, v2)) d = normalize(vadd(v1, v2))
# cos of the half the angle between the segments # cos of the half the angle between the segments
cos_alpha = dotproduct(v1, d) cos_alpha = dotproduct(v1, d)
result.append(vadd(points[i], vscalmul(d, -k/cos_alpha))) result.append(vadd(points[i], vscalmul(d, -k / cos_alpha)))
return result return result