modified lasercut jigsaw to create single puzzle pieces; fixed bug in contour scanner

This commit is contained in:
Mario Voigt 2021-07-13 01:57:17 +02:00
parent 26e06ecfe0
commit 2bf51541e2
3 changed files with 148 additions and 81 deletions

View File

@ -1197,10 +1197,19 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
allSubSplitLineStrings = [] allSubSplitLineStrings = []
allSubSplitLineStringsTransformed = []
for subSplitLine in subSplitLineArray: for subSplitLine in subSplitLineArray:
csp = subSplitLine.path.to_arrays() csp = subSplitLine.path.to_arrays()
cspTransformed = Path(subSplitLine.path.transform(subSplitLine.getparent().composed_transform())).to_arrays()
lineString = [(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])] lineString = [(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])]
lineStringTransformed = [(cspTransformed[0][1][0], cspTransformed[0][1][1]), (cspTransformed[1][1][0], cspTransformed[1][1][1])]
if so.remove_trim_duplicates is True: if so.remove_trim_duplicates is True:
if so.visualize_global_intersections is True: #ignore that calculation if false
if lineStringTransformed not in allSubSplitLineStringsTransformed:
allSubSplitLineStringsTransformed.append(lineStringTransformed)
else:
if so.show_debug is True:
self.msg("transformed line {} already in sub split line collection. Dropping ...".format(lineStringTransformed))
if lineString not in allSubSplitLineStrings: if lineString not in allSubSplitLineStrings:
allSubSplitLineStrings.append(lineString) allSubSplitLineStrings.append(lineString)
else: else:
@ -1208,18 +1217,20 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
self.msg("line {} already in sub split line collection. Dropping ...".format(lineString)) self.msg("line {} already in sub split line collection. Dropping ...".format(lineString))
else: #if false we append all segments without filtering duplicate ones else: #if false we append all segments without filtering duplicate ones
allSubSplitLineStrings.append(lineString) allSubSplitLineStrings.append(lineString)
if so.visualize_global_intersections is True: #ignore that calculation if false
allSubSplitLineStringsTransformed.append(allSubSplitLineStringsTransformed)
# Very small step sizes over near-vertical lines can cause errors. We hide exceptions with try-catch, thus we disabled the debugging in poly_point_isect:
# by setting USE_DEBUG = False (True was default setting)
if so.show_debug is True: if so.show_debug is True:
self.msg("Going to calculate intersections using Bentley Ottmann Sweep Line Algorithm") self.msg("Going to calculate intersections using Bentley Ottmann Sweep Line Algorithm")
globalIntersectionPoints = MultiPoint(isect_segments(allSubSplitLineStrings, validate=True)) globalIntersectionPoints = MultiPoint(isect_segments(allSubSplitLineStrings, validate=True))
if so.visualize_global_intersections is True: #ignore that calculation to save time
globalIntersectionPointsTransformed = MultiPoint(isect_segments(allSubSplitLineStringsTransformed, validate=True))
if so.show_debug is True: if so.show_debug is True:
self.msg("global intersection points count: {}".format(len(globalIntersectionPoints))) self.msg("global intersection points count: {}".format(len(globalIntersectionPoints)))
if len(globalIntersectionPoints) > 0: if len(globalIntersectionPoints) > 0:
if so.visualize_global_intersections is True: if so.visualize_global_intersections is True:
self.visualize_global_intersections(globalIntersectionPoints) self.visualize_global_intersections(globalIntersectionPointsTransformed)
''' '''
now we trim the sub split lines at all calculated intersection points. now we trim the sub split lines at all calculated intersection points.

View File

@ -3,22 +3,27 @@
<name>Lasercut Jigsaw</name> <name>Lasercut Jigsaw</name>
<id>fablabchemnitz.de.lasercut_jigsaw</id> <id>fablabchemnitz.de.lasercut_jigsaw</id>
<param name="tab" type="notebook"> <param name="tab" type="notebook">
<page name="Style" gui-text="Style">
<label>The Jigsaw lines color does not apply if 'Create separated pieces' option is enabled.</label>
<param name="color_border" type="color" appearance="colorbutton" gui-text="Border color">4278190335</param>
<param name="color_jigsaw" type="color" appearance="colorbutton" gui-text="Jigsaw lines color">65535</param>
</page>
<page name="Dimensions" gui-text="Dimensions"> <page name="Dimensions" gui-text="Dimensions">
<label>Define the Jigsaw size and grid size.</label> <label>Define the Jigsaw size and grid size.</label>
<param name="width" type="float" min="0.1" max="1000.0" gui-text="Width">100.0</param> <param name="width" type="float" min="0.1" max="1000.0" precision="2" gui-text="Width" gui-description="The Box Width - in the X dimension">100.0</param>
<param name="height" type="float" min="0.1" max="1000.0" gui-text="Height">80.0</param> <param name="height" type="float" min="0.1" max="1000.0" precision="2" gui-text="Height" gui-description="The Box Height - in the Y dimension">80.0</param>
<param name="innerradius" type="float" min="0.0" max="500.0" gui-text="Corner radius">5.0</param> <param name="innerradius" type="float" min="0.0" max="500.0" precision="2" gui-text="Corner radius" gui-description="0 implies square corners">5.0</param>
<param name="units" gui-text="Units" type="optiongroup" appearance="combo"> <param name="units" gui-text="Units" type="optiongroup" appearance="combo" gui-description="The unit of the box dimensions">
<option value="px">px</option> <option value="px">px</option>
<option value="pt">pt</option> <option value="pt">pt</option>
<option value="in">in</option> <option value="in">in</option>
<option value="cm">cm</option> <option value="cm">cm</option>
<option value="mm">mm</option> <option value="mm">mm</option>
</param> </param>
<param name="border" type="bool" gui-text="Outer Border">false</param> <param name="border" type="bool" gui-text="Outer Border" gui-description="Add Outer Surround">false</param>
<param name="borderwidth" type="float" min="0.0" max="500.0" gui-text="Border width">20.0</param> <param name="borderwidth" type="float" min="0.0" max="500.0" precision="2" gui-text="Border width" gui-description="Size of external surrounding border.">20.0</param>
<param name="outerradius" type="float" min="0.0" max="500.0" gui-text="Border radius">5.0</param> <param name="outerradius" type="float" min="0.0" max="500.0" precision="2" gui-text="Border radius" gui-description="0 implies square corners">5.0</param>
<param name="pack" type="optiongroup" appearance="combo" gui-text="Pack Location"> <param name="pack" type="optiongroup" appearance="combo" gui-text="Pack Location" gui-description="Where to place backing piece on page">
<option value="Right">Right</option> <option value="Right">Right</option>
<option value="Below">Below</option> <option value="Below">Below</option>
<option value="Separate">Separate</option> <option value="Separate">Separate</option>
@ -28,13 +33,13 @@
</page> </page>
<page name="Notches" gui-text="Notches"> <page name="Notches" gui-text="Notches">
<label>The interlocking pieces can be shaped here. Also the random nature of the layout.</label> <label>The interlocking pieces can be shaped here. Also the random nature of the layout.</label>
<param name="notch_percent" type="float" min="0.0" max="1.0" gui-text="Notch relative size">0.5</param> <param name="notch_percent" type="float" min="0.0" max="1.0" precision="2" appearance="full" gui-text="Notch relative size" gui-description="Notch relative size. 0 to 1. 0.15 is good">0.5</param>
<param name="rand" type="float" min="0.0" max="1.0" gui-text="Grid Randomisation">0.4</param> <param name="rand" type="float" min="0.0" max="1.0" precision="2" appearance="full" gui-text="Grid Randomisation" gui-description="Amount to perturb the basic piece grid.">0.4</param>
<param name="smooth_edges" type="bool" gui-text="Some edges can be smooth">false</param> <param name="smooth_edges" type="bool" gui-text="Some edges can be smooth" gui-description="Allow pieces with smooth edges.">false</param>
<param name="noknob_frequency" type="float" min="0.0" max="100.0" gui-text="percentage of smooth edges">10</param> <param name="noknob_frequency" type="float" min="0.0" max="100.0" appearance="full" precision="2" gui-text="percentage of smooth edges">10</param>
<param name="use_seed" type="bool" gui-text="Random jigsaw">true</param> <param name="use_seed" type="bool" gui-text="Random jigsaw" gui-description="Use the kerf value as the drawn line width">true</param>
<param name="seed" type="int" min="0" max="99999999" gui-text="or Jigsaw pattern (seed)">12345</param> <param name="seed" type="int" min="0" max="99999999" gui-text="or Jigsaw pattern (seed)" gui-description="Random seed for repeatability">12345</param>
<param name="pieces" type="bool" gui-text="Create pieces as well (-experimental)">false</param> <param name="pieces" type="bool" gui-text="Create separated pieces">false</param>
</page> </page>
<page name="Usage" gui-text="Usage"> <page name="Usage" gui-text="Usage">
<label xml:space="preserve">Jigsaw lines are single for minimal laser cutting. <label xml:space="preserve">Jigsaw lines are single for minimal laser cutting.

