200 lines
12 KiB
Python
200 lines
12 KiB
Python
|
#! /usr/bin/env python
|
||
|
'''
|
||
|
Generates Inkscape SVG file containing box components needed to
|
||
|
laser cut a tabbed construction box taking kerf into account
|
||
|
|
||
|
Copyright (C) 2018 Thore Mehr thore.mehr@gmail.com
|
||
|
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/>.
|
||
|
'''
|
||
|
__version__ = "1.0" ### please report bugs, suggestions etc to bugs@twot.eu ###
|
||
|
|
||
|
import math,inkex,simplestyle,fablabchemnitz_mehr_plate
|
||
|
|
||
|
class mehr_box_maker(inkex.Effect):
|
||
|
def __init__(self):
|
||
|
# Call the base class constructor.
|
||
|
inkex.Effect.__init__(self)
|
||
|
# Define options
|
||
|
self.OptionParser.add_option('--page',action='store',type='string',dest='page',default='page_1')
|
||
|
self.OptionParser.add_option('--unit',action='store',type='string',dest='unit',default='mm')
|
||
|
self.OptionParser.add_option('--inside',action='store',type='string',dest='inside')
|
||
|
|
||
|
self.OptionParser.add_option('--X_size',action='store',type='float',dest='X_size',default='0.0')
|
||
|
self.OptionParser.add_option('--Y_size',action='store',type='float',dest='Y_size',default='0.0')
|
||
|
self.OptionParser.add_option('--Z_size',action='store',type='float',dest='Z_size',default='0.0')
|
||
|
|
||
|
self.OptionParser.add_option('--tab_mode',action='store',type='string',dest='tab_mode',default='number')
|
||
|
self.OptionParser.add_option('--tab_size',action='store',type='float',dest='tab_size',default='0.0')
|
||
|
|
||
|
|
||
|
self.OptionParser.add_option('--X_tabs',action='store',type='int',dest='X_tabs',default='0')
|
||
|
self.OptionParser.add_option('--Y_tabs',action='store',type='int',dest='Y_tabs',default='0')
|
||
|
self.OptionParser.add_option('--Z_tabs',action='store',type='int',dest='Z_tabs',default='0')
|
||
|
|
||
|
self.OptionParser.add_option('--d_top',action='store',type='inkbool',dest='d_top',default=True)
|
||
|
self.OptionParser.add_option('--d_bottom',action='store',type='inkbool',dest='d_bottom',default=True)
|
||
|
self.OptionParser.add_option('--d_left',action='store',type='inkbool',dest='d_left',default=True)
|
||
|
self.OptionParser.add_option('--d_right',action='store',type='inkbool',dest='d_right',default=True)
|
||
|
self.OptionParser.add_option('--d_front',action='store',type='inkbool',dest='d_front',default=True)
|
||
|
self.OptionParser.add_option('--d_back',action='store',type='inkbool',dest='d_back',default=True)
|
||
|
|
||
|
self.OptionParser.add_option('--thickness',action='store',type='float',dest='thickness',default=4,help='Thickness of Material')
|
||
|
self.OptionParser.add_option('--kerf',action='store',type='float',dest='kerf',default=0.2)
|
||
|
self.OptionParser.add_option('--spaceing',action='store',type='float',dest='spaceing',default=1)
|
||
|
|
||
|
self.OptionParser.add_option('--X_compartments',action='store',type='int',dest='X_compartments',default=1)
|
||
|
self.OptionParser.add_option('--X_divisions',action='store',type='string',dest='X_divisions')
|
||
|
self.OptionParser.add_option('--X_mode',action='store',type='string',dest='X_mode')
|
||
|
self.OptionParser.add_option('--X_fit',action='store',type='inkbool',dest='X_fit')
|
||
|
|
||
|
self.OptionParser.add_option('--Y_compartments',action='store',type='int',dest='Y_compartments',default=1)
|
||
|
self.OptionParser.add_option('--Y_divisions',action='store',type='string',dest='Y_divisions')
|
||
|
self.OptionParser.add_option('--Y_mode',action='store',type='string',dest='Y_mode')
|
||
|
self.OptionParser.add_option('--Y_fit',action='store',type='inkbool',dest='Y_fit')
|
||
|
|
||
|
|
||
|
def effect(self):
|
||
|
thickness=self.unittouu(str(self.options.thickness)+self.options.unit)
|
||
|
kerf=self.unittouu(str(self.options.kerf)+self.options.unit)/2#kerf is diameter in UI and radius in lib
|
||
|
|
||
|
spaceing=self.unittouu(str(self.options.spaceing)+self.options.unit)
|
||
|
XYZ=[self.unittouu(str(self.options.X_size)+self.options.unit),self.unittouu(str(self.options.Y_size)+self.options.unit),self.unittouu(str(self.options.Z_size)+self.options.unit)]
|
||
|
|
||
|
if(self.options.inside=='0'):#if the sizes are outside sizes reduce the size by thickness if the side gets drawn
|
||
|
draw=(self.options.d_left,self.options.d_front,self.options.d_top,self.options.d_right,self.options.d_back,self.options.d_bottom)#order in XYZXYZ
|
||
|
for i in range(6):
|
||
|
XYZ[i%3]-=(thickness if draw[i] else 0)#remove a thickness if drawn
|
||
|
|
||
|
#compartments on the X axis, devisons in Y direction
|
||
|
X_divisions_distances=[]
|
||
|
if (self.options.X_compartments>1):
|
||
|
if (self.options.X_mode=='even'):#spliting in even compartments
|
||
|
X_divisions_distances=[((XYZ[0])-(self.options.X_compartments-1)*(thickness))/self.options.X_compartments]
|
||
|
else:
|
||
|
for dist in self.options.X_divisions.replace(",",".").split(";"):#fixing seperator, spliting string
|
||
|
X_divisions_distances+=[float(self.unittouu(dist+self.options.unit))]#translate into universal units
|
||
|
X_divisions_distances[0]+=kerf#fixing for kerf
|
||
|
if self.options.X_mode!='absolut':#for even and relative fix list lenght and offset compartments to absolut distances
|
||
|
while (len(X_divisions_distances)<self.options.X_compartments+1):#making the list long enought for relative offsets
|
||
|
X_divisions_distances+=X_divisions_distances
|
||
|
for i in range(1,self.options.X_compartments):#offset to absolut distances
|
||
|
X_divisions_distances[i]+=X_divisions_distances[i-1]+thickness-kerf
|
||
|
X_divisions_distances=X_divisions_distances[0:self.options.X_compartments]#cutting excesive lenght off
|
||
|
|
||
|
if(X_divisions_distances[-2]+thickness>XYZ[0])and not self.options.X_fit:
|
||
|
inkex.errormsg("X Axis compartments outside of plate")
|
||
|
if self.options.X_fit:
|
||
|
XYZ[0]=X_divisions_distances[-1]-kerf
|
||
|
X_divisions_distances=X_divisions_distances[0:-1]#cutting the last of
|
||
|
|
||
|
Y_divisions_distances=[]
|
||
|
if (self.options.Y_compartments>1):
|
||
|
if (self.options.Y_mode=='even'):#spliting in even compartments
|
||
|
Y_divisions_distances=[((XYZ[1])-(self.options.Y_compartments-1)*(thickness))/self.options.Y_compartments]
|
||
|
else:
|
||
|
for dist in self.options.Y_divisions.replace(",",".").split(";"):#fixing seperator, spliting string
|
||
|
Y_divisions_distances+=[float(self.unittouu(dist+self.options.unit))]#translate into universal units
|
||
|
Y_divisions_distances[0]+=kerf#fixing for kerf
|
||
|
if self.options.Y_mode!='absolut':#for even and relative fix list lenght and offset compartments to absolut distances
|
||
|
while (len(Y_divisions_distances)<self.options.Y_compartments+1):#making the list long enought for relative offsets
|
||
|
Y_divisions_distances+=Y_divisions_distances
|
||
|
for i in range(1,self.options.Y_compartments):#offset to absolut distances
|
||
|
Y_divisions_distances[i]+=Y_divisions_distances[i-1]+thickness-kerf
|
||
|
Y_divisions_distances=Y_divisions_distances[0:self.options.Y_compartments]#cutting excesive lenght off
|
||
|
|
||
|
if(Y_divisions_distances[-2]+thickness>XYZ[1])and not self.options.X_fit:
|
||
|
inkex.errormsg("Y Axis compartments outside of plate")
|
||
|
if self.options.Y_fit:
|
||
|
XYZ[1]=Y_divisions_distances[-1]-kerf
|
||
|
Y_divisions_distances=Y_divisions_distances[0:-1]#cutting the last of
|
||
|
|
||
|
if (self.options.tab_mode=='number'):#fixed number of tabs
|
||
|
Tabs_XYZ=[self.options.X_tabs,self.options.Y_tabs,self.options.Z_tabs]
|
||
|
else:#compute apropriate number of tabs for the edges
|
||
|
tab_size=float(self.unittouu(str(self.options.tab_size)+self.options.unit))
|
||
|
Tabs_XYZ=[max(1,int(XYZ[0]/(tab_size))/2),max(1,int(XYZ[1]/(tab_size))/2),max(1,int(XYZ[2]/(tab_size))/2)]
|
||
|
|
||
|
|
||
|
#top and bottom plate
|
||
|
tabs_tb=(Tabs_XYZ[0] if self.options.d_back else 0,Tabs_XYZ[1] if self.options.d_right else 0,Tabs_XYZ[0] if self.options.d_front else 0,Tabs_XYZ[1] if self.options.d_left else 0)
|
||
|
start_tb=(True if self.options.d_back else False,True if self.options.d_right else False,True if self.options.d_front else False,True if self.options.d_left else False)
|
||
|
Plate_tb=fablabchemnitz_mehr_plate.Mehr_plate((XYZ[0],XYZ[1]),tabs_tb,start_tb,thickness,kerf)#top and bottom plate
|
||
|
for d in X_divisions_distances:
|
||
|
Plate_tb.add_holes('Y',d,Tabs_XYZ[1])
|
||
|
for d in Y_divisions_distances:
|
||
|
Plate_tb.add_holes('X',d,Tabs_XYZ[0])
|
||
|
#left and right plate
|
||
|
tabs_lr=(Tabs_XYZ[2] if self.options.d_back else 0,Tabs_XYZ[1] if self.options.d_top else 0,Tabs_XYZ[2] if self.options.d_front else 0,Tabs_XYZ[1] if self.options.d_bottom else 0)
|
||
|
start_lr=(True if self.options.d_back else False,False,True if self.options.d_front else False,False)
|
||
|
Plate_lr=fablabchemnitz_mehr_plate.Mehr_plate((XYZ[2],XYZ[1]),tabs_lr,start_lr,thickness,kerf)#left and right plate
|
||
|
for d in Y_divisions_distances:
|
||
|
Plate_lr.add_holes('X',d,Tabs_XYZ[2])
|
||
|
#front and back plate
|
||
|
tabs_fb=(Tabs_XYZ[0] if self.options.d_top else 0,Tabs_XYZ[2] if self.options.d_right else 0,Tabs_XYZ[0] if self.options.d_bottom else 0,Tabs_XYZ[2] if self.options.d_left else 0)#
|
||
|
start_fb=(False,False,False,False)
|
||
|
Plate_fb=fablabchemnitz_mehr_plate.Mehr_plate((XYZ[0],XYZ[2]),tabs_fb,start_fb,thickness,kerf)#font and back plate
|
||
|
for d in X_divisions_distances:
|
||
|
Plate_fb.add_holes('Y',d,Tabs_XYZ[2])
|
||
|
|
||
|
Plate_xc=fablabchemnitz_mehr_plate.Mehr_plate((XYZ[2],XYZ[1]),tabs_lr,(False,False,False,False),thickness,kerf)
|
||
|
for d in Y_divisions_distances:
|
||
|
Plate_xc.holes+=[Plate_xc.rect([0,Plate_xc.corner_offset[1]+d+kerf],[Plate_xc.AABB[0]/2-kerf,thickness-2*kerf])]
|
||
|
|
||
|
Plate_yc=fablabchemnitz_mehr_plate.Mehr_plate((XYZ[0],XYZ[2]),tabs_fb,(False,False,False,False),thickness,kerf)
|
||
|
for d in X_divisions_distances:
|
||
|
Plate_yc.holes+=[Plate_yc.rect([Plate_yc.corner_offset[0]+d+kerf,0],[thickness-2*kerf,Plate_yc.AABB[1]/2-kerf])]
|
||
|
|
||
|
|
||
|
X_offset=0
|
||
|
Y_offset=0
|
||
|
if(self.options.d_top):
|
||
|
Plate_tb.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)#drawing a plate using black for the outline and red for holes
|
||
|
X_offset+=Plate_tb.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_tb.AABB[1])
|
||
|
if(self.options.d_bottom):
|
||
|
Plate_tb.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_tb.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_tb.AABB[1])
|
||
|
|
||
|
if(self.options.d_left):
|
||
|
Plate_lr.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_lr.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_lr.AABB[1])
|
||
|
if(self.options.d_right):
|
||
|
Plate_lr.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_lr.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_lr.AABB[1])
|
||
|
|
||
|
if(self.options.d_front):
|
||
|
Plate_fb.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_fb.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_fb.AABB[1])
|
||
|
if(self.options.d_back):
|
||
|
Plate_fb.draw([X_offset+spaceing,spaceing],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_fb.AABB[0]+spaceing
|
||
|
Y_offset=max(Y_offset,Plate_fb.AABB[1])
|
||
|
X_offset=0
|
||
|
for i in range(self.options.X_compartments-1):
|
||
|
Plate_xc.draw([X_offset+spaceing,spaceing+Y_offset],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_xc.AABB[0]+spaceing
|
||
|
X_offset=0
|
||
|
Y_offset+=spaceing+Plate_xc.AABB[1]
|
||
|
for i in range(self.options.Y_compartments-1):
|
||
|
Plate_yc.draw([X_offset+spaceing,spaceing+Y_offset],["#000000","#ff0000"],self.current_layer)
|
||
|
X_offset+=Plate_yc.AABB[0]+spaceing
|
||
|
|
||
|
|
||
|
effect = mehr_box_maker()
|
||
|
effect.affect()
|