2016-02-12 21:22:32 +01:00
#!/usr/bin/python3
2014-03-16 18:26:12 +01:00
# Copyright (C) 2013-2014 Florian Festi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2013-04-01 09:42:29 +02:00
import cairo
import math
2016-03-03 13:27:22 +01:00
import argparse
2016-03-04 12:09:59 +01:00
from argparse import ArgumentParser
2016-03-03 13:27:22 +01:00
import re
2013-05-14 17:52:33 +02:00
from functools import wraps
2013-04-01 09:42:29 +02:00
2013-04-17 13:25:30 +02:00
def dist ( dx , dy ) :
return ( dx * dx + dy * dy ) * * 0.5
2013-04-01 09:42:29 +02:00
2013-05-14 17:52:33 +02:00
def restore ( func ) :
@wraps ( func )
def f ( self , * args , * * kw ) :
self . ctx . save ( )
2013-06-07 12:50:13 +02:00
pt = self . ctx . get_current_point ( )
2013-05-14 17:52:33 +02:00
func ( self , * args , * * kw )
self . ctx . restore ( )
2013-06-07 12:50:13 +02:00
self . ctx . move_to ( * pt )
2013-05-14 17:52:33 +02:00
return f
2013-06-15 23:26:22 +02:00
class BoltPolicy :
""" Abstract class
Distributes ( bed ) bolts on a number of segments
( fingers of a finger joint )
"""
def drawbolt ( self , pos ) :
""" Add a bolt to this segment? """
return False
def numFingers ( self , numfingers ) :
""" returns next smaller, possible number of fingers """
return numFingers
def _even ( self , numFingers ) :
return ( numFingers / / 2 ) * 2
def _odd ( self , numFingers ) :
if numFingers % 2 :
return numFingers
else :
return numFingers - 1
class Bolts ( BoltPolicy ) :
""" Distribute a fixed number of bolts evenly """
def __init__ ( self , bolts = 1 ) :
self . bolts = bolts
def numFingers ( self , numFingers ) :
if self . bolts % 2 :
self . fingers = self . _even ( numFingers )
else :
self . fingers = numFingers
return self . fingers
def drawBolt ( self , pos ) :
if pos > self . fingers / / 2 :
pos = self . fingers - pos
if pos == 0 :
return False
if pos == self . fingers / / 2 and not ( self . bolts % 2 ) :
return False
result = ( math . floor ( ( float ( pos ) * ( self . bolts + 1 ) / self . fingers ) - 0.01 ) !=
math . floor ( ( float ( pos + 1 ) * ( self . bolts + 1 ) / self . fingers ) - 0.01 ) )
#print pos, result, ((float(pos)*(self.bolts+1)/self.fingers)-0.01), ((float(pos+1)*(self.bolts+1)/self.fingers)-0.01)
return result
2013-05-14 17:52:33 +02:00
2013-07-20 10:49:45 +02:00
#############################################################################
### Settings
#############################################################################
class Settings :
absolute_params = { }
relative_params = { }
def __init__ ( self , thickness , relative = True , * * kw ) :
self . values = self . absolute_params . copy ( )
factor = 1.0
if relative :
factor = thickness
2014-03-03 21:45:01 +01:00
for name , value in self . relative_params . items ( ) :
2013-07-20 10:49:45 +02:00
self . values [ name ] = value * factor
self . setValues ( thickness , relative , * * kw )
def setValues ( self , thickness , relative = True , * * kw ) :
factor = 1.0
if relative :
factor = thickness
2014-03-03 21:45:01 +01:00
for name , value in kw . items ( ) :
2013-07-20 10:49:45 +02:00
if name in self . absolute_params :
self . values [ name ] = value
elif name in self . relative_params :
self . values [ name ] = value * factor
else :
2014-03-03 21:45:01 +01:00
raise ValueError ( " Unknown parameter for %s : %s " % (
self . __class__ . __name__ , name ) )
2013-07-20 10:49:45 +02:00
def __getattr__ ( self , name ) :
return self . values [ name ]
#############################################################################
### Edges
#############################################################################
class Edge :
char = ' e '
def __init__ ( self , boxes , settings ) :
self . boxes = boxes
self . ctx = boxes . ctx
self . settings = settings
def __getattr__ ( self , name ) :
""" Hack for using unalter code form Boxes class """
return getattr ( self . boxes , name )
def __call__ ( self , length , * * kw ) :
self . ctx . move_to ( 0 , 0 )
self . ctx . line_to ( length , 0 )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
def width ( self ) :
return 0.0
def margin ( self ) :
return self . boxes . spacing
def spacing ( self ) :
return self . width ( ) + self . margin ( )
def startAngle ( self ) :
return 0.0
def endAngle ( self ) :
return 0.0
class OutSetEdge ( Edge ) :
char = ' E '
def width ( self ) :
return self . boxes . thickness
2016-02-21 18:32:12 +01:00
class CompoundEdge ( Edge ) :
def __init__ ( self , boxes , types , lengths ) :
Edge . __init__ ( self , boxes , None )
self . types = [ self . edges . get ( edge , edge ) for edge in types ]
self . lengths = lengths
self . length = sum ( lengths )
def width ( self ) :
return self . types [ 0 ] . width ( )
def margin ( self ) :
return max ( ( e . margin ( ) for e in self . types ) )
def __call__ ( self , length , * * kw ) :
if length and abs ( length - self . length ) > 1E-5 :
raise ValueError ( " Wrong length for CompoundEdge " )
for e , l in zip ( self . types , self . lengths ) :
# XXX different margins???
e ( l )
2014-04-06 16:21:29 +02:00
class Slot ( Edge ) :
def __init__ ( self , boxes , depth ) :
Edge . __init__ ( self , boxes , None )
self . depth = depth
def __call__ ( self , length , * * kw ) :
if self . depth :
self . boxes . corner ( 90 )
self . boxes . edge ( self . depth )
self . boxes . corner ( - 90 )
self . boxes . edge ( length )
self . boxes . corner ( - 90 )
self . boxes . edge ( self . depth )
self . boxes . corner ( 90 )
else :
self . boxes . edge ( self . length )
class SlottedEdge ( Edge ) :
def __init__ ( self , boxes , sections , edge = " e " , slots = 0 ) :
Edge . __init__ ( self , boxes , None )
self . edge = self . edges . get ( edge , edge )
self . sections = sections
self . slots = slots
def width ( self ) :
return self . edge . width ( )
def margin ( self ) :
return self . edge . margin ( )
def __call__ ( self , length , * * kw ) :
for l in self . sections [ : - 1 ] :
self . edge ( l )
if self . slots :
Slot ( self . boxes , self . slots ) ( self . thickness )
else :
self . edge ( self . thickness )
self . edge ( self . sections [ - 1 ] )
2013-07-20 10:49:45 +02:00
class FingerJointSettings ( Settings ) :
2013-07-25 14:15:30 +02:00
absolute_params = {
" surroundingspaces " : 2 ,
}
2013-07-20 10:49:45 +02:00
relative_params = {
" space " : 1.0 ,
" finger " : 1.0 ,
2013-07-20 13:10:03 +02:00
" height " : 1.0 ,
" width " : 1.0 ,
2013-07-20 10:49:45 +02:00
}
class FingerJointEdge ( Edge ) :
char = ' f '
positive = True
def __call__ ( self , length ,
bedBolts = None , bedBoltSettings = None , * * kw ) :
positive = self . positive
space , finger = self . settings . space , self . settings . finger
2013-07-25 14:15:30 +02:00
fingers = int ( ( length - ( self . settings . surroundingspaces - 1 ) * space ) / /
( space + finger ) )
2013-08-31 19:36:06 +02:00
2013-07-20 10:49:45 +02:00
if bedBolts :
fingers = bedBolts . numFingers ( fingers )
2013-07-25 14:15:30 +02:00
leftover = length - fingers * ( space + finger ) + space
2013-08-31 19:36:06 +02:00
2013-07-20 10:49:45 +02:00
s , f , thickness = space , finger , self . thickness
2016-03-21 15:57:28 +01:00
d , d_nut , h_nut , l , l1 = bedBoltSettings or self . boxes . bedBoltSettings
2013-07-20 10:49:45 +02:00
p = 1 if positive else - 1
2013-09-01 14:39:26 +02:00
if fingers < = 0 :
2013-08-31 19:36:06 +02:00
fingers = 0
leftover = length
2013-07-20 10:49:45 +02:00
self . edge ( leftover / 2.0 )
2014-03-03 21:45:01 +01:00
for i in range ( fingers ) :
2013-07-25 14:15:30 +02:00
if i != 0 :
if not positive and bedBolts and bedBolts . drawBolt ( i ) :
self . hole ( 0.5 * space ,
0.5 * self . thickness , 0.5 * d )
if positive and bedBolts and bedBolts . drawBolt ( i ) :
self . bedBoltHole ( s , bedBoltSettings )
else :
self . edge ( s )
2013-07-20 10:49:45 +02:00
self . corner ( - 90 * p )
2013-07-20 13:10:03 +02:00
self . edge ( self . settings . height )
2013-07-20 10:49:45 +02:00
self . corner ( 90 * p )
self . edge ( f )
self . corner ( 90 * p )
2013-07-20 13:10:03 +02:00
self . edge ( self . settings . height )
2013-07-20 10:49:45 +02:00
self . corner ( - 90 * p )
2013-07-25 14:15:30 +02:00
self . edge ( leftover / 2.0 )
2013-07-20 10:49:45 +02:00
def margin ( self ) :
return self . boxes . spacing + self . boxes . thickness
class FingerJointEdgeCounterPart ( FingerJointEdge ) :
char = ' F '
positive = False
def width ( self ) :
return self . boxes . thickness
def margin ( self ) :
return self . boxes . spacing
class FingerHoleEdge ( Edge ) :
char = ' h '
def __call__ ( self , length , dist = None ,
bedBolts = None , bedBoltSettings = None , * * kw ) :
if dist is None :
dist = self . fingerHoleEdgeWidth * self . thickness
self . ctx . save ( )
self . moveTo ( 0 , dist + self . thickness / 2 )
self . fingerHoles ( length , bedBolts , bedBoltSettings )
self . ctx . restore ( )
# XXX continue path
self . ctx . move_to ( 0 , 0 )
self . ctx . line_to ( length , 0 )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
def width ( self ) :
return ( self . fingerHoleEdgeWidth + 1 ) * self . thickness
2016-02-21 18:30:25 +01:00
class CrossingFingerHoleEdge ( Edge ) :
def __init__ ( self , boxes , height , * * kw ) :
Edge . __init__ ( self , boxes , None , * * kw )
self . height = height
def __call__ ( self , length , * * kw ) :
self . fingerHolesAt ( length / 2.0 , 0 , self . height )
Edge . __call__ ( self , length )
2013-07-20 10:49:45 +02:00
class DoveTailSettings ( Settings ) :
absolute_params = {
" angle " : 50 ,
}
relative_params = {
" size " : 3 ,
" depth " : 1.5 ,
" radius " : 0.2 ,
}
class DoveTailJoint ( Edge ) :
char = ' d '
positive = True
def __call__ ( self , length , * * kw ) :
s = self . settings
radius = max ( s . radius , self . boxes . burn ) # no smaller than burn
positive = self . positive
a = s . angle + 90
alpha = 0.5 * math . pi - math . pi * s . angle / 180.0
l1 = radius / math . tan ( alpha / 2.0 )
diffx = 0.5 * s . depth / math . tan ( alpha )
l2 = 0.5 * s . depth / math . sin ( alpha )
sections = int ( ( length ) / / ( s . size * 2 ) )
leftover = length - sections * s . size * 2
p = 1 if positive else - 1
self . edge ( ( s . size + leftover ) / 2.0 + diffx - l1 )
2014-03-03 21:45:01 +01:00
for i in range ( sections ) :
2013-07-20 10:49:45 +02:00
self . corner ( - 1 * p * a , radius )
self . edge ( 2 * ( l2 - l1 ) )
self . corner ( p * a , radius )
self . edge ( 2 * ( diffx - l1 ) + s . size )
self . corner ( p * a , radius )
self . edge ( 2 * ( l2 - l1 ) )
self . corner ( - 1 * p * a , radius )
if i < sections - 1 : # all but the last
self . edge ( 2 * ( diffx - l1 ) + s . size )
self . edge ( ( s . size + leftover ) / 2.0 + diffx - l1 )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
def margin ( self ) :
return self . settings . depth + self . boxes . spacing
class DoveTailJointCounterPart ( DoveTailJoint ) :
char = ' D '
positive = False
def width ( self ) :
return self . settings . depth
def margin ( self ) :
return self . boxes . spacing
class FlexSettings ( Settings ) :
relative_params = {
" distance " : 0.5 ,
" connection " : 1.0 ,
" width " : 5.0 ,
}
absolute_params = {
" stretch " : 1.0 ,
}
class FlexEdge ( Edge ) :
char = ' X '
def __call__ ( self , x , h , * * kw ) :
dist = self . settings . distance
connection = self . settings . connection
width = self . settings . width
burn = self . boxes . burn
h + = 2 * burn
lines = int ( x / / dist )
leftover = x - lines * dist
sections = int ( ( h - connection ) / / width )
sheight = ( ( h - connection ) / sections ) - connection
2014-03-03 21:45:01 +01:00
for i in range ( lines ) :
2013-07-20 10:49:45 +02:00
pos = i * dist + leftover / 2
if i % 2 :
self . ctx . move_to ( pos , 0 )
self . ctx . line_to ( pos , connection + sheight )
2014-03-03 21:45:01 +01:00
for j in range ( ( sections - 1 ) / / 2 ) :
2013-07-20 10:49:45 +02:00
self . ctx . move_to ( pos , ( 2 * j + 1 ) * sheight + ( 2 * j + 2 ) * connection )
self . ctx . line_to ( pos , ( 2 * j + 3 ) * ( sheight + connection ) )
if not sections % 2 :
self . ctx . move_to ( pos , h - sheight - connection )
self . ctx . line_to ( pos , h )
else :
if sections % 2 :
self . ctx . move_to ( pos , h )
self . ctx . line_to ( pos , h - connection - sheight )
2014-03-03 21:45:01 +01:00
for j in range ( ( sections - 1 ) / / 2 ) :
2013-07-20 10:49:45 +02:00
self . ctx . move_to (
pos , h - ( ( 2 * j + 1 ) * sheight + ( 2 * j + 2 ) * connection ) )
self . ctx . line_to (
pos , h - ( 2 * j + 3 ) * ( sheight + connection ) )
else :
2014-03-03 21:45:01 +01:00
for j in range ( sections / / 2 ) :
2013-07-20 10:49:45 +02:00
self . ctx . move_to ( pos ,
h - connection - 2 * j * ( sheight + connection ) )
self . ctx . line_to ( pos , h - 2 * ( j + 1 ) * ( sheight + connection ) )
self . ctx . move_to ( 0 , 0 )
self . ctx . line_to ( x , 0 )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
#############################################################################
### Building blocks
#############################################################################
class FingerHoles :
def __init__ ( self , boxes , settings ) :
self . boxes = boxes
self . ctx = boxes . ctx
self . settings = settings
def __call__ ( self , length , bedBolts = None , bedBoltSettings = None ) :
s , f = self . settings . space , self . settings . finger
2013-07-25 14:15:30 +02:00
fingers = int ( ( length - ( self . settings . surroundingspaces - 1 ) * s ) / /
( s + f ) )
2013-07-20 10:49:45 +02:00
if bedBolts :
fingers = bedBolts . numFingers ( fingers )
2016-03-21 15:57:28 +01:00
d , d_nut , h_nut , l , l1 = bedBoltSettings or self . boxes . bedBoltSettings
2013-07-20 10:49:45 +02:00
leftover = length - fingers * ( s + f ) - f
b = self . boxes . burn
2013-08-31 20:04:47 +02:00
if self . boxes . debug :
self . ctx . rectangle ( 0 , - self . settings . width / 2 + b ,
length , self . settings . width - 2 * b )
2014-03-03 21:45:01 +01:00
for i in range ( fingers ) :
2013-07-20 10:49:45 +02:00
pos = leftover / 2.0 + i * ( s + f )
if bedBolts and bedBolts . drawBolt ( i ) :
2016-03-21 15:57:28 +01:00
self . boxes . hole ( pos + 0.5 * s , 0 , d * 0.5 )
2013-07-20 13:10:03 +02:00
self . ctx . rectangle ( pos + s + b , - self . settings . width / 2 + b ,
f - 2 * b , self . settings . width - 2 * b )
2013-07-20 10:49:45 +02:00
self . ctx . move_to ( 0 , length )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
2013-07-25 14:22:55 +02:00
class NutHole :
sizes = {
2016-03-23 09:12:14 +01:00
" M1.6 " : ( 3.2 , 1.3 ) ,
" M2 " : ( 4 , 1.6 ) ,
" M2.5 " : ( 5 , 2.0 ) ,
" M3 " : ( 5.5 , 2.4 ) ,
" M4 " : ( 7 , 3.2 ) ,
" M5 " : ( 8 , 4.7 ) ,
" M6 " : ( 10 , 5.2 ) ,
" M8 " : ( 13 , 6.8 ) ,
" M10 " : ( 16 , 8.4 ) ,
" M12 " : ( 18 , 10.8 ) ,
" M14 " : ( 21 , 12.8 ) ,
" M16 " : ( 24 , 14.8 ) ,
" M20 " : ( 30 , 18.0 ) ,
" M24 " : ( 36 , 21.5 ) ,
" M30 " : ( 46 , 25.6 ) ,
" M36 " : ( 55 , 31 ) ,
" M42 " : ( 65 , 34 ) ,
" M48 " : ( 75 , 38 ) ,
" M56 " : ( 85 , 45 ) ,
" M64 " : ( 95 , 51 ) ,
2013-07-25 14:22:55 +02:00
}
def __init__ ( self , boxes , settings ) :
self . boxes = boxes
self . ctx = boxes . ctx
self . settings = settings
@restore
def __call__ ( self , size , x = 0 , y = 0 , angle = 0 ) :
2016-03-23 09:12:14 +01:00
size = self . sizes . get ( size , ( size , ) ) [ 0 ]
2013-07-25 14:22:55 +02:00
side = size / 3 * * 0.5
self . boxes . moveTo ( x , y , angle )
self . boxes . moveTo ( - 0.5 * side , 0.5 * size , angle )
for i in range ( 6 ) :
self . boxes . edge ( side )
self . boxes . corner ( - 60 )
2016-03-03 13:27:22 +01:00
def argparseSections ( s ) :
m = re . match ( r " ( \ d+( \ . \ d+)?)/( \ d+) " , s )
if m :
n = int ( m . group ( 3 ) )
print ( [ float ( m . group ( 1 ) ) ] * n )
return [ float ( m . group ( 1 ) ) / n ] * n
m = re . match ( r " ( \ d+( \ . \ d+)?) \ *( \ d+) " , s )
if m :
n = int ( m . group ( 3 ) )
return [ float ( m . group ( 1 ) ) ] * n
try :
return [ float ( part ) for part in s . split ( " : " ) ]
except ValueError :
raise argparse . ArgumentTypeError ( " Don ' t understand sections string " )
2013-04-01 09:42:29 +02:00
class Boxes :
2016-03-03 13:27:22 +01:00
def __init__ ( self ) :
2016-03-08 09:33:45 +01:00
self . argparser = ArgumentParser ( description = self . __doc__ )
2016-03-03 13:27:22 +01:00
self . argparser . add_argument (
" --thickness " , action = " store " , type = float , default = 4.0 ,
help = " thickness of the material " )
self . argparser . add_argument (
" --output " , action = " store " , type = str , default = " box.svg " ,
help = " name of resulting file " )
self . argparser . add_argument (
" --debug " , action = " store_true " , default = False ,
help = " print surrounding boxes for some structures " )
self . argparser . add_argument (
" --burn " , action = " store " , type = float , default = 0.05 ,
help = " burn correction in mm " )
def open ( self , width , height ) :
2013-07-20 10:49:45 +02:00
self . spacing = 2 * self . burn + 0.5 * self . thickness
2013-04-16 16:50:29 +02:00
self . fingerHoleEdgeWidth = 1.0 # multitudes of self.thickness
2013-06-15 23:26:22 +02:00
self . bedBoltSettings = ( 3 , 5.5 , 2 , 20 , 15 ) #d, d_nut, h_nut, l, l1
2013-04-18 04:44:33 +02:00
self . hexHolesSettings = ( 5 , 3 , ' circle ' ) # r, dist, style
2013-04-05 20:43:34 +02:00
self . _init_surface ( width , height )
2013-07-20 10:49:45 +02:00
self . _buildObjects ( )
2016-03-03 13:27:22 +01:00
def buildArgParser ( self , * l ) :
for arg in l :
if arg == " x " :
self . argparser . add_argument (
" --x " , action = " store " , type = float , default = 100.0 ,
help = " inner width in mm " )
elif arg == " y " :
self . argparser . add_argument (
" --y " , action = " store " , type = float , default = 100.0 ,
help = " inner depth in mm " )
elif arg == " sx " :
self . argparser . add_argument (
" --sx " , action = " store " , type = argparseSections ,
default = " 50*3 " ,
2016-03-16 11:41:14 +01:00
help = """ sections left to right in mm. Possible formats: overallwidth/numberof sections e.g. " 250/5 " ; sectionwith*numberofsections e.g. " 50*5 " ; section widths separated by " : " e.g. " 30:25.5:70 "
2016-03-03 13:27:22 +01:00
""" )
elif arg == " sy " :
self . argparser . add_argument (
" --sy " , action = " store " , type = argparseSections ,
default = " 50*3 " ,
2016-03-16 11:41:14 +01:00
help = """ sections back to front in mm. See --sx for format """ )
2016-03-03 13:27:22 +01:00
elif arg == " h " :
self . argparser . add_argument (
" --h " , action = " store " , type = float , default = 100.0 ,
help = " inner height in mm " )
elif arg == " hi " :
self . argparser . add_argument (
2016-03-08 22:27:55 +01:00
" --hi " , action = " store " , type = float , default = 0.0 ,
help = " inner height of inner walls in mm (leave to zero for same as outer walls) " )
2016-03-03 13:27:22 +01:00
else :
raise ValueError ( " No default for argument " , arg )
2016-03-04 12:09:59 +01:00
def parseArgs ( self , args = None ) :
self . argparser . parse_args ( args = args , namespace = self )
2016-03-03 13:27:22 +01:00
2013-07-20 10:49:45 +02:00
def addPart ( self , part , name = None ) :
if name is None :
name = part . __class__ . __name__
name = name [ 0 ] . lower ( ) + name [ 1 : ]
2016-03-06 22:50:39 +01:00
#if not hasattr(self, name):
setattr ( self , name , part )
2013-07-20 10:49:45 +02:00
if isinstance ( part , Edge ) :
self . edges [ part . char ] = part
def _buildObjects ( self ) :
self . edges = { }
self . addPart ( Edge ( self , None ) )
self . addPart ( OutSetEdge ( self , None ) )
# Share settings object
s = FingerJointSettings ( self . thickness )
self . addPart ( FingerJointEdge ( self , s ) )
self . addPart ( FingerJointEdgeCounterPart ( self , s ) )
self . addPart ( FingerHoleEdge ( self , s ) )
self . addPart ( FingerHoles ( self , s ) )
s = DoveTailSettings ( self . thickness )
self . addPart ( DoveTailJoint ( self , s ) )
self . addPart ( DoveTailJointCounterPart ( self , s ) )
s = FlexSettings ( self . thickness )
self . addPart ( FlexEdge ( self , s ) )
2013-04-01 09:42:29 +02:00
2013-07-25 14:22:55 +02:00
self . addPart ( NutHole ( self , None ) )
2013-04-05 20:43:34 +02:00
def _init_surface ( self , width , height ) :
2014-03-29 08:23:18 +01:00
#mm2pt = 90 / 25.4 / 1.25
mm2pt = 1
#width *= mm2pt
#height *= mm2pt #3.543307
2013-04-01 09:42:29 +02:00
self . surface = cairo . SVGSurface ( self . output , width , height )
self . ctx = ctx = cairo . Context ( self . surface )
ctx . translate ( 0 , height )
2013-06-25 19:45:09 +02:00
ctx . scale ( mm2pt , - mm2pt )
2013-04-01 09:42:29 +02:00
2014-03-29 08:23:18 +01:00
#ctx.set_source_rgb(1.0, 1.0, 1.0)
#ctx.rectangle(0, 0, width, height)
#ctx.fill()
2013-04-01 09:42:29 +02:00
ctx . set_source_rgb ( 0.0 , 0.0 , 0.0 )
2013-06-15 23:26:22 +02:00
ctx . set_line_width ( 2 * self . burn )
2013-04-01 09:42:29 +02:00
2013-06-29 13:55:57 +02:00
def cc ( self , callback , number , x = 0.0 , y = None ) :
2013-04-16 04:27:48 +02:00
""" call callback """
2013-06-29 13:55:57 +02:00
if y is None :
y = self . burn
2013-04-16 04:27:48 +02:00
self . ctx . save ( )
self . moveTo ( x , y )
if callable ( callback ) :
callback ( number )
elif hasattr ( callback , ' __getitem__ ' ) :
try :
callback = callback [ number ]
if callable ( callback ) :
callback ( )
2013-04-16 05:21:38 +02:00
except ( KeyError , IndexError ) :
2013-04-16 04:27:48 +02:00
pass
except :
self . ctx . restore ( )
raise
self . ctx . restore ( )
2013-06-15 23:26:22 +02:00
def getEntry ( self , param , idx ) :
if isinstance ( param , list ) :
if len ( param ) > idx :
return param [ idx ]
else :
return None
else :
return param
2013-05-14 17:52:33 +02:00
2014-03-21 21:08:54 +01:00
def close ( self ) :
self . ctx . stroke ( )
self . surface . flush ( )
self . surface . finish ( )
2013-07-20 10:49:45 +02:00
2014-03-29 08:23:18 +01:00
f = open ( self . output , " r+ " )
s = f . read ( 1024 )
pos = s . find ( ' pt " ' )
if pos > 0 :
f . seek ( pos )
f . write ( " mm " )
else :
2016-02-12 21:22:32 +01:00
print ( " Could not replace pt with mm " )
2014-03-29 08:23:18 +01:00
pos = s . find ( ' pt " ' , pos + 3 )
if pos > 0 :
f . seek ( pos )
f . write ( " mm " )
else :
2016-02-12 21:22:32 +01:00
print ( " Could not replace pt with mm " )
2014-03-29 08:23:18 +01:00
2013-04-01 09:42:29 +02:00
############################################################
### Turtle graphics commands
############################################################
def corner ( self , degrees , radius = 0 ) :
rad = degrees * math . pi / 180
if degrees > 0 :
self . ctx . arc ( 0 , radius + self . burn , radius + self . burn ,
- 0.5 * math . pi , rad - 0.5 * math . pi )
2013-06-15 23:26:22 +02:00
elif radius > self . burn :
2013-06-08 15:19:28 +02:00
self . ctx . arc_negative ( 0 , - ( radius - self . burn ) , radius - self . burn ,
2013-04-01 09:42:29 +02:00
0.5 * math . pi , rad + 0.5 * math . pi )
2013-06-15 23:26:22 +02:00
else : # not rounded inner corner
self . ctx . arc_negative ( 0 , self . burn - radius , self . burn - radius ,
- 0.5 * math . pi , - 0.5 * math . pi + rad )
2013-04-01 18:32:07 +02:00
self . continueDirection ( rad )
2013-04-01 09:42:29 +02:00
def edge ( self , length ) :
2013-06-15 23:26:22 +02:00
self . ctx . move_to ( 0 , 0 )
2013-04-01 09:42:29 +02:00
self . ctx . line_to ( length , 0 )
self . ctx . translate ( * self . ctx . get_current_point ( ) )
2013-04-05 20:43:34 +02:00
def curveTo ( self , x1 , y1 , x2 , y2 , x3 , y3 ) :
""" control point 1, control point 2, end point """
self . ctx . curve_to ( x1 , y1 , x2 , y2 , x3 , y3 )
dx = x3 - x2
dy = y3 - y2
rad = math . atan2 ( dy , dx )
self . continueDirection ( rad )
2014-04-20 21:54:33 +02:00
def polyline ( self , * args ) :
for i , arg in enumerate ( args ) :
if i % 2 :
self . corner ( arg )
else :
self . edge ( arg )
2013-06-15 23:26:22 +02:00
def bedBoltHole ( self , length , bedBoltSettings = None ) :
d , d_nut , h_nut , l , l1 = bedBoltSettings or self . bedBoltSettings
self . edge ( ( length - d ) / 2.0 )
self . corner ( 90 )
self . edge ( l1 )
self . corner ( 90 )
self . edge ( ( d_nut - d ) / 2.0 )
self . corner ( - 90 )
self . edge ( h_nut )
self . corner ( - 90 )
self . edge ( ( d_nut - d ) / 2.0 )
self . corner ( 90 )
self . edge ( l - l1 - h_nut )
self . corner ( - 90 )
self . edge ( d )
self . corner ( - 90 )
self . edge ( l - l1 - h_nut )
self . corner ( 90 )
self . edge ( ( d_nut - d ) / 2.0 )
self . corner ( - 90 )
self . edge ( h_nut )
self . corner ( - 90 )
self . edge ( ( d_nut - d ) / 2.0 )
self . corner ( 90 )
self . edge ( l1 )
self . corner ( 90 )
self . edge ( ( length - d ) / 2.0 )
2013-04-01 09:42:29 +02:00
2013-06-03 09:49:51 +02:00
def grip ( self , length , depth ) :
""" corrugated edge useful as an gipping area """
grooves = int ( length / / ( depth * 2.0 ) ) + 1
depth = length / grooves / 4.0
2014-03-03 21:45:01 +01:00
for groove in range ( grooves ) :
2013-06-03 09:49:51 +02:00
self . corner ( 90 , depth )
self . corner ( - 180 , depth )
self . corner ( 90 , depth )
def _latchHole ( self , length ) :
2013-06-25 13:40:22 +02:00
self . edge ( 1.1 * self . thickness )
2013-06-03 09:49:51 +02:00
self . corner ( - 90 )
2013-06-25 13:40:22 +02:00
self . edge ( length / 2.0 + 0.2 * self . thickness )
2013-06-03 09:49:51 +02:00
self . corner ( - 90 )
2013-06-25 13:40:22 +02:00
self . edge ( 1.1 * self . thickness )
2013-06-03 09:49:51 +02:00
def _latchGrip ( self , length ) :
self . corner ( 90 , self . thickness / 4.0 )
2013-06-25 13:40:22 +02:00
self . grip ( length / 2.0 - self . thickness / 2.0 - 0.2 * self . thickness , self . thickness / 2.0 )
2013-06-03 09:49:51 +02:00
self . corner ( 90 , self . thickness / 4.0 )
def latch ( self , length , positive = True , reverse = False ) :
""" Fix a flex box door at the box
positive : False : Door side ; True : Box side
reverse : True when running away from the latch
"""
if positive :
if reverse :
self . edge ( length / 2.0 - self . burn )
self . corner ( - 90 )
self . edge ( self . thickness )
self . corner ( 90 )
self . edge ( length / 2.0 )
self . corner ( 90 )
self . edge ( self . thickness )
self . corner ( - 90 )
if not reverse :
self . edge ( length / 2.0 - self . burn )
else :
if reverse :
self . _latchGrip ( length )
else :
self . corner ( 90 )
self . _latchHole ( length )
if not reverse :
self . _latchGrip ( length )
else :
self . corner ( 90 )
2013-07-20 17:47:18 +02:00
def handle ( self , x , h , hl , r = 30 ) :
2013-04-16 05:07:26 +02:00
""" Creates and Edge with a handle """
d = ( x - hl - 2 * r ) / 2.0
if d < 0 :
2014-03-03 21:45:01 +01:00
print ( " Handle too wide " )
2013-04-16 05:07:26 +02:00
self . ctx . save ( )
# Hole
2013-07-20 17:47:18 +02:00
self . moveTo ( d + 2 * r , 0 )
2013-04-16 05:07:26 +02:00
self . edge ( hl - 2 * r )
self . corner ( - 90 , r )
2013-07-20 17:47:18 +02:00
self . edge ( h - 3 * r )
2013-04-16 05:07:26 +02:00
self . corner ( - 90 , r )
self . edge ( hl - 2 * r )
self . corner ( - 90 , r )
2013-07-20 17:47:18 +02:00
self . edge ( h - 3 * r )
2013-04-16 05:07:26 +02:00
self . corner ( - 90 , r )
self . ctx . restore ( )
self . moveTo ( 0 , 0 )
self . curveTo ( d , 0 , d , 0 , d , - h + r )
self . curveTo ( r , 0 , r , 0 , r , r )
self . edge ( hl )
self . curveTo ( r , 0 , r , 0 , r , r )
self . curveTo ( h - r , 0 , h - r , 0 , h - r , - d )
2013-04-01 09:42:29 +02:00
### Navigation
2013-07-20 10:49:45 +02:00
def moveTo ( self , x , y = 0.0 , degrees = 0 ) :
self . ctx . move_to ( 0 , 0 )
2013-04-01 09:42:29 +02:00
self . ctx . translate ( x , y )
self . ctx . rotate ( degrees * math . pi / 180.0 )
self . ctx . move_to ( 0 , 0 )
2013-04-01 18:32:07 +02:00
def continueDirection ( self , angle = 0 ) :
2013-04-01 09:42:29 +02:00
self . ctx . translate ( * self . ctx . get_current_point ( ) )
2013-04-01 18:32:07 +02:00
self . ctx . rotate ( angle )
2013-04-01 09:42:29 +02:00
2013-07-20 10:49:45 +02:00
def move ( self , x , y , where , before = False ) :
""" Intended to be used by parts
where can be combinations of " up " , " down " , " left " , " right " and " only "
when " only " is included the move is only done when before is True
The function returns whether actual drawing of the part
should be omited .
"""
if not where :
return False
terms = where . split ( )
dontdraw = before and " only " in terms
moves = {
" up " : ( 0 , y , False ) ,
" down " : ( 0 , - y , True ) ,
" left " : ( - x , 0 , True ) ,
" right " : ( x , 0 , False ) ,
" only " : ( 0 , 0 , None ) ,
}
for term in terms :
if not term in moves :
2014-03-03 21:45:01 +01:00
raise ValueError ( " Unknown direction: ' %s ' " % term )
2013-07-20 10:49:45 +02:00
x , y , movebeforeprint = moves [ term ]
if movebeforeprint and before :
self . moveTo ( x , y )
elif ( not movebeforeprint and not before ) or dontdraw :
self . moveTo ( x , y )
return dontdraw
2013-04-16 04:27:48 +02:00
# Building blocks
2013-07-20 17:48:11 +02:00
def fingerHolesAt ( self , x , y , length , angle = 90 ,
2013-07-20 10:49:45 +02:00
bedBolts = None , bedBoltSettings = None ) :
2013-04-01 22:20:22 +02:00
self . ctx . save ( )
2013-07-20 17:48:11 +02:00
self . moveTo ( x , y , angle )
2013-07-20 10:49:45 +02:00
self . fingerHoles ( length , bedBolts , bedBoltSettings )
2013-04-01 22:20:22 +02:00
self . ctx . restore ( )
2013-06-07 12:50:13 +02:00
@restore
2013-04-16 04:24:35 +02:00
def hole ( self , x , y , r ) :
self . moveTo ( x + r , y )
self . ctx . arc ( - r , 0 , r , 0 , 2 * math . pi )
2013-07-20 17:51:54 +02:00
@restore
def rectangularHole ( self , x , y , dx , dy , r = 0 ) :
self . moveTo ( x + r - dx / 2.0 , y - dy / 2.0 , 180 )
for d in ( dy , dx , dy , dx ) :
self . corner ( - 90 , r )
2016-03-15 20:28:44 +01:00
self . edge ( d - 2 * r )
2013-07-20 17:51:54 +02:00
2014-01-21 22:44:22 +01:00
@restore
def text ( self , text , x = 0 , y = 0 , angle = 0 , align = " " ) :
self . moveTo ( x , y , angle )
( tx , ty , width , height , dx , dy ) = self . ctx . text_extents ( text )
align = align . split ( )
moves = {
" top " : ( 0 , - height ) ,
" middle " : ( 0 , - 0.5 * height ) ,
" bottom " : ( 0 , 0 ) ,
" left " : ( 0 , 0 ) ,
" center " : ( - 0.5 * width , 0 ) ,
" right " : ( - width , 0 ) ,
}
for a in align :
if a in moves :
self . moveTo ( * moves [ a ] )
else :
raise ValueError ( " Unknown alignment: %s " % align )
self . ctx . scale ( 1 , - 1 )
self . ctx . show_text ( text )
2013-07-20 17:52:28 +02:00
@restore
2013-07-21 23:01:35 +02:00
def NEMA ( self , size , x = 0 , y = 0 , angle = 0 ) :
2013-07-20 17:52:28 +02:00
nema = {
# motor,flange, holes, screws
8 : ( 20.3 , 16 , 15.4 , 3 ) ,
11 : ( 28.2 , 22 , 23 , 4 ) ,
14 : ( 35.2 , 22 , 26 , 4 ) ,
16 : ( 39.2 , 22 , 31 , 4 ) ,
17 : ( 42.2 , 22 , 31 , 4 ) ,
23 : ( 56.4 , 38.1 , 47.1 , 5.2 ) ,
24 : ( 60 , 36 , 49.8 , 5.1 ) ,
34 : ( 86.3 , 73 , 69.8 , 6.6 ) ,
42 : ( 110 , 55.5 , 89 , 8.5 ) ,
}
width , flange , holedistance , diameter = nema [ size ]
2013-07-21 23:01:35 +02:00
self . moveTo ( x , y , angle )
2013-08-31 20:04:47 +02:00
if self . debug :
self . rectangularHole ( 0 , 0 , width , width )
2013-07-20 17:52:28 +02:00
self . hole ( 0 , 0 , 0.5 * flange )
for x in ( - 1 , 1 ) :
for y in ( - 1 , 1 ) :
self . hole ( x * 0.5 * holedistance ,
y * 0.5 * holedistance ,
0.5 * diameter )
2013-04-18 04:44:33 +02:00
# hexHoles
def hexHolesRectangle ( self , x , y , settings = None , skip = None ) :
2013-04-16 16:50:29 +02:00
"""
Fills a rectangle with holes .
r : radius of holes
b : space between holes
style : what types of holes ( not yet implemented )
skip : function to check if hole should be present
gets x , y , r , b , posx , posy
"""
2013-04-18 04:44:33 +02:00
if settings is None :
settings = self . hexHolesSettings
r , b , style = settings
2013-04-16 04:24:35 +02:00
w = r + b / 2.0
dist = w * math . cos ( math . pi / 6.0 )
2013-04-16 16:50:29 +02:00
# how many half circles do fit
cx = int ( ( x - 2 * r ) / / ( w ) ) + 2
cy = int ( ( y - 2 * r ) / / ( dist ) ) + 2
# what's left on the sides
lx = ( x - ( 2 * r + ( cx - 2 ) * w ) ) / 2.0
2013-04-18 04:44:33 +02:00
ly = ( y - ( 2 * r + ( ( cy / / 2 ) * 2 ) * dist - 2 * dist ) ) / 2.0
2013-04-16 16:50:29 +02:00
2014-03-03 21:45:01 +01:00
for i in range ( cy / / 2 ) :
for j in range ( ( cx - ( i % 2 ) ) / / 2 ) :
2013-04-16 16:50:29 +02:00
px = 2 * j * w + r + lx
py = i * 2 * dist + r + ly
if i % 2 :
2013-04-17 13:23:23 +02:00
px + = w
2013-04-16 16:50:29 +02:00
if skip and skip ( x , y , r , b , px , py ) :
continue
self . hole ( px , py , r )
def __skipcircle ( self , x , y , r , b , posx , posy ) :
cx , cy = x / 2.0 , y / 2.0
2013-04-17 13:25:30 +02:00
return ( dist ( posx - cx , posy - cy ) > ( cx - r ) )
2013-04-16 16:50:29 +02:00
2013-04-18 04:44:33 +02:00
def hexHolesCircle ( self , d , settings = None ) :
2013-04-16 16:50:29 +02:00
d2 = d / 2.0
2013-04-18 04:44:33 +02:00
self . hexHolesRectangle ( d , d , settings = settings , skip = self . __skipcircle )
2013-04-16 16:50:29 +02:00
2013-04-18 04:44:33 +02:00
def hexHolesPlate ( self , x , y , rc , settings = None ) :
2013-04-17 13:25:30 +02:00
def skip ( x , y , r , b , posx , posy ) :
posx = abs ( posx - ( x / 2.0 ) )
posy = abs ( posy - ( y / 2.0 ) )
2013-04-18 04:44:33 +02:00
wx = 0.5 * x - rc - r
wy = 0.5 * y - rc - r
2013-04-17 13:25:30 +02:00
if ( posx < = wx ) or ( posy < = wx ) :
return 0
2013-04-18 04:44:33 +02:00
return dist ( posx - wx , posy - wy ) > rc
self . hexHolesRectangle ( x , y , settings , skip = skip )
2013-04-17 13:25:30 +02:00
2013-04-18 04:44:33 +02:00
def hexHolesHex ( self , h , settings = None , grow = None ) :
if settings is None :
settings = self . hexHolesSettings
r , b , style = settings
2013-04-16 04:24:35 +02:00
self . ctx . rectangle ( 0 , 0 , h , h )
w = r + b / 2.0
dist = w * math . cos ( math . pi / 6.0 )
cy = 2 * int ( ( h - 4 * dist ) / / ( 4 * w ) ) + 1
leftover = h - 2 * r - ( cy - 1 ) * 2 * r
if grow == ' space ' :
b + = leftover / ( cy - 1 ) / 2
# recalulate with adjusted values
w = r + b / 2.0
dist = w * math . cos ( math . pi / 6.0 )
self . moveTo ( h / 2.0 - ( cy / / 2 ) * 2 * w , h / 2.0 )
2014-03-03 21:45:01 +01:00
for j in range ( cy ) :
2013-04-16 04:24:35 +02:00
self . hole ( 2 * j * w , 0 , r )
2014-03-03 21:45:01 +01:00
for i in range ( 1 , cy / 2 + 1 ) :
for j in range ( cy - i ) :
2013-04-16 04:24:35 +02:00
self . hole ( j * 2 * w + i * w , i * 2 * dist , r )
self . hole ( j * 2 * w + i * w , - i * 2 * dist , r )
2013-04-16 11:32:13 +02:00
##################################################
### parts
##################################################
2013-04-16 04:24:35 +02:00
2013-05-14 17:52:33 +02:00
def roundedPlate ( self , x , y , r , callback = None ,
2013-06-15 23:26:22 +02:00
holesMargin = None , holesSettings = None ,
2013-07-20 10:49:45 +02:00
bedBolts = None , bedBoltSettings = None ,
move = None ) :
2013-04-16 04:27:48 +02:00
""" fits surroundingWall
first edge is split to have a joint in the middle of the side
callback is called at the beginning of the straight edges
2013-05-14 17:52:33 +02:00
0 , 1 for the two part of the first edge , 2 , 3 , 4 for the others
set holesMargin to get hex holes .
"""
2013-07-20 10:49:45 +02:00
overallwidth = x + 2 * self . fingerJointEdge . spacing ( )
overallheight = y + 2 * self . fingerJointEdge . spacing ( )
if self . move ( overallwidth , overallheight , move , before = True ) :
return
2013-04-16 04:27:48 +02:00
self . ctx . save ( )
2013-07-20 19:29:41 +02:00
self . moveTo ( self . fingerJointEdge . margin ( ) ,
self . fingerJointEdge . margin ( ) )
self . moveTo ( r , 0 )
2013-07-20 10:49:45 +02:00
2013-04-16 04:27:48 +02:00
self . cc ( callback , 0 )
2013-07-20 10:49:45 +02:00
self . fingerJointEdge ( x / 2.0 - r , bedBolts = self . getEntry ( bedBolts , 0 ) ,
2013-06-15 23:26:22 +02:00
bedBoltSettings = self . getEntry ( bedBoltSettings , 0 ) )
2013-04-16 04:27:48 +02:00
self . cc ( callback , 1 )
2013-07-20 10:49:45 +02:00
self . fingerJointEdge ( x / 2.0 - r , bedBolts = self . getEntry ( bedBolts , 1 ) ,
2013-06-15 23:26:22 +02:00
bedBoltSettings = self . getEntry ( bedBoltSettings , 1 ) )
2013-04-16 04:27:48 +02:00
for i , l in zip ( range ( 3 ) , ( y , x , y ) ) :
self . corner ( 90 , r )
self . cc ( callback , i + 2 )
2013-07-20 10:49:45 +02:00
self . fingerJointEdge ( l - 2 * r , bedBolts = self . getEntry ( bedBolts , i + 2 ) ,
2013-06-15 23:26:22 +02:00
bedBoltSettings = self . getEntry ( bedBoltSettings , i + 2 ) )
2013-04-16 04:27:48 +02:00
self . corner ( 90 , r )
2013-05-14 17:52:33 +02:00
self . ctx . restore ( )
self . ctx . save ( )
2013-07-20 19:29:41 +02:00
self . moveTo ( self . fingerJointEdge . margin ( ) ,
self . fingerJointEdge . margin ( ) )
2013-05-14 17:52:33 +02:00
if holesMargin is not None :
self . moveTo ( holesMargin , holesMargin )
if r > holesMargin :
r - = holesMargin
else :
r = 0
self . hexHolesPlate ( x - 2 * holesMargin , y - 2 * holesMargin , r ,
settings = holesSettings )
2013-04-16 04:27:48 +02:00
self . ctx . restore ( )
2013-12-15 20:41:18 +01:00
self . ctx . stroke ( )
2013-07-20 10:49:45 +02:00
self . move ( overallwidth , overallheight , move )
2013-04-16 04:27:48 +02:00
def surroundingWall ( self , x , y , r , h ,
2013-04-16 11:32:13 +02:00
bottom = ' e ' , top = ' e ' ,
2013-07-20 10:49:45 +02:00
callback = None ,
move = None ) :
2013-04-16 04:27:48 +02:00
"""
h : inner height , not counting the joints
callback is called a beginn of the flat sides with
0 for right half of first x side ;
1 and 3 for y sides ;
2 for second x side
2013-05-14 17:52:33 +02:00
4 for second half of the first x side
2013-04-16 04:27:48 +02:00
"""
c4 = ( r + self . burn ) * math . pi * 0.5 # circumference of quarter circle
2013-06-29 13:57:05 +02:00
c4 = 0.9 * c4 # stretch flex 10%
2013-07-20 10:49:45 +02:00
top = self . edges . get ( top , top )
bottom = self . edges . get ( bottom , bottom )
topwidth = top . width ( )
bottomwidth = bottom . width ( )
overallwidth = 2 * x + 2 * y - 8 * r + 4 * c4 + \
self . edges [ " d " ] . spacing ( ) + self . edges [ " D " ] . spacing ( )
overallheight = h + top . spacing ( ) + bottom . spacing ( )
if self . move ( overallwidth , overallheight , move , before = True ) :
return
self . ctx . save ( )
self . moveTo ( self . edges [ " D " ] . margin ( ) , bottom . margin ( ) )
2013-04-16 04:27:48 +02:00
self . cc ( callback , 0 , y = bottomwidth + self . burn )
2013-07-20 10:49:45 +02:00
bottom ( x / 2.0 - r )
2013-04-16 04:27:48 +02:00
for i , l in zip ( range ( 4 ) , ( y , x , y , 0 ) ) :
2013-07-20 10:49:45 +02:00
self . flexEdge ( c4 , h + topwidth + bottomwidth )
2013-04-16 04:27:48 +02:00
self . cc ( callback , i + 1 , y = bottomwidth + self . burn )
if i < 3 :
2013-07-20 10:49:45 +02:00
bottom ( l - 2 * r )
bottom ( x / 2.0 - r )
2013-04-16 04:27:48 +02:00
self . corner ( 90 )
self . edge ( bottomwidth )
self . doveTailJoint ( h )
self . edge ( topwidth )
self . corner ( 90 )
2013-07-20 10:49:45 +02:00
top ( x / 2.0 - r )
2013-04-16 04:27:48 +02:00
for i , l in zip ( range ( 4 ) , ( y , x , y , 0 ) ) :
self . edge ( c4 )
if i < 3 :
2013-07-20 10:49:45 +02:00
top ( l - 2 * r )
top ( x / 2.0 - r )
2013-04-16 04:27:48 +02:00
self . corner ( 90 )
self . edge ( topwidth )
2013-07-20 10:49:45 +02:00
self . doveTailJointCounterPart ( h )
2013-04-16 04:27:48 +02:00
self . edge ( bottomwidth )
self . corner ( 90 )
2013-07-20 10:49:45 +02:00
self . ctx . restore ( )
2013-12-15 20:41:18 +01:00
self . ctx . stroke ( )
2013-07-20 10:49:45 +02:00
self . move ( overallwidth , overallheight , move )
2013-05-14 17:52:33 +02:00
def rectangularWall ( self , x , y , edges = " eeee " ,
2013-06-15 23:26:22 +02:00
holesMargin = None , holesSettings = None ,
2013-07-20 10:49:45 +02:00
bedBolts = None , bedBoltSettings = None ,
2013-07-20 17:54:07 +02:00
callback = None ,
2013-07-20 10:49:45 +02:00
move = None ) :
2013-05-14 17:52:33 +02:00
if len ( edges ) != 4 :
2014-03-03 21:45:01 +01:00
raise ValueError ( " four edges required " )
2013-11-26 22:53:06 +01:00
edges = [ self . edges . get ( e , e ) for e in edges ]
2013-04-16 11:32:13 +02:00
edges + = edges # append for wrapping around
2013-07-20 10:49:45 +02:00
overallwidth = x + edges [ - 1 ] . spacing ( ) + edges [ 1 ] . spacing ( )
overallheight = y + edges [ 0 ] . spacing ( ) + edges [ 2 ] . spacing ( )
if self . move ( overallwidth , overallheight , move , before = True ) :
return
self . ctx . save ( )
self . moveTo ( edges [ - 1 ] . margin ( ) , edges [ 0 ] . margin ( ) )
2013-04-16 11:32:13 +02:00
for i , l in enumerate ( ( x , y , x , y ) ) :
2013-07-20 10:49:45 +02:00
self . edge ( edges [ i - 1 ] . width ( ) )
2013-08-31 20:06:30 +02:00
self . cc ( callback , i , y = edges [ i ] . width ( ) + self . burn )
2013-07-20 10:49:45 +02:00
edges [ i ] ( l ,
bedBolts = self . getEntry ( bedBolts , i ) ,
bedBoltSettings = self . getEntry ( bedBoltSettings , i ) )
self . edge ( edges [ i + 1 ] . width ( ) )
self . corner ( 90 - edges [ i ] . endAngle ( ) - edges [ i + 1 ] . startAngle ( ) )
2013-04-01 22:20:22 +02:00
2013-05-14 17:52:33 +02:00
if holesMargin is not None :
2013-07-20 10:49:45 +02:00
self . moveTo ( holesMargin + edges [ - 1 ] . width ( ) ,
holesMargin + edges [ 0 ] . width ( ) )
2013-05-14 17:52:33 +02:00
self . hexHolesRectangle ( x - 2 * holesMargin , y - 2 * holesMargin )
2013-07-20 10:49:45 +02:00
self . ctx . restore ( )
2013-12-15 20:41:18 +01:00
self . ctx . stroke ( )
2013-07-20 10:49:45 +02:00
self . move ( overallwidth , overallheight , move )
2013-05-14 17:52:33 +02:00
2013-04-01 09:42:29 +02:00
##################################################
### main
##################################################
2016-03-03 13:27:22 +01:00
class DemoBox ( Boxes ) :
2016-03-08 09:33:45 +01:00
""" A simple fully enclosed box showcasing different finger joints """
2016-03-03 13:27:22 +01:00
def __init__ ( self ) :
Boxes . __init__ ( self )
self . buildArgParser ( " x " , " y " , " h " )
def render ( self ) :
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 )
2013-04-01 22:20:22 +02:00
self . ctx . save ( )
2016-03-03 13:27:22 +01:00
self . moveTo ( t , t )
self . rectangularWall ( x , y , " ffff " )
self . moveTo ( x + 4 * t , 0 )
2013-04-16 11:32:13 +02:00
self . rectangularWall ( x , y , " FFFF " )
2013-04-01 22:20:22 +02:00
self . ctx . restore ( )
2013-04-16 04:27:48 +02:00
2016-03-03 13:27:22 +01:00
self . moveTo ( t , y + 4 * t )
2013-04-16 11:32:13 +02:00
for i in range ( 2 ) :
for l in ( x , y ) :
self . rectangularWall ( l , h , " hffF " )
2016-03-04 12:09:59 +01:00
self . moveTo ( l + 4 * t , 0 )
self . moveTo ( - x - y - 8 * t , h + 4 * t )
2013-04-16 11:32:13 +02:00
2014-03-21 21:08:54 +01:00
self . close ( )
2013-04-01 09:42:29 +02:00
if __name__ == ' __main__ ' :
2016-03-03 13:27:22 +01:00
b = DemoBox ( )
b . parseArgs ( )
b . render ( )