Commit 1c168f95 authored by John Slee's avatar John Slee Committed by GitHub

Merge pull request #1 from paulh-rnd/master

resync from paulh-rnd
parents d08f310f 9ee07d73
# BoxMaker: A free tool for creating boxes using tabbed construction # BoxMaker: A free tool for creating boxes using tabbed construction
_version 0.87 - 23 June 2015_ _version 0.93 - 21 Sept 2015_
Original box maker by Elliot White - http://www.keppel.demon.co.uk/111000/111000.html Original box maker by Elliot White - http://www.twot.eu/111000/111000.html
Updated Dec 2014 by Paul Hutchison - additional box options for 2,3,4,5 sides and internal dividers Updated Dec 2014 by Paul Hutchison - additional box options for 2,3,4,5 sides and internal dividers
Updated June 2015 by Paul Hutchison - Inkscape 0.91 compatibility, more logical defaults Updated June 2015 by Paul Hutchison - Inkscape 0.91 compatibility, more logical defaults
Updated July 2015 by John Slee - Added Schroff enclosure generator option. Currently 3U rows only.
Updated Sept 2015 by Paul Hutchison - Elliot White got in touch to provide updated contact details
## About ## About
This tool is designed to simplify and speed up process of making practical boxes using a laser cutter (though it can be used with any CNC cutter) to prepare the pieces. This tool is designed to simplify and speed up process of making practical boxes using a laser cutter (though it can be used with any CNC cutter) to prepare the pieces.
...@@ -22,8 +27,11 @@ This version has been tried on windows XP, windows 7, Ubuntu and Mac OS X with n ...@@ -22,8 +27,11 @@ This version has been tried on windows XP, windows 7, Ubuntu and Mac OS X with n
## To do ## To do
* Tidy the code - it is rough and unpythonic. Needs some work by a master Python guru. * Tidy the code - it is rough and unpythonic. Needs some work by a master Python guru.
* Improve program documentation. Improve input checking to restrict values to correct solutions. * Improve program documentation. Improve input checking to restrict values to correct solutions.
* [Schroff] Maybe replace the somewhat obscure collection of Schroff rail input data with a dropdown box listing well-documented rail types (Vector, Z-rails, whatever it is that Elby sells, others?)
* [Schroff] Add support for multiple mounting holes per rail where possible (this would definitely make the previous todo item worthwhile)
* [Schroff] Add support for 6U row height
## Use ## Use - regular tabbed boxes
The interface is pretty self explanatory, the extension is 'Tabbed Box Maker' in the 'Laser Tools' group ( hopefully more tools will soon{ish} join it ). The interface is pretty self explanatory, the extension is 'Tabbed Box Maker' in the 'Laser Tools' group ( hopefully more tools will soon{ish} join it ).
In order of appearance: In order of appearance:
...@@ -75,8 +83,20 @@ In order of appearance: ...@@ -75,8 +83,20 @@ In order of appearance:
* Space Between Parts - how far apart the pieces are in the drawing produced * Space Between Parts - how far apart the pieces are in the drawing produced
## Use - Schroff enclosures
Much the same as for regular enclosures, except some options are removed, and some others are added. If you're using Elby rails, all you'll need to do is specify:
* Depth
* Number of 3U rows
* Row width in TE/HP units (divide rail length by 5.08mm/0.2")
* If multiple rows, inter-row spacing
## Installation ## Installation
Boxmaker.inx and Boxmaker.py need to be put in the inkscape extensions folder generally in: Boxmaker.inx, Schroffmaker.inx and Boxmaker.py need to be put in the inkscape extensions folder generally in:
`...\Inkscape\share\extensions ` `...\Inkscape\share\extensions `
...@@ -93,3 +113,6 @@ version | Date | Notes ...@@ -93,3 +113,6 @@ version | Date | Notes
0.7 | (24 Oct 2011) | first release 0.7 | (24 Oct 2011) | first release
0.8 | (26 Oct 2011) | basic input checking implemented 0.8 | (26 Oct 2011) | basic input checking implemented
0.86 | (19 Dec 2014) | updates to allow different box types and internal dividers 0.86 | (19 Dec 2014) | updates to allow different box types and internal dividers
0.86a | (23 June 2015) | Updated for compatibility with Inkscape 0.91
0.87 | (28 July 2015) | Schroff enclosure add-on
0.93 | (21 Sept 2015) | Updated versioning to match original author's updated v0.91 plus adding my 0.02
#! /usr/bin/env python #! /usr/bin/env python -t
''' '''
Generates Inkscape SVG file containing box components needed to Generates Inkscape SVG file containing box components needed to
laser cut a tabbed construction box taking kerf and clearance into account laser cut a tabbed construction box taking kerf and clearance into account
...@@ -31,9 +31,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -31,9 +31,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
''' '''
__version__ = "0.86" ### please report bugs, suggestions etc to bugs@twot.eu ### __version__ = "0.86" ### please report bugs, suggestions etc to bugs@twot.eu ###
import sys,inkex,simplestyle,gettext import sys,inkex,simplestyle,gettext,math
_ = gettext.gettext _ = gettext.gettext
def log(text):
if 1:
f = open('/tmp/boxmaker.log', 'a')
f.write(text + "\n")
def drawS(XYstring): # Draw lines from a list def drawS(XYstring): # Draw lines from a list
name='part' name='part'
style = { 'stroke': '#000000', 'fill': 'none' } style = { 'stroke': '#000000', 'fill': 'none' }
...@@ -41,6 +46,23 @@ def drawS(XYstring): # Draw lines from a list ...@@ -41,6 +46,23 @@ def drawS(XYstring): # Draw lines from a list
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), drw ) inkex.etree.SubElement(parent, inkex.addNS('path','svg'), drw )
return return
# jslee - shamelessly adapted from sample code on below Inkscape wiki page 2015-07-28
# http://wiki.inkscape.org/wiki/index.php/Generating_objects_from_extensions
def drawCircle(r, (cx, cy)):
log("putting circle at (%d,%d)" % (cx,cy))
style = { 'stroke': '#000000', 'stroke-width': '1', 'fill': 'none' }
ell_attribs = {'style':simplestyle.formatStyle(style),
inkex.addNS('cx','sodipodi') :str(cx),
inkex.addNS('cy','sodipodi') :str(cy),
inkex.addNS('rx','sodipodi') :str(r),
inkex.addNS('ry','sodipodi') :str(r),
inkex.addNS('start','sodipodi') :str(0),
inkex.addNS('end','sodipodi') :str(2*math.pi),
inkex.addNS('open','sodipodi') :'true', #all ellipse sectors we will draw are open
inkex.addNS('type','sodipodi') :'arc',
'transform' :'' }
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), ell_attribs )
def side((rx,ry),(sox,soy),(eox,eoy),tabVec,length,(dirx,diry),isTab,isDivider,numDividers,divSpacing): def side((rx,ry),(sox,soy),(eox,eoy),tabVec,length,(dirx,diry),isTab,isDivider,numDividers,divSpacing):
# root startOffset endOffset tabVec length direction isTab isDivider numDividers divSpacing # root startOffset endOffset tabVec length direction isTab isDivider numDividers divSpacing
...@@ -166,6 +188,20 @@ class BoxMaker(inkex.Effect): ...@@ -166,6 +188,20 @@ class BoxMaker(inkex.Effect):
# Call the base class constructor. # Call the base class constructor.
inkex.Effect.__init__(self) inkex.Effect.__init__(self)
# Define options # Define options
self.OptionParser.add_option('--schroff',action='store',type='int',
dest='schroff',default=0,help='Enable Schroff mode')
self.OptionParser.add_option('--rail_height',action='store',type='float',
dest='rail_height',default=10.0,help='Height of rail')
self.OptionParser.add_option('--rail_mount_depth',action='store',type='float',
dest='rail_mount_depth',default=17.4,help='Depth at which to place hole for rail mount bolt')
self.OptionParser.add_option('--rail_mount_centre_offset',action='store',type='float',
dest='rail_mount_centre_offset',default=0.0,help='How far toward row centreline to offset rail mount bolt (from rail centreline)')
self.OptionParser.add_option('--rows',action='store',type='int',
dest='rows',default=0,help='Number of Schroff rows')
self.OptionParser.add_option('--hp',action='store',type='int',
dest='hp',default=0,help='Width (TE/HP units) of Schroff rows')
self.OptionParser.add_option('--row_spacing',action='store',type='float',
dest='row_spacing',default=10.0,help='Height of rail')
self.OptionParser.add_option('--unit',action='store',type='string', self.OptionParser.add_option('--unit',action='store',type='string',
dest='unit',default='mm',help='Measure Units') dest='unit',default='mm',help='Measure Units')
self.OptionParser.add_option('--inside',action='store',type='int', self.OptionParser.add_option('--inside',action='store',type='int',
...@@ -217,8 +253,33 @@ class BoxMaker(inkex.Effect): ...@@ -217,8 +253,33 @@ class BoxMaker(inkex.Effect):
# Get script's option values. # Get script's option values.
unit=self.options.unit unit=self.options.unit
inside=self.options.inside inside=self.options.inside
schroff=self.options.schroff
if schroff:
hp=self.options.hp
rows=self.options.rows
rail_height=self.unittouu(str(self.options.rail_height)+unit)
row_centre_spacing=self.unittouu(str(122.5)+unit)
row_spacing=self.unittouu(str(self.options.row_spacing)+unit)
rail_mount_depth=self.unittouu(str(self.options.rail_mount_depth)+unit)
rail_mount_centre_offset=self.unittouu(str(self.options.rail_mount_centre_offset)+unit)
rail_mount_radius=self.unittouu(str(2.5)+unit)
## minimally different behaviour for schroffmaker.inx vs. boxmaker.inx
## essentially schroffmaker.inx is just an alternate interface with different
## default settings, some options removed, and a tiny amount of extra logic
if schroff:
## schroffmaker.inx
X = self.unittouu(str(self.options.hp * 5.08) + unit)
# 122.5mm vertical distance between mounting hole centres of 3U Schroff panels
row_height = rows * (row_centre_spacing + rail_height)
# rail spacing in between rows but never between rows and case panels
row_spacing_total = (rows - 1) * row_spacing
Y = row_height + row_spacing_total
else:
## boxmaker.inx
X = self.unittouu( str(self.options.length) + unit ) X = self.unittouu( str(self.options.length) + unit )
Y = self.unittouu( str(self.options.width) + unit ) Y = self.unittouu( str(self.options.width) + unit )
Z = self.unittouu( str(self.options.height) + unit ) Z = self.unittouu( str(self.options.height) + unit )
thickness = self.unittouu( str(self.options.thickness) + unit ) thickness = self.unittouu( str(self.options.thickness) + unit )
nomTab = self.unittouu( str(self.options.tab) + unit ) nomTab = self.unittouu( str(self.options.tab) + unit )
...@@ -362,6 +423,38 @@ class BoxMaker(inkex.Effect): ...@@ -362,6 +423,38 @@ class BoxMaker(inkex.Effect):
yspacing=(Y-thickness)/(divx+1) yspacing=(Y-thickness)/(divx+1)
xholes = 1 if piece[6]<3 else 0 xholes = 1 if piece[6]<3 else 0
yholes = 1 if piece[6]!=2 else 0 yholes = 1 if piece[6]!=2 else 0
railholes = 1 if piece[6]==3 else 0
if schroff and railholes:
log("rail holes enabled on piece %d at (%d, %d)" % (idx, x+thickness,y+thickness))
log("abcd = (%d,%d,%d,%d)" % (a,b,c,d))
log("dxdy = (%d,%d)" % (dx,dy))
rhxoffset = rail_mount_depth + thickness
if idx == 1:
rhx=x+rhxoffset
elif idx == 3:
rhx=x-rhxoffset+dx
else:
rhx=0
log("rhxoffset = %d, rhx= %d" % (rhxoffset, rhx))
rystart=y+(rail_height/2)+thickness
if rows == 1:
log("just one row this time, rystart = %d" % rystart)
rh1y=rystart+rail_mount_centre_offset
rh2y=rh1y+(row_centre_spacing-rail_mount_centre_offset)
drawCircle(rail_mount_radius,(rhx,rh1y))
drawCircle(rail_mount_radius,(rhx,rh2y))
else:
for n in range(0,rows):
log("drawing row %d, rystart = %d" % (n+1, rystart))
# if holes are offset (eg. Vector T-strut rails), they should be offset
# toward each other, ie. toward the centreline of the Schroff row
rh1y=rystart+rail_mount_centre_offset
rh2y=rh1y+row_centre_spacing-rail_mount_centre_offset
drawCircle(rail_mount_radius,(rhx,rh1y))
drawCircle(rail_mount_radius,(rhx,rh2y))
rystart+=row_centre_spacing+row_spacing+rail_height
# generate and draw the sides of each piece # generate and draw the sides of each piece
drawS(side((x,y),(d,a),(-b,a),atabs * (-thickness if a else thickness),dx,(1,0),a,0,divx*yholes*atabs,yspacing)) # side a drawS(side((x,y),(d,a),(-b,a),atabs * (-thickness if a else thickness),dx,(1,0),a,0,divx*yholes*atabs,yspacing)) # side a
drawS(side((x+dx,y),(-b,a),(-b,-c),btabs * (thickness if b else -thickness),dy,(0,1),b,0,divy*xholes*btabs,xspacing)) # side b drawS(side((x+dx,y),(-b,a),(-b,-c),btabs * (thickness if b else -thickness),dy,(0,1),b,0,divy*xholes*btabs,xspacing)) # side b
...@@ -390,6 +483,7 @@ class BoxMaker(inkex.Effect): ...@@ -390,6 +483,7 @@ class BoxMaker(inkex.Effect):
drawS(side((x+dx,y),(-b,a),(-b,-c),btabs * (thickness if b else -thickness),dy,(0,1),b,1,0,0)) # side b drawS(side((x+dx,y),(-b,a),(-b,-c),btabs * (thickness if b else -thickness),dy,(0,1),b,1,0,0)) # side b
drawS(side((x+dx,y+dy),(-b,-c),(d,-c),ctabs * (thickness if c else -thickness),dx,(-1,0),c,1,0,0)) # side c drawS(side((x+dx,y+dy),(-b,-c),(d,-c),ctabs * (thickness if c else -thickness),dx,(-1,0),c,1,0,0)) # side c
drawS(side((x,y+dy),(d,-c),(d,a),dtabs * (-thickness if d else thickness),dy,(0,-1),d,1,0,0)) # side d drawS(side((x,y+dy),(d,-c),(d,a),dtabs * (-thickness if d else thickness),dy,(0,-1),d,1,0,0)) # side d
# Create effect instance and apply it. # Create effect instance and apply it.
effect = BoxMaker() effect = BoxMaker()
effect.affect() effect.affect()
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<_name>Schroff Box Maker</_name>
<id>eu.twot.render.schroffboxmaker</id>
<dependency type="executable" location="extensions">boxmaker.py</dependency>
<dependency type="executable" location="extensions">simpletransform.py</dependency>
<dependency type="executable" location="extensions">inkex.py</dependency>
<param name="unit" type="string" gui-hidden="true">mm</param>
<param name="inside" type="string" gui-hidden="true">1</param>
<param name="schroff" type="int" gui-hidden="true">1</param>
<param name="rows" type="int" min="1" max="6" _gui-text="Number of 3U rows:">1</param>
<param name="hp" type="int" min="4" max="168" _gui-text="Width (TE/HP units):">84</param>
<param name="length" type="float" precision="3" gui-hidden="true">0.0</param>
<param name="width" type="float" precision="3" gui-hidden="true">0.0</param>
<param name="depth" type="float" precision="3" min="30" max="300" _gui-text="Depth:">65</param>
<!-- these defaults are suitable for the rails sold by Elby Designs -->
<param name="rail_height" type="float" precision="3" min="7.0" max="10.0" _gui-text="Rail height:">10.0</param>
<param name="rail_mount_depth" type="float" precision="3" min="5" max="30" _gui-text="Rail mounting hole depth:">17.4</param>
<param name="rail_mount_centre_offset" type="float" precision="3" min="0.0" max="5.0" _gui-text="Rail mount hole centre-offset:">0.0</param>
<param name="row_spacing" type="float" precision="3" min="0.0" max="50.0" _gui-text="Spacing between rows:">0.0</param>
<param name="tab" type="float" precision="2" min="0.0" max="10000.0" _gui-text="Minimum/Prefered Tab Width">6.0</param>
<param name="equal" type="optiongroup" _gui-text="Tab Width">
<_option value="0">Fixed</_option>
<_option value="1">Proportional</_option>
</param>
<param name="thickness" type="float" precision="2" min="0.0" max="10000.0" _gui-text="Material Thickness">3.0</param>
<param name="kerf" type="float" precision="3" min="0.0" max="10000.0" _gui-text="Kerf (cut width)">0.1</param>
<param name="clearance" type="float" precision="3" min="0.0" max="10000.0" _gui-text="Joint clearance">0.01</param>
<param name="div_l" type="int" gui-hidden="true">0</param>
<param name="div_w" type="int" gui-hidden="true">0</param>
<param name="style" type="string" gui-hidden="true">1</param>
<param name="boxtype" type="int" gui-hidden="true">2</param>
<param name="spacing" type="float" precision="2" min="0.0" max="10000.0" _gui-text="Space Between Parts">1.0</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu _name="Laser Tools" />
</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">boxmaker.py</command>
</script>
</inkscape-extension>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment