#!/usr/bin/env python3
'''
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 .
'''
__version__ = "1.0" ### please report bugs, suggestions etc to bugs@twot.eu ###
import math
import inkex
import mehr_plate
class mehr_box_maker(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument('--page',default='page_1')
pars.add_argument('--unit',default='mm')
pars.add_argument('--inside')
pars.add_argument('--X_size',type=float,default='0.0')
pars.add_argument('--Y_size',type=float,default='0.0')
pars.add_argument('--Z_size',type=float,default='0.0')
pars.add_argument('--tab_mode',default='number')
pars.add_argument('--tab_size',type=float,default='0.0')
pars.add_argument('--X_tabs',type=int,default='0')
pars.add_argument('--Y_tabs',type=int,default='0')
pars.add_argument('--Z_tabs',type=int,default='0')
pars.add_argument('--d_top',type=inkex.Boolean,default=True)
pars.add_argument('--d_bottom',type=inkex.Boolean,default=True)
pars.add_argument('--d_left',type=inkex.Boolean,default=True)
pars.add_argument('--d_right',type=inkex.Boolean,default=True)
pars.add_argument('--d_front',type=inkex.Boolean,default=True)
pars.add_argument('--d_back',type=inkex.Boolean,default=True)
pars.add_argument('--thickness',type=float,default=4,help='Thickness of Material')
pars.add_argument('--kerf',type=float,default=0.2)
pars.add_argument('--spaceing',type=float,default=1)
pars.add_argument('--X_compartments',type=int,default=1)
pars.add_argument('--X_divisions')
pars.add_argument('--X_mode')
pars.add_argument('--X_fit',type=inkex.Boolean)
pars.add_argument('--Y_compartments',type=int,default=1)
pars.add_argument('--Y_divisions')
pars.add_argument('--Y_mode')
pars.add_argument('--Y_fit',type=inkex.Boolean)
def effect(self):
thickness=self.svg.unittouu(str(self.options.thickness)+self.options.unit)
kerf=self.svg.unittouu(str(self.options.kerf)+self.options.unit)/2#kerf is diameter in UI and radius in lib
spaceing=self.svg.unittouu(str(self.options.spaceing)+self.options.unit)
XYZ=[self.svg.unittouu(str(self.options.X_size)+self.options.unit),self.svg.unittouu(str(self.options.Y_size)+self.options.unit),self.svg.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.svg.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)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.svg.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)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.svg.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=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=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=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=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=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.svg.get_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.svg.get_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.svg.get_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.svg.get_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.svg.get_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.svg.get_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.svg.get_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.svg.get_current_layer())
X_offset+=Plate_yc.AABB[0]+spaceing
if __name__ == '__main__':
mehr_box_maker().run()