updated tabbed box maker

This commit is contained in:
Mario Voigt 2021-10-10 23:27:29 +02:00
parent 61f3a6e67a
commit 74bc089594
2 changed files with 272 additions and 194 deletions

View File

@ -1,88 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Box Maker - Tabbed</name> <name>Box Maker - Tabbed</name>
<id>fablabchemnitz.de.box_maker_tabbed</id> <id>fablabchemnitz.de.box_maker_tabbed</id>
<hbox> <hbox>
<vbox> <vbox>
<label>Dimensions</label> <label>Dimensions</label>
<separator/> <separator />
<param name="unit" gui-text=" Units" type="optiongroup" appearance="combo"> <param name="unit" gui-text=" Units" type="optiongroup" appearance="combo">
<option value="mm">mm</option> <option value="mm">mm</option>
<option value="cm">cm</option> <option value="cm">cm</option>
<option value="in">in</option> <option value="in">in</option>
</param> </param>
<param name="inside" type="optiongroup" gui-text=" Box Dimensions" appearance="combo"> <param name="inside" type="optiongroup" gui-text=" Box Dimensions" appearance="combo">
<option value="1">Inside</option> <option value="1">Inside</option>
<option value="0">Outside</option> <option value="0">Outside</option>
</param> </param>
<param name="length" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Length">180</param> <param name="length" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Length">180</param>
<param name="width" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Width">240</param> <param name="width" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Width">240</param>
<param name="depth" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Height">50</param> <param name="depth" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Height">50</param>
<spacer/> <spacer />
<label>Tabs</label> <label>Tabs</label>
<separator/> <separator />
<param name="equal" type="optiongroup" appearance="combo" gui-text=" Width"> <param name="equal" type="optiongroup" appearance="combo" gui-text=" Width">
<option value="0">Fixed</option> <option value="0">Fixed</option>
<option value="1">Proportional</option> <option value="1">Proportional</option>
</param> </param>
<param name="tab" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Min/Preferred Width">3.0</param> <param name="tab" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Min/Preferred Width">3.0</param>
<param name="tabsymmetry" type="optiongroup" gui-text=" Symmetry" appearance="combo"> <param name="tabtype" type="optiongroup" gui-text=" Type" appearance="combo">
<option value="0">XY Symmetric</option> <option value="0">Regular (Laser)</option>
<option value="1">Rotate Symmetric</option> <option value="1">Dogbone (Mill)</option>
<!--option value="2">Antisymmetric</option--> </param>
</param> <param name="tabsymmetry" type="optiongroup" gui-text=" Symmetry" appearance="combo">
<param name="dimpleheight" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Dimple Height">0.0</param> <option value="0">XY Symmetric</option>
<param name="dimplelength" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Dimple Length">0.0</param> <option value="1">Rotate Symmetric</option>
</vbox> <!--option value="2">Antisymmetric</option-->
<spacer/> </param>
<separator/> <param name="dimpleheight" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Dimple Height">0.0</param>
<spacer/> <param name="dimplelength" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Dimple Length">0.0</param>
<vbox> </vbox>
<label>Line and kerf</label> <spacer />
<separator/> <separator />
<param name="hairline" type="optiongroup" gui-text=" Line Thickness" appearance="combo"> <spacer />
<option value="0">Default</option> <vbox>
<option value="1">Hairline (0.002" for Epilog)</option> <label>Line and kerf</label>
</param> <separator />
<param name="thickness" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Material Thickness">3.0</param> <param name="hairline" type="optiongroup" gui-text=" Line Thickness" appearance="combo">
<param name="kerf" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Kerf (cut width)">0.1</param> <option value="0">Default</option>
<param name="clearance" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Joint clearance">0.01</param> <option value="1">Hairline (0.002" for Epilog)</option>
<spacer/> </param>
<label>Layout</label> <param name="thickness" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Material Thickness">3.0</param>
<separator/> <param name="kerf" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Kerf (cut width)">0.1</param>
<param name="style" gui-text=" Layout" type="optiongroup" appearance="combo"> <param name="clearance" type="float" precision="3" min="0.0" max="10000.0" gui-text=" Joint clearance">0.01</param>
<option value="1">Diagramatic</option> <spacer />
<option value="2">3 piece</option> <label>Layout</label>
<option value="3">Inline(compact)</option> <separator />
</param> <param name="style" gui-text=" Layout" type="optiongroup" appearance="combo">
<param name="boxtype" gui-text=" Box Type" type="optiongroup" appearance="combo"> <option value="1">Diagramatic</option>
<option value="1">Fully enclosed</option> <option value="2">3 piece</option>
<option value="2">One side open (LxW)</option> <option value="3">Inline(compact)</option>
<option value="3">Two sides open (LxW and LxH)</option> </param>
<option value="4">Three sides open (LxW, LxH, HxW)</option> <param name="boxtype" gui-text=" Box Type" type="optiongroup" appearance="combo">
<option value="5">Opposite ends open (LxW)</option> <option value="1">Fully enclosed</option>
<option value="6">Two panels only (LxW and LxH)</option> <option value="2">One side open (LxW)</option>
</param> <option value="3">Two sides open (LxW and LxH)</option>
<param name="div_l" type="int" min="0" max="10" gui-text=" Dividers (Length axis)">2</param> <option value="4">Three sides open (LxW, LxH, HxW)</option>
<param name="div_w" type="int" min="0" max="10" gui-text=" Dividers (Width axis)">3</param> <option value="5">Opposite ends open (LxW)</option>
<param name="keydiv" gui-text=" Key the dividers into" type="optiongroup" appearance="combo"> <option value="6">Two panels only (LxW and LxH)</option>
<option value="3">None</option> </param>
<option value="2">Walls</option> <param name="div_l" type="int" min="0" max="10" gui-text=" Dividers (Length axis)">2</param>
<option value="1">Floor / Ceiling</option> <param name="div_w" type="int" min="0" max="10" gui-text=" Dividers (Width axis)">3</param>
<option value="0">All sides</option> <param name="keydiv" gui-text=" Key the dividers into" type="optiongroup" appearance="combo">
</param> <option value="3">None</option>
<param name="spacing" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Space Between Parts">1.0</param> <option value="2">Walls</option>
</vbox> <option value="1">Floor / Ceiling</option>
</hbox> <option value="0">All sides</option>
<effect needs-live-preview="true"> </param>
<object-type>path</object-type> <param name="spacing" type="float" precision="2" min="0.0" max="10000.0" gui-text=" Space Between Parts">1.0</param>
<effects-menu> </vbox>
<submenu name="FabLab Chemnitz"> </hbox>
<submenu name="Finger-jointed/Tabbed Boxes"/> <effect needs-live-preview="true">
</submenu> <object-type>path</object-type>
</effects-menu> <effects-menu>
</effect> <submenu name="FabLab Chemnitz">
<script> <submenu name="Finger-jointed/Tabbed Boxes" />
<command location="inx" interpreter="python">box_maker_tabbed.py</command> </submenu>
</script> </effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">box_maker_tabbed.py</command>
</script>
</inkscape-extension> </inkscape-extension>

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python3 #! /usr/bin/env python3
''' '''
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 CNC (laser/mill) cut a box with tabbed joints taking kerf and clearance into account
Copyright (C) 2011 elliot white Original Tabbed Box Maker Copyright (C) 2011 elliot white
Changelog: Changelog:
19/12/2014 Paul Hutchison: 19/12/2014 Paul Hutchison:
@ -35,6 +35,16 @@ v0.99 - 2020-06-01 by Paul Hutchison
- Fixed divider issues with Rotate Symmetric - Fixed divider issues with Rotate Symmetric
- Made individual panels and their keyholes/slots grouped - Made individual panels and their keyholes/slots grouped
v1.0 - 2020-06-17 by Paul Hutchison
- Removed clearance parameter, as this was just subtracted from kerf - pointless?
- Corrected kerf adjustments for overall box size and divider keyholes
- Added dogbone cuts: CNC mills now supported!
- Fix for floor/ceiling divider key issue (#17)
- Increased max dividers to 20 (#35)
v1.1 - 2021-08-09 by Paul Hutchison
- Fixed for current Inkscape release version 1.1 - thanks to PR from https://github.com/roastedneutrons
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -48,12 +58,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
''' '''
__version__ = "0.99" ### please report bugs, suggestions etc at https://github.com/paulh-rnd/TabbedBoxMaker ### __version__ = "1.0" ### please report bugs, suggestions etc at https://github.com/paulh-rnd/TabbedBoxMaker ###
import os import os,sys,inkex,simplestyle,gettext,math
import inkex
import math
from copy import deepcopy from copy import deepcopy
_ = gettext.gettext
linethickness = 1 # default unless overridden by settings linethickness = 1 # default unless overridden by settings
@ -72,7 +81,7 @@ def getLine(XYstring):
line = inkex.PathElement() line = inkex.PathElement()
line.style = { 'stroke': '#000000', 'stroke-width' : str(linethickness), 'fill': 'none' } line.style = { 'stroke': '#000000', 'stroke-width' : str(linethickness), 'fill': 'none' }
line.path = XYstring line.path = XYstring
#etree.SubElement(parent, inkex.addNS('path','svg'), drw) #inkex.etree.SubElement(parent, inkex.addNS('path','svg'), drw)
return line return line
# jslee - shamelessly adapted from sample code on below Inkscape wiki page 2015-07-28 # jslee - shamelessly adapted from sample code on below Inkscape wiki page 2015-07-28
@ -82,9 +91,21 @@ def getCircle(r, c):
log("putting circle at (%d,%d)" % (cx,cy)) log("putting circle at (%d,%d)" % (cx,cy))
circle = inkex.PathElement.arc((cx, cy), r) circle = inkex.PathElement.arc((cx, cy), r)
circle.style = { 'stroke': '#000000', 'stroke-width': str(linethickness), 'fill': 'none' } circle.style = { 'stroke': '#000000', 'stroke-width': str(linethickness), '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 )
return circle return circle
def dimpleStr(tabVector,vectorX,vectorY,directionX,directionY,dirxN,diryN,ddir,isTab): def dimpleStr(tabVector,vectorX,vectorY,dirX,dirY,dirxN,diryN,ddir,isTab):
ds='' ds=''
if not isTab: if not isTab:
ddir = -ddir ddir = -ddir
@ -98,14 +119,14 @@ def dimpleStr(tabVector,vectorX,vectorY,directionX,directionY,dirxN,diryN,ddir,i
Vxd=vectorX+dirxN*dimpleStart Vxd=vectorX+dirxN*dimpleStart
Vyd=vectorY+diryN*dimpleStart Vyd=vectorY+diryN*dimpleStart
ds+='L '+str(Vxd)+','+str(Vyd)+' ' ds+='L '+str(Vxd)+','+str(Vyd)+' '
Vxd=Vxd+(tabSgn*dirxN-ddir*directionX)*dimpleHeight Vxd=Vxd+(tabSgn*dirxN-ddir*dirX)*dimpleHeight
Vyd=Vyd+(tabSgn*diryN-ddir*directionY)*dimpleHeight Vyd=Vyd+(tabSgn*diryN-ddir*dirY)*dimpleHeight
ds+='L '+str(Vxd)+','+str(Vyd)+' ' ds+='L '+str(Vxd)+','+str(Vyd)+' '
Vxd=Vxd+tabSgn*dirxN*dimpleLength Vxd=Vxd+tabSgn*dirxN*dimpleLength
Vyd=Vyd+tabSgn*diryN*dimpleLength Vyd=Vyd+tabSgn*diryN*dimpleLength
ds+='L '+str(Vxd)+','+str(Vyd)+' ' ds+='L '+str(Vxd)+','+str(Vyd)+' '
Vxd=Vxd+(tabSgn*dirxN+ddir*directionX)*dimpleHeight Vxd=Vxd+(tabSgn*dirxN+ddir*dirX)*dimpleHeight
Vyd=Vyd+(tabSgn*diryN+ddir*directionY)*dimpleHeight Vyd=Vyd+(tabSgn*diryN+ddir*dirY)*dimpleHeight
ds+='L '+str(Vxd)+','+str(Vyd)+' ' ds+='L '+str(Vxd)+','+str(Vyd)+' '
return ds return ds
@ -113,7 +134,8 @@ def side(group,root,startOffset,endOffset,tabVec,length,direction,isTab,isDivide
rootX, rootY = root rootX, rootY = root
startOffsetX, startOffsetY = startOffset startOffsetX, startOffsetY = startOffset
endOffsetX, endOffsetY = endOffset endOffsetX, endOffsetY = endOffset
directionX, directionY = direction dirX, dirY = direction
notTab=0 if isTab else 1
if (tabSymmetry==1): # waffle-block style rotationally symmetric tabs if (tabSymmetry==1): # waffle-block style rotationally symmetric tabs
divisions=int((length-2*thickness)/nomTab) divisions=int((length-2*thickness)/nomTab)
@ -135,127 +157,172 @@ def side(group,root,startOffset,endOffset,tabVec,length,direction,isTab,isDivide
gapWidth=(length-tabs*nomTab)/(divisions-tabs) gapWidth=(length-tabs*nomTab)/(divisions-tabs)
if isTab: # kerf correction if isTab: # kerf correction
gapWidth-=correction gapWidth-=kerf
tabWidth+=correction tabWidth+=kerf
first=correction/2 first=halfkerf
else: else:
gapWidth+=correction gapWidth+=kerf
tabWidth-=correction tabWidth-=kerf
first=-correction/2 first=-halfkerf
firstholelenX=0
firstholelenY=0
s=[] s=[]
h=[] h=[]
firstVec=0; secondVec=tabVec firstVec=0; secondVec=tabVec
dividerEdgeOffsetX = dividerEdgeOffsetY = thickness dividerEdgeOffsetX = dividerEdgeOffsetY = thickness
dirxN=0 if directionX else 1 # used to select operation on x or y notDirX=0 if dirX else 1 # used to select operation on x or y
diryN=0 if directionY else 1 notDirY=0 if dirY else 1
if (tabSymmetry==1): if (tabSymmetry==1):
dividerEdgeOffsetX = directionX*thickness; dividerEdgeOffsetX = dirX*thickness;
#dividerEdgeOffsetY = ; #dividerEdgeOffsetY = ;
vectorX = rootX + (startOffsetX*thickness if dirxN else 0) vectorX = rootX + (startOffsetX*thickness if notDirX else 0)
vectorY = rootY + (startOffsetY*thickness if diryN else 0) vectorY = rootY + (startOffsetY*thickness if notDirY else 0)
s='M '+str(vectorX)+','+str(vectorY)+' ' s='M '+str(vectorX)+','+str(vectorY)+' '
vectorX = rootX+(startOffsetX if startOffsetX else directionX)*thickness vectorX = rootX+(startOffsetX if startOffsetX else dirX)*thickness
vectorY = rootY+(startOffsetY if startOffsetY else directionY)*thickness vectorY = rootY+(startOffsetY if startOffsetY else dirY)*thickness
if dirxN: endOffsetX=0 if notDirX: endOffsetX=0
if diryN: endOffsetY=0 if notDirY: endOffsetY=0
else: else:
(vectorX,vectorY)=(rootX+startOffsetX*thickness,rootY+startOffsetY*thickness) (vectorX,vectorY)=(rootX+startOffsetX*thickness,rootY+startOffsetY*thickness)
dividerEdgeOffsetX=directionY*thickness dividerEdgeOffsetX=dirY*thickness
dividerEdgeOffsetY=directionX*thickness dividerEdgeOffsetY=dirX*thickness
s='M '+str(vectorX)+','+str(vectorY)+' ' s='M '+str(vectorX)+','+str(vectorY)+' '
if dirxN: vectorY=rootY # set correct line start for tab generation if notDirX: vectorY=rootY # set correct line start for tab generation
if diryN: vectorX=rootX if notDirY: vectorX=rootX
# generate line as tab or hole using: # generate line as tab or hole using:
# last co-ord:Vx,Vy ; tab dir:tabVec ; direction:dirx,diry ; thickness:thickness # last co-ord:Vx,Vy ; tab dir:tabVec ; direction:dirx,diry ; thickness:thickness
# divisions:divs ; gap width:gapWidth ; tab width:tabWidth # divisions:divs ; gap width:gapWidth ; tab width:tabWidth
for n in range(1,int(divisions)): for tabDivision in range(1,int(divisions)):
if ((n%2) ^ (not isTab)) and numDividers>0 and not isDivider: # draw holes for divider joints in side walls if ((tabDivision%2) ^ (not isTab)) and numDividers>0 and not isDivider: # draw holes for divider tabs to key into side walls
w=gapWidth if isTab else tabWidth w=gapWidth if isTab else tabWidth
if n==1 and tabSymmetry==0: if tabDivision==1 and tabSymmetry==0:
w-=startOffsetX*thickness w-=startOffsetX*thickness
for m in range(1,int(numDividers)+1): holeLenX=dirX*w+notDirX*firstVec+first*dirX
Dx=vectorX+-directionY*dividerSpacing*m holeLenY=dirY*w+notDirY*firstVec+first*dirY
Dy=vectorY+directionX*dividerSpacing*m if first:
if n==1 and tabSymmetry==0: firstholelenX=holeLenX
firstholelenY=holeLenY
for dividerNumber in range(1,int(numDividers)+1):
Dx=vectorX+-dirY*dividerSpacing*dividerNumber+notDirX*halfkerf+dirX*dogbone*halfkerf-dogbone*first*dirX
Dy=vectorY+dirX*dividerSpacing*dividerNumber-notDirY*halfkerf+dirY*dogbone*halfkerf-dogbone*first*dirY
if tabDivision==1 and tabSymmetry==0:
Dx+=startOffsetX*thickness Dx+=startOffsetX*thickness
h='M '+str(Dx)+','+str(Dy)+' ' h='M '+str(Dx)+','+str(Dy)+' '
Dx=Dx+directionX*w+dirxN*firstVec+first*directionX Dx=Dx+holeLenX
Dy=Dy+directionY*w+diryN*firstVec+first*directionY Dy=Dy+holeLenY
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx+dirxN*secondVec Dx=Dx+notDirX*(secondVec-kerf)
Dy=Dy+diryN*secondVec Dy=Dy+notDirY*(secondVec+kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx-(directionX*w+dirxN*firstVec+first*directionX) Dx=Dx-holeLenX
Dy=Dy-(directionY*w+diryN*firstVec+first*directionY) Dy=Dy-holeLenY
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx-dirxN*secondVec Dx=Dx-notDirX*(secondVec-kerf)
Dy=Dy-diryN*secondVec Dy=Dy-notDirY*(secondVec+kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
group.add(getLine(h)) group.add(getLine(h))
if n%2: if tabDivision%2:
if n==1 and numDividers>0 and isDivider: # draw slots for dividers to slot into each other if tabDivision==1 and numDividers>0 and isDivider: # draw slots for dividers to slot into each other
for m in range(1,int(numDividers)+1): for dividerNumber in range(1,int(numDividers)+1):
Dx=vectorX+-directionY*dividerSpacing*m-dividerEdgeOffsetX Dx=vectorX+-dirY*dividerSpacing*dividerNumber-dividerEdgeOffsetX+notDirX*halfkerf
Dy=vectorY+directionX*dividerSpacing*m-dividerEdgeOffsetY Dy=vectorY+dirX*dividerSpacing*dividerNumber-dividerEdgeOffsetY+notDirY*halfkerf
h='M '+str(Dx)+','+str(Dy)+' ' h='M '+str(Dx)+','+str(Dy)+' '
Dx=Dx+directionX*(first+length/2) Dx=Dx+dirX*(first+length/2)
Dy=Dy+directionY*(first+length/2) Dy=Dy+dirY*(first+length/2)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx+dirxN*thickness Dx=Dx+notDirX*(thickness-kerf)
Dy=Dy+diryN*thickness Dy=Dy+notDirY*(thickness-kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx-directionX*(first+length/2) Dx=Dx-dirX*(first+length/2)
Dy=Dy-directionY*(first+length/2) Dy=Dy-dirY*(first+length/2)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx-dirxN*thickness Dx=Dx-notDirX*(thickness-kerf)
Dy=Dy-diryN*thickness Dy=Dy-notDirY*(thickness-kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
group.add(getLine(h)) group.add(getLine(h))
# draw the gap # draw the gap
vectorX=vectorX+directionX*gapWidth+dirxN*firstVec+first*directionX vectorX+=dirX*(gapWidth+(isTab&dogbone&1 ^ 0x1)*first+dogbone*kerf*isTab)+notDirX*firstVec
vectorY=vectorY+directionY*gapWidth+diryN*firstVec+first*directionY vectorY+=dirY*(gapWidth+(isTab&dogbone&1 ^ 0x1)*first+dogbone*kerf*isTab)+notDirY*firstVec
s+='L '+str(vectorX)+','+str(vectorY)+' ' s+='L '+str(vectorX)+','+str(vectorY)+' '
if dogbone and isTab:
vectorX-=dirX*halfkerf
vectorY-=dirY*halfkerf
s+='L '+str(vectorX)+','+str(vectorY)+' '
# draw the starting edge of the tab # draw the starting edge of the tab
s+=dimpleStr(secondVec,vectorX,vectorY,directionX,directionY,dirxN,diryN,1,isTab) s+=dimpleStr(secondVec,vectorX,vectorY,dirX,dirY,notDirX,notDirY,1,isTab)
vectorX=vectorX+dirxN*secondVec vectorX+=notDirX*secondVec
vectorY=vectorY+diryN*secondVec vectorY+=notDirY*secondVec
s+='L '+str(vectorX)+','+str(vectorY)+' ' s+='L '+str(vectorX)+','+str(vectorY)+' '
if dogbone and notTab:
vectorX-=dirX*halfkerf
vectorY-=dirY*halfkerf
s+='L '+str(vectorX)+','+str(vectorY)+' '
else: else:
# draw the tab # draw the tab
vectorX=vectorX+directionX*tabWidth+dirxN*firstVec vectorX+=dirX*(tabWidth+dogbone*kerf*notTab)+notDirX*firstVec
vectorY=vectorY+directionY*tabWidth+diryN*firstVec vectorY+=dirY*(tabWidth+dogbone*kerf*notTab)+notDirY*firstVec
s+='L '+str(vectorX)+','+str(vectorY)+' ' s+='L '+str(vectorX)+','+str(vectorY)+' '
if dogbone and notTab:
vectorX-=dirX*halfkerf
vectorY-=dirY*halfkerf
s+='L '+str(vectorX)+','+str(vectorY)+' '
# draw the ending edge of the tab # draw the ending edge of the tab
s+=dimpleStr(secondVec,vectorX,vectorY,directionX,directionY,dirxN,diryN,-1,isTab) s+=dimpleStr(secondVec,vectorX,vectorY,dirX,dirY,notDirX,notDirY,-1,isTab)
vectorX=vectorX+dirxN*secondVec vectorX+=notDirX*secondVec
vectorY=vectorY+diryN*secondVec vectorY+=notDirY*secondVec
s+='L '+str(vectorX)+','+str(vectorY)+' ' s+='L '+str(vectorX)+','+str(vectorY)+' '
if dogbone and isTab:
vectorX-=dirX*halfkerf
vectorY-=dirY*halfkerf
s+='L '+str(vectorX)+','+str(vectorY)+' '
(secondVec,firstVec)=(-secondVec,-firstVec) # swap tab direction (secondVec,firstVec)=(-secondVec,-firstVec) # swap tab direction
first=0 first=0
#finish the line off #finish the line off
s+='L '+str(rootX+endOffsetX*thickness+directionX*length)+','+str(rootY+endOffsetY*thickness+directionY*length)+' ' s+='L '+str(rootX+endOffsetX*thickness+dirX*length)+','+str(rootY+endOffsetY*thickness+dirY*length)+' '
if isTab and numDividers>0 and tabSymmetry==0 and not isDivider: # draw last for divider joints in side walls if isTab and numDividers>0 and tabSymmetry==0 and not isDivider: # draw last for divider joints in side walls
for m in range(1,int(numDividers)+1): for dividerNumber in range(1,int(numDividers)+1):
Dx=vectorX Dx=vectorX+-dirY*dividerSpacing*dividerNumber+notDirX*halfkerf+dirX*dogbone*halfkerf-dogbone*first*dirX
Dy=vectorY+directionX*dividerSpacing*m # Dy=vectorY+dirX*dividerSpacing*dividerNumber-notDirY*halfkerf+dirY*dogbone*halfkerf-dogbone*first*dirY
# Dx=vectorX+-dirY*dividerSpacing*dividerNumber-dividerEdgeOffsetX+notDirX*halfkerf
Dy=vectorY+dirX*dividerSpacing*dividerNumber-dividerEdgeOffsetY+notDirY*halfkerf
h='M '+str(Dx)+','+str(Dy)+' ' h='M '+str(Dx)+','+str(Dy)+' '
Dx=rootX+endOffsetX*thickness+directionX*length Dx=Dx+firstholelenX
Dy=Dy+directionY*tabWidth+diryN*firstVec+first*directionY Dy=Dy+firstholelenY
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx+dirxN*secondVec Dx=Dx+notDirX*(thickness-kerf)
Dy=Dy+diryN*secondVec Dy=Dy+notDirY*(thickness-kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=vectorX Dx=Dx-firstholelenX
Dy=Dy-(directionY*tabWidth+diryN*firstVec+first*directionY) Dy=Dy-firstholelenY
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
Dx=Dx-dirxN*secondVec Dx=Dx-notDirX*(thickness-kerf)
Dy=Dy-diryN*secondVec Dy=Dy-notDirY*(thickness-kerf)
h+='L '+str(Dx)+','+str(Dy)+' ' h+='L '+str(Dx)+','+str(Dy)+' '
group.add(getLine(h)) group.add(getLine(h))
# for dividerNumber in range(1,int(numDividers)+1):
# Dx=vectorX+-dirY*dividerSpacing*dividerNumber+notDirX*halfkerf+dirX*dogbone*halfkerf
# Dy=vectorY+dirX*dividerSpacing*dividerNumber-notDirY*halfkerf+dirY*dogbone*halfkerf
# # Dx=vectorX+dirX*dogbone*halfkerf
# # Dy=vectorY+dirX*dividerSpacing*dividerNumber-dirX*halfkerf+dirY*dogbone*halfkerf
# h='M '+str(Dx)+','+str(Dy)+' '
# Dx=rootX+endOffsetX*thickness+dirX*length
# Dy+=dirY*tabWidth+notDirY*firstVec+first*dirY
# h+='L '+str(Dx)+','+str(Dy)+' '
# Dx+=notDirX*(secondVec-kerf)
# Dy+=notDirY*(secondVec+kerf)
# h+='L '+str(Dx)+','+str(Dy)+' '
# Dx-=vectorX
# Dy-=(dirY*tabWidth+notDirY*firstVec+first*dirY)
# h+='L '+str(Dx)+','+str(Dy)+' '
# Dx-=notDirX*(secondVec-kerf)
# Dy-=notDirY*(secondVec+kerf)
# h+='L '+str(Dx)+','+str(Dy)+' '
# group.add(getLine(h))
group.add(getLine(s)) group.add(getLine(s))
return s return s
@ -276,6 +343,7 @@ class BoxMaker(inkex.EffectExtension):
pars.add_argument('--width',type=float,default=100,help='Width of Box') pars.add_argument('--width',type=float,default=100,help='Width of Box')
pars.add_argument('--depth',type=float,default=100,help='Height of Box') pars.add_argument('--depth',type=float,default=100,help='Height of Box')
pars.add_argument('--tab',type=float,default=25,help='Nominal Tab Width') pars.add_argument('--tab',type=float,default=25,help='Nominal Tab Width')
pars.add_argument('--tabtype',type=int,default=0,help='Tab type: regular or dogbone')
pars.add_argument('--equal',type=int,default=0,help='Equal/Prop Tabs') pars.add_argument('--equal',type=int,default=0,help='Equal/Prop Tabs')
pars.add_argument('--tabsymmetry',type=int,default=0,help='Tab style') pars.add_argument('--tabsymmetry',type=int,default=0,help='Tab style')
pars.add_argument('--dimpleheight',type=float,default=0,help='Tab Dimple Height') pars.add_argument('--dimpleheight',type=float,default=0,help='Tab Dimple Height')
@ -292,7 +360,7 @@ class BoxMaker(inkex.EffectExtension):
pars.add_argument('--keydiv',type=int,default=3,help='Key dividers into walls/floor') pars.add_argument('--keydiv',type=int,default=3,help='Key dividers into walls/floor')
def effect(self): def effect(self):
global group,nomTab,equalTabs,tabSymmetry,dimpleHeight,dimpleLength,thickness,correction,divx,divy,hairline,linethickness,keydivwalls,keydivfloor global group,nomTab,equalTabs,tabSymmetry,dimpleHeight,dimpleLength,thickness,kerf,halfkerf,dogbone,divx,divy,hairline,linethickness,keydivwalls,keydivfloor
# Get access to main SVG document element and get its dimensions. # Get access to main SVG document element and get its dimensions.
svg = self.document.getroot() svg = self.document.getroot()
@ -306,6 +374,8 @@ class BoxMaker(inkex.EffectExtension):
unit=self.options.unit unit=self.options.unit
inside=self.options.inside inside=self.options.inside
schroff=self.options.schroff schroff=self.options.schroff
kerf = self.svg.unittouu( str(self.options.kerf) + unit )
halfkerf=kerf/2
# Set the line thickness # Set the line thickness
if hairline: if hairline:
@ -335,18 +405,17 @@ class BoxMaker(inkex.EffectExtension):
Y = row_height + row_spacing_total Y = row_height + row_spacing_total
else: else:
## boxmaker.inx ## boxmaker.inx
X = self.svg.unittouu( str(self.options.length) + unit ) X = self.svg.unittouu( str(self.options.length + kerf) + unit )
Y = self.svg.unittouu( str(self.options.width) + unit ) Y = self.svg.unittouu( str(self.options.width + kerf) + unit )
Z = self.svg.unittouu( str(self.options.rail_height) + unit ) Z = self.svg.unittouu( str(self.options.depth + kerf) + unit )
thickness = self.svg.unittouu( str(self.options.thickness) + unit ) thickness = self.svg.unittouu( str(self.options.thickness) + unit )
nomTab = self.svg.unittouu( str(self.options.tab) + unit ) nomTab = self.svg.unittouu( str(self.options.tab) + unit )
equalTabs=self.options.equal equalTabs=self.options.equal
tabSymmetry=self.options.tabsymmetry tabSymmetry=self.options.tabsymmetry
dimpleHeight=self.options.dimpleheight dimpleHeight=self.options.dimpleheight
dimpleLength=self.options.dimplelength dimpleLength=self.options.dimplelength
kerf = self.svg.unittouu( str(self.options.kerf) + unit ) dogbone = 1 if self.options.tabtype == 1 else 0
clearance = self.svg.unittouu( str(self.options.clearance) + unit )
layout=self.options.style layout=self.options.style
spacing = self.svg.unittouu( str(self.options.spacing) + unit ) spacing = self.svg.unittouu( str(self.options.spacing) + unit )
boxtype = self.options.boxtype boxtype = self.options.boxtype
@ -354,45 +423,45 @@ class BoxMaker(inkex.EffectExtension):
divy = self.options.div_w divy = self.options.div_w
keydivwalls = 0 if self.options.keydiv == 3 or self.options.keydiv == 1 else 1 keydivwalls = 0 if self.options.keydiv == 3 or self.options.keydiv == 1 else 1
keydivfloor = 0 if self.options.keydiv == 3 or self.options.keydiv == 2 else 1 keydivfloor = 0 if self.options.keydiv == 3 or self.options.keydiv == 2 else 1
initOffsetX=0
initOffsetY=0
if inside: # if inside dimension selected correct values to outside dimension if inside: # if inside dimension selected correct values to outside dimension
X+=thickness*2 X+=thickness*2
Y+=thickness*2 Y+=thickness*2
Z+=thickness*2 Z+=thickness*2
correction=kerf-clearance
# check input values mainly to avoid python errors # check input values mainly to avoid python errors
# TODO restrict values to *correct* solutions # TODO restrict values to *correct* solutions
# TODO restrict divisions to logical values # TODO restrict divisions to logical values
error=0 error=0
if min(X,Y,Z)==0: if min(X,Y,Z)==0:
inkex.errormsg('Error: Dimensions must be non zero') inkex.errormsg(_('Error: Dimensions must be non zero'))
error=1 error=1
if max(X,Y,Z)>max(widthDoc,heightDoc)*10: # crude test if max(X,Y,Z)>max(widthDoc,heightDoc)*10: # crude test
inkex.errormsg('Error: Dimensions Too Large') inkex.errormsg(_('Error: Dimensions Too Large'))
error=1 error=1
if min(X,Y,Z)<3*nomTab: if min(X,Y,Z)<3*nomTab:
inkex.errormsg('Error: Tab size too large') inkex.errormsg(_('Error: Tab size too large'))
error=1 error=1
if nomTab<thickness: if nomTab<thickness:
inkex.errormsg('Error: Tab size too small') inkex.errormsg(_('Error: Tab size too small'))
error=1 error=1
if thickness==0: if thickness==0:
inkex.errormsg('Error: Thickness is zero') inkex.errormsg(_('Error: Thickness is zero'))
error=1 error=1
if thickness>min(X,Y,Z)/3: # crude test if thickness>min(X,Y,Z)/3: # crude test
inkex.errormsg('Error: Material too thick') inkex.errormsg(_('Error: Material too thick'))
error=1 error=1
if correction>min(X,Y,Z)/3: # crude test if kerf>min(X,Y,Z)/3: # crude test
inkex.errormsg('Error: Kerf/Clearence too large') inkex.errormsg(_('Error: Kerf too large'))
error=1 error=1
if spacing>max(X,Y,Z)*10: # crude test if spacing>max(X,Y,Z)*10: # crude test
inkex.errormsg('Error: Spacing too large') inkex.errormsg(_('Error: Spacing too large'))
error=1 error=1
if spacing<kerf: if spacing<kerf:
inkex.errormsg('Error: Spacing too small') inkex.errormsg(_('Error: Spacing too small'))
error=1 error=1
if error: exit() if error: exit()
@ -552,8 +621,8 @@ class BoxMaker(inkex.EffectExtension):
for idx, piece in enumerate(pieces): # generate and draw each piece of the box for idx, piece in enumerate(pieces): # generate and draw each piece of the box
(xs,xx,xy,xz)=piece[0] (xs,xx,xy,xz)=piece[0]
(ys,yx,yy,yz)=piece[1] (ys,yx,yy,yz)=piece[1]
x=xs*spacing+xx*X+xy*Y+xz*Z # root x co-ord for piece x=xs*spacing+xx*X+xy*Y+xz*Z+initOffsetX # root x co-ord for piece
y=ys*spacing+yx*X+yy*Y+yz*Z # root y co-ord for piece y=ys*spacing+yx*X+yy*Y+yz*Z+initOffsetY # root y co-ord for piece
dx=piece[2] dx=piece[2]
dy=piece[3] dy=piece[3]
tabs=piece[4] tabs=piece[4]
@ -613,15 +682,20 @@ class BoxMaker(inkex.EffectExtension):
side(group,(x,y+dy),(d,-c),(d,a),dtabs * (-thickness if d else thickness),dy,(0,-1),d,0,(keydivfloor|wall) * (keydivwalls|floor) * divy*xholes*dtabs,xspacing) # side d side(group,(x,y+dy),(d,-c),(d,a),dtabs * (-thickness if d else thickness),dy,(0,-1),d,0,(keydivfloor|wall) * (keydivwalls|floor) * divy*xholes*dtabs,xspacing) # side d
if idx==0: if idx==0:
# remove tabs from dividers if not required
if not keydivfloor:
a=c=1
atabs=ctabs=0
if not keydivwalls: if not keydivwalls:
a=b=c=d=1 b=d=1
atabs=btabs=ctabs=dtabs=0 btabs=dtabs=0
y=4*spacing+1*Y+2*Z # root y co-ord for piece y=4*spacing+1*Y+2*Z # root y co-ord for piece
for n in range(0,divx): # generate X dividers for n in range(0,divx): # generate X dividers
group = newGroup(self) group = newGroup(self)
x=n*(spacing+X) # root x co-ord for piece x=n*(spacing+X) # root x co-ord for piece
side(group,(x,y),(d,a),(-b,a),keydivfloor*atabs*(-thickness if a else thickness),dx,(1,0),a,1,0,0) # side a side(group,(x,y),(d,a),(-b,a),keydivfloor*atabs*(-thickness if a else thickness),dx,(1,0),a,1,0,0) # side a
side(group,(x+dx,y),(-b,a),(-b,-c),keydivwalls*btabs*(thickness if keydivwalls*b else -thickness),dy,(0,1),b,1,divy*xholes,xspacing) # side b side(group,(x+dx,y),(-b,a),(-b,-c),keydivwalls*btabs*(thickness if b else -thickness),dy,(0,1),b,1,divy*xholes,xspacing) # side b
side(group,(x+dx,y+dy),(-b,-c),(d,-c),keydivfloor*ctabs*(thickness if c else -thickness),dx,(-1,0),c,1,0,0) # side c side(group,(x+dx,y+dy),(-b,-c),(d,-c),keydivfloor*ctabs*(thickness if c else -thickness),dx,(-1,0),c,1,0,0) # side c
side(group,(x,y+dy),(d,-c),(d,a),keydivwalls*dtabs*(-thickness if d else thickness),dy,(0,-1),d,1,0,0) # side d side(group,(x,y+dy),(d,-c),(d,a),keydivwalls*dtabs*(-thickness if d else thickness),dy,(0,-1),d,1,0,0) # side d
elif idx==1: elif idx==1:
@ -634,5 +708,5 @@ class BoxMaker(inkex.EffectExtension):
side(group,(x+dx,y+dy),(-b,-c),(d,-c),keydivwalls*ctabs*(thickness if c else -thickness),dx,(-1,0),c,1,0,0) # side c side(group,(x+dx,y+dy),(-b,-c),(d,-c),keydivwalls*ctabs*(thickness if c else -thickness),dx,(-1,0),c,1,0,0) # side c
side(group,(x,y+dy),(d,-c),(d,a),keydivfloor*dtabs*(-thickness if d else thickness),dy,(0,-1),d,1,0,0) # side d side(group,(x,y+dy),(d,-c),(d,a),keydivfloor*dtabs*(-thickness if d else thickness),dy,(0,-1),d,1,0,0) # side d
if __name__ == '__main__': # Create effect instance and apply it.
BoxMaker().run() BoxMaker().run()