View File

@ -37,10 +37,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
__version__ = "0.3" __version__ = "0.3"
import inkex
import sys, math, random, copy import sys, math, random, copy
from lxml import etree from lxml import etree
from inkex.paths import Path, CubicSuperPath import inkex
from inkex import Path, CubicSuperPath, Color
from inkex.command import inkscape
def dirtyFormat(path): def dirtyFormat(path):
return str(path).replace('[','').replace(']','').replace(',','').replace('\'','') return str(path).replace('[','').replace(']','').replace(',','').replace('\'','')
@ -103,36 +104,36 @@ def get_derivative(polynomial):
deriv.append(i* polynomial[i]) deriv.append(i* polynomial[i])
return deriv return deriv
class LasercutJigsaw(inkex.Effect): class LasercutJigsaw(inkex.EffectExtension):
def __init__(self): def add_arguments(self, pars):
inkex.Effect.__init__(self) # General settings
self.arg_parser.add_argument("-x", "--width", type=float, default=50.0, help="The Box Width - in the X dimension") pars.add_argument("--tab")
self.arg_parser.add_argument("-y", "--height", type=float, default=30.0, help="The Box Height - in the Y dimension")
self.arg_parser.add_argument("-u", "--units", default="cm", help="The unit of the box dimensions") #Style
self.arg_parser.add_argument("-w", "--pieces_W", type=int, default=11, help="How many pieces across") pars.add_argument("--color_border", type=Color, default='4278190335', help="Border color")
self.arg_parser.add_argument("-z", "--pieces_H", type=int, default=11, help="How many pieces down") pars.add_argument("--color_jigsaw", type=Color, default='65535', help="Jigsaw lines color")
self.arg_parser.add_argument("-k", "--notch_percent", type=float, default=0.0, help="Notch relative size. 0 to 1. 0.15 is good")
self.arg_parser.add_argument("-r", "--rand", type=float, default=0.1, help="Amount to perturb the basic piece grid.") #Dimensions
self.arg_parser.add_argument("-i", "--innerradius", type=float, default=5.0, help="0 implies square corners") pars.add_argument("--width", type=float, default=50.0, help="The Box Width - in the X dimension")
self.arg_parser.add_argument("-b", "--border", type=inkex.Boolean, default=False, help="Add Outer Surround") pars.add_argument("--height", type=float, default=30.0, help="The Box Height - in the Y dimension")
self.arg_parser.add_argument("-a", "--borderwidth", type=float, default=10.0, help="Size of external surrounding border.") pars.add_argument("--innerradius", type=float, default=5.0, help="0 implies square corners")
self.arg_parser.add_argument("-o", "--outerradius", type=float, default=5.0, help="0 implies square corners") pars.add_argument("--units", default="cm", help="The unit of the box dimensions")
self.arg_parser.add_argument("-p", "--pack", default="Below", help="Where to place backing piece on page") pars.add_argument("--border", type=inkex.Boolean, default=False, help="Add Outer Surround")
self.arg_parser.add_argument("-g", "--use_seed", type=inkex.Boolean, default=False, help="Use the kerf value as the drawn line width") pars.add_argument("--borderwidth", type=float, default=10.0, help="Size of external surrounding border.")
self.arg_parser.add_argument("-s", "--seed", type=int, default=12345, help="Random seed for repeatability") pars.add_argument("--outerradius", type=float, default=5.0, help="0 implies square corners")
self.arg_parser.add_argument("-j", "--pieces", type=inkex.Boolean, default=False, help="Make extra pieces for manual boolean separation.") pars.add_argument("--pack", default="Below", help="Where to place backing piece on page")
self.arg_parser.add_argument("-n", "--smooth_edges", type=inkex.Boolean, default=False, help="Allow pieces with smooth edges.") pars.add_argument("--pieces_W", type=int, default=11, help="How many pieces across")
self.arg_parser.add_argument("-f", "--noknob_frequency", type=float, default=10, help="Percentage of smooth-sided edges.") pars.add_argument("--pieces_H", type=int, default=11, help="How many pieces down")
# dummy for the doc tab - which is named
self.arg_parser.add_argument("--tab", default="use", help="The selected UI-tab when OK was pressed") #Notches
# internal useful variables pars.add_argument("--notch_percent", type=float, default=0.0, help="Notch relative size. 0 to 1. 0.15 is good")
self.stroke_width = 0.1 # default for visiblity pars.add_argument("--rand", type=float, default=0.1, help="Amount to perturb the basic piece grid.")
self.line_style = {'stroke': '#0000FF', # Ponoko blue pars.add_argument("--noknob_frequency", type=float, default=10, help="Percentage of smooth-sided edges.")
'fill': 'none', pars.add_argument("--smooth_edges", type=inkex.Boolean, default=False, help="Allow pieces with smooth edges.")
'stroke-width': self.stroke_width, pars.add_argument("--use_seed", type=inkex.Boolean, default=False, help="Use the kerf value as the drawn line width")
'stroke-linecap': 'butt', pars.add_argument("--seed", type=int, default=12345, help="Random seed for repeatability")
'stroke-linejoin': 'miter'} pars.add_argument("--pieces", type=inkex.Boolean, default=False, help="Make extra pieces for manual boolean separation.")
def add_jigsaw_horiz_line(self, startx, starty, stepx, steps, width, style, name, parent): def add_jigsaw_horiz_line(self, startx, starty, stepx, steps, width, style, name, parent):
""" complex version All C smooth """ complex version All C smooth
@ -194,8 +195,8 @@ class LasercutJigsaw(inkex.Effect):
# #
clist.extend([width, starty, width, starty]) # doubled up at end for smooth curve clist.extend([width, starty, width, starty]) # doubled up at end for smooth curve
line_path.append(['C',clist]) line_path.append(['C',clist])
line_style = str(inkex.Style(style)) borderLineStyle = str(inkex.Style(style))
attribs = { 'style':line_style, 'id':name, 'd':dirtyFormat(line_path)} attribs = { 'style':borderLineStyle, 'id':name, 'd':dirtyFormat(line_path)}
etree.SubElement(parent, inkex.addNS('path','svg'), attribs ) etree.SubElement(parent, inkex.addNS('path','svg'), attribs )
def create_horiz_blocks(self, group, gridy, style): def create_horiz_blocks(self, group, gridy, style):
@ -319,37 +320,84 @@ class LasercutJigsaw(inkex.Effect):
def create_pieces(self, jigsaw, gridx, gridy): def create_pieces(self, jigsaw, gridx, gridy):
""" Loop through each row """ """ Loop through each row """
# Treat outer edge carefully as border runs around. So special code the edges # Treat outer edge carefully as border runs around. So special code the edges
# Internal lines should be in pairs -with second line reversed and appended to first. Close with a 'z' # Internal lines should be in pairs - with second line reversed and appended to first. Close with a 'z'
# Create new group # Create new group
g_attribs = {inkex.addNS('label','inkscape'):'JigsawPieces:X' + \ g_attribs = {inkex.addNS('label','inkscape'):'JigsawPieces:X' + \
str( self.pieces_W )+':Y'+str( self.pieces_H ) } str( self.pieces_W )+':Y'+str( self.pieces_H ) }
jigsaw_pieces = etree.SubElement(jigsaw, 'g', g_attribs) jigsaw_pieces = etree.SubElement(jigsaw, 'g', g_attribs)
line_style = str(inkex.Style(self.line_style)) borderLineStyle = str(inkex.Style(self.borderLineStyle))
#
xblocks = self.create_horiz_blocks(jigsaw_pieces, gridy, line_style) xblocks = self.create_horiz_blocks(jigsaw_pieces, gridy, borderLineStyle)
#sys.stderr.write("count: %s\n"% dir(gridx)) yblocks = self.create_vert_blocks(jigsaw_pieces, gridx, borderLineStyle)
yblocks = self.create_vert_blocks(jigsaw_pieces, gridx, line_style)
#
# for each xblock intersect it with each Y block # for each xblock intersect it with each Y block
#for x in range(len(xblocks)): puzzlePartNo = 1
# for y in range(len(yblocks)): allPathPairsToIntersect = []
allPathsToDelete = []
# delete the paths in xblocks and yblocks for x in range(len(xblocks)):
# transform them out of the way for now for y in range(len(yblocks)):
for node in xblocks: allPathPairsToIntersect.append([copy.copy(xblocks[x]), copy.copy(yblocks[y])])
node.set('transform', 'translate(%f,%f)' % (self.width, 0)) allPathsToDelete.append(xblocks[x])
node.apply_transform() allPathsToDelete.append(yblocks[y])
for node in yblocks:
node.set('transform', 'translate(%f,%f)' % (self.width, 0)) for pair in allPathPairsToIntersect:
node.apply_transform() pair[0].attrib['id'] = str(puzzlePartNo) + "_X"
pair[1].attrib['id'] = str(puzzlePartNo) + "_Y"
xId = pair[0].get('id')
yId = pair[1].get('id')
#self.msg("intersecting {} with {}".format(xId, yId))
puzzlePartNo += 1
jigsaw_pieces.append(pair[0])
jigsaw_pieces.append(pair[1])
for pathToDelete in allPathsToDelete:
pathToDelete.delete()
actions_list = []
for pair in allPathPairsToIntersect:
actions_list.append("select:{}".format(pair[0].attrib['id']))
actions_list.append("select:{}".format(pair[1].attrib['id']))
actions_list.append("SelectionIntersect")
actions_list.append("EditDeselect")
#self.msg(actions_list)
#workaround to fix it (we use export to tempfile instead processing and saving again)
tempfile = self.options.input_file + "-intersected.svg"
with open(tempfile, 'wb') as fp:
fp.write(self.svg.tostring())
extra_param = "--batch-process"
actions_list.append("export-type:svg")
actions_list.append("export-filename:{}".format(tempfile))
actions_list.append("export-do")
actions = ";".join(actions_list)
#self.msg(actions)
cli_output = inkscape(tempfile, extra_param, actions=actions) #process recent file
if len(cli_output) > 0:
self.msg("Inkscape returned the following output when trying to run the file export; the file export may still have worked:")
self.msg(cli_output)
# replace current document with content of temp copy file
self.document = inkex.load_svg(tempfile)
# update self.svg
self.svg = self.document.getroot()
###--------------------------------------------
### The main function called by the Inkscape UI
def effect(self): def effect(self):
# internal useful variables
self.stroke_width = 0.1 # default for visiblity
self.borderLineStyle = {'stroke': self.options.color_border, 'fill': 'none', 'stroke-width': self.stroke_width,
'stroke-linecap': 'butt', 'stroke-linejoin': 'miter'}
self.jigsawLineStyle = {'stroke': self.options.color_jigsaw, 'fill': 'none', 'stroke-width': self.stroke_width,
'stroke-linecap': 'butt', 'stroke-linejoin': 'miter'}
# document dimensions (for centering) # document dimensions (for centering)
docW = self.svg.unittouu(self.document.getroot().get('width')) docW = self.svg.unittouu(self.document.getroot().get('width'))
docH = self.svg.unittouu(self.document.getroot().get('height')) docH = self.svg.unittouu(self.document.getroot().get('height'))
# extract fields from UI # extract fields from UI
self.width = self.svg.unittouu( str(self.options.width) + self.options.units ) self.width = self.svg.unittouu( str(self.options.width) + self.options.units )
self.height = self.svg.unittouu( str(self.options.height) + self.options.units ) self.height = self.svg.unittouu( str(self.options.height) + self.options.units )
@ -386,43 +434,46 @@ class LasercutJigsaw(inkex.Effect):
gridy = etree.SubElement(jigsaw_group, 'g', g_attribs) gridy = etree.SubElement(jigsaw_group, 'g', g_attribs)
# Draw the Border # Draw the Border
add_rounded_rectangle(0,0, self.inner_radius, self.width, self.height, self.line_style, 'innerborder', jigsaw_group) add_rounded_rectangle(0,0, self.inner_radius, self.width, self.height, self.borderLineStyle, 'innerborder', jigsaw_group)
# Do the Border # Do the Border
if self.border: if self.border:
add_rounded_rectangle(-self.borderwidth,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width, add_rounded_rectangle(-self.borderwidth,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width,
self.borderwidth*2+self.height, self.line_style, 'outerborder', jigsaw_group) self.borderwidth*2+self.height, self.borderLineStyle, 'outerborder', jigsaw_group)
# make a second copy below the jigsaw for the cutout BG # make a second copy below the jigsaw for the cutout BG
if self.pack == "Below": if self.pack == "Below":
add_rounded_rectangle(-self.borderwidth,self.borderwidth+ self.height, self.outer_radius, self.borderwidth*2+self.width, add_rounded_rectangle(-self.borderwidth,self.borderwidth+ self.height, self.outer_radius, self.borderwidth*2+self.width,
self.borderwidth*2+self.height, self.line_style, 'BG', jigsaw_group, self.pack) self.borderwidth*2+self.height, self.borderLineStyle, 'BG', jigsaw_group, self.pack)
elif self.pack == "Right": elif self.pack == "Right":
add_rounded_rectangle(self.width+self.borderwidth,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width, add_rounded_rectangle(self.width+self.borderwidth,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width,
self.borderwidth*2+self.height, self.line_style, 'BG', jigsaw_group, self.pack) self.borderwidth*2+self.height, self.borderLineStyle, 'BG', jigsaw_group, self.pack)
else: # Separate else: # Separate
add_rounded_rectangle(self.width+self.borderwidth*2,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width, add_rounded_rectangle(self.width+self.borderwidth*2,-self.borderwidth, self.outer_radius, self.borderwidth*2+self.width,
self.borderwidth*2+self.height, self.line_style, 'BG', jigsaw_group) self.borderwidth*2+self.height, self.borderLineStyle, 'BG', jigsaw_group)
# Step through the Grid # Step through the Grid
Xstep = self.width / (self.pieces_W) Xstep = self.width / (self.pieces_W)
Ystep = self.height / (self.pieces_H) Ystep = self.height / (self.pieces_H)
# Draw Horizontal lines on Y step with Xstep notches # Draw Horizontal lines on Y step with Xstep notches
for i in range(1, self.pieces_H): for i in range(1, self.pieces_H):
self.add_jigsaw_horiz_line(0, Ystep*i, Xstep, self.pieces_W, self.width, self.line_style, 'YDiv'+str(i), gridy) self.add_jigsaw_horiz_line(0, Ystep*i, Xstep, self.pieces_W, self.width, self.jigsawLineStyle, 'YDiv'+str(i), gridy)
# Draw Vertical lines on X step with Ystep notches # Draw Vertical lines on X step with Ystep notches
for i in range(1, self.pieces_W): for i in range(1, self.pieces_W):
self.add_jigsaw_horiz_line(0, Xstep*i, Ystep, self.pieces_H, self.height, self.line_style, 'XDiv'+str(i), gridx) self.add_jigsaw_horiz_line(0, Xstep*i, Ystep, self.pieces_H, self.height, self.jigsawLineStyle, 'XDiv'+str(i), gridx)
# Rotate lines into pos # Rotate lines into pos
# actualy transform can have multiple transforms in it e.g. 'translate(10,10) rotate(10)' # actualy transform can have multiple transforms in it e.g. 'translate(10,10) rotate(10)'
for node in gridx.iterchildren(): for node in gridx.iterchildren():
if node.tag == inkex.addNS('path','svg'): if node.tag == inkex.addNS('path','svg'):
node.set('transform', 'translate(%f,%f) rotate(90)' % (self.width, 0)) node.set('transform', 'translate(%f,%f) rotate(90)' % (self.width, 0))
node.apply_transform()
# center the jigsaw # center the jigsaw
jigsaw_group.set('transform', 'translate(%f,%f)' % ( (docW-self.width)/2, (docH-self.height)/2 ) ) jigsaw_group.set('transform', 'translate(%f,%f)' % ( (docW-self.width)/2, (docH-self.height)/2 ) )
# pieces # pieces
if self.pieces: if self.pieces:
gridx.delete() #delete the previous x generated stuff because we have single pieces instead!
gridy.delete() #delete the previous y generated stuff because we have single pieces instead!
jigsaw_group.getchildren()[0].delete() #delete inner border
self.create_pieces(jigsaw_group, gridx,gridy) self.create_pieces(jigsaw_group, gridx,gridy)
# needs manual boolean ops until that is exposed or we get all the commented code working up top :-(
if __name__ == '__main__': if __name__ == '__main__':
LasercutJigsaw().run() LasercutJigsaw().run()