Add minimal doc strings
This commit is contained in:
parent
31a6af5116
commit
09871be797
|
@ -23,9 +23,21 @@ from functools import wraps
|
||||||
from boxes import edges
|
from boxes import edges
|
||||||
|
|
||||||
def dist(dx, dy):
|
def dist(dx, dy):
|
||||||
|
"""
|
||||||
|
Return distance
|
||||||
|
|
||||||
|
:param dx: delta x
|
||||||
|
:param dy: delat y
|
||||||
|
"""
|
||||||
return (dx*dx+dy*dy)**0.5
|
return (dx*dx+dy*dy)**0.5
|
||||||
|
|
||||||
def restore(func):
|
def restore(func):
|
||||||
|
"""
|
||||||
|
Wrapper: Restore coordiantes after function
|
||||||
|
|
||||||
|
: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()
|
||||||
|
@ -41,6 +53,7 @@ def restore(func):
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
class NutHole:
|
class NutHole:
|
||||||
|
"""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),
|
||||||
|
@ -80,6 +93,12 @@ class NutHole:
|
||||||
self.boxes.corner(-60)
|
self.boxes.corner(-60)
|
||||||
|
|
||||||
def argparseSections(s):
|
def argparseSections(s):
|
||||||
|
"""
|
||||||
|
Parse sections parameter
|
||||||
|
|
||||||
|
:param s: string to parse
|
||||||
|
|
||||||
|
"""
|
||||||
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))
|
||||||
|
@ -95,6 +114,7 @@ def argparseSections(s):
|
||||||
raise argparse.ArgumentTypeError("Don't understand sections string")
|
raise argparse.ArgumentTypeError("Don't understand sections string")
|
||||||
|
|
||||||
class Boxes:
|
class Boxes:
|
||||||
|
"""Main class -- Generator should sub class this """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.argparser = ArgumentParser(description=self.__doc__)
|
self.argparser = ArgumentParser(description=self.__doc__)
|
||||||
|
@ -112,6 +132,15 @@ class Boxes:
|
||||||
help="burn correction in mm")
|
help="burn correction in mm")
|
||||||
|
|
||||||
def open(self, width, height):
|
def open(self, width, height):
|
||||||
|
"""
|
||||||
|
Prepare for rendering
|
||||||
|
|
||||||
|
Call this function from your .render() method
|
||||||
|
|
||||||
|
:param width: width of canvas in mm
|
||||||
|
:param height: height of canvas in mm
|
||||||
|
|
||||||
|
"""
|
||||||
self.spacing = 2*self.burn + 0.5 * self.thickness
|
self.spacing = 2*self.burn + 0.5 * self.thickness
|
||||||
|
|
||||||
self.fingerHoleEdgeWidth = 1.0 # multitudes of self.thickness
|
self.fingerHoleEdgeWidth = 1.0 # multitudes of self.thickness
|
||||||
|
@ -121,6 +150,12 @@ class Boxes:
|
||||||
self._buildObjects()
|
self._buildObjects()
|
||||||
|
|
||||||
def buildArgParser(self, *l):
|
def buildArgParser(self, *l):
|
||||||
|
"""
|
||||||
|
Add commonly used commandf line parameters
|
||||||
|
|
||||||
|
:param \*l: parameter names
|
||||||
|
|
||||||
|
"""
|
||||||
for arg in l:
|
for arg in l:
|
||||||
if arg == "x":
|
if arg == "x":
|
||||||
self.argparser.add_argument(
|
self.argparser.add_argument(
|
||||||
|
@ -153,9 +188,22 @@ class Boxes:
|
||||||
raise ValueError("No default for argument", arg)
|
raise ValueError("No default for argument", arg)
|
||||||
|
|
||||||
def parseArgs(self, args=None):
|
def parseArgs(self, args=None):
|
||||||
|
"""
|
||||||
|
Parse command line parameters
|
||||||
|
|
||||||
|
:param args: (Default value = None) parameters, None for using sys.argv
|
||||||
|
|
||||||
|
"""
|
||||||
self.argparser.parse_args(args=args, namespace=self)
|
self.argparser.parse_args(args=args, namespace=self)
|
||||||
|
|
||||||
def addPart(self, part, name=None):
|
def addPart(self, part, name=None):
|
||||||
|
"""
|
||||||
|
Add Edge or other part instance to this one and add it as attribute
|
||||||
|
|
||||||
|
:param part: Callable
|
||||||
|
:param name: (Default value = None) attribute name (__name__ as default)
|
||||||
|
|
||||||
|
"""
|
||||||
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:]
|
||||||
|
@ -165,6 +213,7 @@ class Boxes:
|
||||||
self.edges[part.char] = part
|
self.edges[part.char] = part
|
||||||
|
|
||||||
def _buildObjects(self):
|
def _buildObjects(self):
|
||||||
|
"""Add default edges and parts """
|
||||||
self.edges = {}
|
self.edges = {}
|
||||||
self.addPart(edges.Edge(self, None))
|
self.addPart(edges.Edge(self, None))
|
||||||
self.addPart(edges.OutSetEdge(self, None))
|
self.addPart(edges.OutSetEdge(self, None))
|
||||||
|
@ -185,6 +234,13 @@ class Boxes:
|
||||||
self.addPart(NutHole(self, None))
|
self.addPart(NutHole(self, None))
|
||||||
|
|
||||||
def _init_surface(self, width, height):
|
def _init_surface(self, width, height):
|
||||||
|
"""
|
||||||
|
Initialize cairo canvas
|
||||||
|
|
||||||
|
:param width: canvas size
|
||||||
|
:param height: canvas height
|
||||||
|
|
||||||
|
"""
|
||||||
#mm2pt = 90 / 25.4 / 1.25
|
#mm2pt = 90 / 25.4 / 1.25
|
||||||
mm2pt = 1
|
mm2pt = 1
|
||||||
#width *= mm2pt
|
#width *= mm2pt
|
||||||
|
@ -203,7 +259,14 @@ class Boxes:
|
||||||
|
|
||||||
|
|
||||||
def cc(self, callback, number, x=0.0, y=None):
|
def cc(self, callback, number, x=0.0, y=None):
|
||||||
"""call callback"""
|
"""Call callback from edge of a part
|
||||||
|
|
||||||
|
:param callback: callback (callable or list of callables)
|
||||||
|
:param number: number of the callback
|
||||||
|
:param x: (Default value = 0.0) x position to be call on
|
||||||
|
:param y: (Default value = None) y position to be called on (default does burn correction)
|
||||||
|
|
||||||
|
"""
|
||||||
if y is None:
|
if y is None:
|
||||||
y = self.burn
|
y = self.burn
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
|
@ -223,6 +286,13 @@ class Boxes:
|
||||||
self.ctx.restore()
|
self.ctx.restore()
|
||||||
|
|
||||||
def getEntry(self, param, idx):
|
def getEntry(self, param, idx):
|
||||||
|
"""
|
||||||
|
Get entry from list or items itself
|
||||||
|
|
||||||
|
:param param: list or item
|
||||||
|
:param idx: index in list
|
||||||
|
|
||||||
|
"""
|
||||||
if isinstance(param, list):
|
if isinstance(param, list):
|
||||||
if len(param)>idx:
|
if len(param)>idx:
|
||||||
return param[idx]
|
return param[idx]
|
||||||
|
@ -232,6 +302,9 @@ class Boxes:
|
||||||
return param
|
return param
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Finish rendering
|
||||||
|
|
||||||
|
Call at the end of your .render() method"""
|
||||||
self.ctx.stroke()
|
self.ctx.stroke()
|
||||||
self.surface.flush()
|
self.surface.flush()
|
||||||
self.surface.finish()
|
self.surface.finish()
|
||||||
|
@ -256,6 +329,15 @@ class Boxes:
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
def corner(self, degrees, radius=0):
|
def corner(self, degrees, radius=0):
|
||||||
|
"""
|
||||||
|
Draw a corner
|
||||||
|
|
||||||
|
This is what does the burn corrections
|
||||||
|
|
||||||
|
:param degrees: angle
|
||||||
|
: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,
|
||||||
|
@ -270,12 +352,26 @@ class Boxes:
|
||||||
self.continueDirection(rad)
|
self.continueDirection(rad)
|
||||||
|
|
||||||
def edge(self, length):
|
def edge(self, length):
|
||||||
|
"""
|
||||||
|
Simple line
|
||||||
|
: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())
|
||||||
|
|
||||||
def curveTo(self, x1, y1, x2, y2, x3, y3):
|
def curveTo(self, x1, y1, x2, y2, x3, y3):
|
||||||
"""control point 1, control point 2, end point"""
|
"""control point 1, control point 2, end point
|
||||||
|
|
||||||
|
:param x1:
|
||||||
|
:param y1:
|
||||||
|
:param x2:
|
||||||
|
:param y2:
|
||||||
|
:param x3:
|
||||||
|
:param y3:
|
||||||
|
|
||||||
|
"""
|
||||||
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
|
||||||
|
@ -283,6 +379,12 @@ class Boxes:
|
||||||
self.continueDirection(rad)
|
self.continueDirection(rad)
|
||||||
|
|
||||||
def polyline(self, *args):
|
def polyline(self, *args):
|
||||||
|
"""
|
||||||
|
Draw multiple connected lines
|
||||||
|
|
||||||
|
:param \*args: Alternating length in mm and angle
|
||||||
|
|
||||||
|
"""
|
||||||
for i, arg in enumerate(args):
|
for i, arg in enumerate(args):
|
||||||
if i % 2:
|
if i % 2:
|
||||||
self.corner(arg)
|
self.corner(arg)
|
||||||
|
@ -290,6 +392,13 @@ class Boxes:
|
||||||
self.edge(arg)
|
self.edge(arg)
|
||||||
|
|
||||||
def bedBoltHole(self, length, bedBoltSettings=None):
|
def bedBoltHole(self, length, bedBoltSettings=None):
|
||||||
|
"""
|
||||||
|
Draw an edge with slot for a bed bolt
|
||||||
|
|
||||||
|
:param length: length of the edge in mm
|
||||||
|
:param bedBoltSettings: (Default value = None) Dimmensions of the slot
|
||||||
|
|
||||||
|
"""
|
||||||
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)
|
||||||
|
@ -319,7 +428,12 @@ class Boxes:
|
||||||
|
|
||||||
|
|
||||||
def grip(self, length, depth):
|
def grip(self, length, depth):
|
||||||
"""corrugated edge useful as an gipping area"""
|
"""Corrugated edge useful as an gipping area
|
||||||
|
|
||||||
|
:param length: length
|
||||||
|
: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):
|
||||||
|
@ -328,6 +442,11 @@ class Boxes:
|
||||||
self.corner(90, depth)
|
self.corner(90, depth)
|
||||||
|
|
||||||
def _latchHole(self, length):
|
def _latchHole(self, 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)
|
||||||
|
@ -335,14 +454,22 @@ class Boxes:
|
||||||
self.edge(1.1*self.thickness)
|
self.edge(1.1*self.thickness)
|
||||||
|
|
||||||
def _latchGrip(self, length):
|
def _latchGrip(self, 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):
|
||||||
"""Fix a flex box door at the box
|
"""Latch to fix a flex box door to the box
|
||||||
positive: False: Door side; True: Box side
|
|
||||||
reverse: True when running away from the latch
|
:param length: length in mm
|
||||||
|
:param positive: (Default value = True) False: Door side; True: Box side
|
||||||
|
:param reverse: (Default value = False) True when running away from the latch
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if positive:
|
if positive:
|
||||||
if reverse:
|
if reverse:
|
||||||
|
@ -368,7 +495,14 @@ class Boxes:
|
||||||
self.corner(90)
|
self.corner(90)
|
||||||
|
|
||||||
def handle(self, x, h, hl, r=30):
|
def handle(self, x, h, hl, r=30):
|
||||||
"""Creates and Edge with a handle"""
|
"""Creates an Edge with a handle
|
||||||
|
|
||||||
|
:param x: width in mm
|
||||||
|
:param h: height in mm
|
||||||
|
:param hl: height if th grip hole
|
||||||
|
: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")
|
||||||
|
@ -398,12 +532,26 @@ class Boxes:
|
||||||
### Navigation
|
### Navigation
|
||||||
|
|
||||||
def moveTo(self, x, y=0.0, degrees=0):
|
def moveTo(self, x, y=0.0, degrees=0):
|
||||||
|
"""
|
||||||
|
Move coordinate system to given point
|
||||||
|
|
||||||
|
:param x:
|
||||||
|
:param y: (Default value = 0.0)
|
||||||
|
:param degrees: (Default value = 0)
|
||||||
|
|
||||||
|
"""
|
||||||
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):
|
||||||
|
"""
|
||||||
|
Set coordinate system to current position (end point)
|
||||||
|
|
||||||
|
:param angle: (Default value = 0) heading
|
||||||
|
|
||||||
|
"""
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
self.ctx.rotate(angle)
|
self.ctx.rotate(angle)
|
||||||
|
|
||||||
|
@ -413,6 +561,12 @@ class Boxes:
|
||||||
when "only" is included the move is only done when before is True
|
when "only" is included the move is only done when before is True
|
||||||
The function returns whether actual drawing of the part
|
The function returns whether actual drawing of the part
|
||||||
should be omited.
|
should be omited.
|
||||||
|
|
||||||
|
:param x: width of part
|
||||||
|
:param y: height of part
|
||||||
|
:param where: which direction to move
|
||||||
|
:param before: (Default value = False) called before or after part being drawn
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not where:
|
if not where:
|
||||||
return False
|
return False
|
||||||
|
@ -443,6 +597,17 @@ class Boxes:
|
||||||
|
|
||||||
def fingerHolesAt(self, x, y, length, angle=90,
|
def fingerHolesAt(self, x, y, length, angle=90,
|
||||||
bedBolts=None, bedBoltSettings=None):
|
bedBolts=None, bedBoltSettings=None):
|
||||||
|
"""
|
||||||
|
Draw holes for a matching finger joint edge
|
||||||
|
|
||||||
|
:param x: position
|
||||||
|
:param y: position
|
||||||
|
:param length: length of matching edge
|
||||||
|
:param angle: (Default value = 90)
|
||||||
|
:param bedBolts: (Default value = None)
|
||||||
|
:param bedBoltSettings: (Default value = None)
|
||||||
|
|
||||||
|
"""
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
self.moveTo(x, y, angle)
|
self.moveTo(x, y, angle)
|
||||||
self.fingerHoles(length, bedBolts, bedBoltSettings)
|
self.fingerHoles(length, bedBolts, bedBoltSettings)
|
||||||
|
@ -450,11 +615,32 @@ class Boxes:
|
||||||
|
|
||||||
@restore
|
@restore
|
||||||
def hole(self, x, y, r):
|
def hole(self, x, y, r):
|
||||||
|
"""
|
||||||
|
Draw a round hole
|
||||||
|
|
||||||
|
:param x: position
|
||||||
|
:param y: postion
|
||||||
|
:param r: radius
|
||||||
|
|
||||||
|
"""
|
||||||
|
radius -= self.burn
|
||||||
|
if radius < 0:
|
||||||
|
radius = 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
|
||||||
def rectangularHole(self, x, y, dx, dy, r=0):
|
def rectangularHole(self, x, y, dx, dy, r=0):
|
||||||
|
"""
|
||||||
|
Draw an rectangulat hole
|
||||||
|
|
||||||
|
:param x: position
|
||||||
|
:param y: position
|
||||||
|
:param dx: width
|
||||||
|
:param dy: height
|
||||||
|
: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)
|
||||||
|
@ -462,6 +648,16 @@ class Boxes:
|
||||||
|
|
||||||
@restore
|
@restore
|
||||||
def text(self, text, x=0, y=0, angle=0, align=""):
|
def text(self, text, x=0, y=0, angle=0, align=""):
|
||||||
|
"""
|
||||||
|
Draw text
|
||||||
|
|
||||||
|
:param text: text to render
|
||||||
|
:param x: (Default value = 0)
|
||||||
|
:param y: (Default value = 0)
|
||||||
|
:param angle: (Default value = 0)
|
||||||
|
:param align: (Default value = "") string with combinations of (top|middle|bottom) and (left|center|right) separated by a space
|
||||||
|
|
||||||
|
"""
|
||||||
self.moveTo(x, y, angle)
|
self.moveTo(x, y, angle)
|
||||||
(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()
|
||||||
|
@ -484,6 +680,14 @@ class Boxes:
|
||||||
|
|
||||||
@restore
|
@restore
|
||||||
def NEMA(self, size, x=0, y=0, angle=0):
|
def NEMA(self, size, x=0, y=0, angle=0):
|
||||||
|
"""Draw holes for mounting a NEMA stepper motor
|
||||||
|
|
||||||
|
:param size: Nominal size in tenths of inches
|
||||||
|
:param x: (Default value = 0)
|
||||||
|
:param y: (Default value = 0)
|
||||||
|
:param angle: (Default value = 0)
|
||||||
|
|
||||||
|
"""
|
||||||
nema = {
|
nema = {
|
||||||
# motor,flange, holes, screws
|
# motor,flange, holes, screws
|
||||||
8 : (20.3, 16, 15.4, 3),
|
8 : (20.3, 16, 15.4, 3),
|
||||||
|
@ -511,13 +715,20 @@ class Boxes:
|
||||||
# hexHoles
|
# hexHoles
|
||||||
|
|
||||||
def hexHolesRectangle(self, x, y, settings=None, skip=None):
|
def hexHolesRectangle(self, x, y, settings=None, skip=None):
|
||||||
"""
|
"""Fills a rectangle with holes in a hex pattern.
|
||||||
Fills a rectangle with holes.
|
|
||||||
|
Settings have:
|
||||||
r : radius of holes
|
r : radius of holes
|
||||||
b : space between holes
|
b : space between holes
|
||||||
style : what types of holes (not yet implemented)
|
style : what types of holes (not yet implemented)
|
||||||
skip : function to check if hole should be present
|
|
||||||
|
:param x: width
|
||||||
|
:param y: heigth
|
||||||
|
:param settings: (Default value = None)
|
||||||
|
:param skip: (Default value = None) function to check if hole should be present
|
||||||
gets x, y, r, b, posx, posy
|
gets x, y, r, b, posx, posy
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if settings is None:
|
if settings is None:
|
||||||
settings = self.hexHolesSettings
|
settings = self.hexHolesSettings
|
||||||
|
@ -549,11 +760,37 @@ class Boxes:
|
||||||
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):
|
||||||
|
"""
|
||||||
|
Fill circle with holes in a hex pattern
|
||||||
|
|
||||||
|
:param d: diameter of the circle
|
||||||
|
: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):
|
||||||
|
"""
|
||||||
|
Fill a plate with holes in a hex pattern
|
||||||
|
|
||||||
|
:param x: width
|
||||||
|
:param y: height
|
||||||
|
:param rc: radius of the corners
|
||||||
|
:param settings: (Default value = None)
|
||||||
|
|
||||||
|
"""
|
||||||
def skip(x, y, r, b, posx, posy):
|
def skip(x, y, r, b, posx, posy):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param x:
|
||||||
|
:param y:
|
||||||
|
:param r:
|
||||||
|
:param b:
|
||||||
|
:param posx:
|
||||||
|
: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))
|
||||||
|
|
||||||
|
@ -567,6 +804,14 @@ class Boxes:
|
||||||
self.hexHolesRectangle(x, y, settings, skip=skip)
|
self.hexHolesRectangle(x, y, settings, skip=skip)
|
||||||
|
|
||||||
def hexHolesHex(self, h, settings=None, grow=None):
|
def hexHolesHex(self, h, settings=None, grow=None):
|
||||||
|
"""
|
||||||
|
Fill a hexagon with holes in a hex pattern
|
||||||
|
|
||||||
|
:param h: height
|
||||||
|
:param settings: (Default value = None)
|
||||||
|
:param grow: (Default value = None)
|
||||||
|
|
||||||
|
"""
|
||||||
if settings is None:
|
if settings is None:
|
||||||
settings = self.hexHolesSettings
|
settings = self.hexHolesSettings
|
||||||
r, b, style = settings
|
r, b, style = settings
|
||||||
|
@ -600,12 +845,22 @@ class Boxes:
|
||||||
holesMargin=None, holesSettings=None,
|
holesMargin=None, holesSettings=None,
|
||||||
bedBolts=None, bedBoltSettings=None,
|
bedBolts=None, bedBoltSettings=None,
|
||||||
move=None):
|
move=None):
|
||||||
"""fits surroundingWall
|
"""Plate with rounded corner fitting to .surroundingWall()
|
||||||
first edge is split to have a joint in the middle of the side
|
|
||||||
|
First edge is split to have a joint in the middle of the side
|
||||||
callback is called at the beginning of the straight edges
|
callback is called at the beginning of the straight edges
|
||||||
0, 1 for the two part of the first edge, 2, 3, 4 for the others
|
0, 1 for the two part of the first edge, 2, 3, 4 for the others
|
||||||
|
|
||||||
set holesMargin to get hex holes.
|
:param x: width
|
||||||
|
:param y: hight
|
||||||
|
:param r: radius of the corners
|
||||||
|
:param callback: (Default value = None)
|
||||||
|
:param holesMargin: (Default value = None) set to get hex holes
|
||||||
|
:param holesSettings: (Default value = None)
|
||||||
|
:param bedBolts: (Default value = None)
|
||||||
|
:param bedBoltSettings: (Default value = None)
|
||||||
|
:param move: (Default value = None)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
overallwidth = x+2*self.fingerJointEdge.spacing()
|
overallwidth = x+2*self.fingerJointEdge.spacing()
|
||||||
|
@ -654,13 +909,23 @@ class Boxes:
|
||||||
bottom='e', top='e',
|
bottom='e', top='e',
|
||||||
callback=None,
|
callback=None,
|
||||||
move=None):
|
move=None):
|
||||||
"""
|
"""h : inner height, not counting the joints
|
||||||
h : inner height, not counting the joints
|
|
||||||
callback is called a beginn of the flat sides with
|
callback is called a beginn of the flat sides with
|
||||||
0 for right half of first x side;
|
|
||||||
1 and 3 for y sides;
|
* 0 for right half of first x side;
|
||||||
2 for second x side
|
* 1 and 3 for y sides;
|
||||||
4 for second half of the first x side
|
* 2 for second x side
|
||||||
|
* 4 for second half of the first x side
|
||||||
|
|
||||||
|
:param x: width of matching roundedPlate
|
||||||
|
:param y: height of matching roundedPlate
|
||||||
|
:param r: corner radius of matching roundedPlate
|
||||||
|
:param h: height of the wall
|
||||||
|
:param bottom: (Default value = 'e') Edge type
|
||||||
|
:param top: (Default value = 'e') Edge type
|
||||||
|
:param callback: (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 = 0.9 * c4 # stretch flex 10%
|
c4 = 0.9 * c4 # stretch flex 10%
|
||||||
|
@ -721,6 +986,20 @@ class Boxes:
|
||||||
bedBolts=None, bedBoltSettings=None,
|
bedBolts=None, bedBoltSettings=None,
|
||||||
callback=None,
|
callback=None,
|
||||||
move=None):
|
move=None):
|
||||||
|
"""
|
||||||
|
Rectangular wall for all kind of box like objects
|
||||||
|
|
||||||
|
:param x: width
|
||||||
|
:param y: height
|
||||||
|
:param edges: (Default value = "eeee") bottom, right, top, left
|
||||||
|
:param holesMargin: (Default value = None)
|
||||||
|
:param holesSettings: (Default value = None)
|
||||||
|
:param bedBolts: (Default value = None)
|
||||||
|
:param bedBoltSettings: (Default value = None)
|
||||||
|
:param callback: (Default value = None)
|
||||||
|
:param move: (Default value = None)
|
||||||
|
|
||||||
|
"""
|
||||||
if len(edges) != 4:
|
if len(edges) != 4:
|
||||||
raise ValueError("four edges required")
|
raise ValueError("four edges required")
|
||||||
edges = [self.edges.get(e, e) for e in edges]
|
edges = [self.edges.get(e, e) for e in edges]
|
||||||
|
@ -764,6 +1043,7 @@ class DemoBox(Boxes):
|
||||||
self.buildArgParser("x", "y", "h")
|
self.buildArgParser("x", "y", "h")
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
|
""" """
|
||||||
x, y, h, t = self.x, self.y, self.h, self.thickness
|
x, y, h, t = self.x, self.y, self.h, self.thickness
|
||||||
self.open(2*x+10*self.thickness, y+2*h+20*self.thickness)
|
self.open(2*x+10*self.thickness, y+2*h+20*self.thickness)
|
||||||
self.ctx.save()
|
self.ctx.save()
|
||||||
|
|
|
@ -20,18 +20,39 @@ class BoltPolicy:
|
||||||
"""Abstract class
|
"""Abstract class
|
||||||
Distributes (bed) bolts on a number of segments
|
Distributes (bed) bolts on a number of segments
|
||||||
(fingers of a finger joint)
|
(fingers of a finger joint)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def drawbolt(self, pos):
|
def drawbolt(self, pos):
|
||||||
"""Add a bolt to this segment?"""
|
"""Add a bolt to this segment?
|
||||||
|
|
||||||
|
:param pos: number of the finger
|
||||||
|
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def numFingers(self, numfingers):
|
def numFingers(self, numfingers):
|
||||||
"""returns next smaller, possible number of fingers"""
|
"""Return next smaller, possible number of fingers
|
||||||
|
|
||||||
|
:param numfingers: number of fingers to aim for
|
||||||
|
|
||||||
|
"""
|
||||||
return numFingers
|
return numFingers
|
||||||
|
|
||||||
def _even(self, numFingers):
|
def _even(self, numFingers):
|
||||||
|
"""
|
||||||
|
Return same or next smaller even number
|
||||||
|
|
||||||
|
:param numFingers:
|
||||||
|
|
||||||
|
"""
|
||||||
return (numFingers//2) * 2
|
return (numFingers//2) * 2
|
||||||
def _odd(self, numFingers):
|
def _odd(self, numFingers):
|
||||||
|
"""
|
||||||
|
Return same or next smaller odd number
|
||||||
|
|
||||||
|
:param numFingers:
|
||||||
|
|
||||||
|
"""
|
||||||
if numFingers % 2:
|
if numFingers % 2:
|
||||||
return numFingers
|
return numFingers
|
||||||
else:
|
else:
|
||||||
|
@ -41,6 +62,7 @@ class Bolts(BoltPolicy):
|
||||||
"""Distribute a fixed number of bolts evenly"""
|
"""Distribute a fixed number of bolts evenly"""
|
||||||
def __init__(self, bolts=1):
|
def __init__(self, bolts=1):
|
||||||
self.bolts = bolts
|
self.bolts = bolts
|
||||||
|
|
||||||
def numFingers(self, numFingers):
|
def numFingers(self, numFingers):
|
||||||
if self.bolts % 2:
|
if self.bolts % 2:
|
||||||
self.fingers = self._even(numFingers)
|
self.fingers = self._even(numFingers)
|
||||||
|
@ -49,6 +71,12 @@ class Bolts(BoltPolicy):
|
||||||
return self.fingers
|
return self.fingers
|
||||||
|
|
||||||
def drawBolt(self, pos):
|
def drawBolt(self, pos):
|
||||||
|
"""
|
||||||
|
Return if this finger needs a bolt
|
||||||
|
|
||||||
|
:param pos: number of this finger
|
||||||
|
|
||||||
|
"""
|
||||||
if pos > self.fingers//2:
|
if pos > self.fingers//2:
|
||||||
pos = self.fingers - pos
|
pos = self.fingers - pos
|
||||||
if pos==0:
|
if pos==0:
|
||||||
|
@ -65,6 +93,12 @@ class Bolts(BoltPolicy):
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
"""Generic Settings class
|
||||||
|
|
||||||
|
Used by different other classes to store messurements and details.
|
||||||
|
Supports absolutevalues and settings that grow with the thinckness
|
||||||
|
of the material used.
|
||||||
|
"""
|
||||||
absolute_params = { }
|
absolute_params = { }
|
||||||
relative_params = { }
|
relative_params = { }
|
||||||
|
|
||||||
|
@ -79,6 +113,14 @@ class Settings:
|
||||||
self.setValues(thickness, relative, **kw)
|
self.setValues(thickness, relative, **kw)
|
||||||
|
|
||||||
def setValues(self, thickness, relative=True, **kw):
|
def setValues(self, thickness, relative=True, **kw):
|
||||||
|
"""
|
||||||
|
Set values
|
||||||
|
|
||||||
|
:param thickness: thickness of the material used
|
||||||
|
:param relative: (Default value = True) Do scale by thinckness
|
||||||
|
:param **kw: parameters to set
|
||||||
|
|
||||||
|
"""
|
||||||
factor = 1.0
|
factor = 1.0
|
||||||
if relative:
|
if relative:
|
||||||
factor = thickness
|
factor = thickness
|
||||||
|
@ -100,6 +142,7 @@ class Settings:
|
||||||
|
|
||||||
|
|
||||||
class Edge:
|
class Edge:
|
||||||
|
"""Straight edge"""
|
||||||
char = 'e'
|
char = 'e'
|
||||||
|
|
||||||
def __init__(self, boxes, settings):
|
def __init__(self, boxes, settings):
|
||||||
|
@ -117,27 +160,35 @@ class Edge:
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
def width(self):
|
def width(self):
|
||||||
|
"""Amount of space the beginning of the edge is set below the inner space of the part """
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def margin(self):
|
def margin(self):
|
||||||
|
"""Space needed right of the starting point"""
|
||||||
return self.boxes.spacing
|
return self.boxes.spacing
|
||||||
|
|
||||||
def spacing(self):
|
def spacing(self):
|
||||||
|
"""Space the edge needs outside of the inner space of the part"""
|
||||||
return self.width() + self.margin()
|
return self.width() + self.margin()
|
||||||
|
|
||||||
def startAngle(self):
|
def startAngle(self):
|
||||||
|
"""Not yet supported"""
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def endAngle(self):
|
def endAngle(self):
|
||||||
|
"""Not yet supported"""
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
class OutSetEdge(Edge):
|
class OutSetEdge(Edge):
|
||||||
|
"""Straight edge out set by one thickness"""
|
||||||
char = 'E'
|
char = 'E'
|
||||||
|
|
||||||
def width(self):
|
def width(self):
|
||||||
return self.boxes.thickness
|
return self.boxes.thickness
|
||||||
|
|
||||||
class CompoundEdge(Edge):
|
class CompoundEdge(Edge):
|
||||||
|
"""Edge composed of multiple different Edges"""
|
||||||
|
|
||||||
def __init__(self, boxes, types, lengths):
|
def __init__(self, boxes, types, lengths):
|
||||||
Edge.__init__(self, boxes, None)
|
Edge.__init__(self, boxes, None)
|
||||||
self.types = [self.edges.get(edge, edge) for edge in types]
|
self.types = [self.edges.get(edge, edge) for edge in types]
|
||||||
|
@ -158,6 +209,7 @@ class CompoundEdge(Edge):
|
||||||
e(l)
|
e(l)
|
||||||
|
|
||||||
class Slot(Edge):
|
class Slot(Edge):
|
||||||
|
"""Edge with an slot to slid another pice through """
|
||||||
def __init__(self, boxes, depth):
|
def __init__(self, boxes, depth):
|
||||||
Edge.__init__(self, boxes, None)
|
Edge.__init__(self, boxes, None)
|
||||||
self.depth = depth
|
self.depth = depth
|
||||||
|
@ -175,6 +227,7 @@ class Slot(Edge):
|
||||||
self.boxes.edge(self.length)
|
self.boxes.edge(self.length)
|
||||||
|
|
||||||
class SlottedEdge(Edge):
|
class SlottedEdge(Edge):
|
||||||
|
"""Edge with multiple slots"""
|
||||||
|
|
||||||
def __init__(self, boxes, sections, edge="e", slots=0):
|
def __init__(self, boxes, sections, edge="e", slots=0):
|
||||||
Edge.__init__(self, boxes, None)
|
Edge.__init__(self, boxes, None)
|
||||||
|
@ -198,6 +251,10 @@ class SlottedEdge(Edge):
|
||||||
self.edge(self.sections[-1])
|
self.edge(self.sections[-1])
|
||||||
|
|
||||||
class FingerJointSettings(Settings):
|
class FingerJointSettings(Settings):
|
||||||
|
"""Setting for all different finger joint components
|
||||||
|
|
||||||
|
Both sides should use the same instance to ensure they match"""
|
||||||
|
|
||||||
absolute_params = {
|
absolute_params = {
|
||||||
"surroundingspaces" : 2,
|
"surroundingspaces" : 2,
|
||||||
}
|
}
|
||||||
|
@ -210,6 +267,7 @@ class FingerJointSettings(Settings):
|
||||||
}
|
}
|
||||||
|
|
||||||
class FingerJointEdge(Edge):
|
class FingerJointEdge(Edge):
|
||||||
|
"""Finger joint edge """
|
||||||
char = 'f'
|
char = 'f'
|
||||||
positive = True
|
positive = True
|
||||||
|
|
||||||
|
@ -253,19 +311,24 @@ class FingerJointEdge(Edge):
|
||||||
self.edge(leftover/2.0)
|
self.edge(leftover/2.0)
|
||||||
|
|
||||||
def margin(self):
|
def margin(self):
|
||||||
|
""" """
|
||||||
return self.boxes.spacing + self.boxes.thickness
|
return self.boxes.spacing + self.boxes.thickness
|
||||||
|
|
||||||
class FingerJointEdgeCounterPart(FingerJointEdge):
|
class FingerJointEdgeCounterPart(FingerJointEdge):
|
||||||
|
"""Finger joint edge - other side"""
|
||||||
char = 'F'
|
char = 'F'
|
||||||
positive = False
|
positive = False
|
||||||
|
|
||||||
def width(self):
|
def width(self):
|
||||||
|
""" """
|
||||||
return self.boxes.thickness
|
return self.boxes.thickness
|
||||||
|
|
||||||
def margin(self):
|
def margin(self):
|
||||||
|
""" """
|
||||||
return self.boxes.spacing
|
return self.boxes.spacing
|
||||||
|
|
||||||
class FingerHoleEdge(Edge):
|
class FingerHoleEdge(Edge):
|
||||||
|
"""Edge with holes for a parallel finger joint"""
|
||||||
char = 'h'
|
char = 'h'
|
||||||
|
|
||||||
def __call__(self, length, dist=None,
|
def __call__(self, length, dist=None,
|
||||||
|
@ -282,9 +345,11 @@ class FingerHoleEdge(Edge):
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
def width(self):
|
def width(self):
|
||||||
|
""" """
|
||||||
return (self.fingerHoleEdgeWidth+1) * self.thickness
|
return (self.fingerHoleEdgeWidth+1) * self.thickness
|
||||||
|
|
||||||
class FingerHoles:
|
class FingerHoles:
|
||||||
|
"""Hole mathcing a finger joint edge"""
|
||||||
def __init__(self, boxes, settings):
|
def __init__(self, boxes, settings):
|
||||||
self.boxes = boxes
|
self.boxes = boxes
|
||||||
self.ctx = boxes.ctx
|
self.ctx = boxes.ctx
|
||||||
|
@ -313,6 +378,7 @@ class FingerHoles:
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
class CrossingFingerHoleEdge(Edge):
|
class CrossingFingerHoleEdge(Edge):
|
||||||
|
"""Edge with holes for finger joints 90° above"""
|
||||||
def __init__(self, boxes, height, **kw):
|
def __init__(self, boxes, height, **kw):
|
||||||
Edge.__init__(self, boxes, None, **kw)
|
Edge.__init__(self, boxes, None, **kw)
|
||||||
self.height = height
|
self.height = height
|
||||||
|
@ -323,6 +389,9 @@ class CrossingFingerHoleEdge(Edge):
|
||||||
|
|
||||||
|
|
||||||
class DoveTailSettings(Settings):
|
class DoveTailSettings(Settings):
|
||||||
|
"""Settings used for dove tail joints
|
||||||
|
|
||||||
|
Both sides should use the same instance to ensure they match"""
|
||||||
absolute_params = {
|
absolute_params = {
|
||||||
"angle" : 50,
|
"angle" : 50,
|
||||||
}
|
}
|
||||||
|
@ -333,6 +402,7 @@ class DoveTailSettings(Settings):
|
||||||
}
|
}
|
||||||
|
|
||||||
class DoveTailJoint(Edge):
|
class DoveTailJoint(Edge):
|
||||||
|
"""Edge with dove tail joints """
|
||||||
char = 'd'
|
char = 'd'
|
||||||
positive = True
|
positive = True
|
||||||
|
|
||||||
|
@ -367,9 +437,11 @@ class DoveTailJoint(Edge):
|
||||||
self.ctx.translate(*self.ctx.get_current_point())
|
self.ctx.translate(*self.ctx.get_current_point())
|
||||||
|
|
||||||
def margin(self):
|
def margin(self):
|
||||||
|
""" """
|
||||||
return self.settings.depth + self.boxes.spacing
|
return self.settings.depth + self.boxes.spacing
|
||||||
|
|
||||||
class DoveTailJointCounterPart(DoveTailJoint):
|
class DoveTailJointCounterPart(DoveTailJoint):
|
||||||
|
"""Edge for other side of dove joints """
|
||||||
char = 'D'
|
char = 'D'
|
||||||
|
|
||||||
positive = False
|
positive = False
|
||||||
|
@ -381,6 +453,7 @@ class DoveTailJointCounterPart(DoveTailJoint):
|
||||||
return self.boxes.spacing
|
return self.boxes.spacing
|
||||||
|
|
||||||
class FlexSettings(Settings):
|
class FlexSettings(Settings):
|
||||||
|
"""Settings for one directional flex cuts"""
|
||||||
relative_params = {
|
relative_params = {
|
||||||
"distance" : 0.5,
|
"distance" : 0.5,
|
||||||
"connection" : 1.0,
|
"connection" : 1.0,
|
||||||
|
@ -391,6 +464,7 @@ class FlexSettings(Settings):
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlexEdge(Edge):
|
class FlexEdge(Edge):
|
||||||
|
"""Edge with flex cuts - use straight edge for the opposing side"""
|
||||||
char = 'X'
|
char = 'X'
|
||||||
|
|
||||||
def __call__(self, x, h, **kw):
|
def __call__(self, x, h, **kw):
|
||||||
|
|
Loading…
Reference in New Issue