mightyscape-1.2/extensions/fablabchemnitz/cutcraft/cutcraftshape.py

119 lines
4.6 KiB
Python

#!/usr/bin/env python3
import gettext
import inkex
from math import floor
from cutcraft.core import Point, Rectangle
from lxml import etree
#TODOS
'''
since InkScape 1.0 / Python 3 adjustments are required to fix "TypeError: '<' not supported between instances of 'Pier' and 'Pier'". A __lt__ method has to be implemented
"for this reasion items = sorted([(p[0].area(),p[0]) for p in shape.parts], reverse=True)" was commented out
'''
class CutCraftNode(object):
def __init__(self, rect):
self.children = []
self.rectangle = rect
self.part = None
def insert(self, part, shape):
if len(self.children)>0:
node = self.children[0].insert(part, shape)
if node is not None:
return node
else:
return self.children[1].insert(part, shape)
if self.part is not None:
return None
pwidth, pheight = part.bbox().expanded().size()
nwidth, nheight = self.rectangle.expanded().size()
if pwidth>nwidth or pheight>nheight:
# Too small.
return None
if pwidth==nwidth and pheight==nheight:
# This node fits.
self.part = part
return self
nleft, ntop = self.rectangle.expanded().topleft.tup()
nright, nbottom = self.rectangle.expanded().bottomright.tup()
if nwidth - pwidth > nheight - pheight:
r1 = Rectangle(Point(nleft, ntop),
Point(nleft+pwidth, nbottom))
r2 = Rectangle(Point(nleft+pwidth+1.0, ntop),
Point(nright, nbottom))
else:
r1 = Rectangle(Point(nleft, ntop),
Point(nright, ntop+pheight))
r2 = Rectangle(Point(nleft, ntop+pheight+1.0),
Point(nright, nbottom))
self.children = [CutCraftNode(r1), CutCraftNode(r2)]
return self.children[0].insert(part, shape)
class CutCraftShape(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--active-tab", default="Options", help="The tab selected when OK was pressed")
pars.add_argument("--unit", default="mm", help="unit of measure for circular pitch and center diameter")
pars.add_argument("--thickness", type=float, default=20.0, help="Material Thickness")
pars.add_argument("--kerf", type=float, default=20.0, help="Laser Cutter Kerf")
pars.add_argument("--linethickness", default="1px", help="Line Thickness")
def effect(self):
self.unit = self.options.unit
self.thickness = self.svg.unittouu( str(self.options.thickness) + self.unit)
self.kerf = self.svg.unittouu( str(self.options.kerf) + self.unit)
self.linethickness = self.svg.unittouu(self.options.linethickness)
svg = self.document.getroot()
self.docwidth = self.svg.unittouu(svg.get('width'))
self.docheight = self.svg.unittouu(svg.get('height'))
self.parent=self.svg.get_current_layer()
layer = etree.SubElement(svg, 'g')
layer.set(inkex.addNS('label', 'inkscape'), 'newlayer')
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
def _debug(self, string):
inkex.debug( gettext.gettext(str(string)) )
def _error(self, string):
inkex.errormsg( gettext.gettext(str(string)) )
def pack(self, shape):
# Pack the individual parts onto the current canvas.
line_style = { 'stroke': '#000000',
'stroke-width': str(self.linethickness),
'fill': 'none' }
#items = sorted([(p[0].area(),p[0]) for p in shape.parts], reverse=True)
items = [(p[0].area(),p[0]) for p in shape.parts]
#for p in shape.parts:
# inkex.utils.debug(p[0])
rootnode = CutCraftNode(Rectangle(Point(0.0, 0.0), Point(floor(self.docwidth), floor(self.docheight))))
for i, (_, part) in enumerate(items):
node = rootnode.insert(part, self)
if node is None:
self._error("ERROR: Cannot fit parts onto canvas.\n" +
"Try a larger canvas and then manually arrange if required.")
exit()
bbox = part.bbox().expanded()
part += -bbox.topleft
part += node.rectangle.topleft
line_attribs = { 'style' : str(inkex.Style(line_style)),
inkex.addNS('label','inkscape') : 'Test ' + str(i),
'd' : part.svg() }
_ = etree.SubElement(self.parent, inkex.addNS('path','svg'), line_attribs)