Commit f77cdfe1 authored by John Slee's avatar John Slee

first spin of Schroff enclosure generator

parent d08f310f
......@@ -6,6 +6,7 @@ Original box maker by Elliot White - http://www.keppel.demon.co.uk/111000/111000
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 July 2015 by John Slee - Added Schroff enclosure generator option. Currently 3U rows only.
## 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.
......@@ -22,8 +23,11 @@ This version has been tried on windows XP, windows 7, Ubuntu and Mac OS X with n
## To do
* 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.
* [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 ).
In order of appearance:
......@@ -75,8 +79,20 @@ In order of appearance:
* 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
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 `
......
#! /usr/bin/env python
#! /usr/bin/env python -t
'''
Generates Inkscape SVG file containing box components needed to
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/>.
'''
__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
def log(text):
if 1:
f = open('/tmp/boxmaker.log', 'a')
f.write(text + "\n")
def drawS(XYstring): # Draw lines from a list
name='part'
style = { 'stroke': '#000000', 'fill': 'none' }
......@@ -41,6 +46,23 @@ def drawS(XYstring): # Draw lines from a list
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), drw )
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):
# root startOffset endOffset tabVec length direction isTab isDivider numDividers divSpacing
......@@ -166,6 +188,20 @@ class BoxMaker(inkex.Effect):
# Call the base class constructor.
inkex.Effect.__init__(self)
# 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',
dest='unit',default='mm',help='Measure Units')
self.OptionParser.add_option('--inside',action='store',type='int',
......@@ -217,8 +253,33 @@ class BoxMaker(inkex.Effect):
# Get script's option values.
unit=self.options.unit
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 )
Y = self.unittouu( str(self.options.width) + unit )
Z = self.unittouu( str(self.options.height) + unit )
thickness = self.unittouu( str(self.options.thickness) + unit )
nomTab = self.unittouu( str(self.options.tab) + unit )
......@@ -362,6 +423,38 @@ class BoxMaker(inkex.Effect):
yspacing=(Y-thickness)/(divx+1)
xholes = 1 if piece[6]<3 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
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
......@@ -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+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
# Create effect instance and apply it.
effect = BoxMaker()
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