hpgl_encoder.py revision d95ba1e6f34e61039087ca05ab91b4b828b534e6
# coding=utf-8
'''
Copyright (C) 2008 Aaron Spike, aaron@ekips.org
Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de
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 re
import string
#from StringIO import StringIO
# local libraries
import bezmisc
import cspsubdiv
import cubicsuperpath
import inkex
import simplestyle
import simpletransform
class hpglEncoder:
''' options:
"resolutionX":float
"resolutionY":float
"pen":int
"force:int
"speed:int
"orientation":string // "0", "90", "-90", "180"
"mirrorX":bool
"mirrorY":bool
"center":bool
"flat":float
"overcut":float
"toolOffset":float
"precut":bool
"autoAlign":bool
"debug":bool
'''
self.scaleX = self.options.resolutionX / effect.unittouu("1.0in") # dots per inch to dots per user unit
self.scaleY = self.options.resolutionY / effect.unittouu("1.0in") # dots per inch to dots per user unit
self.overcut = effect.unittouu(str(self.options.overcut) + "mm") * scaleXY # mm to dots (plotter coordinate system)
self.flat = self.options.flat / (1016 / ((self.options.resolutionX + self.options.resolutionY) / 2)) # scale flatness to resolution
else:
self.debugValues = {}
# process viewBox attribute to correct page scaling
if viewBox:
# dryRun to find edges
groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]
groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')'))
if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False':
raise Exception('NO_PATHS')
# live run
# move drawing according to various modifiers
else:
else:
# initialize transformation matrix and cache
groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, -self.divergenceX + self.offsetX],
groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')'))
# store initial hpgl commands
# add move to zero point and precut
# TODO: get this FU to work or remove precut functionality
'''
newDoc = inkex.etree.parse(StringIO('<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" width="10" height="' + str(10 * 3.5433070866) + '"></svg>'))
newLayer = inkex.etree.SubElement(newDoc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): 'null'})
newPath = inkex.etree.SubElement(newLayer, 'path', {'d': 'M ' + str(oldDivergenceX) + ',' + str(oldDivergenceY) + ' L ' + str(oldDivergenceX) + ',' + str(oldDivergenceY + (self.options.toolOffset * 8 * 3.5433070866)), 'style': 'stroke:#000000; stroke-width:0.4; fill:none;'})
self.processPath(newPath, groupmat)
'''
pass
else:
# start conversion
# shift an empty node in in order to process last node in cache
# add return to zero point
else:
# flatten layers and groups to avoid recursion
paths = []
if (node.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(node)) or node.tag == inkex.addNS('path', 'svg'):
doc = ''
while hasGroups:
if (path.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(path)) or path.tag == inkex.addNS('path', 'svg'):
# get and merge two matrixes into one
if trans:
else:
return matrix
if style:
return False
return True
# process path
if path:
# parse and transform path
# path to HPGL commands
oldPosX = 0.0
oldPosY = 0.0
for singlePath in path:
cmd = 'PU'
for singlePathPoint in singlePath:
# check if point is repeating, if so, ignore
cmd = 'PD'
# perform overcut
# 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:
# check if point is repeating, if so, ignore
break
else:
# calc absoulute or relative length between two points
if absolute:
return length
# change length of line
if offset < 0:
return [x, y]
# calculate offset correction (or dont)
else:
# insert data into cache
# decide if enough data is availabe
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.toolOffset)
# 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.toolOffset)
else:
# Else just write the 3rd entry
# 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.toolOffset:
pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.toolOffset)
else:
pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2],
(self.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
angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart
# switch direction when arc is bigger than 180°
# draw arc
if angleVector >= 0:
self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset)
else:
self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset)
# skip when no change in movement
return
# find edges
self.divergenceX = x
self.divergenceY = y
else:
# store point
# only positive values are allowed (usually)
if x < 0:
x = 0
if y < 0:
y = 0
# do not repeat command
else:
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99