From 7858bd3f3f6acf19964274472062546d84986cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 13 Jul 2013 19:21:28 +0200 Subject: moved main hpgl processing to new classes, moved plotter control to a extension dialog (bzr r12417.1.1) --- share/extensions/hpgl_decoder.py | 88 ++++++++++++ share/extensions/hpgl_encoder.py | 261 +++++++++++++++++++++++++++++++++++ share/extensions/hpgl_input.inx | 3 +- share/extensions/hpgl_input.py | 99 ++++--------- share/extensions/hpgl_output.inx | 78 +++++------ share/extensions/hpgl_output.py | 290 +++++---------------------------------- share/extensions/plotter.inx | 72 ++++++++++ share/extensions/plotter.py | 92 +++++++++++++ 8 files changed, 609 insertions(+), 374 deletions(-) create mode 100644 share/extensions/hpgl_decoder.py create mode 100644 share/extensions/hpgl_encoder.py create mode 100644 share/extensions/plotter.inx create mode 100644 share/extensions/plotter.py diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py new file mode 100644 index 000000000..1a455829e --- /dev/null +++ b/share/extensions/hpgl_decoder.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ +This importer supports the "HP-GL/2 kernel" set of commands only (More should not be necessary). + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard library +from StringIO import StringIO +# local library +import inkex + + +class hpglDecoder: + def __init__(self, options): + ''' options: + "resolutionX":float + "resolutionY":float + "showMovements":bool + ''' + self.options = options + self.scaleX = options.resolutionX / 90.0 # dots/inch to dots/pixels + self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels + self.hasUnknownCommands = False + + def getSvg(self, data): + # parse hpgl data + data = data.split(';') + if data[-1].strip() == '': + data.pop() + if len(data) < 3: + return (False, True, '') + # prepare document + doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) + layerDrawing = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing'}) + if self.options.showMovements: + layerMovements = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) + # parse paths + oldCoordinates = (0.0, self.options.docHeight) + path = '' + for i, command in enumerate(data): + if command.strip() != '': + # TODO:2013-07-13:Sebastian Wüst:Implement the "HP-GL/2 kernel" set of commands. + if command[:2] == 'PU': # if Pen Up command + if " L" in path: + # TODO:2013-07-13:Sebastian Wüst:Make a method for adding a SubElement. + inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) + if self.options.showMovements and i != len(data) - 1: + path = 'M %f,%f' % oldCoordinates + path += ' L %f,%f' % self.getCoordinates(command[2:]) + inkex.etree.SubElement(layerMovements, 'path', {'d':path, 'style':'stroke:#ff0000; stroke-width:0.3; fill:none;'}) + path = 'M %f,%f' % self.getCoordinates(command[2:]) + elif command[:2] == 'PD': # if Pen Down command + path += ' L %f,%f' % self.getCoordinates(command[2:]) + oldCoordinates = self.getCoordinates(command[2:]) + elif command[:2] == 'IN': # if Initialize command + pass + elif command[:2] == 'SP': # if Select Pen command + # TODO:2013-07-13:Sebastian Wüst:Every pen number should go to a different layer. + pass + else: + self.hasUnknownCommands = True + if " L" in path: + inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) + return (self.hasUnknownCommands, False, doc) + + def getCoordinates(self, coord): + # process coordinates + (x, y) = coord.split(',') + x = float(x) / self.scaleX; # convert to pixels coordinate system + y = self.options.docHeight - float(y) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system + return (x, y) + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py new file mode 100644 index 000000000..f6eef630c --- /dev/null +++ b/share/extensions/hpgl_encoder.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard library +import math, string, +# local library +import bezmisc, cspsubdiv, cubicsuperpath, inkex, simplestyle, simpletransform + +class hpglEncoder: + def __init__(self, doc, options): + ''' options: + "resolutionX":float + "resolutionY":float + "pen":int + "orientation":string // "0", "90", "-90", "180" + "mirrorX":bool + "mirrorY":bool + "center":bool + "flat":float + "useOvercut":bool + "overcut":float + "useToolOffset":bool + "toolOffset":float + "toolOffsetReturn":float + "precut":bool + "offsetX":float + "offsetY":float + ''' + self.doc = doc + self.options = options + # TODO:2013-07-13:Sebastian Wüst:Find a way to avoid this crap, maybe make it a string so one can check if it was set before. + self.divergenceX = 9999999999999.0 + self.divergenceY = 9999999999999.0 + self.sizeX = -9999999999999.0 + self.sizeY = -9999999999999.0 + self.dryRun = True + self.scaleX = self.options.resolutionX / 90 # inch to pixels + self.scaleY = self.options.resolutionY / 90 # inch to pixels + self.options.offsetX = self.options.offsetX * 3.5433070866 * self.scaleX # mm to dots (plotter coordinate system) + self.options.offsetY = self.options.offsetY * 3.5433070866 * self.scaleY # mm to dots + self.options.overcut = self.options.overcut * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots + self.options.toolOffset = self.options.toolOffset * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots + self.options.flat = ((self.options.resolutionX + self.options.resolutionY) / 2) * self.options.flat / 1000 # scale flatness to resolution + self.mirrorX = 1.0 + if self.options.mirrorX: + self.mirrorX = -1.0 + self.mirrorY = -1.0 + if self.options.mirrorY: + self.mirrorY = 1.0 + # process viewBox parameter to correct scaling + viewBox = doc.get('viewBox') + self.viewBoxTransformX = 1 + self.viewBoxTransformY = 1 + if viewBox: + viewBox = string.split(viewBox, ' ') + if viewBox[2] and viewBox[3]: + self.viewBoxTransformX = float(inkex.unittouu(doc.get('width'))) / float(viewBox[2]) + self.viewBoxTransformY = float(inkex.unittouu(doc.get('height'))) / float(viewBox[3]) + + def getHpgl(self): + # dryRun to find edges + self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]] + self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) + self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] + self.process_group(self.doc) + if self.divergenceX == 9999999999999.0 or self.divergenceY == 9999999999999.0 or self.sizeX == -9999999999999.0 or self.sizeY == -9999999999999.0: + return -1 + # live run + self.dryRun = False + if self.options.center: + self.divergenceX += (self.sizeX - self.divergenceX) / 2 + self.divergenceY += (self.sizeY - self.divergenceY) / 2 + elif self.options.useToolOffset: + self.options.offsetX += self.options.toolOffset + self.options.offsetY += self.options.toolOffset + self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, -self.divergenceX + self.options.offsetX], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, -self.divergenceY + self.options.offsetY]]] + self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) + self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] + # store first hpgl commands + self.hpgl = 'IN;SP%d;' % self.options.pen + # add precut + if self.options.useToolOffset and self.options.precut: + self.calcOffset('PU', 0, 0) + self.calcOffset('PD', 0, self.options.toolOffset * self.options.toolOffsetReturn * 2) + # start conversion + self.process_group(self.doc) + # shift an empty node in in order to process last node in cache + self.calcOffset('PU', 0, 0) + # add return to zero point + self.hpgl += 'PU0,0;' + return self.hpgl + + def process_group(self, group): + # process groups + style = group.get('style') + if style: + style = simplestyle.parseStyle(style) + if style.has_key('display'): + if style['display'] == 'none': + return + # TODO:2013-07-13:Sebastian Wüst:Pass groupmat in recursion instead of manipulating it. + trans = group.get('transform') + if trans: + self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) + for node in group: + if node.tag == inkex.addNS('path', 'svg'): + self.process_path(node, self.groupmat[-1]) + if node.tag == inkex.addNS('g', 'svg'): + self.process_group(node) + if trans: + self.groupmat.pop() + + def process_path(self, node, mat): + # process path + # TODO:2013-07-13:Sebastian Wüst:Find better variable names. + d = node.get('d') + if d: + # transform path + p = cubicsuperpath.parsePath(d) + trans = node.get('transform') + if trans: + mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) + simpletransform.applyTransformToPath(mat, p) + cspsubdiv.cspsubdiv(p, self.options.flat) + # break path into HPGL commands + # TODO:2013-07-13:Sebastian Wüst:Somehow make this for more readable. + xPosOld = -1 + yPosOld = -1 + for sp in p: + cmd = 'PU' + for csp in sp: + xPos = csp[1][0] + yPos = csp[1][1] + if int(xPos) != int(xPosOld) or int(yPos) != int(yPosOld): + self.calcOffset(cmd, xPos, yPos) + cmd = 'PD' + xPosOld = xPos + yPosOld = yPos + # perform overcut + if self.options.useOvercut and not self.dryRun: + if int(xPos) == int(sp[0][1][0]) and int(yPos) == int(sp[0][1][1]): + for csp in sp: + xPos2 = csp[1][0] + yPos2 = csp[1][1] + if int(xPos) != int(xPos2) or int(yPos) != int(yPos2): + self.calcOffset(cmd, xPos2, yPos2) + if self.options.overcut - self.getLength(xPosOld, yPosOld, xPos2, yPos2) <= 0: + break + xPos = xPos2 + yPos = yPos2 + + # TODO:2013-07-13:Sebastian Wüst:Find methods from the existing classes to replace the next 4 methods. + def getLength(self, x1, y1, x2, y2, abs = True): + # calc absoulute or relative length between two points + if abs: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) + else: return math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) + + def changeLengthX(self, x1, y1, x2, y2, offset): + # change length of line - x axis + if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) + return x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; + + def changeLengthY(self, x1, y1, x2, y2, offset): + # change length of line - y axis + if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) + return y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; + + def getAlpha(self, x1, y1, x2, y2, x3, y3): + # get alpha of point 2 + temp1 = (x1-x2)**2 + (y1-y2)**2 + (x3-x2)**2 + (y3-y2)**2 - (x1-x3)**2 - (y1-y3)**2 + temp2 = 2 * math.sqrt((x1-x2)**2 + (y1-y2)**2) * math.sqrt((x3-x2)**2 + (y3-y2)**2) + temp3 = temp1 / temp2 + if temp3 < -1.0: + temp3 = -1.0 + if temp3 > 1.0: + temp3 = 1.0 + return math.acos(temp3) + + def calcOffset(self, cmd, xPos, yPos): + # calculate offset correction (or dont) + if not self.options.useToolOffset or self.dryRun: + self.storeData(cmd, xPos, yPos) + else: + # insert data into cache + self.vData.pop(0) + self.vData.insert(3, [cmd, xPos, yPos]) + # decide if enough data is availabe + if self.vData[2][1] != -1.0: + if self.vData[1][1] == -1.0: + self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + else: + # check if tool offset correction is needed (if the angle is big enough) + if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': + if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 2.748893: + self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + return + # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) + if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset + # TODO:2013-07-13:Sebastian Wüst:Find a better name for the variables. + pointTwoX = self.changeLengthX(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + pointTwoY = self.changeLengthY(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + self.storeData('PD', pointTwoX, pointTwoY) + elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data shift the 3rd entry by the current tool offset position according to the 2nd command + pointTwoX = self.vData[2][1] - (self.vData[1][1] - self.changeLengthX(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) + pointTwoY = self.vData[2][2] - (self.vData[1][2] - self.changeLengthY(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) + self.storeData('PU', pointTwoX, pointTwoY) + else: # Else just write the 3rd entry to HPGL + pointTwoX = self.vData[2][1] + pointTwoY = self.vData[2][2] + self.storeData('PU', pointTwoX, pointTwoY) + if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command + # TODO:2013-07-13:Sebastian Wüst:Either remove old method or make it selectable by parameter. + if 1 == 1: + pointThreeX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) + pointThreeY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) + self.storeData('PD', pointThreeX, pointThreeY) + else: + # Create a circle between 3rd and 4th entry to correctly guide the tool around the corner + pointThreeX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) + pointThreeY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) + # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) + alpha1 = math.atan2(pointTwoY - self.vData[2][2], pointTwoX - self.vData[2][1]) + alpha2 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) + step = (2 * math.pi - math.fabs(alpha2 - alpha1)) * 6 + 1 + #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) + for alpha in range(int(step), 101, int(step)): + alpha = alpha1 + alpha * (alpha2 - alpha1) / 100 + self.storeData('PD', self.vData[2][1] + math.cos(alpha) * self.options.toolOffset, self.vData[2][2] + math.sin(alpha) * self.options.toolOffset) + self.storeData('PD', pointThreeX, pointThreeY) + + def storeData(self, command, x, y): + # store point + if self.dryRun: + if x < self.divergenceX: self.divergenceX = x + if y < self.divergenceY: self.divergenceY = y + if x > self.sizeX: self.sizeX = x + if y > self.sizeY: self.sizeY = y + else: + if not self.options.center: + if x < 0: x = 0 # only positive values are allowed + if y < 0: y = 0 + self.hpgl += '%s%d,%d;' % (command, x, y) + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_input.inx b/share/extensions/hpgl_input.inx index 0d8cad158..dcf78c6ce 100644 --- a/share/extensions/hpgl_input.inx +++ b/share/extensions/hpgl_input.inx @@ -3,10 +3,11 @@ <_name>HPGL Input org.inkscape.input.hpgl hpgl_input.py + hpgl_decoder.py inkex.py 1016.0 1016.0 - false + false .hpgl image/hpgl diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index d20b344f5..2620c74dd 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -23,91 +23,40 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # standard library from StringIO import StringIO # local library -import inkex - +import hpgl_decoder, inkex inkex.localize() + # parse options parser = inkex.optparse.OptionParser(usage="usage: %prog [options] HPGLfile", option_class=inkex.InkOption) -parser.add_option("-a", "--resolutionX", - action="store", type="float", - dest="resolutionX", default=1016.0, - help="Resolution X (dpi)") -parser.add_option("-b", "--resolutionY", - action="store", type="float", - dest="resolutionY", default=1016.0, - help="Resolution Y (dpi)") -parser.add_option("-c", "--showMovements", - action="store", type="inkbool", - dest="showMovements", default="FALSE", - help="Show Movements between paths") +parser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") +parser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") +parser.add_option("--showMovements", action="store", type="inkbool", dest="showMovements", default="FALSE", help="Show Movements between paths") (options, args) = parser.parse_args(inkex.sys.argv[1:]) +# needed to initialize the document +options.docWidth = 210.0 * 3.5433070866 # 210mm to pixels (DIN A4) +options.docHeight = 297.0 * 3.5433070866 # 297mm to pixels (DIN A4) -# global vars -scaleX = options.resolutionX / 90.0 # dots/inch to dots/pixels -scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels -documentWidth = 210.0 * 3.5433070866 # 210mm to pixels -documentHeight = 297.0 * 3.5433070866 # 297mm to pixels -hasUnknownCommands = False - -def getData(file): - # read file (read only one line, there should not be more than one line) - stream = open(file, 'r') - data = stream.readline().strip() - data = data.split(';') - if len(data) < 2: - inkex.errormsg(_("No HPGL data found.")) - return False - if data[-1].strip() == '': - data.pop() - return data - -def getCoordinates(coord): - # process coordinates - (x, y) = coord.split(',') - x = float(x) / scaleX; # convert to pixels coordinate system - y = documentHeight - float(y) / scaleY; # convert to pixels coordinate system - return (x, y) - -# prepare document -doc = inkex.etree.parse(StringIO('' % (documentWidth, documentHeight))) -layerDrawing = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing'}) -if options.showMovements: - layerMovements = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) +# TODO:2013-07-13:Sebastian Wüst:Load the whole file and try to parse all the different HPGL formats correctly. +# read file (read only one line, there should not be more than one line) +stream = open(args[0], 'r') +data = stream.readline().strip() -# load data -data = getData(args[0]) -if data != False: - # parse paths - oldCoordinates = (0.0, documentHeight) - path = '' - for i, command in enumerate(data): - if command.strip() != '': - if command[:2] == 'PU': # if Pen Up command - if " L" in path: - inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.2; fill:none;'}) - if options.showMovements and i != len(data) - 1: - path = 'M %f,%f' % oldCoordinates - path += ' L %f,%f' % getCoordinates(command[2:]) - inkex.etree.SubElement(layerMovements, 'path', {'d':path, 'style':'stroke:#ff0000; stroke-width:0.2; fill:none;'}) - path = 'M %f,%f' % getCoordinates(command[2:]) - elif command[:2] == 'PD': # if Pen Down command - path += ' L %f,%f' % getCoordinates(command[2:]) - oldCoordinates = getCoordinates(command[2:]) - elif command[:2] == 'IN': # if Initialize command - pass - elif command[:2] == 'SP': # if Select Pen command - pass - else: - hasUnknownCommands = True - if " L" in path: - inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.2; fill:none;'}) +# interpret data +myHpglDecoder = hpgl_decoder.hpglDecoder(options) +# TODO:2013-07-13:Sebastian Wüst:Find a better way to pass errors correctly, think about how data is passed. +(hasUnknownCommands, hasNoHpglData, doc) = myHpglDecoder.getSvg(data) -# deliver document to inkscape -doc.write(inkex.sys.stdout) +# issue warning if no hpgl data found +if hasNoHpglData: + inkex.errormsg(_("No HPGL data found.")) + doc = inkex.etree.parse(StringIO('' % (options.docWidth, options.docHeight))) # issue warning if unknown commands where found if hasUnknownCommands: inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 +# deliver document to inkscape +doc.write(inkex.sys.stdout) + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index 2ce284200..a008c59e4 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -4,51 +4,42 @@ org.ekips.output.hpgl org.inkscape.output.svg.inkscape hpgl_output.py + hpgl_encoder.py inkex.py - <_param name="introduction" type="description">Please make sure that all objects you want to plot are converted to paths. The plot will automatically be aligned to the zero point. - ————————————————————————————— - 1016 - 1 - - - - - + <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The plot will automatically be aligned to the zero point. + + + 1 + 1016.0 + 1016.0 + false + false + + + + + + + false + + + true + 1.00 + + + true + 0.25 + 2.50 + true + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point by the tool offset specified on both axes. + + + 1.2 + 0.00 + 0.00 + - false - false - 1.2 - ————————————————————————————— - true - 1.00 - ————————————————————————————— - true - 0.25 - 2.50 - ————————————————————————————— - 0.00 - 0.00 - false - ————————————————————————————— - false - COM1 - - - - - - - - - - - - - - - - - + .hpgl image/hpgl <_filetypename>HP Graphics Language file (*.hpgl) @@ -57,6 +48,5 @@ diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 83d6da5af..cc87c6947 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -2,7 +2,7 @@ # coding=utf-8 ''' Copyright (C) 2008 Aaron Spike, aaron@ekips.org -Overcut, Tool Offset, Rotation, Serial Com., Many Bugfixes and Improvements: Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ +Overcut, Tool Offset, Rotation, Serial Com., Many Bugfixes and Improvements: Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 @@ -18,272 +18,54 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' -import inkex, simpletransform, cubicsuperpath, simplestyle, sys, math, bezmisc, string, cspsubdiv + +# standard library +import sys +# local library +import hpgl_encoder, inkex +inkex.localize() + class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("-f", "--flatness", - action="store", type="float", - dest="flat", default=1.2, - help="Minimum flatness of the subdivided curves") - self.OptionParser.add_option("-m", "--mirror", - action="store", type="inkbool", - dest="mirror", default="FALSE", - help="Mirror Y-Axis") - self.OptionParser.add_option("-v", "--center", - action="store", type="inkbool", - dest="center", default="FALSE", - help="Center Zero Point") - self.OptionParser.add_option("-x", "--xOffset", - action="store", type="float", - dest="xOffset", default=0.0, - help="X offset (mm)") - self.OptionParser.add_option("-y", "--yOffset", - action="store", type="float", - dest="yOffset", default=0.0, - help="Y offset (mm)") - self.OptionParser.add_option("-r", "--resolution", - action="store", type="int", - dest="resolution", default=1016, - help="Resolution (dpi)") - self.OptionParser.add_option("-n", "--pen", - action="store", type="int", - dest="pen", default=1, - help="Pen number") - self.OptionParser.add_option("-p", "--plotInvisibleLayers", - action="store", type="inkbool", - dest="plotInvisibleLayers", default="FALSE", - help="Plot invisible layers") - self.OptionParser.add_option("-u", "--useOvercut", - action="store", type="inkbool", - dest="useOvercut", default="TRUE", - help="Use Overcut") - self.OptionParser.add_option("-o", "--overcut", - action="store", type="float", - dest="overcut", default=1.0, - help="Overcut (mm)") - self.OptionParser.add_option("-c", "--correctToolOffset", - action="store", type="inkbool", - dest="correctToolOffset", default="TRUE", - help="Correct tool offset") - self.OptionParser.add_option("-t", "--toolOffset", - action="store", type="float", - dest="toolOffset", default=0.25, - help="Tool offset (mm)") - self.OptionParser.add_option("-w", "--toolOffsetReturn", - action="store", type="float", - dest="toolOffsetReturn", default=2.5, - help="Return Factor") - self.OptionParser.add_option("-a", "--angle", - action="store", type="string", - dest="rotation", default="90", - help="Orientation") - self.OptionParser.add_option("-s", "--sendToPlotter", - action="store", type="inkbool", - dest="sendToPlotter", default="FALSE", - help="Send to Plotter also") - self.OptionParser.add_option("-z", "--port", - action="store", type="string", - dest="port", default="COM1", - help="Serial Port") - self.OptionParser.add_option("-b", "--baudRate", - action="store", type="string", - dest="baudRate", default="9600", - help="Baud Rate") + self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") + self.OptionParser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") + self.OptionParser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") + self.OptionParser.add_option("--pen", action="store", type="int", dest="pen", default=1, help="Pen number") + self.OptionParser.add_option("--orientation", action="store", type="string", dest="orientation", default="90", help="orientation") + self.OptionParser.add_option("--mirrorX", action="store", type="inkbool", dest="mirrorX", default="FALSE", help="Mirror X-axis") + self.OptionParser.add_option("--mirrorY", action="store", type="inkbool", dest="mirrorY", default="FALSE", help="Mirror Y-axis") + self.OptionParser.add_option("--center", action="store", type="inkbool", dest="center", default="FALSE", help="Center zero point") + self.OptionParser.add_option("--flat", action="store", type="float", dest="flat", default=1.2, help="Curve flatness") + self.OptionParser.add_option("--useOvercut", action="store", type="inkbool", dest="useOvercut", default="TRUE", help="Use overcut") + self.OptionParser.add_option("--overcut", action="store", type="float", dest="overcut", default=1.0, help="Overcut (mm)") + self.OptionParser.add_option("--useToolOffset", action="store", type="inkbool", dest="useToolOffset", default="TRUE", help="Correct tool offset") + self.OptionParser.add_option("--toolOffset", action="store", type="float", dest="toolOffset", default=0.25, help="Tool offset (mm)") + self.OptionParser.add_option("--toolOffsetReturn", action="store", type="float", dest="toolOffsetReturn", default=2.5, help="Return factor") + self.OptionParser.add_option("--precut", action="store", type="inkbool", dest="precut", default="TRUE", help="Use precut") + self.OptionParser.add_option("--offsetX", action="store", type="float", dest="offsetX", default=0.0, help="X offset (mm)") + self.OptionParser.add_option("--offsetY", action="store", type="float", dest="offsetY", default=0.0, help="Y offset (mm)") def effect(self): - # initiate vars - self.xDivergence = 9999999999999.0 - self.yDivergence = 9999999999999.0 - self.xSize = -9999999999999.0 - self.ySize = -9999999999999.0 - scale = float(self.options.resolution) / 90 # dots/inch to dots/pixels - x0 = self.options.xOffset * 3.5433070866 * scale # mm to dots - y0 = self.options.yOffset * 3.5433070866 * scale # mm to dots - self.options.overcut = self.options.overcut * 3.5433070866 * scale # mm to dots - self.options.toolOffset = self.options.toolOffset * 3.5433070866 * scale # mm to dots - self.options.flat = float(self.options.resolution) * self.options.flat / 1000 - doc = self.document.getroot() - mirror = 1.0 - if self.options.mirror: - mirror = -1.0 - # get viewBox parameter to correct scaling - viewBox = doc.get('viewBox') - viewBoxTransformX = 1 - viewBoxTransformY = 1 - if viewBox: - viewBox = string.split(viewBox, ' ') - if viewBox[2] and viewBox[3]: - viewBoxTransformX = float(inkex.unittouu(doc.get('width'))) / float(viewBox[2]) - viewBoxTransformY = float(inkex.unittouu(doc.get('height'))) / float(viewBox[3]) - # dryRun to find edges - self.dryRun = True - self.groupmat = [[[scale*viewBoxTransformX, 0.0, 0.0], [0.0, mirror*scale*viewBoxTransformY, 0.0]]] - self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.rotation + ')')) - self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] - self.process_group(doc) - if self.options.center: - self.xDivergence += (self.xSize - self.xDivergence) / 2 - self.yDivergence += (self.ySize - self.yDivergence) / 2 - # life run - self.dryRun = False - self.groupmat = [[[scale*viewBoxTransformX, 0.0, -self.xDivergence + x0], [0.0, mirror*scale*viewBoxTransformY, -self.yDivergence + y0]]] - self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.rotation + ')')) - self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] - self.hpgl = 'IN;SP%d;' % self.options.pen - if self.options.sendToPlotter: - try: - import serial - except ImportError, e: - inkex.errormsg('pySerial is not installed.\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial\n2. Extract the "serial" folder from the zip to the following folder: "C:\Program Files (x86)\inkscape\python\Lib"\n3. Restart Inkscape.') - self.options.sendToPlotter = False - if self.options.sendToPlotter: - self.S = serial.Serial(port=self.options.port, baudrate=self.options.baudRate, timeout=0.01, writeTimeout=None) - self.S.write('IN;SP%d;' % self.options.pen) - self.process_group(doc) - self.calcOffset('PU', 0, 0) - self.hpgl += 'PU0,0;' - if self.options.sendToPlotter: - self.S.write('PU0,0;') - self.S.read(2) - self.S.close() - - def process_group(self, group): - # process groups - style = group.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('display'): - if style['display'] == 'none': - if not self.options.plotInvisibleLayers: - return - trans = group.get('transform') - if trans: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) - for node in group: - if node.tag == inkex.addNS('path','svg'): - self.process_path(node, self.groupmat[-1]) - if node.tag == inkex.addNS('g','svg'): - self.process_group(node) - if trans: - self.groupmat.pop() - - def process_path(self, node, mat): - # process oath - d = node.get('d') - if d: - # transform path - p = cubicsuperpath.parsePath(d) - trans = node.get('transform') - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - simpletransform.applyTransformToPath(mat, p) - cspsubdiv.cspsubdiv(p, self.options.flat) - # break path into HPGL commands - xPosOld = -1 - yPosOld = -1 - for sp in p: - cmd = 'PU' - for csp in sp: - xPos = csp[1][0] - yPos = csp[1][1] - if int(xPos) != int(xPosOld) or int(yPos) != int(yPosOld): - self.calcOffset(cmd, xPos, yPos) - cmd = 'PD' - xPosOld = xPos - yPosOld = yPos - # perform overcut - if self.options.useOvercut: - if int(xPos) == int(sp[0][1][0]) and int(yPos) == int(sp[0][1][1]): - for csp in sp: - xPos2 = csp[1][0] - yPos2 = csp[1][1] - if int(xPos) != int(xPos2) or int(yPos) != int(yPos2): - self.calcOffset(cmd, xPos2, yPos2) - if self.options.overcut - self.getLength(xPosOld, yPosOld, xPos2, yPos2) <= 0: - break - xPos = xPos2 - yPos = yPos2 - - def getLength(self, x1, y1, x2, y2, abs = True): - # calc absoulute or relative length of two points - if abs: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) - else: return math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) - - def getAlpha(self, x1, y1, x2, y2, x3, y3): - temp1 = (x1-x2)**2 + (y1-y2)**2 + (x3-x2)**2 + (y3-y2)**2 - (x1-x3)**2 - (y1-y3)**2 - temp2 = 2 * math.sqrt((x1-x2)**2 + (y1-y2)**2) * math.sqrt((x3-x2)**2 + (y3-y2)**2) - temp3 = temp1 / temp2 - if temp3 < -1: - temp3 = -1 - return math.acos(temp3) - - def calcOffset(self, cmd, xPos, yPos): - # calculate offset correction (or dont)) - if not self.options.correctToolOffset: - self.storeData(cmd, xPos, yPos) - else: - self.vData.pop(0) - self.vData.insert(3, [cmd, xPos, yPos]) - if self.vData[2][1] != -1.0: - if self.vData[1][1] != -1.0: - if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': - if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 2.748893: - self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - return - if self.vData[2][0] == 'PD': - self.storeData('PD', - self.changeLengthX(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset), - self.changeLengthY(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset)) - elif self.vData[0][1] != -1.0: - self.storeData('PU', - self.vData[2][1] - (self.vData[1][1] - self.changeLengthX(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)), - self.vData[2][2] - (self.vData[1][2] - self.changeLengthY(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset))) - else: - self.storeData('PU', - self.vData[2][1], - self.vData[2][2]) - if self.vData[3][0] == 'PD': - self.storeData('PD', - self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)), - self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn))) - else: - self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - - def storeData(self, command, x, y): - if self.dryRun: - if x < self.xDivergence: self.xDivergence = x - if y < self.yDivergence: self.yDivergence = y - if x > self.xSize: self.xSize = x - if y > self.ySize: self.ySize = y - else: - if not self.options.center: - if x < 0: x = 0 # only positive values are allowed - if y < 0: y = 0 - self.hpgl += '%s%d,%d;' % (command, x, y) - if self.options.sendToPlotter: - self.S.write('%s%d,%d;' % (command, x, y)) - - def changeLengthX(self, x1, y1, x2, y2, offset): - # change length between two points - x axis - if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) - return x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; - - def changeLengthY(self, x1, y1, x2, y2, offset): - # change length between two points - y axis - if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) - return y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; + # get hpgl data + # TODO:2013-07-13:Sebastian Wüst:Think about how data is passed. + myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) + # TODO:2013-07-13:Sebastian Wüst:Find a better way to pass errors correctly. + self.hpgl = myHpglEncoder.getHpgl() + if self.hpgl == -1: + inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) def output(self): # print to file - print self.hpgl + if self.hpgl != -1: + print self.hpgl if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); - # start calculations + # start extension e = MyEffect() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx new file mode 100644 index 000000000..0dc5a35fc --- /dev/null +++ b/share/extensions/plotter.inx @@ -0,0 +1,72 @@ + + + <_name>Plot + org.ekips.filter.plot + plotter.py + hpgl_decoder.py + hpgl_encoder.py + inkex.py + <_param name="introduction" type="description">Please make sure that all objects you want to plot are converted to paths. The plot will automatically be aligned to the zero point. + + + 1 + 1016.0 + 1016.0 + false + false + + + + + + + false + + + COM1 + + + + + + + + + + + + + + + + + <_param name="serialHelp" type="description">This can be a physical serial connection or a virtual USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. + <_param name="parallelHelp" type="description">Parallel (LPT) connections are not supported. + + + true + 1.00 + + + true + 0.25 + 2.50 + true + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point on both axes by the tool offset specified. + + + 1.2 + 0.00 + 0.00 + + + + path + + + + + + diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py new file mode 100644 index 000000000..7b760e33e --- /dev/null +++ b/share/extensions/plotter.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard library +import sys +# local library +import gettext, hpgl_decoder, hpgl_encoder, inkex +inkex.localize() + + +class MyEffect(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") + self.OptionParser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") + self.OptionParser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") + self.OptionParser.add_option("--pen", action="store", type="int", dest="pen", default=1, help="Pen number") + self.OptionParser.add_option("--orientation", action="store", type="string", dest="orientation", default="90", help="orientation") + self.OptionParser.add_option("--mirrorX", action="store", type="inkbool", dest="mirrorX", default="FALSE", help="Mirror X-axis") + self.OptionParser.add_option("--mirrorY", action="store", type="inkbool", dest="mirrorY", default="FALSE", help="Mirror Y-axis") + self.OptionParser.add_option("--center", action="store", type="inkbool", dest="center", default="FALSE", help="Center zero point") + self.OptionParser.add_option("--flat", action="store", type="float", dest="flat", default=1.2, help="Curve flatness") + self.OptionParser.add_option("--useOvercut", action="store", type="inkbool", dest="useOvercut", default="TRUE", help="Use overcut") + self.OptionParser.add_option("--overcut", action="store", type="float", dest="overcut", default=1.0, help="Overcut (mm)") + self.OptionParser.add_option("--useToolOffset", action="store", type="inkbool", dest="useToolOffset", default="TRUE", help="Correct tool offset") + self.OptionParser.add_option("--toolOffset", action="store", type="float", dest="toolOffset", default=0.25, help="Tool offset (mm)") + self.OptionParser.add_option("--toolOffsetReturn", action="store", type="float", dest="toolOffsetReturn", default=2.5, help="Return factor") + self.OptionParser.add_option("--precut", action="store", type="inkbool", dest="precut", default="TRUE", help="Use precut") + self.OptionParser.add_option("--offsetX", action="store", type="float", dest="offsetX", default=0.0, help="X offset (mm)") + self.OptionParser.add_option("--offsetY", action="store", type="float", dest="offsetY", default=0.0, help="Y offset (mm)") + self.OptionParser.add_option("--serialPort", action="store", type="string", dest="serialPort", default="COM1", help="Serial port") + self.OptionParser.add_option("--serialBaudRate", action="store", type="string", dest="serialBaudRate", default="9600", help="Serial Baud rate") + + def effect(self): + # gracefully exit script when pySerial is missing + try: + import serial + except ImportError, e: + # TODO:2013-07-13:Sebastian Wüst:Maybe add this text to extension window + inkex.errormsg(_("pySerial is not installed." + + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"C:\\Program Files (x86)\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" + + "\n3. Restart Inkscape.")) + return + # get hpgl data + myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) + self.hpgl = myHpglEncoder.getHpgl() + if self.hpgl == -1: + inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) + return + # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. + if 1 == 2: # reparse data for preview + self.options.showMovements = True + self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) + self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) + myHpglDecoder = hpgl_decoder.hpglDecoder(self.options) + (hasUnknownCommands, hasNoHpglData, doc) = myHpglDecoder.getSvg(self.hpgl) + if not hasNoHpglData: + self.document = doc + if 1 == 1: # send data to plotter + # TODO:2013-07-13:Sebastian Wüst:Somehow slow down sending to avoid buffer overruns in the plotter on very large drawings. + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) + mySerial.write(self.hpgl) + # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) + mySerial.read(2) + mySerial.close() + +if __name__ == '__main__': + # Raise recursion limit to avoid exceptions on big documents + sys.setrecursionlimit(20000); + # start extension + e = MyEffect() + e.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 9c2812df7879eadc3d6743555b7d0a808d9ad9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 15:08:21 +0200 Subject: minor changes (bzr r12417.1.2) --- share/extensions/hpgl_encoder.py | 2 +- share/extensions/hpgl_input.py | 15 +++++++-------- share/extensions/plotter.py | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index f6eef630c..58b1f79ea 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library -import math, string, +import math, string # local library import bezmisc, cspsubdiv, cubicsuperpath, inkex, simplestyle, simpletransform diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index 2620c74dd..8290cf0a7 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -50,13 +50,12 @@ myHpglDecoder = hpgl_decoder.hpglDecoder(options) # issue warning if no hpgl data found if hasNoHpglData: inkex.errormsg(_("No HPGL data found.")) - doc = inkex.etree.parse(StringIO('' % (options.docWidth, options.docHeight))) - -# issue warning if unknown commands where found -if hasUnknownCommands: - inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) - -# deliver document to inkscape -doc.write(inkex.sys.stdout) + print 1 +else: + # issue warning if unknown commands where found + if hasUnknownCommands: + inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) + # deliver document to inkscape + doc.write(inkex.sys.stdout) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 7b760e33e..f17c7dcf0 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -66,7 +66,8 @@ class MyEffect(inkex.Effect): inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. - if 1 == 2: # reparse data for preview + ''' + # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) @@ -74,13 +75,14 @@ class MyEffect(inkex.Effect): (hasUnknownCommands, hasNoHpglData, doc) = myHpglDecoder.getSvg(self.hpgl) if not hasNoHpglData: self.document = doc - if 1 == 1: # send data to plotter - # TODO:2013-07-13:Sebastian Wüst:Somehow slow down sending to avoid buffer overruns in the plotter on very large drawings. - mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) - mySerial.write(self.hpgl) - # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) - mySerial.read(2) - mySerial.close() + ''' + # send data to plotter + # TODO:2013-07-13:Sebastian Wüst:Somehow slow down sending to avoid buffer overruns in the plotter on very large drawings. + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) + mySerial.write(self.hpgl) + # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) + mySerial.read(2) + mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents -- cgit v1.2.3 From 8d0d0ff393bde4b53bcd9c8e57b59d1a3021ba77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 17:06:36 +0200 Subject: changed how decoder is called and errors are passed (bzr r12417.1.3) --- share/extensions/hpgl_decoder.py | 31 ++++++++++++++++--------------- share/extensions/hpgl_input.py | 38 ++++++++++++++++++++------------------ share/extensions/hpgl_output.py | 3 +-- share/extensions/plotter.py | 14 ++++++++++---- 4 files changed, 47 insertions(+), 39 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 1a455829e..a2427cc8e 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -26,24 +26,25 @@ import inkex class hpglDecoder: - def __init__(self, options): + def __init__(self, hpglString, options): ''' options: "resolutionX":float "resolutionY":float "showMovements":bool ''' + self.hpglString = hpglString self.options = options self.scaleX = options.resolutionX / 90.0 # dots/inch to dots/pixels self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels - self.hasUnknownCommands = False + self.warnings = [] - def getSvg(self, data): + def getSvg(self): # parse hpgl data - data = data.split(';') - if data[-1].strip() == '': - data.pop() - if len(data) < 3: - return (False, True, '') + hpglData = self.hpglString.split(';') + if hpglData[-1].strip() == '': + hpglData.pop() + if len(hpglData) < 3: + raise Exception('NO_HPGL_DATA') # prepare document doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) layerDrawing = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing'}) @@ -52,14 +53,14 @@ class hpglDecoder: # parse paths oldCoordinates = (0.0, self.options.docHeight) path = '' - for i, command in enumerate(data): + for i, command in enumerate(hpglData): if command.strip() != '': # TODO:2013-07-13:Sebastian Wüst:Implement the "HP-GL/2 kernel" set of commands. if command[:2] == 'PU': # if Pen Up command - if " L" in path: + if ' L' in path: # TODO:2013-07-13:Sebastian Wüst:Make a method for adding a SubElement. inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) - if self.options.showMovements and i != len(data) - 1: + if self.options.showMovements and i != len(hpglData) - 1: path = 'M %f,%f' % oldCoordinates path += ' L %f,%f' % self.getCoordinates(command[2:]) inkex.etree.SubElement(layerMovements, 'path', {'d':path, 'style':'stroke:#ff0000; stroke-width:0.3; fill:none;'}) @@ -73,16 +74,16 @@ class hpglDecoder: # TODO:2013-07-13:Sebastian Wüst:Every pen number should go to a different layer. pass else: - self.hasUnknownCommands = True - if " L" in path: + self.warnings.append('UNKNOWN_COMMANDS') + if ' L' in path: inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) - return (self.hasUnknownCommands, False, doc) + return (doc, self.warnings) def getCoordinates(self, coord): # process coordinates (x, y) = coord.split(',') x = float(x) / self.scaleX; # convert to pixels coordinate system y = self.options.docHeight - float(y) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system - return (x, y) + return (x, y) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index 8290cf0a7..41e7cc608 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -28,11 +28,12 @@ inkex.localize() # parse options -parser = inkex.optparse.OptionParser(usage="usage: %prog [options] HPGLfile", option_class=inkex.InkOption) -parser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") -parser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") -parser.add_option("--showMovements", action="store", type="inkbool", dest="showMovements", default="FALSE", help="Show Movements between paths") +parser = inkex.optparse.OptionParser(usage='usage: %prog [options] HPGLfile', option_class=inkex.InkOption) +parser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') +parser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') +parser.add_option('--showMovements', action='store', type='inkbool', dest='showMovements', default='FALSE', help='Show Movements between paths') (options, args) = parser.parse_args(inkex.sys.argv[1:]) + # needed to initialize the document options.docWidth = 210.0 * 3.5433070866 # 210mm to pixels (DIN A4) options.docHeight = 297.0 * 3.5433070866 # 297mm to pixels (DIN A4) @@ -40,22 +41,23 @@ options.docHeight = 297.0 * 3.5433070866 # 297mm to pixels (DIN A4) # TODO:2013-07-13:Sebastian Wüst:Load the whole file and try to parse all the different HPGL formats correctly. # read file (read only one line, there should not be more than one line) stream = open(args[0], 'r') -data = stream.readline().strip() - -# interpret data -myHpglDecoder = hpgl_decoder.hpglDecoder(options) -# TODO:2013-07-13:Sebastian Wüst:Find a better way to pass errors correctly, think about how data is passed. -(hasUnknownCommands, hasNoHpglData, doc) = myHpglDecoder.getSvg(data) - -# issue warning if no hpgl data found -if hasNoHpglData: - inkex.errormsg(_("No HPGL data found.")) - print 1 -else: +hpglString = stream.readline().strip() + +# interpret HPGL data +myHpglDecoder = hpgl_decoder.hpglDecoder(hpglString, options) +try: + doc, warnings = myHpglDecoder.getSvg() # issue warning if unknown commands where found - if hasUnknownCommands: + if 'UNKNOWN_COMMANDS' in warnings: inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) # deliver document to inkscape - doc.write(inkex.sys.stdout) + doc.write(inkex.sys.stdout) +except Exception as inst: + if inst.args[0] == 'NO_HPGL_DATA': + # issue error if no hpgl data found + inkex.errormsg(_("No HPGL data found.")) + print 1 + else: + raise Exception(inst) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index cc87c6947..1a12b5a49 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -29,7 +29,7 @@ inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") + self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") self.OptionParser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") self.OptionParser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") self.OptionParser.add_option("--pen", action="store", type="int", dest="pen", default=1, help="Pen number") @@ -49,7 +49,6 @@ class MyEffect(inkex.Effect): def effect(self): # get hpgl data - # TODO:2013-07-13:Sebastian Wüst:Think about how data is passed. myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) # TODO:2013-07-13:Sebastian Wüst:Find a better way to pass errors correctly. self.hpgl = myHpglEncoder.getHpgl() diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index f17c7dcf0..d54f9ed6c 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -71,10 +71,16 @@ class MyEffect(inkex.Effect): self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) - myHpglDecoder = hpgl_decoder.hpglDecoder(self.options) - (hasUnknownCommands, hasNoHpglData, doc) = myHpglDecoder.getSvg(self.hpgl) - if not hasNoHpglData: - self.document = doc + myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) + try: + doc, warnings = myHpglDecoder.getSvg() + # deliver document to inkscape + self.document = doc + except Exception as inst: + if inst.args[0] == 'NO_HPGL_DATA': + # do nothing + else: + raise Exception(inst) ''' # send data to plotter # TODO:2013-07-13:Sebastian Wüst:Somehow slow down sending to avoid buffer overruns in the plotter on very large drawings. -- cgit v1.2.3 From 00406587c1417c9c84cdefe12456d5d637a2d421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 19:28:22 +0200 Subject: load whole file instead of one line. (bzr r12417.1.4) --- share/extensions/hpgl_decoder.py | 1 + share/extensions/hpgl_input.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index a2427cc8e..e9fe2f020 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -40,6 +40,7 @@ class hpglDecoder: def getSvg(self): # parse hpgl data + # TODO:2013-07-13:Sebastian Wüst:Try to parse all the different HPGL formats correctly. hpglData = self.hpglString.split(';') if hpglData[-1].strip() == '': hpglData.pop() diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index 41e7cc608..3bd698082 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -38,10 +38,14 @@ parser.add_option('--showMovements', action='store', type='inkbool', dest='showM options.docWidth = 210.0 * 3.5433070866 # 210mm to pixels (DIN A4) options.docHeight = 297.0 * 3.5433070866 # 297mm to pixels (DIN A4) -# TODO:2013-07-13:Sebastian Wüst:Load the whole file and try to parse all the different HPGL formats correctly. -# read file (read only one line, there should not be more than one line) -stream = open(args[0], 'r') -hpglString = stream.readline().strip() +# read file +fobj = open(args[0], 'r') +hpglString = [] +for line in fobj: + hpglString.append(line.strip()) +fobj.close() +# combine all lines +hpglString = ';'.join(hpglString) # interpret HPGL data myHpglDecoder = hpgl_decoder.hpglDecoder(hpglString, options) -- cgit v1.2.3 From 7108556bbdc57d1d6ea3c5002c6b475667cea4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 19:44:08 +0200 Subject: changed how encoder passes errors (bzr r12417.1.5) --- share/extensions/hpgl_encoder.py | 2 +- share/extensions/hpgl_output.py | 15 ++++++++++----- share/extensions/plotter.py | 14 +++++++++----- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 58b1f79ea..e7308beff 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -81,7 +81,7 @@ class hpglEncoder: self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] self.process_group(self.doc) if self.divergenceX == 9999999999999.0 or self.divergenceY == 9999999999999.0 or self.sizeX == -9999999999999.0 or self.sizeY == -9999999999999.0: - return -1 + raise Exception('NO_PATHS') # live run self.dryRun = False if self.options.center: diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 1a12b5a49..10d118a95 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -50,14 +50,19 @@ class MyEffect(inkex.Effect): def effect(self): # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) - # TODO:2013-07-13:Sebastian Wüst:Find a better way to pass errors correctly. - self.hpgl = myHpglEncoder.getHpgl() - if self.hpgl == -1: - inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) + try: + self.hpgl = myHpglEncoder.getHpgl() + except Exception as inst: + if inst.args[0] == 'NO_PATHS': + # issue error if no paths found + inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) + self.hpgl = 1 + else: + raise Exception(inst) def output(self): # print to file - if self.hpgl != -1: + if self.hpgl != 1: print self.hpgl if __name__ == '__main__': diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index d54f9ed6c..ebb69e8a1 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -53,7 +53,6 @@ class MyEffect(inkex.Effect): try: import serial except ImportError, e: - # TODO:2013-07-13:Sebastian Wüst:Maybe add this text to extension window inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"C:\\Program Files (x86)\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" @@ -61,10 +60,15 @@ class MyEffect(inkex.Effect): return # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) - self.hpgl = myHpglEncoder.getHpgl() - if self.hpgl == -1: - inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) - return + try: + self.hpgl = myHpglEncoder.getHpgl() + except Exception as inst: + if inst.args[0] == 'NO_PATHS': + # issue error if no paths found + inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) + return 1 + else: + raise Exception(inst) # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. ''' # reparse data for preview -- cgit v1.2.3 From cbc6385db94389b5b9ebbf0a1893eb8368d71efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 19:50:20 +0200 Subject: changed all quotes to single quotes except for translations (bzr r12417.1.6) --- share/extensions/hpgl_decoder.py | 4 ++-- share/extensions/hpgl_output.py | 34 +++++++++++++++++----------------- share/extensions/plotter.py | 38 +++++++++++++++++++------------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index e9fe2f020..977d1bd06 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -2,7 +2,7 @@ # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ -This importer supports the "HP-GL/2 kernel" set of commands only (More should not be necessary). +This importer supports the HP-GL commands only (More should not be necessary). 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 @@ -56,7 +56,7 @@ class hpglDecoder: path = '' for i, command in enumerate(hpglData): if command.strip() != '': - # TODO:2013-07-13:Sebastian Wüst:Implement the "HP-GL/2 kernel" set of commands. + # TODO:2013-07-13:Sebastian Wüst:Implement the HP-GL commands. if command[:2] == 'PU': # if Pen Up command if ' L' in path: # TODO:2013-07-13:Sebastian Wüst:Make a method for adding a SubElement. diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 10d118a95..1de2a857b 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -29,23 +29,23 @@ inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") - self.OptionParser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") - self.OptionParser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") - self.OptionParser.add_option("--pen", action="store", type="int", dest="pen", default=1, help="Pen number") - self.OptionParser.add_option("--orientation", action="store", type="string", dest="orientation", default="90", help="orientation") - self.OptionParser.add_option("--mirrorX", action="store", type="inkbool", dest="mirrorX", default="FALSE", help="Mirror X-axis") - self.OptionParser.add_option("--mirrorY", action="store", type="inkbool", dest="mirrorY", default="FALSE", help="Mirror Y-axis") - self.OptionParser.add_option("--center", action="store", type="inkbool", dest="center", default="FALSE", help="Center zero point") - self.OptionParser.add_option("--flat", action="store", type="float", dest="flat", default=1.2, help="Curve flatness") - self.OptionParser.add_option("--useOvercut", action="store", type="inkbool", dest="useOvercut", default="TRUE", help="Use overcut") - self.OptionParser.add_option("--overcut", action="store", type="float", dest="overcut", default=1.0, help="Overcut (mm)") - self.OptionParser.add_option("--useToolOffset", action="store", type="inkbool", dest="useToolOffset", default="TRUE", help="Correct tool offset") - self.OptionParser.add_option("--toolOffset", action="store", type="float", dest="toolOffset", default=0.25, help="Tool offset (mm)") - self.OptionParser.add_option("--toolOffsetReturn", action="store", type="float", dest="toolOffsetReturn", default=2.5, help="Return factor") - self.OptionParser.add_option("--precut", action="store", type="inkbool", dest="precut", default="TRUE", help="Use precut") - self.OptionParser.add_option("--offsetX", action="store", type="float", dest="offsetX", default=0.0, help="X offset (mm)") - self.OptionParser.add_option("--offsetY", action="store", type="float", dest="offsetY", default=0.0, help="Y offset (mm)") + self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') + self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') + self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') + self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') + self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') + self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') + self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') + self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') + self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') + self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') + self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') + self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') + self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') + self.OptionParser.add_option('--toolOffsetReturn', action='store', type='float', dest='toolOffsetReturn', default=2.5, help='Return factor') + self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') + self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') + self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') def effect(self): # get hpgl data diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index ebb69e8a1..42e348742 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -28,25 +28,25 @@ inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", action="store", type="string", dest="tab") - self.OptionParser.add_option("--resolutionX", action="store", type="float", dest="resolutionX", default=1016.0, help="Resolution X (dpi)") - self.OptionParser.add_option("--resolutionY", action="store", type="float", dest="resolutionY", default=1016.0, help="Resolution Y (dpi)") - self.OptionParser.add_option("--pen", action="store", type="int", dest="pen", default=1, help="Pen number") - self.OptionParser.add_option("--orientation", action="store", type="string", dest="orientation", default="90", help="orientation") - self.OptionParser.add_option("--mirrorX", action="store", type="inkbool", dest="mirrorX", default="FALSE", help="Mirror X-axis") - self.OptionParser.add_option("--mirrorY", action="store", type="inkbool", dest="mirrorY", default="FALSE", help="Mirror Y-axis") - self.OptionParser.add_option("--center", action="store", type="inkbool", dest="center", default="FALSE", help="Center zero point") - self.OptionParser.add_option("--flat", action="store", type="float", dest="flat", default=1.2, help="Curve flatness") - self.OptionParser.add_option("--useOvercut", action="store", type="inkbool", dest="useOvercut", default="TRUE", help="Use overcut") - self.OptionParser.add_option("--overcut", action="store", type="float", dest="overcut", default=1.0, help="Overcut (mm)") - self.OptionParser.add_option("--useToolOffset", action="store", type="inkbool", dest="useToolOffset", default="TRUE", help="Correct tool offset") - self.OptionParser.add_option("--toolOffset", action="store", type="float", dest="toolOffset", default=0.25, help="Tool offset (mm)") - self.OptionParser.add_option("--toolOffsetReturn", action="store", type="float", dest="toolOffsetReturn", default=2.5, help="Return factor") - self.OptionParser.add_option("--precut", action="store", type="inkbool", dest="precut", default="TRUE", help="Use precut") - self.OptionParser.add_option("--offsetX", action="store", type="float", dest="offsetX", default=0.0, help="X offset (mm)") - self.OptionParser.add_option("--offsetY", action="store", type="float", dest="offsetY", default=0.0, help="Y offset (mm)") - self.OptionParser.add_option("--serialPort", action="store", type="string", dest="serialPort", default="COM1", help="Serial port") - self.OptionParser.add_option("--serialBaudRate", action="store", type="string", dest="serialBaudRate", default="9600", help="Serial Baud rate") + self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') + self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') + self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') + self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') + self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') + self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') + self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') + self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') + self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') + self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') + self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') + self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') + self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') + self.OptionParser.add_option('--toolOffsetReturn', action='store', type='float', dest='toolOffsetReturn', default=2.5, help='Return factor') + self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') + self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') + self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') + self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') + self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') def effect(self): # gracefully exit script when pySerial is missing -- cgit v1.2.3 From bd94ced075960d9d4339d1d8e3f207668385e250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 20:11:26 +0200 Subject: changed find border algorythm to work without number initialization (bzr r12417.1.7) --- share/extensions/hpgl_encoder.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index e7308beff..9b2604ee9 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -45,11 +45,10 @@ class hpglEncoder: ''' self.doc = doc self.options = options - # TODO:2013-07-13:Sebastian Wüst:Find a way to avoid this crap, maybe make it a string so one can check if it was set before. - self.divergenceX = 9999999999999.0 - self.divergenceY = 9999999999999.0 - self.sizeX = -9999999999999.0 - self.sizeY = -9999999999999.0 + self.divergenceX = 'False' # dirty hack: i need to know if this was set before, but since False is evaluated to 0 it can not be determined, therefore the string. + self.divergenceY = 'False' + self.sizeX = 'False' + self.sizeY = 'False' self.dryRun = True self.scaleX = self.options.resolutionX / 90 # inch to pixels self.scaleY = self.options.resolutionY / 90 # inch to pixels @@ -80,7 +79,7 @@ class hpglEncoder: self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] self.process_group(self.doc) - if self.divergenceX == 9999999999999.0 or self.divergenceY == 9999999999999.0 or self.sizeX == -9999999999999.0 or self.sizeY == -9999999999999.0: + if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': raise Exception('NO_PATHS') # live run self.dryRun = False @@ -248,13 +247,13 @@ class hpglEncoder: def storeData(self, command, x, y): # store point if self.dryRun: - if x < self.divergenceX: self.divergenceX = x - if y < self.divergenceY: self.divergenceY = y - if x > self.sizeX: self.sizeX = x - if y > self.sizeY: self.sizeY = y + if self.divergenceX == 'False' or x < self.divergenceX: self.divergenceX = x + if self.divergenceY == 'False' or y < self.divergenceY: self.divergenceY = y + if self.sizeX == 'False' or x > self.sizeX: self.sizeX = x + if self.sizeY == 'False' or y > self.sizeY: self.sizeY = y else: if not self.options.center: - if x < 0: x = 0 # only positive values are allowed + if x < 0: x = 0 # only positive values are allowed (usually) if y < 0: y = 0 self.hpgl += '%s%d,%d;' % (command, x, y) -- cgit v1.2.3 From e115901f0115d50adfde399eea9c7db66da322d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 20:22:23 +0200 Subject: pass group transformations via recursion instead of manipulating variable (bzr r12417.1.8) --- share/extensions/hpgl_encoder.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 9b2604ee9..4ac2b303b 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -78,7 +78,7 @@ class hpglEncoder: self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]] self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] - self.process_group(self.doc) + self.process_group(self.doc, self.groupmat) if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': raise Exception('NO_PATHS') # live run @@ -99,14 +99,14 @@ class hpglEncoder: self.calcOffset('PU', 0, 0) self.calcOffset('PD', 0, self.options.toolOffset * self.options.toolOffsetReturn * 2) # start conversion - self.process_group(self.doc) + self.process_group(self.doc, self.groupmat) # shift an empty node in in order to process last node in cache self.calcOffset('PU', 0, 0) # add return to zero point self.hpgl += 'PU0,0;' return self.hpgl - def process_group(self, group): + def process_group(self, group, groupmat): # process groups style = group.get('style') if style: @@ -114,17 +114,14 @@ class hpglEncoder: if style.has_key('display'): if style['display'] == 'none': return - # TODO:2013-07-13:Sebastian Wüst:Pass groupmat in recursion instead of manipulating it. trans = group.get('transform') if trans: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) + groupmat.append(simpletransform.composeTransform(groupmat[-1], simpletransform.parseTransform(trans))) for node in group: if node.tag == inkex.addNS('path', 'svg'): - self.process_path(node, self.groupmat[-1]) + self.process_path(node, groupmat[-1]) if node.tag == inkex.addNS('g', 'svg'): - self.process_group(node) - if trans: - self.groupmat.pop() + self.process_group(node, groupmat) def process_path(self, node, mat): # process path -- cgit v1.2.3 From 9085752fcdce1f02b9b15761159f553a2cd10646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 20:26:19 +0200 Subject: changed variable names to reflect data (bzr r12417.1.9) --- share/extensions/hpgl_encoder.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 4ac2b303b..5cd5c3b4c 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -136,7 +136,7 @@ class hpglEncoder: simpletransform.applyTransformToPath(mat, p) cspsubdiv.cspsubdiv(p, self.options.flat) # break path into HPGL commands - # TODO:2013-07-13:Sebastian Wüst:Somehow make this for more readable. + # TODO:2013-07-13:Sebastian Wüst:Somehow make this more readable. xPosOld = -1 yPosOld = -1 for sp in p: @@ -209,37 +209,36 @@ class hpglEncoder: return # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset - # TODO:2013-07-13:Sebastian Wüst:Find a better name for the variables. - pointTwoX = self.changeLengthX(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - pointTwoY = self.changeLengthY(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - self.storeData('PD', pointTwoX, pointTwoY) + pointThreeX = self.changeLengthX(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + pointThreeY = self.changeLengthY(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + self.storeData('PD', pointThreeX, pointThreeY) elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data shift the 3rd entry by the current tool offset position according to the 2nd command - pointTwoX = self.vData[2][1] - (self.vData[1][1] - self.changeLengthX(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) - pointTwoY = self.vData[2][2] - (self.vData[1][2] - self.changeLengthY(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) - self.storeData('PU', pointTwoX, pointTwoY) + pointThreeX = self.vData[2][1] - (self.vData[1][1] - self.changeLengthX(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) + pointThreeY = self.vData[2][2] - (self.vData[1][2] - self.changeLengthY(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) + self.storeData('PU', pointThreeX, pointThreeY) else: # Else just write the 3rd entry to HPGL - pointTwoX = self.vData[2][1] - pointTwoY = self.vData[2][2] - self.storeData('PU', pointTwoX, pointTwoY) + pointThreeX = self.vData[2][1] + pointThreeY = self.vData[2][2] + self.storeData('PU', pointThreeX, pointThreeY) if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command # TODO:2013-07-13:Sebastian Wüst:Either remove old method or make it selectable by parameter. if 1 == 1: - pointThreeX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) - pointThreeY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) - self.storeData('PD', pointThreeX, pointThreeY) + pointFourX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) + pointFourY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) + self.storeData('PD', pointFourX, pointFourY) else: # Create a circle between 3rd and 4th entry to correctly guide the tool around the corner - pointThreeX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) - pointThreeY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) + pointFourX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) + pointFourY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) - alpha1 = math.atan2(pointTwoY - self.vData[2][2], pointTwoX - self.vData[2][1]) - alpha2 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) + alpha1 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) + alpha2 = math.atan2(pointFourY - self.vData[2][2], pointFourX - self.vData[2][1]) step = (2 * math.pi - math.fabs(alpha2 - alpha1)) * 6 + 1 #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) for alpha in range(int(step), 101, int(step)): alpha = alpha1 + alpha * (alpha2 - alpha1) / 100 self.storeData('PD', self.vData[2][1] + math.cos(alpha) * self.options.toolOffset, self.vData[2][2] + math.sin(alpha) * self.options.toolOffset) - self.storeData('PD', pointThreeX, pointThreeY) + self.storeData('PD', pointFourX, pointFourY) def storeData(self, command, x, y): # store point -- cgit v1.2.3 From d79f319d72810a94f9f411964aa289c167b5f0db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 21:28:37 +0200 Subject: made process_path more readable (bzr r12417.1.10) --- share/extensions/hpgl_encoder.py | 59 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 5cd5c3b4c..d6605d829 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -125,42 +125,43 @@ class hpglEncoder: def process_path(self, node, mat): # process path - # TODO:2013-07-13:Sebastian Wüst:Find better variable names. - d = node.get('d') - if d: + drawing = node.get('d') + if drawing: # transform path - p = cubicsuperpath.parsePath(d) + paths = cubicsuperpath.parsePath(drawing) trans = node.get('transform') if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - simpletransform.applyTransformToPath(mat, p) - cspsubdiv.cspsubdiv(p, self.options.flat) + simpletransform.applyTransformToPath(mat, paths) + cspsubdiv.cspsubdiv(paths, self.options.flat) # break path into HPGL commands - # TODO:2013-07-13:Sebastian Wüst:Somehow make this more readable. - xPosOld = -1 - yPosOld = -1 - for sp in p: + oldPosX = '' + oldPosY = '' + for singlePath in paths: cmd = 'PU' - for csp in sp: - xPos = csp[1][0] - yPos = csp[1][1] - if int(xPos) != int(xPosOld) or int(yPos) != int(yPosOld): - self.calcOffset(cmd, xPos, yPos) + for singlePathPoint in singlePath: + posX, posY = singlePathPoint[1] + # check if point is repeating, if so, ignore + if posX != oldPosX or posY != oldPosY: + self.calcOffset(cmd, posX, posY) cmd = 'PD' - xPosOld = xPos - yPosOld = yPos + oldPosX = posX + oldPosY = posY + endPosX = posX + endPosY = posY # perform overcut if self.options.useOvercut and not self.dryRun: - if int(xPos) == int(sp[0][1][0]) and int(yPos) == int(sp[0][1][1]): - for csp in sp: - xPos2 = csp[1][0] - yPos2 = csp[1][1] - if int(xPos) != int(xPos2) or int(yPos) != int(yPos2): - self.calcOffset(cmd, xPos2, yPos2) - if self.options.overcut - self.getLength(xPosOld, yPosOld, xPos2, yPos2) <= 0: + # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed + if int(endPosX) == int(singlePath[0][1][0]) and int(endPosY) == int(singlePath[0][1][1]): + for singlePathPoint in singlePath: + posX, posY = singlePathPoint[1] + # check if point is repeating, if so, ignore + if posX != oldPosX or posY != oldPosY: + self.calcOffset(cmd, posX, posY) + if self.options.overcut - self.getLength(endPosX, endPosY, posX, posY) <= 0: break - xPos = xPos2 - yPos = yPos2 + oldPosX = posX + oldPosY = posY # TODO:2013-07-13:Sebastian Wüst:Find methods from the existing classes to replace the next 4 methods. def getLength(self, x1, y1, x2, y2, abs = True): @@ -189,14 +190,14 @@ class hpglEncoder: temp3 = 1.0 return math.acos(temp3) - def calcOffset(self, cmd, xPos, yPos): + def calcOffset(self, cmd, posX, posY): # calculate offset correction (or dont) if not self.options.useToolOffset or self.dryRun: - self.storeData(cmd, xPos, yPos) + self.storeData(cmd, posX, posY) else: # insert data into cache self.vData.pop(0) - self.vData.insert(3, [cmd, xPos, yPos]) + self.vData.insert(3, [cmd, posX, posY]) # decide if enough data is availabe if self.vData[2][1] != -1.0: if self.vData[1][1] == -1.0: -- cgit v1.2.3 From 180b2dcb9d669d5fcf96547ed1a22f77e64bd79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 14 Jul 2013 22:00:32 +0200 Subject: small bugfixes (bzr r12417.1.11) --- share/extensions/hpgl_encoder.py | 2 +- share/extensions/plotter.inx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index d6605d829..b53f61109 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -122,6 +122,7 @@ class hpglEncoder: self.process_path(node, groupmat[-1]) if node.tag == inkex.addNS('g', 'svg'): self.process_group(node, groupmat) + groupmat.pop() def process_path(self, node, mat): # process path @@ -163,7 +164,6 @@ class hpglEncoder: oldPosX = posX oldPosY = posY - # TODO:2013-07-13:Sebastian Wüst:Find methods from the existing classes to replace the next 4 methods. def getLength(self, x1, y1, x2, y2, abs = True): # calc absoulute or relative length between two points if abs: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index 0dc5a35fc..ebf675a85 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -60,7 +60,7 @@ 0.00 - + path -- cgit v1.2.3 From 578ea34c5a2a7aa0c01d0ffe520ee901f3b11d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Mon, 15 Jul 2013 22:24:32 +0200 Subject: minor stuff (bzr r12417.1.12) --- share/extensions/hpgl_encoder.py | 11 ++++++++--- share/extensions/hpgl_output.py | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index b53f61109..27d1bf755 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -164,9 +164,9 @@ class hpglEncoder: oldPosX = posX oldPosY = posY - def getLength(self, x1, y1, x2, y2, abs = True): + def getLength(self, x1, y1, x2, y2, absolute = True): # calc absoulute or relative length between two points - if abs: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) + if absolute: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) else: return math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) def changeLengthX(self, x1, y1, x2, y2, offset): @@ -205,6 +205,10 @@ class hpglEncoder: else: # check if tool offset correction is needed (if the angle is big enough) if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': + # TODO:2013-07-13:Sebastian Wüst:Is this necessary? + if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) < self.options.toolOffset: + self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + return if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 2.748893: self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) return @@ -223,7 +227,7 @@ class hpglEncoder: self.storeData('PU', pointThreeX, pointThreeY) if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command # TODO:2013-07-13:Sebastian Wüst:Either remove old method or make it selectable by parameter. - if 1 == 1: + if 1 == 2: pointFourX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) pointFourY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) self.storeData('PD', pointFourX, pointFourY) @@ -234,6 +238,7 @@ class hpglEncoder: # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) alpha1 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) alpha2 = math.atan2(pointFourY - self.vData[2][2], pointFourX - self.vData[2][1]) + inkex.errormsg(str(math.fabs(alpha2 - alpha1))) step = (2 * math.pi - math.fabs(alpha2 - alpha1)) * 6 + 1 #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) for alpha in range(int(step), 101, int(step)): diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 1de2a857b..b72996315 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -19,6 +19,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' +# TODO:2013-07-15:Sebastian Wüst:make text to guide the user to the extension when he wants to plot + # standard library import sys # local library -- cgit v1.2.3 From de3cd4c192b87660d348ca146b3a7409d8d05108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 27 Jul 2013 17:18:36 +0200 Subject: small changes + fixes (bzr r12417.1.13) --- share/extensions/hpgl_encoder.py | 7 ++++--- share/extensions/hpgl_output.inx | 14 ++++++++++---- share/extensions/hpgl_output.py | 5 +---- share/extensions/plotter.py | 1 - 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 27d1bf755..026b839f4 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -45,7 +45,7 @@ class hpglEncoder: ''' self.doc = doc self.options = options - self.divergenceX = 'False' # dirty hack: i need to know if this was set before, but since False is evaluated to 0 it can not be determined, therefore the string. + self.divergenceX = 'False' # dirty hack: i need to know if this was set to a number before, but since False is evaluated to 0 it can not be determined, therefore the string. self.divergenceY = 'False' self.sizeX = 'False' self.sizeY = 'False' @@ -97,7 +97,7 @@ class hpglEncoder: # add precut if self.options.useToolOffset and self.options.precut: self.calcOffset('PU', 0, 0) - self.calcOffset('PD', 0, self.options.toolOffset * self.options.toolOffsetReturn * 2) + self.calcOffset('PD', 0, self.options.toolOffset * 8) # start conversion self.process_group(self.doc, self.groupmat) # shift an empty node in in order to process last node in cache @@ -122,7 +122,8 @@ class hpglEncoder: self.process_path(node, groupmat[-1]) if node.tag == inkex.addNS('g', 'svg'): self.process_group(node, groupmat) - groupmat.pop() + if trans: + groupmat.pop() def process_path(self, node, mat): # process path diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index a008c59e4..ac93ffe36 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -10,8 +10,10 @@ 1 +   1016.0 1016.0 +   false false @@ -30,16 +32,20 @@ true 0.25 2.50 +   true - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point by the tool offset specified on both axes. +   + <_param name="offsetNote" type="description">Please note that using the tool offset correction will shift your drawing away from the zero point by the length of the tool offset on both axes. 1.2 - 0.00 - 0.00 +   + 0.00 + 0.00 - + <_param name="plottingNote" type="description">Please use the plotter extension from the extension menu to plot directly out of Inkscape. + .hpgl image/hpgl <_filetypename>HP Graphics Language file (*.hpgl) diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index b72996315..4c3217d63 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -19,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' -# TODO:2013-07-15:Sebastian Wüst:make text to guide the user to the extension when he wants to plot - # standard library import sys # local library @@ -64,8 +62,7 @@ class MyEffect(inkex.Effect): def output(self): # print to file - if self.hpgl != 1: - print self.hpgl + print self.hpgl if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 42e348742..4556e9058 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -87,7 +87,6 @@ class MyEffect(inkex.Effect): raise Exception(inst) ''' # send data to plotter - # TODO:2013-07-13:Sebastian Wüst:Somehow slow down sending to avoid buffer overruns in the plotter on very large drawings. mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) -- cgit v1.2.3 From dd9257291dbfc85d74b6e61c22fa5d5c6afcfc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 27 Jul 2013 17:22:13 +0200 Subject: small changes + fixes (bzr r12417.1.14) --- share/extensions/hpgl_encoder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 026b839f4..fa7c1bf3f 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -1,7 +1,8 @@ #!/usr/bin/env python # coding=utf-8 ''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ +Copyright (C) 2008 Aaron Spike, aaron@ekips.org +Overcut, Tool Offset, Rotation, Serial Com., Many Bugfixes and Improvements: Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 -- cgit v1.2.3 From 0cccda91e5b2d2ab5d21a6cc1365aa1c73d5bc9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Thu, 3 Oct 2013 20:26:22 +0200 Subject: parser can now work with multiple pens, better exception handling (bzr r12417.1.15) --- share/extensions/hpgl_decoder.py | 78 +++++++++++++++++++++++++--------------- share/extensions/hpgl_encoder.py | 9 +++-- share/extensions/hpgl_input.py | 8 ++--- share/extensions/hpgl_output.py | 3 +- share/extensions/plotter.inx | 2 ++ share/extensions/plotter.py | 36 ++++++++++--------- 6 files changed, 81 insertions(+), 55 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 977d1bd06..fde81cf39 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -38,51 +38,71 @@ class hpglDecoder: self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels self.warnings = [] - def getSvg(self): - # parse hpgl data + def getSvg(self): # parse hpgl data + # prepare document + self.doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) + actualLayer = 0; + self.layers = {} + if self.options.showMovements: + self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) + # parse paths # TODO:2013-07-13:Sebastian Wüst:Try to parse all the different HPGL formats correctly. hpglData = self.hpglString.split(';') - if hpglData[-1].strip() == '': - hpglData.pop() if len(hpglData) < 3: raise Exception('NO_HPGL_DATA') - # prepare document - doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) - layerDrawing = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing'}) - if self.options.showMovements: - layerMovements = inkex.etree.SubElement(doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) - # parse paths oldCoordinates = (0.0, self.options.docHeight) path = '' for i, command in enumerate(hpglData): if command.strip() != '': - # TODO:2013-07-13:Sebastian Wüst:Implement the HP-GL commands. + # TODO:2013-07-13:Sebastian Wüst:Implement all the HP-GL commands. if command[:2] == 'PU': # if Pen Up command - if ' L' in path: - # TODO:2013-07-13:Sebastian Wüst:Make a method for adding a SubElement. - inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) + if ' L ' in path: + self.addPathToLayer(path, actualLayer) if self.options.showMovements and i != len(hpglData) - 1: path = 'M %f,%f' % oldCoordinates - path += ' L %f,%f' % self.getCoordinates(command[2:]) - inkex.etree.SubElement(layerMovements, 'path', {'d':path, 'style':'stroke:#ff0000; stroke-width:0.3; fill:none;'}) - path = 'M %f,%f' % self.getCoordinates(command[2:]) + path += ' L %f,%f' % self.getParameters(command[2:]) + self.addPathToLayer(path, 0) + path = 'M %f,%f' % self.getParameters(command[2:]) elif command[:2] == 'PD': # if Pen Down command - path += ' L %f,%f' % self.getCoordinates(command[2:]) - oldCoordinates = self.getCoordinates(command[2:]) - elif command[:2] == 'IN': # if Initialize command + path += ' L %f,%f' % self.getParameters(command[2:]) + oldCoordinates = self.getParameters(command[2:]) + elif command[:2] == 'IN': # if Initialize command, ignore pass elif command[:2] == 'SP': # if Select Pen command - # TODO:2013-07-13:Sebastian Wüst:Every pen number should go to a different layer. - pass + actualLayer = command[2:] + self.createLayer(actualLayer) else: self.warnings.append('UNKNOWN_COMMANDS') - if ' L' in path: - inkex.etree.SubElement(layerDrawing, 'path', {'d':path, 'style':'stroke:#000000; stroke-width:0.3; fill:none;'}) - return (doc, self.warnings) - - def getCoordinates(self, coord): - # process coordinates - (x, y) = coord.split(',') + if ' L ' in path: + self.addPathToLayer(path, actualLayer) + return (self.doc, self.warnings) + + def createLayer(self, layerNumber): + self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing Pen ' + layerNumber}) + + def addPathToLayer(self, path, layerNumber): + if layerNumber == 0: + lineColor = 'ff0000' + else: + lineColor = '000000' + inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d':path, 'style':'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) + + def getParameters(self, parameterString): # process coordinates + if parameterString.strip() == '': + return [] + # remove command delimiter + parameterString = parameterString.replace(';', '').strip() + # correct parameter delimiter + parameterString = parameterString.replace(' ', ',') + parameterString = parameterString.replace('+', ',') + parameterString = parameterString.replace('-', ',-') + while ',,' in parameterString: + parameterString = parameterString.replace(',,', ',') + # split parameter + parameterString = parameterString.split(',') + return self.correctAbsoluteCoordinates(parameterString[0], parameterString[1]) + + def correctAbsoluteCoordinates(self, x, y): x = float(x) / self.scaleX; # convert to pixels coordinate system y = self.options.docHeight - float(y) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system return (x, y) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index fa7c1bf3f..8790ade89 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -137,7 +137,7 @@ class hpglEncoder: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, paths) cspsubdiv.cspsubdiv(paths, self.options.flat) - # break path into HPGL commands + # path to HPGL commands oldPosX = '' oldPosY = '' for singlePath in paths: @@ -208,9 +208,9 @@ class hpglEncoder: # check if tool offset correction is needed (if the angle is big enough) if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': # TODO:2013-07-13:Sebastian Wüst:Is this necessary? - if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) < self.options.toolOffset: - self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - return + #if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) < self.options.toolOffset: + # self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + # return if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 2.748893: self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) return @@ -240,7 +240,6 @@ class hpglEncoder: # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) alpha1 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) alpha2 = math.atan2(pointFourY - self.vData[2][2], pointFourX - self.vData[2][1]) - inkex.errormsg(str(math.fabs(alpha2 - alpha1))) step = (2 * math.pi - math.fabs(alpha2 - alpha1)) * 6 + 1 #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) for alpha in range(int(step), 101, int(step)): diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index 3bd698082..e841e1138 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -1,8 +1,6 @@ #!/usr/bin/env python # coding=utf-8 ''' -hpgl_input.py - input a HP Graphics Language file - Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ This program is free software; you can redistribute it and/or modify @@ -21,9 +19,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library +import sys from StringIO import StringIO # local library -import hpgl_decoder, inkex +import hpgl_decoder, inkex, sys inkex.localize() @@ -62,6 +61,7 @@ except Exception as inst: inkex.errormsg(_("No HPGL data found.")) print 1 else: - raise Exception(inst) + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 4c3217d63..adee92cae 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -58,7 +58,8 @@ class MyEffect(inkex.Effect): inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) self.hpgl = 1 else: - raise Exception(inst) + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback def output(self): # print to file diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index ebf675a85..c837e1926 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -51,7 +51,9 @@ true 0.25 2.50 +   true +   <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point on both axes by the tool offset specified. diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 4556e9058..0c802ddc9 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -68,25 +68,29 @@ class MyEffect(inkex.Effect): inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: - raise Exception(inst) - # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback + # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' - # reparse data for preview - self.options.showMovements = True - self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) - self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) - myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) - try: - doc, warnings = myHpglDecoder.getSvg() - # deliver document to inkscape - self.document = doc - except Exception as inst: - if inst.args[0] == 'NO_HPGL_DATA': - # do nothing - else: - raise Exception(inst) + # reparse data for preview + self.options.showMovements = True + self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) + self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) + myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) + try: + doc, warnings = myHpglDecoder.getSvg() + # deliver document to inkscape + self.document = doc + except Exception as inst: + if inst.args[0] == 'NO_HPGL_DATA': + # do nothing + pass + else: + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback ''' # send data to plotter + # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow (Somewhat esotherical) mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) -- cgit v1.2.3 From 74ab23d467f0a8e128ae0c09f009878e49e94427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 6 Oct 2013 21:06:09 +0200 Subject: numerous optimizations, fixed bug tool offset correction calculates wrong points when length of line is smaller than tool offset (bzr r12417.1.16) --- share/extensions/hpgl_decoder.py | 2 +- share/extensions/hpgl_encoder.py | 89 ++++++++++++++++++---------------------- share/extensions/plotter.inx | 5 ++- share/extensions/plotter.py | 1 + 4 files changed, 45 insertions(+), 52 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index fde81cf39..3b8a86f6b 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -54,7 +54,7 @@ class hpglDecoder: path = '' for i, command in enumerate(hpglData): if command.strip() != '': - # TODO:2013-07-13:Sebastian Wüst:Implement all the HP-GL commands. + # TODO:2013-07-13:Sebastian Wüst:Implement all the HP-GL commands. (Or pass it as PLT to UniConverter when unknown commands are found?) if command[:2] == 'PU': # if Pen Up command if ' L ' in path: self.addPathToLayer(path, actualLayer) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 8790ade89..d08b297ae 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -150,19 +150,22 @@ class hpglEncoder: cmd = 'PD' oldPosX = posX oldPosY = posY - endPosX = posX - endPosY = posY # perform overcut if self.options.useOvercut and not self.dryRun: # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed - if int(endPosX) == int(singlePath[0][1][0]) and int(endPosY) == int(singlePath[0][1][1]): + if int(oldPosX) == int(singlePath[0][1][0]) and int(oldPosY) == int(singlePath[0][1][1]): + overcutLength = 0 for singlePathPoint in singlePath: posX, posY = singlePathPoint[1] # check if point is repeating, if so, ignore if posX != oldPosX or posY != oldPosY: - self.calcOffset(cmd, posX, posY) - if self.options.overcut - self.getLength(endPosX, endPosY, posX, posY) <= 0: - break + overcutLength += self.getLength(oldPosX, oldPosY, posX, posY) + if overcutLength >= self.options.overcut: + newLength = self.changeLength(oldPosX, oldPosY, posX, posY, -(overcutLength - self.options.overcut)); + self.calcOffset(cmd, newLength[0], newLength[1]) + break + else: + self.calcOffset(cmd, posX, posY) oldPosX = posX oldPosY = posY @@ -171,16 +174,13 @@ class hpglEncoder: if absolute: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) else: return math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) - def changeLengthX(self, x1, y1, x2, y2, offset): - # change length of line - x axis + def changeLength(self, x1, y1, x2, y2, offset): + # change length of line if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) - return x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; - - def changeLengthY(self, x1, y1, x2, y2, offset): - # change length of line - y axis - if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) - return y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; - + x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; + y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; + return [x, y] + def getAlpha(self, x1, y1, x2, y2, x3, y3): # get alpha of point 2 temp1 = (x1-x2)**2 + (y1-y2)**2 + (x3-x2)**2 + (y3-y2)**2 - (x1-x3)**2 - (y1-y3)**2 @@ -207,45 +207,36 @@ class hpglEncoder: else: # check if tool offset correction is needed (if the angle is big enough) if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': - # TODO:2013-07-13:Sebastian Wüst:Is this necessary? - #if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) < self.options.toolOffset: - # self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - # return - if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 2.748893: + if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 3: self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) return # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset - pointThreeX = self.changeLengthX(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - pointThreeY = self.changeLengthY(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - self.storeData('PD', pointThreeX, pointThreeY) - elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data shift the 3rd entry by the current tool offset position according to the 2nd command - pointThreeX = self.vData[2][1] - (self.vData[1][1] - self.changeLengthX(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) - pointThreeY = self.vData[2][2] - (self.vData[1][2] - self.changeLengthY(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset)) - self.storeData('PU', pointThreeX, pointThreeY) - else: # Else just write the 3rd entry to HPGL - pointThreeX = self.vData[2][1] - pointThreeY = self.vData[2][2] - self.storeData('PU', pointThreeX, pointThreeY) - if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command - # TODO:2013-07-13:Sebastian Wüst:Either remove old method or make it selectable by parameter. - if 1 == 2: - pointFourX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) - pointFourY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -(self.options.toolOffset * self.options.toolOffsetReturn)) - self.storeData('PD', pointFourX, pointFourY) + pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + self.storeData('PD', pointThree[0], pointThree[1]) + elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift the 3rd entry by the current tool offset position according to the 2nd command + pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset) + pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) + pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) + self.storeData('PU', pointThree[0], pointThree[1]) + else: # Else just write the 3rd entry + pointThree = [self.vData[2][1], self.vData[2][2]] + self.storeData('PU', pointThree[0], pointThree[1]) + if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next angle + # Create a circle between the prolonged 3rd and 4th entry to correctly guide the tool around the corner + if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: + pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) else: - # Create a circle between 3rd and 4th entry to correctly guide the tool around the corner - pointFourX = self.changeLengthX(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) - pointFourY = self.changeLengthY(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) - # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) - alpha1 = math.atan2(pointThreeY - self.vData[2][2], pointThreeX - self.vData[2][1]) - alpha2 = math.atan2(pointFourY - self.vData[2][2], pointFourX - self.vData[2][1]) - step = (2 * math.pi - math.fabs(alpha2 - alpha1)) * 6 + 1 - #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) - for alpha in range(int(step), 101, int(step)): - alpha = alpha1 + alpha * (alpha2 - alpha1) / 100 - self.storeData('PD', self.vData[2][1] + math.cos(alpha) * self.options.toolOffset, self.vData[2][2] + math.sin(alpha) * self.options.toolOffset) - self.storeData('PD', pointFourX, pointFourY) + pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) + alpha1 = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) + alpha2 = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) + # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) + step = 10 + #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) + for alpha in range(int(step), 101, int(step)): + alpha = alpha1 + alpha * (alpha2 - alpha1) / 100 + self.storeData('PD', self.vData[2][1] + math.cos(alpha) * self.options.toolOffset, self.vData[2][2] + math.sin(alpha) * self.options.toolOffset) + self.storeData('PD', pointFour[0], pointFour[1]) def storeData(self, command, x, y): # store point diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index c837e1926..1232890c9 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -40,8 +40,9 @@ - <_param name="serialHelp" type="description">This can be a physical serial connection or a virtual USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. - <_param name="parallelHelp" type="description">Parallel (LPT) connections are not supported. + <_param name="serialHelp" type="description">This can be a physical serial connection or a USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. + <_param name="parallelHelp" type="description">Please note that Parallel (LPT) connections are not supported. + <_param name="hpglNote" type="description">Please note that only the HPGL command language is supported at the moment. true diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 0c802ddc9..9b8aff54f 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -58,6 +58,7 @@ class MyEffect(inkex.Effect): + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"C:\\Program Files (x86)\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" + "\n3. Restart Inkscape.")) return + # TODO:2013-07-13:Sebastian Wüst:Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: -- cgit v1.2.3 From d88806501eed58d77af06eab96352a667d895063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Wed, 9 Oct 2013 21:35:15 +0200 Subject: small stuff (bzr r12417.1.17) --- share/extensions/hpgl_output.inx | 8 ++++---- share/extensions/plotter.inx | 10 +++++----- share/extensions/plotter.py | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index ac93ffe36..e295df054 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -9,18 +9,18 @@ <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The plot will automatically be aligned to the zero point. - 1 + 1   1016.0 1016.0   false false - - - + + + false diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index 1232890c9..b034fd4a5 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -9,16 +9,16 @@ <_param name="introduction" type="description">Please make sure that all objects you want to plot are converted to paths. The plot will automatically be aligned to the zero point. - 1 + 1 1016.0 1016.0 - false + false false - - - + + + false diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 9b8aff54f..db05c03cc 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -92,6 +92,7 @@ class MyEffect(inkex.Effect): ''' # send data to plotter # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow (Somewhat esotherical) + # TODO:2013-10-09:Sebastian Wüst: add rtscts=1 ? mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) -- cgit v1.2.3 From 2bae41d2e7cac21f3b62f19bdc8a9e162ef3db48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 12 Oct 2013 21:39:52 +0200 Subject: finished new offset correction (bzr r12417.1.18) --- share/extensions/hpgl_decoder.py | 40 ++++++++++++++++++++-------------------- share/extensions/hpgl_encoder.py | 37 +++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 3b8a86f6b..6843cca2a 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -2,7 +2,7 @@ # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ -This importer supports the HP-GL commands only (More should not be necessary). +This importer supports HP-GL commands only. 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 @@ -55,7 +55,16 @@ class hpglDecoder: for i, command in enumerate(hpglData): if command.strip() != '': # TODO:2013-07-13:Sebastian Wüst:Implement all the HP-GL commands. (Or pass it as PLT to UniConverter when unknown commands are found?) - if command[:2] == 'PU': # if Pen Up command + if command[:2] == 'IN': # if Initialize command, ignore + pass + elif command[:2] == 'SP': # if Select Pen command + actualLayer = command[2:] + self.createLayer(actualLayer) + elif command[:2] == 'AA': # if arc command + # a150,150 0 1,0 150,-150 + path += ' A %f,%f,%d,%d,%d,%f,%f' % (150, 150, 0, 0, 0, 150, 150) + oldCoordinates = self.getParameters(command[2:]) + elif command[:2] == 'PU': # if Pen Up command if ' L ' in path: self.addPathToLayer(path, actualLayer) if self.options.showMovements and i != len(hpglData) - 1: @@ -63,14 +72,10 @@ class hpglDecoder: path += ' L %f,%f' % self.getParameters(command[2:]) self.addPathToLayer(path, 0) path = 'M %f,%f' % self.getParameters(command[2:]) + oldCoordinates = self.getParameters(command[2:]) elif command[:2] == 'PD': # if Pen Down command path += ' L %f,%f' % self.getParameters(command[2:]) oldCoordinates = self.getParameters(command[2:]) - elif command[:2] == 'IN': # if Initialize command, ignore - pass - elif command[:2] == 'SP': # if Select Pen command - actualLayer = command[2:] - self.createLayer(actualLayer) else: self.warnings.append('UNKNOWN_COMMANDS') if ' L ' in path: @@ -92,19 +97,14 @@ class hpglDecoder: return [] # remove command delimiter parameterString = parameterString.replace(';', '').strip() - # correct parameter delimiter - parameterString = parameterString.replace(' ', ',') - parameterString = parameterString.replace('+', ',') - parameterString = parameterString.replace('-', ',-') - while ',,' in parameterString: - parameterString = parameterString.replace(',,', ',') # split parameter - parameterString = parameterString.split(',') - return self.correctAbsoluteCoordinates(parameterString[0], parameterString[1]) - - def correctAbsoluteCoordinates(self, x, y): - x = float(x) / self.scaleX; # convert to pixels coordinate system - y = self.options.docHeight - float(y) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system - return (x, y) + parameter = parameterString.split(',') + # convert to svg coordinate system + parameter[0] = float(parameter[0]) / self.scaleX; # convert to pixels coordinate system + parameter[1] = self.options.docHeight - float(parameter[1]) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system + if len(parameter) == 2: + return (parameter[0], parameter[1]) + elif len(parameter) == 3: + return (parameter[0], parameter[1], parameter[2]) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index d08b297ae..d90493a11 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -205,11 +205,6 @@ class hpglEncoder: if self.vData[1][1] == -1.0: self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) else: - # check if tool offset correction is needed (if the angle is big enough) - if self.vData[2][0] == 'PD' and self.vData[3][0] == 'PD': - if self.getAlpha(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) > 3: - self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - return # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) @@ -227,18 +222,17 @@ class hpglEncoder: if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) else: - pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) - alpha1 = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) - alpha2 = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - # TODO:2013-07-13:Sebastian Wüst:Fix that sucker! (number of points in the circle has to be calculated) - step = 10 - #inkex.errormsg(str(alpha1) + ' | ' + str(alpha2)) - for alpha in range(int(step), 101, int(step)): - alpha = alpha1 + alpha * (alpha2 - alpha1) / 100 - self.storeData('PD', self.vData[2][1] + math.cos(alpha) * self.options.toolOffset, self.vData[2][2] + math.sin(alpha) * self.options.toolOffset) + pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], + (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) + alpha = self.angleDiff(math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) * 57.295779, + math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) * 57.295779) + if alpha > 15.0: + self.storeData('AA', self.vData[2][1], self.vData[2][2], alpha - 10) + if alpha < -15.0: + self.storeData('AA', self.vData[2][1], self.vData[2][2], alpha + 10) self.storeData('PD', pointFour[0], pointFour[1]) - def storeData(self, command, x, y): + def storeData(self, command, x, y, z="False"): # store point if self.dryRun: if self.divergenceX == 'False' or x < self.divergenceX: self.divergenceX = x @@ -249,6 +243,17 @@ class hpglEncoder: if not self.options.center: if x < 0: x = 0 # only positive values are allowed (usually) if y < 0: y = 0 - self.hpgl += '%s%d,%d;' % (command, x, y) + if z == "False": + self.hpgl += '%s%d,%d;' % (command, x, y) + else: + self.hpgl += '%s%d,%d,%d;' % (command, x, y, z) + + def angleDiff(self, a1, a2): + diff = a2 - a1 + if diff > 180: + diff -= 360 + elif diff < -180: + diff += 360 + return diff # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 98dd5f60f4e00979adae608b8acb1cfbabee62f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 12 Oct 2013 21:44:14 +0200 Subject: removed broken code (bzr r12417.1.19) --- share/extensions/hpgl_decoder.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 6843cca2a..6331d8c03 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -60,10 +60,6 @@ class hpglDecoder: elif command[:2] == 'SP': # if Select Pen command actualLayer = command[2:] self.createLayer(actualLayer) - elif command[:2] == 'AA': # if arc command - # a150,150 0 1,0 150,-150 - path += ' A %f,%f,%d,%d,%d,%f,%f' % (150, 150, 0, 0, 0, 150, 150) - oldCoordinates = self.getParameters(command[2:]) elif command[:2] == 'PU': # if Pen Up command if ' L ' in path: self.addPathToLayer(path, actualLayer) -- cgit v1.2.3 From 5026142ebb8fc6be3dae2f4156b7f06af5b2d33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Fri, 18 Oct 2013 22:55:27 +0200 Subject: fixed float to int conversion (bzr r12417.1.20) --- share/extensions/hpgl_encoder.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index d90493a11..ce668ff28 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -233,19 +233,23 @@ class hpglEncoder: self.storeData('PD', pointFour[0], pointFour[1]) def storeData(self, command, x, y, z="False"): - # store point + x = int(round(x)) + y = int(round(y)) if self.dryRun: + # find edges if self.divergenceX == 'False' or x < self.divergenceX: self.divergenceX = x if self.divergenceY == 'False' or y < self.divergenceY: self.divergenceY = y if self.sizeX == 'False' or x > self.sizeX: self.sizeX = x if self.sizeY == 'False' or y > self.sizeY: self.sizeY = y else: + # store point if not self.options.center: if x < 0: x = 0 # only positive values are allowed (usually) if y < 0: y = 0 if z == "False": self.hpgl += '%s%d,%d;' % (command, x, y) else: + z = int(round(z)) self.hpgl += '%s%d,%d,%d;' % (command, x, y, z) def angleDiff(self, a1, a2): -- cgit v1.2.3 From 8bc4fd8b36f86b6a6c02a5118486bc7da999076f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 19 Oct 2013 20:50:05 +0200 Subject: finished tool offset correction; optimized hpgl data; fixed texts, small bugs, parameters; added flow control parameter; and more (bzr r12417.1.21) --- share/extensions/hpgl_decoder.py | 27 +++++++++------- share/extensions/hpgl_encoder.py | 67 ++++++++++++++++++++++++---------------- share/extensions/hpgl_input.inx | 2 ++ share/extensions/hpgl_output.inx | 10 ++---- share/extensions/hpgl_output.py | 1 - share/extensions/plotter.inx | 10 ++++-- share/extensions/plotter.py | 52 +++++++++++++++++-------------- 7 files changed, 95 insertions(+), 74 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 6331d8c03..802f6d0e4 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # standard library from StringIO import StringIO +import math # local library import inkex @@ -46,7 +47,6 @@ class hpglDecoder: if self.options.showMovements: self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) # parse paths - # TODO:2013-07-13:Sebastian Wüst:Try to parse all the different HPGL formats correctly. hpglData = self.hpglString.split(';') if len(hpglData) < 3: raise Exception('NO_HPGL_DATA') @@ -54,7 +54,6 @@ class hpglDecoder: path = '' for i, command in enumerate(hpglData): if command.strip() != '': - # TODO:2013-07-13:Sebastian Wüst:Implement all the HP-GL commands. (Or pass it as PLT to UniConverter when unknown commands are found?) if command[:2] == 'IN': # if Initialize command, ignore pass elif command[:2] == 'SP': # if Select Pen command @@ -70,8 +69,18 @@ class hpglDecoder: path = 'M %f,%f' % self.getParameters(command[2:]) oldCoordinates = self.getParameters(command[2:]) elif command[:2] == 'PD': # if Pen Down command - path += ' L %f,%f' % self.getParameters(command[2:]) - oldCoordinates = self.getParameters(command[2:]) + parameterString = command[2:] + if parameterString.strip() != '': + parameterString = parameterString.replace(';', '').strip() + parameter = parameterString.split(',') + oldCoordinates = (float(parameter[-2]) / self.scaleX, self.options.docHeight - float(parameter[-1]) / self.scaleX) + for i, param in enumerate(parameter): + if i % 2 == 0: + parameter[i] = str(float(param) / self.scaleX) + else: + parameter[i] = str(self.options.docHeight - float(param) / self.scaleY) + parameterString = ','.join(parameter) + path += ' L %s' % parameterString else: self.warnings.append('UNKNOWN_COMMANDS') if ' L ' in path: @@ -87,7 +96,7 @@ class hpglDecoder: else: lineColor = '000000' inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d':path, 'style':'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) - + def getParameters(self, parameterString): # process coordinates if parameterString.strip() == '': return [] @@ -95,12 +104,6 @@ class hpglDecoder: parameterString = parameterString.replace(';', '').strip() # split parameter parameter = parameterString.split(',') - # convert to svg coordinate system - parameter[0] = float(parameter[0]) / self.scaleX; # convert to pixels coordinate system - parameter[1] = self.options.docHeight - float(parameter[1]) / self.scaleY; # convert to pixels coordinate system, flip vertically for inkscape coordinate system - if len(parameter) == 2: - return (parameter[0], parameter[1]) - elif len(parameter) == 3: - return (parameter[0], parameter[1], parameter[2]) + return (float(parameter[0]) / self.scaleX, self.options.docHeight - float(parameter[1]) / self.scaleY) # convert to svg coordinate system # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index ce668ff28..58935e8fb 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -25,6 +25,10 @@ import math, string import bezmisc, cspsubdiv, cubicsuperpath, inkex, simplestyle, simpletransform class hpglEncoder: + + PI = math.pi + TWO_PI = PI * 2 + def __init__(self, doc, options): ''' options: "resolutionX":float @@ -39,7 +43,6 @@ class hpglEncoder: "overcut":float "useToolOffset":bool "toolOffset":float - "toolOffsetReturn":float "precut":bool "offsetX":float "offsetY":float @@ -51,6 +54,7 @@ class hpglEncoder: self.sizeX = 'False' self.sizeY = 'False' self.dryRun = True + self.lastPoint = [0, 0, 0] self.scaleX = self.options.resolutionX / 90 # inch to pixels self.scaleY = self.options.resolutionY / 90 # inch to pixels self.options.offsetX = self.options.offsetX * 3.5433070866 * self.scaleX # mm to dots (plotter coordinate system) @@ -58,13 +62,14 @@ class hpglEncoder: self.options.overcut = self.options.overcut * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots self.options.toolOffset = self.options.toolOffset * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots self.options.flat = ((self.options.resolutionX + self.options.resolutionY) / 2) * self.options.flat / 1000 # scale flatness to resolution + self.toolOffsetFlat = self.options.flat / self.options.toolOffset * 4.5 # scale flatness to offset self.mirrorX = 1.0 if self.options.mirrorX: self.mirrorX = -1.0 self.mirrorY = -1.0 if self.options.mirrorY: self.mirrorY = 1.0 - # process viewBox parameter to correct scaling + # process viewBox attribute to correct page scaling viewBox = doc.get('viewBox') self.viewBoxTransformX = 1 self.viewBoxTransformY = 1 @@ -94,7 +99,7 @@ class hpglEncoder: self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] # store first hpgl commands - self.hpgl = 'IN;SP%d;' % self.options.pen + self.hpgl = 'IN;SP%d' % self.options.pen # add precut if self.options.useToolOffset and self.options.precut: self.calcOffset('PU', 0, 0) @@ -104,7 +109,7 @@ class hpglEncoder: # shift an empty node in in order to process last node in cache self.calcOffset('PU', 0, 0) # add return to zero point - self.hpgl += 'PU0,0;' + self.hpgl += ';PU0,0;' return self.hpgl def process_group(self, group, groupmat): @@ -153,7 +158,7 @@ class hpglEncoder: # perform overcut if self.options.useOvercut and not self.dryRun: # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed - if int(oldPosX) == int(singlePath[0][1][0]) and int(oldPosY) == int(singlePath[0][1][1]): + if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])): overcutLength = 0 for singlePathPoint in singlePath: posX, posY = singlePathPoint[1] @@ -217,24 +222,39 @@ class hpglEncoder: else: # Else just write the 3rd entry pointThree = [self.vData[2][1], self.vData[2][2]] self.storeData('PU', pointThree[0], pointThree[1]) - if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next angle - # Create a circle between the prolonged 3rd and 4th entry to correctly guide the tool around the corner + if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) else: pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) - alpha = self.angleDiff(math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) * 57.295779, - math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) * 57.295779) - if alpha > 15.0: - self.storeData('AA', self.vData[2][1], self.vData[2][2], alpha - 10) - if alpha < -15.0: - self.storeData('AA', self.vData[2][1], self.vData[2][2], alpha + 10) + # get start and end angle + angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) + angleDiff = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart + # switch direction when arc is bigger than 180° + if angleDiff > self.PI: + angleDiff -= self.TWO_PI + elif angleDiff < -self.PI: + angleDiff += self.TWO_PI + # draw arc + if angleDiff >= 0: + angle = angleStart + self.toolOffsetFlat + while angle < angleStart + angleDiff: + self.storeData('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + angle += self.toolOffsetFlat + else: + angle = angleStart - self.toolOffsetFlat + while angle > angleStart + angleDiff: + self.storeData('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + angle -= self.toolOffsetFlat self.storeData('PD', pointFour[0], pointFour[1]) - def storeData(self, command, x, y, z="False"): + def storeData(self, command, x, y): x = int(round(x)) y = int(round(y)) + # skip when no change in movement + if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y: + return if self.dryRun: # find edges if self.divergenceX == 'False' or x < self.divergenceX: self.divergenceX = x @@ -246,18 +266,13 @@ class hpglEncoder: if not self.options.center: if x < 0: x = 0 # only positive values are allowed (usually) if y < 0: y = 0 - if z == "False": - self.hpgl += '%s%d,%d;' % (command, x, y) + # do not repeat command + if command == 'PD' and self.lastPoint[0] == 'PD': + self.hpgl += ',%d,%d' % (x, y) else: - z = int(round(z)) - self.hpgl += '%s%d,%d,%d;' % (command, x, y, z) - - def angleDiff(self, a1, a2): - diff = a2 - a1 - if diff > 180: - diff -= 360 - elif diff < -180: - diff += 360 - return diff + self.hpgl += ';%s%d,%d' % (command, x, y) + self.lastPoint[0] = command + self.lastPoint[1] = x + self.lastPoint[2] = y # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_input.inx b/share/extensions/hpgl_input.inx index dcf78c6ce..be0a0e943 100644 --- a/share/extensions/hpgl_input.inx +++ b/share/extensions/hpgl_input.inx @@ -5,6 +5,8 @@ hpgl_input.py hpgl_decoder.py inkex.py + <_param name="introduction" type="description">Please note that you can only open HPGL files written by Inkscape, to open other HPGL files please change their file extension to .plt, make sure you have UniConverter installed and open them again. +   1016.0 1016.0 false diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index e295df054..087ddeb7d 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -6,14 +6,12 @@ hpgl_output.py hpgl_encoder.py inkex.py - <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The plot will automatically be aligned to the zero point. + <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The drawing will be automatically aligned to the zero point. Please use the plotter extension from the extension menu to plot directly out of Inkscape. 1 -   1016.0 1016.0 -   false false @@ -29,22 +27,18 @@ 1.00 - true + true 0.25 - 2.50 -   true   <_param name="offsetNote" type="description">Please note that using the tool offset correction will shift your drawing away from the zero point by the length of the tool offset on both axes. 1.2 -   0.00 0.00 - <_param name="plottingNote" type="description">Please use the plotter extension from the extension menu to plot directly out of Inkscape. .hpgl image/hpgl diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index adee92cae..d2f9a8e75 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -42,7 +42,6 @@ class MyEffect(inkex.Effect): self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') - self.OptionParser.add_option('--toolOffsetReturn', action='store', type='float', dest='toolOffsetReturn', default=2.5, help='Return factor') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index b034fd4a5..dc4152180 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -40,6 +40,12 @@ + + + + + +   <_param name="serialHelp" type="description">This can be a physical serial connection or a USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. <_param name="parallelHelp" type="description">Please note that Parallel (LPT) connections are not supported. <_param name="hpglNote" type="description">Please note that only the HPGL command language is supported at the moment. @@ -49,10 +55,8 @@ 1.00 - true + true 0.25 - 2.50 -   true   <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point on both axes by the tool offset specified. diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index db05c03cc..7e2481d29 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -28,25 +28,25 @@ inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') - self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') - self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') - self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') - self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') - self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') - self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') - self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') - self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') - self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') - self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') - self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') - self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') - self.OptionParser.add_option('--toolOffsetReturn', action='store', type='float', dest='toolOffsetReturn', default=2.5, help='Return factor') - self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') - self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') - self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') - self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') - self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') + self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') + self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') + self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') + self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') + self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') + self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') + self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') + self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') + self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') + self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') + self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') + self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') + self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') + self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') + self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') + self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') + self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') + self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') + self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing @@ -55,10 +55,10 @@ class MyEffect(inkex.Effect): except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" - + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"C:\\Program Files (x86)\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" + + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" + "\n3. Restart Inkscape.")) return - # TODO:2013-07-13:Sebastian Wüst:Maybe implement DMPL? + # TODO:2013-10-01:Sebastian Wüst:Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: @@ -91,9 +91,13 @@ class MyEffect(inkex.Effect): raise ValueError, ("", type, value), traceback ''' # send data to plotter - # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow (Somewhat esotherical) - # TODO:2013-10-09:Sebastian Wüst: add rtscts=1 ? - mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None) + # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow on plotter side (should be investigated first) + if self.options.flowControl == '1': + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) + elif self.options.flowControl == '2': + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) + else: + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) -- cgit v1.2.3 From 00f4975ff60ea3b2095470e96b822776cf9d493e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 19 Oct 2013 20:56:59 +0200 Subject: changed text (bzr r12417.1.22) --- share/extensions/hpgl_output.inx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index 087ddeb7d..14123c23e 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -6,7 +6,7 @@ hpgl_output.py hpgl_encoder.py inkex.py - <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The drawing will be automatically aligned to the zero point. Please use the plotter extension from the extension menu to plot directly out of Inkscape. + <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The drawing will be automatically aligned to the zero point. Please use the plotter extension from the extension menu to plot directly on a serial plotter. 1 -- cgit v1.2.3 From ba4502382379fc02e2ff57bd52e6e6926bfeee1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 20 Oct 2013 00:13:25 +0200 Subject: changed text (bzr r12417.1.23) --- share/extensions/plotter.py | 114 +------------------------------------------- 1 file changed, 1 insertion(+), 113 deletions(-) diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 7e2481d29..56869e617 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1,113 +1 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -''' - -# standard library -import sys -# local library -import gettext, hpgl_decoder, hpgl_encoder, inkex -inkex.localize() - - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') - self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') - self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') - self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') - self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') - self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') - self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') - self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') - self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') - self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') - self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') - self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') - self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') - self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') - self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') - self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') - self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') - self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') - self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') - - def effect(self): - # gracefully exit script when pySerial is missing - try: - import serial - except ImportError, e: - inkex.errormsg(_("pySerial is not installed." - + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" - + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: \"\\inkscape\\python\\Lib\\\" (Or wherever your Inkscape is installed to)" - + "\n3. Restart Inkscape.")) - return - # TODO:2013-10-01:Sebastian Wüst:Maybe implement DMPL? - # get hpgl data - myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) - try: - self.hpgl = myHpglEncoder.getHpgl() - except Exception as inst: - if inst.args[0] == 'NO_PATHS': - # issue error if no paths found - inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) - return 1 - else: - type, value, traceback = sys.exc_info() - raise ValueError, ("", type, value), traceback - # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) - ''' - # reparse data for preview - self.options.showMovements = True - self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) - self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) - myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) - try: - doc, warnings = myHpglDecoder.getSvg() - # deliver document to inkscape - self.document = doc - except Exception as inst: - if inst.args[0] == 'NO_HPGL_DATA': - # do nothing - pass - else: - type, value, traceback = sys.exc_info() - raise ValueError, ("", type, value), traceback - ''' - # send data to plotter - # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow on plotter side (should be investigated first) - if self.options.flowControl == '1': - mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) - elif self.options.flowControl == '2': - mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) - else: - mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) - mySerial.write(self.hpgl) - # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) - mySerial.read(2) - mySerial.close() - -if __name__ == '__main__': - # Raise recursion limit to avoid exceptions on big documents - sys.setrecursionlimit(20000); - # start extension - e = MyEffect() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [...]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO:2013-10-01:Sebastian Wüst:Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow on plotter side (should be investigated first) if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 873bd3de82d9d190b27f80466d64016ad3f84dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 20 Oct 2013 17:59:18 +0200 Subject: changed text (bzr r12417.1.25) --- share/extensions/hpgl_output.inx | 6 +++--- share/extensions/plotter.inx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index 14123c23e..1a9047ce0 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -6,7 +6,7 @@ hpgl_output.py hpgl_encoder.py inkex.py - <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The drawing will be automatically aligned to the zero point. Please use the plotter extension from the extension menu to plot directly on a serial plotter. + <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. The drawing will be automatically aligned to the zero point. Please use the plotter extension (Extensions menu) to plot directly on a plotter. 1 @@ -20,7 +20,7 @@ - false + false true @@ -31,7 +31,7 @@ 0.25 true   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will shift your drawing away from the zero point by the length of the tool offset on both axes. + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset specified. 1.2 diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index dc4152180..f0989ba1c 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -20,7 +20,7 @@ - false + false COM1 @@ -59,7 +59,7 @@ 0.25 true   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your drawing away from the zero point on both axes by the tool offset specified. + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset specified. 1.2 -- cgit v1.2.3 From ab8acd061c218268293120a933993a449461ff43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 20 Oct 2013 18:00:51 +0200 Subject: changed text (bzr r12417.1.26) --- share/extensions/hpgl_output.inx | 2 +- share/extensions/plotter.inx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index 1a9047ce0..d5cc37d33 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -31,7 +31,7 @@ 0.25 true   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset specified. + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset. 1.2 diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index f0989ba1c..f22df3380 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -59,7 +59,7 @@ 0.25 true   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset specified. + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset. 1.2 -- cgit v1.2.3 From 012165f8eaa0f2ef5572d096d62e36c9069c964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 20 Oct 2013 18:05:04 +0200 Subject: changed todo format (bzr r12417.1.27) --- share/extensions/plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 56869e617..d93cf0783 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [...]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO:2013-10-01:Sebastian Wüst:Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO:2013-07-13:Sebastian Wüst:Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter # TODO:2013-07-13:Sebastian Wüst:Slow down sending to prevent buffer overflow on plotter side (should be investigated first) if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [...]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter # TODO: Slow down sending to prevent buffer overflow on plotter side (should be investigated first) if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 7fdb6606c3fe8a492e750a59c49e847b265196e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 20 Oct 2013 18:40:41 +0200 Subject: small optimizations (bzr r12417.1.28) --- share/extensions/hpgl_decoder.py | 3 +-- share/extensions/hpgl_encoder.py | 58 ++++++++++++++++++---------------------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 802f6d0e4..cb8079e6b 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -91,10 +91,9 @@ class hpglDecoder: self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing Pen ' + layerNumber}) def addPathToLayer(self, path, layerNumber): + lineColor = '000000' if layerNumber == 0: lineColor = 'ff0000' - else: - lineColor = '000000' inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d':path, 'style':'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) def getParameters(self, parameterString): # process coordinates diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 58935e8fb..4e642e4a2 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -174,33 +174,27 @@ class hpglEncoder: oldPosX = posX oldPosY = posY - def getLength(self, x1, y1, x2, y2, absolute = True): - # calc absoulute or relative length between two points - if absolute: return math.fabs(math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)) - else: return math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) + def getLength(self, x1, y1, x2, y2, absolute = True): # calc absoulute or relative length between two points + length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) + if absolute: + length = math.fabs(length) + return length - def changeLength(self, x1, y1, x2, y2, offset): - # change length of line + def changeLength(self, x1, y1, x2, y2, offset): # change length of line if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; return [x, y] - def getAlpha(self, x1, y1, x2, y2, x3, y3): - # get alpha of point 2 + def getAlpha(self, x1, y1, x2, y2, x3, y3): # get alpha of point 2 temp1 = (x1-x2)**2 + (y1-y2)**2 + (x3-x2)**2 + (y3-y2)**2 - (x1-x3)**2 - (y1-y3)**2 temp2 = 2 * math.sqrt((x1-x2)**2 + (y1-y2)**2) * math.sqrt((x3-x2)**2 + (y3-y2)**2) - temp3 = temp1 / temp2 - if temp3 < -1.0: - temp3 = -1.0 - if temp3 > 1.0: - temp3 = 1.0 - return math.acos(temp3) + return math.acos(max(min(temp1 / temp2, 1.0), -1.0)) def calcOffset(self, cmd, posX, posY): # calculate offset correction (or dont) if not self.options.useToolOffset or self.dryRun: - self.storeData(cmd, posX, posY) + self.storePoint(cmd, posX, posY) else: # insert data into cache self.vData.pop(0) @@ -208,48 +202,48 @@ class hpglEncoder: # decide if enough data is availabe if self.vData[2][1] != -1.0: if self.vData[1][1] == -1.0: - self.storeData(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2]) else: # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - self.storeData('PD', pointThree[0], pointThree[1]) + self.storePoint('PD', pointThree[0], pointThree[1]) elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift the 3rd entry by the current tool offset position according to the 2nd command pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset) pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) - self.storeData('PU', pointThree[0], pointThree[1]) + self.storePoint('PU', pointThree[0], pointThree[1]) else: # Else just write the 3rd entry pointThree = [self.vData[2][1], self.vData[2][2]] - self.storeData('PU', pointThree[0], pointThree[1]) + self.storePoint('PU', pointThree[0], pointThree[1]) if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) else: pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) - # get start and end angle + # get angle start and angle vector angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) - angleDiff = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart + angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart # switch direction when arc is bigger than 180° - if angleDiff > self.PI: - angleDiff -= self.TWO_PI - elif angleDiff < -self.PI: - angleDiff += self.TWO_PI + if angleVector > self.PI: + angleVector -= self.TWO_PI + elif angleVector < -self.PI: + angleVector += self.TWO_PI # draw arc - if angleDiff >= 0: + if angleVector >= 0: angle = angleStart + self.toolOffsetFlat - while angle < angleStart + angleDiff: - self.storeData('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + while angle < angleStart + angleVector: + self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) angle += self.toolOffsetFlat else: angle = angleStart - self.toolOffsetFlat - while angle > angleStart + angleDiff: - self.storeData('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + while angle > angleStart + angleVector: + self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) angle -= self.toolOffsetFlat - self.storeData('PD', pointFour[0], pointFour[1]) + self.storePoint('PD', pointFour[0], pointFour[1]) - def storeData(self, command, x, y): + def storePoint(self, command, x, y): x = int(round(x)) y = int(round(y)) # skip when no change in movement -- cgit v1.2.3 From 27839ab6126ade297f3e0f79f2dfa36de7964bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 26 Oct 2013 22:29:08 +0200 Subject: small changes (mainly text) (bzr r12417.1.29) --- share/extensions/hpgl_encoder.py | 2 ++ share/extensions/hpgl_input.inx | 2 +- share/extensions/hpgl_output.inx | 11 +++++----- share/extensions/plotter.inx | 45 ++++++++++++++++++++-------------------- share/extensions/plotter.py | 2 +- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 4e642e4a2..435ee2faa 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -145,6 +145,7 @@ class hpglEncoder: # path to HPGL commands oldPosX = '' oldPosY = '' + # TODO: Plot smallest parts first to avid plotter dragging parts of foil around (on text) for singlePath in paths: cmd = 'PU' for singlePathPoint in singlePath: @@ -156,6 +157,7 @@ class hpglEncoder: oldPosX = posX oldPosY = posY # perform overcut + # TODO: Find that evasive bug that produces an extra point between the end of the path and the overcut if self.options.useOvercut and not self.dryRun: # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])): diff --git a/share/extensions/hpgl_input.inx b/share/extensions/hpgl_input.inx index be0a0e943..d8c33713f 100644 --- a/share/extensions/hpgl_input.inx +++ b/share/extensions/hpgl_input.inx @@ -6,7 +6,7 @@ hpgl_decoder.py inkex.py <_param name="introduction" type="description">Please note that you can only open HPGL files written by Inkscape, to open other HPGL files please change their file extension to .plt, make sure you have UniConverter installed and open them again. -   +   1016.0 1016.0 false diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx index d5cc37d33..7f8705996 100644 --- a/share/extensions/hpgl_output.inx +++ b/share/extensions/hpgl_output.inx @@ -14,7 +14,7 @@ 1016.0 false false - + @@ -22,16 +22,15 @@ false - + true 1.00 - - +   true 0.25 true -   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset. +   + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the length in mm specified by the tool offset. 1.2 diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index f22df3380..6aba009cf 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -8,20 +8,6 @@ inkex.py <_param name="introduction" type="description">Please make sure that all objects you want to plot are converted to paths. The plot will automatically be aligned to the zero point. - - 1 - 1016.0 - 1016.0 - false - false - - - - - - - false - COM1 @@ -41,25 +27,38 @@ - - - + + + -   +   <_param name="serialHelp" type="description">This can be a physical serial connection or a USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. <_param name="parallelHelp" type="description">Please note that Parallel (LPT) connections are not supported. <_param name="hpglNote" type="description">Please note that only the HPGL command language is supported at the moment. - + + 1 + 1016.0 + 1016.0 + false + false + + + + + + + false + + true 1.00 - - +   true 0.25 true -   - <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the tool offset. +   + <_param name="offsetNote" type="description">Please note that using the tool offset correction will move your plot away from the zero point by the length in mm specified by the tool offset. 1.2 diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index d93cf0783..c888bd51e 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [...]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter # TODO: Slow down sending to prevent buffer overflow on plotter side (should be investigated first) if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, rtscts=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, dsrdtr=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=None, xonxoff=True) mySerial.write(self.hpgl) # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [Program files]/inkscape/python/Lib/" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 41dcf1ea9364fe4edc14c08a08b65707f72068fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 27 Oct 2013 14:09:57 +0100 Subject: text change (bzr r12417.1.30) --- share/extensions/plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index c888bd51e..5f3ceaea0 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: [Program files]/inkscape/python/Lib/" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self.document.getroot(), self.options) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 75681d0c8c5d5d4929d03d960ef95a8db913c493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Mon, 28 Oct 2013 18:30:45 +0100 Subject: be more specific for pyserial download (bzr r12417.1.32) --- share/extensions/plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 737e389c4..c9dd2d7ff 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here: http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here (not the \".exe\"): http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From 9d4d82ce94c327033bce64c289648c8f7b84c5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sat, 2 Nov 2013 22:52:43 +0100 Subject: text changes (bzr r12417.1.33) --- share/extensions/hpgl_decoder.py | 1 - share/extensions/plotter.inx | 6 +++--- share/extensions/plotter.py | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index cb8079e6b..08009a31c 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -2,7 +2,6 @@ # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ -This importer supports HP-GL commands only. 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 diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx index 6aba009cf..b950e0246 100644 --- a/share/extensions/plotter.inx +++ b/share/extensions/plotter.inx @@ -26,10 +26,10 @@ - + - - + +   <_param name="serialHelp" type="description">This can be a physical serial connection or a USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed. diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index c9dd2d7ff..29ad2d177 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here (not the \".exe\"): http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() # TODO: Materialvorschub nach plot, rechtecke plotten class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here (not the \".exe\"): http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From a1a79d1ce4108f7bb462253d8c100f642cf8dcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 3 Nov 2013 01:23:14 +0100 Subject: better PEP 8 compatibility (bzr r12417.1.34) --- share/extensions/hpgl_decoder.py | 213 +++++++-------- share/extensions/hpgl_encoder.py | 560 ++++++++++++++++++++------------------- share/extensions/hpgl_input.inx | 2 +- share/extensions/hpgl_input.py | 12 +- share/extensions/hpgl_output.py | 15 +- share/extensions/plotter.py | 125 ++++++++- 6 files changed, 533 insertions(+), 394 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 08009a31c..88c4a9a95 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -1,107 +1,108 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -''' - -# standard library -from StringIO import StringIO -import math -# local library -import inkex - - -class hpglDecoder: - def __init__(self, hpglString, options): - ''' options: - "resolutionX":float - "resolutionY":float - "showMovements":bool - ''' - self.hpglString = hpglString - self.options = options - self.scaleX = options.resolutionX / 90.0 # dots/inch to dots/pixels - self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels - self.warnings = [] - - def getSvg(self): # parse hpgl data - # prepare document - self.doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) - actualLayer = 0; - self.layers = {} - if self.options.showMovements: - self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Movements'}) - # parse paths - hpglData = self.hpglString.split(';') - if len(hpglData) < 3: - raise Exception('NO_HPGL_DATA') - oldCoordinates = (0.0, self.options.docHeight) - path = '' - for i, command in enumerate(hpglData): - if command.strip() != '': - if command[:2] == 'IN': # if Initialize command, ignore - pass - elif command[:2] == 'SP': # if Select Pen command - actualLayer = command[2:] - self.createLayer(actualLayer) - elif command[:2] == 'PU': # if Pen Up command - if ' L ' in path: - self.addPathToLayer(path, actualLayer) - if self.options.showMovements and i != len(hpglData) - 1: - path = 'M %f,%f' % oldCoordinates - path += ' L %f,%f' % self.getParameters(command[2:]) - self.addPathToLayer(path, 0) - path = 'M %f,%f' % self.getParameters(command[2:]) - oldCoordinates = self.getParameters(command[2:]) - elif command[:2] == 'PD': # if Pen Down command - parameterString = command[2:] - if parameterString.strip() != '': - parameterString = parameterString.replace(';', '').strip() - parameter = parameterString.split(',') - oldCoordinates = (float(parameter[-2]) / self.scaleX, self.options.docHeight - float(parameter[-1]) / self.scaleX) - for i, param in enumerate(parameter): - if i % 2 == 0: - parameter[i] = str(float(param) / self.scaleX) - else: - parameter[i] = str(self.options.docHeight - float(param) / self.scaleY) - parameterString = ','.join(parameter) - path += ' L %s' % parameterString - else: - self.warnings.append('UNKNOWN_COMMANDS') - if ' L ' in path: - self.addPathToLayer(path, actualLayer) - return (self.doc, self.warnings) - - def createLayer(self, layerNumber): - self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode','inkscape'):'layer', inkex.addNS('label','inkscape'):'Drawing Pen ' + layerNumber}) - - def addPathToLayer(self, path, layerNumber): - lineColor = '000000' - if layerNumber == 0: - lineColor = 'ff0000' - inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d':path, 'style':'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) - - def getParameters(self, parameterString): # process coordinates - if parameterString.strip() == '': - return [] - # remove command delimiter - parameterString = parameterString.replace(';', '').strip() - # split parameter - parameter = parameterString.split(',') - return (float(parameter[0]) / self.scaleX, self.options.docHeight - float(parameter[1]) / self.scaleY) # convert to svg coordinate system - +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard libraries +from StringIO import StringIO +import math +# local library +import inkex + + +class hpglDecoder: + + def __init__(self, hpglString, options): + ''' options: + "resolutionX":float + "resolutionY":float + "showMovements":bool + ''' + self.hpglString = hpglString + self.options = options + self.scaleX = options.resolutionX / 90.0 # dots/inch to dots/pixels + self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels + self.warnings = [] + + def getSvg(self): # parse hpgl data + # prepare document + self.doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) + actualLayer = 0 + self.layers = {} + if self.options.showMovements: + self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): 'Movements'}) + # parse paths + hpglData = self.hpglString.split(';') + if len(hpglData) < 3: + raise Exception('NO_HPGL_DATA') + oldCoordinates = (0.0, self.options.docHeight) + path = '' + for i, command in enumerate(hpglData): + if command.strip() != '': + if command[:2] == 'IN': # if Initialize command, ignore + pass + elif command[:2] == 'SP': # if Select Pen command + actualLayer = command[2:] + self.createLayer(actualLayer) + elif command[:2] == 'PU': # if Pen Up command + if ' L ' in path: + self.addPathToLayer(path, actualLayer) + if self.options.showMovements and i != len(hpglData) - 1: + path = 'M %f,%f' % oldCoordinates + path += ' L %f,%f' % self.getParameters(command[2:]) + self.addPathToLayer(path, 0) + path = 'M %f,%f' % self.getParameters(command[2:]) + oldCoordinates = self.getParameters(command[2:]) + elif command[:2] == 'PD': # if Pen Down command + parameterString = command[2:] + if parameterString.strip() != '': + parameterString = parameterString.replace(';', '').strip() + parameter = parameterString.split(',') + oldCoordinates = (float(parameter[-2]) / self.scaleX, self.options.docHeight - float(parameter[-1]) / self.scaleX) + for i, param in enumerate(parameter): + if i % 2 == 0: + parameter[i] = str(float(param) / self.scaleX) + else: + parameter[i] = str(self.options.docHeight - float(param) / self.scaleY) + parameterString = ','.join(parameter) + path += ' L %s' % parameterString + else: + self.warnings.append('UNKNOWN_COMMANDS') + if ' L ' in path: + self.addPathToLayer(path, actualLayer) + return (self.doc, self.warnings) + + def createLayer(self, layerNumber): + self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): 'Drawing Pen ' + layerNumber}) + + def addPathToLayer(self, path, layerNumber): + lineColor = '000000' + if layerNumber == 0: + lineColor = 'ff0000' + inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d': path, 'style': 'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) + + def getParameters(self, parameterString): # process coordinates + if parameterString.strip() == '': + return [] + # remove command delimiter + parameterString = parameterString.replace(';', '').strip() + # split parameter + parameter = parameterString.split(',') + return (float(parameter[0]) / self.scaleX, self.options.docHeight - float(parameter[1]) / self.scaleY) # convert to svg coordinate system + # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 42fa9aaec..35d9300fb 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -1,275 +1,287 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2008 Aaron Spike, aaron@ekips.org -Overcut, Tool Offset, Rotation, Serial Com., Many Bugfixes and Improvements: Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -''' - -# standard library -import math, string -# local library -import bezmisc, cspsubdiv, cubicsuperpath, inkex, simplestyle, simpletransform - - -class hpglEncoder: - - PI = math.pi - TWO_PI = PI * 2 - - def __init__(self, effect): - ''' options: - "resolutionX":float - "resolutionY":float - "pen":int - "orientation":string // "0", "90", "-90", "180" - "mirrorX":bool - "mirrorY":bool - "center":bool - "flat":float - "useOvercut":bool - "overcut":float - "useToolOffset":bool - "toolOffset":float - "precut":bool - "offsetX":float - "offsetY":float - ''' - self.doc = effect.document.getroot() - self.options = effect.options - self.divergenceX = 'False' # dirty hack: i need to know if this was set to a number before, but since False is evaluated to 0 it can not be determined, therefore the string. - self.divergenceY = 'False' - self.sizeX = 'False' - self.sizeY = 'False' - self.dryRun = True - self.lastPoint = [0, 0, 0] - self.scaleX = self.options.resolutionX / 90 # inch to pixels - self.scaleY = self.options.resolutionY / 90 # inch to pixels - self.options.offsetX = self.options.offsetX * 3.5433070866 * self.scaleX # mm to dots (plotter coordinate system) - self.options.offsetY = self.options.offsetY * 3.5433070866 * self.scaleY # mm to dots - self.options.overcut = self.options.overcut * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots - self.options.toolOffset = self.options.toolOffset * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots - self.options.flat = ((self.options.resolutionX + self.options.resolutionY) / 2) * self.options.flat / 1000 # scale flatness to resolution - self.toolOffsetFlat = self.options.flat / self.options.toolOffset * 4.5 # scale flatness to offset - self.mirrorX = 1.0 - if self.options.mirrorX: - self.mirrorX = -1.0 - self.mirrorY = -1.0 - if self.options.mirrorY: - self.mirrorY = 1.0 - # process viewBox attribute to correct page scaling - viewBox = self.doc.get('viewBox') - self.viewBoxTransformX = 1 - self.viewBoxTransformY = 1 - if viewBox: - viewBox = string.split(viewBox, ' ') - if viewBox[2] and viewBox[3]: - self.viewBoxTransformX = float(effect.unittouu(self.doc.get('width'))) / float(viewBox[2]) - self.viewBoxTransformY = float(effect.unittouu(self.doc.get('height'))) / float(viewBox[3]) - - def getHpgl(self): - # dryRun to find edges - self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]] - self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) - self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] - self.process_group(self.doc, self.groupmat) - if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': - raise Exception('NO_PATHS') - # live run - self.dryRun = False - if self.options.center: - self.divergenceX += (self.sizeX - self.divergenceX) / 2 - self.divergenceY += (self.sizeY - self.divergenceY) / 2 - elif self.options.useToolOffset: - self.options.offsetX += self.options.toolOffset - self.options.offsetY += self.options.toolOffset - self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, -self.divergenceX + self.options.offsetX], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, -self.divergenceY + self.options.offsetY]]] - self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) - self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] - # store first hpgl commands - self.hpgl = 'IN;SP%d' % self.options.pen - # add precut - if self.options.useToolOffset and self.options.precut: - self.calcOffset('PU', 0, 0) - self.calcOffset('PD', 0, self.options.toolOffset * 8) - # start conversion - self.process_group(self.doc, self.groupmat) - # shift an empty node in in order to process last node in cache - self.calcOffset('PU', 0, 0) - # add return to zero point - self.hpgl += ';PU0,0;' - return self.hpgl - - def process_group(self, group, groupmat): - # process groups - style = group.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('display'): - if style['display'] == 'none': - return - trans = group.get('transform') - if trans: - groupmat.append(simpletransform.composeTransform(groupmat[-1], simpletransform.parseTransform(trans))) - for node in group: - if node.tag == inkex.addNS('path', 'svg'): - self.process_path(node, groupmat[-1]) - if node.tag == inkex.addNS('g', 'svg'): - self.process_group(node, groupmat) - if trans: - groupmat.pop() - - def process_path(self, node, mat): - # process path - drawing = node.get('d') - if drawing: - # transform path - paths = cubicsuperpath.parsePath(drawing) - trans = node.get('transform') - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - simpletransform.applyTransformToPath(mat, paths) - cspsubdiv.cspsubdiv(paths, self.options.flat) - # path to HPGL commands - oldPosX = '' - oldPosY = '' - # TODO: Plot smallest parts first to avid plotter dragging parts of foil around (on text) - for singlePath in paths: - cmd = 'PU' - for singlePathPoint in singlePath: - posX, posY = singlePathPoint[1] - # check if point is repeating, if so, ignore - if posX != oldPosX or posY != oldPosY: - self.calcOffset(cmd, posX, posY) - cmd = 'PD' - oldPosX = posX - oldPosY = posY - # perform overcut - # TODO: Find that evasive bug that produces an extra point between the end of the path and the overcut - if self.options.useOvercut and not self.dryRun: - # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed - if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])): - overcutLength = 0 - for singlePathPoint in singlePath: - posX, posY = singlePathPoint[1] - # check if point is repeating, if so, ignore - if posX != oldPosX or posY != oldPosY: - overcutLength += self.getLength(oldPosX, oldPosY, posX, posY) - if overcutLength >= self.options.overcut: - newLength = self.changeLength(oldPosX, oldPosY, posX, posY, -(overcutLength - self.options.overcut)); - self.calcOffset(cmd, newLength[0], newLength[1]) - break - else: - self.calcOffset(cmd, posX, posY) - oldPosX = posX - oldPosY = posY - - def getLength(self, x1, y1, x2, y2, absolute = True): # calc absoulute or relative length between two points - length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) - if absolute: - length = math.fabs(length) - return length - - def changeLength(self, x1, y1, x2, y2, offset): # change length of line - if offset < 0: offset = max(-self.getLength(x1, y1, x2, y2), offset) - x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset; - y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset; - return [x, y] - - def getAlpha(self, x1, y1, x2, y2, x3, y3): # get alpha of point 2 - temp1 = (x1-x2)**2 + (y1-y2)**2 + (x3-x2)**2 + (y3-y2)**2 - (x1-x3)**2 - (y1-y3)**2 - temp2 = 2 * math.sqrt((x1-x2)**2 + (y1-y2)**2) * math.sqrt((x3-x2)**2 + (y3-y2)**2) - return math.acos(max(min(temp1 / temp2, 1.0), -1.0)) - - def calcOffset(self, cmd, posX, posY): - # calculate offset correction (or dont) - if not self.options.useToolOffset or self.dryRun: - self.storePoint(cmd, posX, posY) - else: - # insert data into cache - self.vData.pop(0) - self.vData.insert(3, [cmd, posX, posY]) - # decide if enough data is availabe - if self.vData[2][1] != -1.0: - if self.vData[1][1] == -1.0: - self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2]) - else: - # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) - if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset - pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) - self.storePoint('PD', pointThree[0], pointThree[1]) - elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift the 3rd entry by the current tool offset position according to the 2nd command - pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset) - pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) - pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) - self.storePoint('PU', pointThree[0], pointThree[1]) - else: # Else just write the 3rd entry - pointThree = [self.vData[2][1], self.vData[2][2]] - self.storePoint('PU', pointThree[0], pointThree[1]) - if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry - if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: - pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], -self.options.toolOffset) - else: - pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], - (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) - # get angle start and angle vector - angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) - angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart - # switch direction when arc is bigger than 180° - if angleVector > self.PI: - angleVector -= self.TWO_PI - elif angleVector < -self.PI: - angleVector += self.TWO_PI - # draw arc - if angleVector >= 0: - angle = angleStart + self.toolOffsetFlat - while angle < angleStart + angleVector: - self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) - angle += self.toolOffsetFlat - else: - angle = angleStart - self.toolOffsetFlat - while angle > angleStart + angleVector: - self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) - angle -= self.toolOffsetFlat - self.storePoint('PD', pointFour[0], pointFour[1]) - - def storePoint(self, command, x, y): - x = int(round(x)) - y = int(round(y)) - # skip when no change in movement - if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y: - return - if self.dryRun: - # find edges - if self.divergenceX == 'False' or x < self.divergenceX: self.divergenceX = x - if self.divergenceY == 'False' or y < self.divergenceY: self.divergenceY = y - if self.sizeX == 'False' or x > self.sizeX: self.sizeX = x - if self.sizeY == 'False' or y > self.sizeY: self.sizeY = y - else: - # store point - if not self.options.center: - if x < 0: x = 0 # only positive values are allowed (usually) - if y < 0: y = 0 - # do not repeat command - if command == 'PD' and self.lastPoint[0] == 'PD': - self.hpgl += ',%d,%d' % (x, y) - else: - self.hpgl += ';%s%d,%d' % (command, x, y) - self.lastPoint[0] = command - self.lastPoint[1] = x - self.lastPoint[2] = y - +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2008 Aaron Spike, aaron@ekips.org +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard libraries +import math +import string +# local libraries +import bezmisc +import cspsubdiv +import cubicsuperpath +import inkex +import simplestyle +import simpletransform + + +class hpglEncoder: + PI = math.pi + TWO_PI = PI * 2 + + def __init__(self, effect): + ''' options: + "resolutionX":float + "resolutionY":float + "pen":int + "orientation":string // "0", "90", "-90", "180" + "mirrorX":bool + "mirrorY":bool + "center":bool + "flat":float + "useOvercut":bool + "overcut":float + "useToolOffset":bool + "toolOffset":float + "precut":bool + "offsetX":float + "offsetY":float + ''' + self.doc = effect.document.getroot() + self.options = effect.options + self.divergenceX = 'False' # dirty hack: i need to know if this was set to a number before, but since False is evaluated to 0 it can not be determined, therefore the string. + self.divergenceY = 'False' + self.sizeX = 'False' + self.sizeY = 'False' + self.dryRun = True + self.lastPoint = [0, 0, 0] + self.scaleX = self.options.resolutionX / 90 # inch to pixels + self.scaleY = self.options.resolutionY / 90 # inch to pixels + self.options.offsetX = self.options.offsetX * 3.5433070866 * self.scaleX # mm to dots (plotter coordinate system) + self.options.offsetY = self.options.offsetY * 3.5433070866 * self.scaleY # mm to dots + self.options.overcut = self.options.overcut * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots + self.options.toolOffset = self.options.toolOffset * 3.5433070866 * ((self.scaleX + self.scaleY) / 2) # mm to dots + self.options.flat = ((self.options.resolutionX + self.options.resolutionY) / 2) * self.options.flat / 1000 # scale flatness to resolution + self.toolOffsetFlat = self.options.flat / self.options.toolOffset * 4.5 # scale flatness to offset + self.mirrorX = 1.0 + if self.options.mirrorX: + self.mirrorX = -1.0 + self.mirrorY = -1.0 + if self.options.mirrorY: + self.mirrorY = 1.0 + # process viewBox attribute to correct page scaling + viewBox = self.doc.get('viewBox') + self.viewBoxTransformX = 1 + self.viewBoxTransformY = 1 + if viewBox: + viewBox = string.split(viewBox, ' ') + if viewBox[2] and viewBox[3]: + self.viewBoxTransformX = float(effect.unittouu(self.doc.get('width'))) / float(viewBox[2]) + self.viewBoxTransformY = float(effect.unittouu(self.doc.get('height'))) / float(viewBox[3]) + + def getHpgl(self): + # dryRun to find edges + self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]] + self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) + self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] + self.process_group(self.doc, self.groupmat) + if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': + raise Exception('NO_PATHS') + # live run + self.dryRun = False + if self.options.center: + self.divergenceX += (self.sizeX - self.divergenceX) / 2 + self.divergenceY += (self.sizeY - self.divergenceY) / 2 + elif self.options.useToolOffset: + self.options.offsetX += self.options.toolOffset + self.options.offsetY += self.options.toolOffset + self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, - self.divergenceX + self.options.offsetX], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, - self.divergenceY + self.options.offsetY]]] + self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) + self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] + # store first hpgl commands + self.hpgl = 'IN;SP%d' % self.options.pen + # add precut + if self.options.useToolOffset and self.options.precut: + self.calcOffset('PU', 0, 0) + self.calcOffset('PD', 0, self.options.toolOffset * 8) + # start conversion + self.process_group(self.doc, self.groupmat) + # shift an empty node in in order to process last node in cache + self.calcOffset('PU', 0, 0) + # add return to zero point + self.hpgl += ';PU0,0;' + return self.hpgl + + def process_group(self, group, groupmat): + # process groups + style = group.get('style') + if style: + style = simplestyle.parseStyle(style) + if style.has_key('display'): + if style['display'] == 'none': + return + trans = group.get('transform') + if trans: + groupmat.append(simpletransform.composeTransform(groupmat[-1], simpletransform.parseTransform(trans))) + for node in group: + if node.tag == inkex.addNS('path', 'svg'): + self.process_path(node, groupmat[-1]) + if node.tag == inkex.addNS('g', 'svg'): + self.process_group(node, groupmat) + if trans: + groupmat.pop() + + def process_path(self, node, mat): + # process path + drawing = node.get('d') + if drawing: + # transform path + paths = cubicsuperpath.parsePath(drawing) + trans = node.get('transform') + if trans: + mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) + simpletransform.applyTransformToPath(mat, paths) + cspsubdiv.cspsubdiv(paths, self.options.flat) + # path to HPGL commands + oldPosX = '' + oldPosY = '' + # TODO: Plot smallest parts first to avid plotter dragging parts of foil around (on text) + for singlePath in paths: + cmd = 'PU' + for singlePathPoint in singlePath: + posX, posY = singlePathPoint[1] + # check if point is repeating, if so, ignore + if posX != oldPosX or posY != oldPosY: + self.calcOffset(cmd, posX, posY) + cmd = 'PD' + oldPosX = posX + oldPosY = posY + # perform overcut + # TODO: Find that evasive bug that produces an extra point between the end of the path and the overcut + if self.options.useOvercut and not self.dryRun: + # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed + if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])): + overcutLength = 0 + for singlePathPoint in singlePath: + posX, posY = singlePathPoint[1] + # check if point is repeating, if so, ignore + if posX != oldPosX or posY != oldPosY: + overcutLength += self.getLength(oldPosX, oldPosY, posX, posY) + if overcutLength >= self.options.overcut: + newLength = self.changeLength(oldPosX, oldPosY, posX, posY, - (overcutLength - self.options.overcut)) + self.calcOffset(cmd, newLength[0], newLength[1]) + break + else: + self.calcOffset(cmd, posX, posY) + oldPosX = posX + oldPosY = posY + + def getLength(self, x1, y1, x2, y2, absolute=True): # calc absoulute or relative length between two points + length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) + if absolute: + length = math.fabs(length) + return length + + def changeLength(self, x1, y1, x2, y2, offset): # change length of line + if offset < 0: + offset = max( - self.getLength(x1, y1, x2, y2), offset) + x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset + y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset + return [x, y] + + def getAlpha(self, x1, y1, x2, y2, x3, y3): # get alpha of point 2 + temp1 = (x1 - x2) ** 2 + (y1 - y2) ** 2 + (x3 - x2) ** 2 + (y3 - y2) ** 2 - (x1 - x3) ** 2 - (y1 - y3) ** 2 + temp2 = 2 * math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) * math.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2) + return math.acos(max(min(temp1 / temp2, 1.0), -1.0)) + + def calcOffset(self, cmd, posX, posY): + # calculate offset correction (or dont) + if not self.options.useToolOffset or self.dryRun: + self.storePoint(cmd, posX, posY) + else: + # insert data into cache + self.vData.pop(0) + self.vData.insert(3, [cmd, posX, posY]) + # decide if enough data is availabe + if self.vData[2][1] != -1.0: + if self.vData[1][1] == -1.0: + self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2]) + else: + # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) + if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset + pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) + self.storePoint('PD', pointThree[0], pointThree[1]) + elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift the 3rd entry by the current tool offset position according to the 2nd command + pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset) + pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) + pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) + self.storePoint('PU', pointThree[0], pointThree[1]) + else: # Else just write the 3rd entry + pointThree = [self.vData[2][1], self.vData[2][2]] + self.storePoint('PU', pointThree[0], pointThree[1]) + if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry + if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: + pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.options.toolOffset) + else: + pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], + (self.options.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) + # get angle start and angle vector + angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) + angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart + # switch direction when arc is bigger than 180° + if angleVector > self.PI: + angleVector -= self.TWO_PI + elif angleVector < - self.PI: + angleVector += self.TWO_PI + # draw arc + if angleVector >= 0: + angle = angleStart + self.toolOffsetFlat + while angle < angleStart + angleVector: + self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + angle += self.toolOffsetFlat + else: + angle = angleStart - self.toolOffsetFlat + while angle > angleStart + angleVector: + self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.options.toolOffset, self.vData[2][2] + math.sin(angle) * self.options.toolOffset) + angle -= self.toolOffsetFlat + self.storePoint('PD', pointFour[0], pointFour[1]) + + def storePoint(self, command, x, y): + x = int(round(x)) + y = int(round(y)) + # skip when no change in movement + if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y: + return + if self.dryRun: + # find edges + if self.divergenceX == 'False' or x < self.divergenceX: + self.divergenceX = x + if self.divergenceY == 'False' or y < self.divergenceY: + self.divergenceY = y + if self.sizeX == 'False' or x > self.sizeX: + self.sizeX = x + if self.sizeY == 'False' or y > self.sizeY: + self.sizeY = y + else: + # store point + if not self.options.center: + if x < 0: + x = 0 # only positive values are allowed (usually) + if y < 0: + y = 0 + # do not repeat command + if command == 'PD' and self.lastPoint[0] == 'PD': + self.hpgl += ',%d,%d' % (x, y) + else: + self.hpgl += ';%s%d,%d' % (command, x, y) + self.lastPoint[0] = command + self.lastPoint[1] = x + self.lastPoint[2] = y + # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_input.inx b/share/extensions/hpgl_input.inx index d8c33713f..69711d85a 100644 --- a/share/extensions/hpgl_input.inx +++ b/share/extensions/hpgl_input.inx @@ -9,7 +9,7 @@   1016.0 1016.0 - false + false .hpgl image/hpgl diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index e841e1138..bf99a5e72 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding=utf-8 ''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de 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 @@ -18,11 +18,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' -# standard library +# standard libraries import sys from StringIO import StringIO -# local library -import hpgl_decoder, inkex, sys +# local libraries +import hpgl_decoder +import inkex +import sys inkex.localize() @@ -53,7 +55,7 @@ try: # issue warning if unknown commands where found if 'UNKNOWN_COMMANDS' in warnings: inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) - # deliver document to inkscape + # deliver document to inkscape doc.write(inkex.sys.stdout) except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 68d3ab9d7..16a656856 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python # coding=utf-8 ''' -Copyright (C) 2008 Aaron Spike, aaron@ekips.org -Overcut, Tool Offset, Rotation, Serial Com., Many Bugfixes and Improvements: Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.com/ +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de 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 @@ -21,12 +20,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # standard library import sys -# local library -import hpgl_encoder, inkex +# local libraries +import hpgl_encoder +import inkex inkex.localize() class MyEffect(inkex.Effect): + def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') @@ -45,7 +46,7 @@ class MyEffect(inkex.Effect): self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') - + def effect(self): # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) @@ -66,7 +67,7 @@ class MyEffect(inkex.Effect): if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents - sys.setrecursionlimit(20000); + sys.setrecursionlimit(20000) # start extension e = MyEffect() e.affect() diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 29ad2d177..d0d42c671 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -1 +1,124 @@ -#!/usr/bin/env python # coding=utf-8 ''' Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de, http://www.timewasters-place.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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' # standard library import sys # local library import gettext, hpgl_decoder, hpgl_encoder, inkex inkex.localize() # TODO: Materialvorschub nach plot, rechtecke plotten class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') def effect(self): # gracefully exit script when pySerial is missing try: import serial except ImportError, e: inkex.errormsg(_("pySerial is not installed." + "\n\n1. Download pySerial here (not the \".exe\"): http://pypi.python.org/pypi/pyserial" + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + "\n3. Restart Inkscape.")) return # TODO: Maybe implement DMPL? # get hpgl data myHpglEncoder = hpgl_encoder.hpglEncoder(self) try: self.hpgl = myHpglEncoder.getHpgl() except Exception as inst: if inst.args[0] == 'NO_PATHS': # issue error if no paths found inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) return 1 else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) try: doc, warnings = myHpglDecoder.getSvg() # deliver document to inkscape self.document = doc except Exception as inst: if inst.args[0] == 'NO_HPGL_DATA': # do nothing pass else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback ''' # send data to plotter if self.options.flowControl == '1': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) elif self.options.flowControl == '2': mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) else: mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) try: mySerial.write(self.hpgl) except Exception as inst: if inst.args[0] == 'Write timeout': inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) mySerial.read(2) mySerial.close() if __name__ == '__main__': # Raise recursion limit to avoid exceptions on big documents sys.setrecursionlimit(20000); # start extension e = MyEffect() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file +#!/usr/bin/env python +# coding=utf-8 +''' +Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +# standard library +import sys +# local libraries +import gettext +import hpgl_decoder +import hpgl_encoder +import inkex +inkex.localize() + + +# TODO: Materialvorschub nach plot, rechtecke plotten +class MyEffect(inkex.Effect): + + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') + self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') + self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') + self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') + self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='orientation') + self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X-axis') + self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y-axis') + self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') + self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') + self.OptionParser.add_option('--useOvercut', action='store', type='inkbool', dest='useOvercut', default='TRUE', help='Use overcut') + self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') + self.OptionParser.add_option('--useToolOffset', action='store', type='inkbool', dest='useToolOffset', default='TRUE', help='Correct tool offset') + self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool offset (mm)') + self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') + self.OptionParser.add_option('--offsetX', action='store', type='float', dest='offsetX', default=0.0, help='X offset (mm)') + self.OptionParser.add_option('--offsetY', action='store', type='float', dest='offsetY', default=0.0, help='Y offset (mm)') + self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') + self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') + self.OptionParser.add_option('--flowControl', action='store', type='string', dest='flowControl', default='0', help='Flow control') + + def effect(self): + # gracefully exit script when pySerial is missing + try: + import serial + except ImportError, e: + inkex.errormsg(_("pySerial is not installed." + + "\n\n1. Download pySerial here (not the \".exe\"): http://pypi.python.org/pypi/pyserial" + + "\n2. Extract the \"serial\" subfolder from the zip to the following folder: C:\\[Program files]\\inkscape\\python\\Lib\\" + + "\n3. Restart Inkscape.")) + return + # TODO: Maybe implement DMPL? + # get hpgl data + myHpglEncoder = hpgl_encoder.hpglEncoder(self) + try: + self.hpgl = myHpglEncoder.getHpgl() + except Exception as inst: + if inst.args[0] == 'NO_PATHS': + # issue error if no paths found + inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) + return 1 + else: + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback + # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) + ''' + # reparse data for preview + self.options.showMovements = True + self.options.docWidth = float(inkex.unittouu(self.document.getroot().get('width'))) + self.options.docHeight = float(inkex.unittouu(self.document.getroot().get('height'))) + myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) + try: + doc, warnings = myHpglDecoder.getSvg() + # deliver document to inkscape + self.document = doc + except Exception as inst: + if inst.args[0] == 'NO_HPGL_DATA': + # do nothing + pass + else: + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback + ''' + # send data to plotter + if self.options.flowControl == '1': + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, xonxoff=True) + elif self.options.flowControl == '2': + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10, dsrdtr=None, rtscts=True) + else: + mySerial = serial.Serial(port=self.options.serialPort, baudrate=self.options.serialBaudRate, timeout=0.1, writeTimeout=10) + try: + mySerial.write(self.hpgl) + except Exception as inst: + if inst.args[0] == 'Write timeout': + inkex.errormsg(_("Could not send data. Please check that your plotter is running, connected and the settings are correct.")) + else: + type, value, traceback = sys.exc_info() + raise ValueError, ("", type, value), traceback + # Read back 2 chars to avoid plotter not plotting last command (I have no idea why this is necessary) + mySerial.read(2) + mySerial.close() + +if __name__ == '__main__': + # Raise recursion limit to avoid exceptions on big documents + sys.setrecursionlimit(20000) + # start extension + e = MyEffect() + e.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file -- cgit v1.2.3 From fac095aac7e613ac44076d7a45ab71a8771a04c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 3 Nov 2013 02:11:28 +0100 Subject: a 'bit' shorter lines (bzr r12417.1.35) --- share/extensions/hpgl_decoder.py | 27 ++++++++++++++++++--------- share/extensions/hpgl_encoder.py | 31 +++++++++++++++++++------------ share/extensions/plotter.py | 3 ++- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 88c4a9a95..1b6106430 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -39,9 +39,11 @@ class hpglDecoder: self.scaleY = options.resolutionY / 90.0 # dots/inch to dots/pixels self.warnings = [] - def getSvg(self): # parse hpgl data + def getSvg(self): + # parse hpgl data # prepare document - self.doc = inkex.etree.parse(StringIO('' % (self.options.docWidth, self.options.docHeight))) + self.doc = inkex.etree.parse(StringIO('' % + (self.options.docWidth, self.options.docHeight))) actualLayer = 0 self.layers = {} if self.options.showMovements: @@ -54,12 +56,15 @@ class hpglDecoder: path = '' for i, command in enumerate(hpglData): if command.strip() != '': - if command[:2] == 'IN': # if Initialize command, ignore + if command[:2] == 'IN': + # if Initialize command, ignore pass - elif command[:2] == 'SP': # if Select Pen command + elif command[:2] == 'SP': + # if Select Pen command actualLayer = command[2:] self.createLayer(actualLayer) - elif command[:2] == 'PU': # if Pen Up command + elif command[:2] == 'PU': + # if Pen Up command if ' L ' in path: self.addPathToLayer(path, actualLayer) if self.options.showMovements and i != len(hpglData) - 1: @@ -68,7 +73,8 @@ class hpglDecoder: self.addPathToLayer(path, 0) path = 'M %f,%f' % self.getParameters(command[2:]) oldCoordinates = self.getParameters(command[2:]) - elif command[:2] == 'PD': # if Pen Down command + elif command[:2] == 'PD': + # if Pen Down command parameterString = command[2:] if parameterString.strip() != '': parameterString = parameterString.replace(';', '').strip() @@ -88,7 +94,8 @@ class hpglDecoder: return (self.doc, self.warnings) def createLayer(self, layerNumber): - self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): 'Drawing Pen ' + layerNumber}) + self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g', + {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): 'Drawing Pen ' + layerNumber}) def addPathToLayer(self, path, layerNumber): lineColor = '000000' @@ -96,13 +103,15 @@ class hpglDecoder: lineColor = 'ff0000' inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d': path, 'style': 'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'}) - def getParameters(self, parameterString): # process coordinates + def getParameters(self, parameterString): + # process coordinates if parameterString.strip() == '': return [] # remove command delimiter parameterString = parameterString.replace(';', '').strip() # split parameter parameter = parameterString.split(',') - return (float(parameter[0]) / self.scaleX, self.options.docHeight - float(parameter[1]) / self.scaleY) # convert to svg coordinate system + # convert to svg coordinate system and return + return (float(parameter[0]) / self.scaleX, self.options.docHeight - float(parameter[1]) / self.scaleY) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index 35d9300fb..a5060d2c5 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -55,7 +55,7 @@ class hpglEncoder: ''' self.doc = effect.document.getroot() self.options = effect.options - self.divergenceX = 'False' # dirty hack: i need to know if this was set to a number before, but since False is evaluated to 0 it can not be determined, therefore the string. + self.divergenceX = 'False' self.divergenceY = 'False' self.sizeX = 'False' self.sizeY = 'False' @@ -101,7 +101,8 @@ class hpglEncoder: elif self.options.useToolOffset: self.options.offsetX += self.options.toolOffset self.options.offsetY += self.options.toolOffset - self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, - self.divergenceX + self.options.offsetX], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, - self.divergenceY + self.options.offsetY]]] + self.groupmat = [[[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, - self.divergenceX + self.options.offsetX], + [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, - self.divergenceY + self.options.offsetY]]] self.groupmat[0] = simpletransform.composeTransform(self.groupmat[0], simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] # store first hpgl commands @@ -182,20 +183,23 @@ class hpglEncoder: oldPosX = posX oldPosY = posY - def getLength(self, x1, y1, x2, y2, absolute=True): # calc absoulute or relative length between two points + def getLength(self, x1, y1, x2, y2, absolute=True): + # calc absoulute or relative length between two points length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) if absolute: length = math.fabs(length) return length - def changeLength(self, x1, y1, x2, y2, offset): # change length of line + def changeLength(self, x1, y1, x2, y2, offset): + # change length of line if offset < 0: offset = max( - self.getLength(x1, y1, x2, y2), offset) x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset return [x, y] - def getAlpha(self, x1, y1, x2, y2, x3, y3): # get alpha of point 2 + def getAlpha(self, x1, y1, x2, y2, x3, y3): + # get alpha of point 2 temp1 = (x1 - x2) ** 2 + (y1 - y2) ** 2 + (x3 - x2) ** 2 + (y3 - y2) ** 2 - (x1 - x3) ** 2 - (y1 - y3) ** 2 temp2 = 2 * math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) * math.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2) return math.acos(max(min(temp1 / temp2, 1.0), -1.0)) @@ -217,15 +221,19 @@ class hpglEncoder: if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.options.toolOffset) self.storePoint('PD', pointThree[0], pointThree[1]) - elif self.vData[0][1] != -1.0: # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift the 3rd entry by the current tool offset position according to the 2nd command + elif self.vData[0][1] != -1.0: + # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift + # the 3rd entry by the current tool offset position according to the 2nd command pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.options.toolOffset) pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) self.storePoint('PU', pointThree[0], pointThree[1]) - else: # Else just write the 3rd entry + else: + # Else just write the 3rd entry pointThree = [self.vData[2][1], self.vData[2][2]] self.storePoint('PU', pointThree[0], pointThree[1]) - if self.vData[3][0] == 'PD': # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry + if self.vData[3][0] == 'PD': + # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.options.toolOffset: pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.options.toolOffset) else: @@ -271,8 +279,9 @@ class hpglEncoder: else: # store point if not self.options.center: + # only positive values are allowed (usually) if x < 0: - x = 0 # only positive values are allowed (usually) + x = 0 if y < 0: y = 0 # do not repeat command @@ -280,8 +289,6 @@ class hpglEncoder: self.hpgl += ',%d,%d' % (x, y) else: self.hpgl += ';%s%d,%d' % (command, x, y) - self.lastPoint[0] = command - self.lastPoint[1] = x - self.lastPoint[2] = y + self.lastPoint = [command, x, y] # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 \ No newline at end of file diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index d0d42c671..6ff6adeaf 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -76,7 +76,8 @@ class MyEffect(inkex.Effect): else: type, value, traceback = sys.exc_info() raise ValueError, ("", type, value), traceback - # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is a preview or a final run. (Remember to set to true) + # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is + # a preview or a final run. (Remember to set to true) ''' # reparse data for preview self.options.showMovements = True -- cgit v1.2.3 From 1f06a9b2e406c219c815583aae8161993d154c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 3 Nov 2013 14:29:36 +0100 Subject: added todo for recursion (bzr r12417.1.36) --- share/extensions/hpgl_encoder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index a5060d2c5..b5c927959 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -134,6 +134,7 @@ class hpglEncoder: if node.tag == inkex.addNS('path', 'svg'): self.process_path(node, groupmat[-1]) if node.tag == inkex.addNS('g', 'svg'): + # TODO: Remove recursion self.process_group(node, groupmat) if trans: groupmat.pop() -- cgit v1.2.3 From adb9bd4e463b14d5b5860d8bc17848a30991d48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20W=C3=BCst?= Date: Sun, 3 Nov 2013 15:52:50 +0100 Subject: added more todos (bzr r12417.1.37) --- share/extensions/hpgl_decoder.py | 1 + share/extensions/hpgl_encoder.py | 1 + share/extensions/hpgl_input.py | 1 + share/extensions/hpgl_output.py | 1 + share/extensions/plotter.py | 3 ++- 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py index 1b6106430..870775cb2 100644 --- a/share/extensions/hpgl_decoder.py +++ b/share/extensions/hpgl_decoder.py @@ -25,6 +25,7 @@ import math import inkex +# TODO: Unittests class hpglDecoder: def __init__(self, hpglString, options): diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py index b5c927959..90d2734be 100644 --- a/share/extensions/hpgl_encoder.py +++ b/share/extensions/hpgl_encoder.py @@ -31,6 +31,7 @@ import simplestyle import simpletransform +# TODO: Unittests class hpglEncoder: PI = math.pi TWO_PI = PI * 2 diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py index bf99a5e72..d1d46c76f 100644 --- a/share/extensions/hpgl_input.py +++ b/share/extensions/hpgl_input.py @@ -28,6 +28,7 @@ import sys inkex.localize() +# TODO: Unittests # parse options parser = inkex.optparse.OptionParser(usage='usage: %prog [options] HPGLfile', option_class=inkex.InkOption) parser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 16a656856..c5fec0ec8 100755 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -26,6 +26,7 @@ import inkex inkex.localize() +# TODO: Unittests class MyEffect(inkex.Effect): def __init__(self): diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 6ff6adeaf..aef9e016d 100644 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -28,7 +28,8 @@ import inkex inkex.localize() -# TODO: Materialvorschub nach plot, rechtecke plotten +# TODO: Unittests +# TODO: Material feed after plot, plot rectangles class MyEffect(inkex.Effect): def __init__(self): -- cgit v1.2.3