summaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorSebastian Wüst <sebi@timewaster.de>2013-11-03 00:23:14 +0000
committerSebastian Wüst <sebi@timewaster.de>2013-11-03 00:23:14 +0000
commita1a79d1ce4108f7bb462253d8c100f642cf8dcc3 (patch)
tree9649d3fe0b16d77bd365a6fab5fd2ce6f95e2028 /share
parenttext changes (diff)
downloadinkscape-a1a79d1ce4108f7bb462253d8c100f642cf8dcc3.tar.gz
inkscape-a1a79d1ce4108f7bb462253d8c100f642cf8dcc3.zip
better PEP 8 compatibility
(bzr r12417.1.34)
Diffstat (limited to 'share')
-rw-r--r--share/extensions/hpgl_decoder.py213
-rw-r--r--share/extensions/hpgl_encoder.py560
-rw-r--r--share/extensions/hpgl_input.inx2
-rw-r--r--share/extensions/hpgl_input.py12
-rwxr-xr-xshare/extensions/hpgl_output.py15
-rw-r--r--share/extensions/plotter.py125
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('<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" width="%s" height="%s"></svg>' % (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('<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" width="%s" height="%s"></svg>' % (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 @@
<param name="space" type="description">&#xa0;</param>
<param name="resolutionX" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution X (dpi)" _gui-description="The amount of steps in one inch on the X axis (Default: 1016.0)">1016.0</param>
<param name="resolutionY" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution Y (dpi)" _gui-description="The amount of steps in one inch on the Y axis (Default: 1016.0)">1016.0</param>
- <param name="showMovements" type="boolean" _gui-text="Show Movements between paths" _gui-description="Check this to show movements between paths with a different color (Default: Unchecked)">false</param>
+ <param name="showMovements" type="boolean" _gui-text="Show Movements between paths" _gui-description="Check this to show movements between paths (Default: Unchecked)">false</param>
<input>
<extension>.hpgl</extension>
<mimetype>image/hpgl</mimetype>
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 <effect needs-live-preview='false'> 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 <effect needs-live-preview='false'> 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