def processClone(self, clone): trans = node.get('transform') x = node.get('x') y = node.get('y') mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) if x: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) if y: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) if trans or x or y: self.builder.pushTransform(mat) refid = node.get(ix.addNS('href', 'xlink')) refnode = self.getElementById(refid[1:]) if refnode is not None: if refnode.tag == ix.addNS('g', 'svg'): self.processGroup(refnode) elif refnode.tag == ix.addNS('use', 'svg'): self.processClone(refnode) else: self.processShape(refnode) if trans or x or y: self.builder.popTransform()
def match(p1, p2, a1, a2): x = 0 y = 1 # distances dp = [p2[x] - p1[x], p2[y] - p1[y]] da = [a2[x] - a1[x], a2[y] - a1[y]] # angles angle_p = math.atan2(dp[x], dp[y]) angle_a = math.atan2(da[x], da[y]) # radians #rp = math.sqrt( dp[x]*dp[x] + dp[y]*dp[y] ) #ra = math.sqrt( da[x]*da[x] + da[y]*da[y] ) rp = math.hypot(dp[x], dp[y]) ra = math.hypot(da[x], da[y]) # scale scale = ra / rp # transforms in the order they are applied t1 = simpletransform.parseTransform("translate(%f,%f)" % (-p1[x], -p1[y])) #t2 = simpletransform.parseTransform( "rotate(%f)"%(-angle_p) ) #t3 = simpletransform.parseTransform( "scale(%f,%f)"%(scale,scale) ) #t4 = simpletransform.parseTransform( "rotate(%f)"%angle_a ) t2 = rotateTransform(-angle_p) t3 = scaleTransform(scale, scale) t4 = rotateTransform(angle_a) t5 = simpletransform.parseTransform("translate(%f,%f)" % (a1[x], a1[y])) # transforms in the order they are multiplied t = t5 t = simpletransform.composeTransform(t, t4) t = simpletransform.composeTransform(t, t3) t = simpletransform.composeTransform(t, t2) t = simpletransform.composeTransform(t, t1) # return the combined transform return t
def match( p1, p2, a1, a2 ): x = 0 y = 1 # distances dp = [ p2[x]-p1[x], p2[y]-p1[y] ] da = [ a2[x]-a1[x], a2[y]-a1[y] ] # angles angle_p = math.atan2( dp[x], dp[y] ) angle_a = math.atan2( da[x], da[y] ) # radians #rp = math.sqrt( dp[x]*dp[x] + dp[y]*dp[y] ) #ra = math.sqrt( da[x]*da[x] + da[y]*da[y] ) rp = math.hypot( dp[x], dp[y] ) ra = math.hypot( da[x], da[y] ) # scale scale = ra / rp # transforms in the order they are applied t1 = simpletransform.parseTransform( "translate(%f,%f)"%(-p1[x],-p1[y]) ) #t2 = simpletransform.parseTransform( "rotate(%f)"%(-angle_p) ) #t3 = simpletransform.parseTransform( "scale(%f,%f)"%(scale,scale) ) #t4 = simpletransform.parseTransform( "rotate(%f)"%angle_a ) t2 = rotateTransform(-angle_p) t3 = scaleTransform( scale, scale ) t4 = rotateTransform( angle_a ) t5 = simpletransform.parseTransform( "translate(%f,%f)"%(a1[x],a1[y]) ) # transforms in the order they are multiplied t = t5 t = simpletransform.composeTransform( t, t4 ) t = simpletransform.composeTransform( t, t3 ) t = simpletransform.composeTransform( t, t2 ) t = simpletransform.composeTransform( t, t1 ) # return the combined transform return t
def process_clone(self, node): trans = node.get('transform') x = node.get('x') y = node.get('y') mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) if x: mat = simpletransform.composeTransform(mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) if y: mat = simpletransform.composeTransform(mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) # push transform if trans or x or y: self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], mat)) # get referenced node refid = node.get(inkex.addNS('href','xlink')) refnode = self.getElementById(refid[1:]) if refnode is not None: if refnode.tag == inkex.addNS('g','svg'): self.process_group(refnode) elif refnode.tag == inkex.addNS('use', 'svg'): self.process_clone(refnode) else: self.process_shape(refnode, self.groupmat[-1]) # pop transform if trans or x or y: self.groupmat.pop()
def getHpgl(self): # 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 + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] self.processGroups(self.doc, 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 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]] groupmat = simpletransform.composeTransform(groupmat, 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.processOffset('PU', 0, 0) self.processOffset('PD', 0, self.options.toolOffset * 8) # start conversion self.processGroups(self.doc, groupmat) # shift an empty node in in order to process last node in cache self.processOffset('PU', 0, 0) # add return to zero point self.hpgl += ';PU0,0;' return self.hpgl
def process_clone(self, node): trans = node.get('transform') x = node.get('x') y = node.get('y') mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) if x: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) if y: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) # push transform if trans or x or y: self.groupmat.append( simpletransform.composeTransform(self.groupmat[-1], mat)) # get referenced node refid = node.get(inkex.addNS('href', 'xlink')) refnode = self.getElementById(refid[1:]) if refnode is not None: if refnode.tag == inkex.addNS('g', 'svg'): self.process_group(refnode) elif refnode.tag == inkex.addNS('use', 'svg'): self.process_clone(refnode) else: self.process_shape(refnode, self.groupmat[-1]) # pop transform if trans or x or y: self.groupmat.pop()
def get_transform(c1,c2,a1,a2): [c1x,c1y], [c2x,c2y] = c1,c2 # move c1 to 0 transform = [ [1,0,-c1x], [0,1,-c1y] ] # Rotate to a1 to 0 transform = simpletransform.composeTransform([ [math.cos(a1), -math.sin(a1), 0], [math.sin(a1), math.cos(a1), 0] ], transform ) # Move c2 to 0 transform = simpletransform.composeTransform( [ [1,0,-c2x+c1x], [0,1,-c2y+c1y] ], transform) # Rotate to a2 to 0 transform = simpletransform.composeTransform( [ [math.cos(a2), -math.sin(a2), 0], [math.sin(a2), math.cos(a2), 0] ] , transform) # move c2 back to c2 transform = simpletransform.composeTransform([ [1,0,c2x], [0,1,c2y] ], transform) return transform
def fixUses(self, node, index): ''' Fix <use> objects after transformation the objects their refer to ''' # Go deep first for i in node: self.fixUses(i, index) # Is it a <use> tag? if node.tag == inkex.addNS("use", "svg"): # Get reference href = node.get(inkex.addNS('href', 'xlink')) if href[0] == "#": # Did we apply any transforms to the referred node? if href[1:] in index: # Yes! thatTr = index[href[1:]] thisTr = SpeleoTransform.getTransform(node) invThatTr = SpeleoTransform.invertTransform(thatTr) # So, first transform of this <use> should be *reverting* that transform! node.set( "transform", simpletransform.formatTransform( simpletransform.composeTransform( thisTr, invThatTr)))
def composeParents(self, node, m): t = node.get('transform') if t: m = simpletransform.composeTransform(simpletransform.parseTransform(t), m) if node.getparent().tag == inkex.addNS('g','svg') or node.getparent().tag == inkex.addNS('a','svg'): m = self.composeParents(node.getparent(), m) return m
def mergeTransform(self, doc, matrix): # get and merge two matrixes into one trans = doc.get('transform') if trans: return simpletransform.composeTransform(matrix, simpletransform.parseTransform(trans)) else: return matrix
def process_group(self, group): ############################################## ### Get color set at group level stroke_group = group.get('stroke') ############################################## ### Handle 'style' data style = group.get('style') if style: declarations = style.split(';') for i, decl in enumerate(declarations): parts = decl.split(':', 2) if len(parts) == 2: (prop, val) = parts prop = prop.strip().lower() if prop == 'stroke': stroke_group = val.strip() if prop == 'display' and val == "none": #group display is 'none' return without processing group return ############################################## if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if 'display' in style: if style['display'] == 'none': #layer display is 'none' return without processing layer return layer = group.get(inkex.addNS('label', 'inkscape')) layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer 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('g', 'svg') or node.tag == inkex.addNS( 'switch', 'svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) elif node.tag == inkex.addNS('style', 'svg'): if node.get('type') == "text/css": self.parse_css(node.text) elif node.tag == inkex.addNS('defs', 'svg'): for sub in node: if sub.tag == inkex.addNS('style', 'svg'): self.parse_css(sub.text) else: self.process_shape(node, self.groupmat[-1], group_stroke=stroke_group) if trans: self.groupmat.pop()
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style['display'] == 'none' and self.options.layer_option and self.options.layer_option=='visible': return layer = group.get(inkex.addNS('label', 'inkscape')) if self.options.layer_name and self.options.layer_option and self.options.layer_option=='name' and not layer.lower() in self.options.layer_name: return layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer 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('g','svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def rotate_matrix(node, a): bbox = simpletransform.computeBBox([node]) cx = (bbox[0] + bbox[1]) / 2.0 cy = (bbox[2] + bbox[3]) / 2.0 return simpletransform.composeTransform( [[cos(a), -sin(a), cx], [sin(a), cos(a), cy]], [[1, 0, -cx], [0, 1, -cy]])
def process_group(self, group): style = group.get('style') if style: style = simplestyle.parseStyle(style) if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': if style: if style.has_key('display'): if style['display'] == 'none' and self.visibleLayers: return #stack the style of each group prevstyle = self.groupstyle.copy() if style: self.groupstyle.update(style) 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('g', 'svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop() #pop the current group style self.groupstyle = prevstyle
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style['display'] == 'none': return layer = group.get(inkex.addNS('label', 'inkscape')) layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer 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('g', 'svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) elif node.tag == inkex.addNS('defs', 'svg'): for sub in node: if sub.tag == inkex.addNS('style', 'svg'): self.parse_css(sub.text) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def get_viewbox_transform(node): # somewhat cribbed from inkscape-silhouette doc_width, doc_height = get_doc_size(node) viewbox = get_viewbox(node) dx = -float(viewbox[0]) dy = -float(viewbox[1]) transform = simpletransform.parseTransform("translate(%f, %f)" % (dx, dy)) try: sx = doc_width / float(viewbox[2]) sy = doc_height / float(viewbox[3]) # preserve aspect ratio aspect_ratio = node.get('preserveAspectRatio', 'xMidYMid meet') if aspect_ratio != 'none': sx = sy = max(sx, sy) if 'slice' in aspect_ratio else min(sx, sy) scale_transform = simpletransform.parseTransform("scale(%f, %f)" % (sx, sy)) transform = simpletransform.composeTransform(transform, scale_transform) except ZeroDivisionError: pass return transform
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style[ 'display'] == 'none' and self.options.layer_option and self.options.layer_option == 'visible': return layer = group.get(inkex.addNS('label', 'inkscape')) if self.options.layer_name and self.options.layer_option and self.options.layer_option == 'name' and not layer.lower( ) in self.options.layer_name: return layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer 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('g', 'svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def get_ancestor_transform(self, elem): """ Returns the cumulative transform of all this element's ancestors (excluding this element's own transform) """ transform = [[1,0,0], [0,1,0], [0,0,1]] for a in self.ancestors(elem): transform = simpletransform.composeTransform(transform, self.get_transform(a)) return transform
def process_shape(self, node, mat): rgb = (0, 0, 0) # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) if style.has_key('stroke-width'): stroke = self.unittouu( style['stroke-width']) / self.unittouu('1px') stroke = int(stroke * self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][ 0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256 * fill[1] + 256 * 256 * fill[2] color = rgb[0] + 256 * rgb[1] + 256 * 256 * rgb[2] if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y], [x, y], [x, y]]] p.append([[x + width, y], [x + width, y], [x + width, y]]) p.append([[x + width, y + height], [x + width, y + height], [x + width, y + height]]) p.append([[x, y + height], [x, y + height], [x, y + height]]) p.append([[x, y], [x, y], [x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) hPen = mygdi.CreatePen(0, stroke, color) mygdi.SelectObject(self.hDC, hPen) self.emit_path(p) if fillcolor is not None: brush = LOGBRUSH(0, fillcolor, 0) hBrush = mygdi.CreateBrushIndirect(addressof(brush)) mygdi.SelectObject(self.hDC, hBrush) mygdi.BeginPath(self.hDC) self.emit_path(p) mygdi.EndPath(self.hDC) mygdi.FillPath(self.hDC) return
def exportDrill(self, kicad_mod=False): x0 = 0 y0 = 0 mirror = 1.0 self.setInkscapeScaling() kicad_drill_string = "" i = 0 if kicad_mod: pad_template = "(pad {n} thru_hole circle (at {x} {y}) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask))\n" else: pad_template = """ (module Wire_Pads:SolderWirePad_single_0-8mmDrill (layer F.Cu) (tedit 0) (tstamp 5ABD66D0) (at {x} {y}) (pad {n} thru_hole circle (at 0 0) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask)) ) """ layerPath = '//svg:g[@inkscape:groupmode="layer"][@inkscape:label="Drill"]' for layer in self.document.getroot().xpath(layerPath, namespaces=inkex.NSS): layer_trans = layer.get('transform') if layer_trans: layer_m = simpletransform.parseTransform(layer_trans) else: layer_m = IDENTITY_MATRIX nodePath = 'descendant::svg:circle' count = 0 for node in layer.xpath(nodePath, namespaces=inkex.NSS): count = count + 1 cx = float(node.get('cx')) cy = float(node.get('cy')) radius = float(node.get('r')) drill_size = radius * 2 t = node.get('transform') pt = [cx, cy] if t: m = simpletransform.parseTransform(t) trans = simpletransform.composeTransform(layer_m, m) else: trans = layer_m simpletransform.applyTransformToPoint(trans,pt) padCoord = self.coordToKicad(pt) kicad_drill_string += pad_template.format(x=padCoord[0], y=padCoord[1], n=count, d=drill_size) return kicad_drill_string
def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): transf = composeTransform(transf, parseTransform(node.get("transform", None))) if 'transform' in node.attrib: del node.attrib['transform'] if 'style' in node.attrib: style = node.attrib.get('style') style = simplestyle.parseStyle(style) update = False if 'stroke-width' in style: try: stroke_width = self.unittouu(style.get('stroke-width').strip()) # pixelsnap ext assumes scaling is similar in x and y # and uses the x scale... # let's try to be a bit smarter stroke_width *= math.sqrt(transf[0][0]**2 + transf[1][1]**2) style['stroke-width'] = str(stroke_width) update = True except AttributeError: pass if update: style = simplestyle.formatStyle(style) node.attrib['style'] = style node = ApplyTransform.objectToPath(node) if 'd' in node.attrib: d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(transf, p) node.set('d', cubicsuperpath.formatPath(p)) elif node.tag in [inkex.addNS('polygon', 'svg'), inkex.addNS('polyline', 'svg')]: points = node.get('points') points = points.strip().split(' ') for k,p in enumerate(points): if ',' in p: p = p.split(',') p = [float(p[0]),float(p[1])] applyTransformToPoint(transf, p) p = [str(p[0]),str(p[1])] p = ','.join(p) points[k] = p points = ' '.join(points) node.set('points', points) elif node.tag in [inkex.addNS('rect', 'svg'), inkex.addNS('text', 'svg'), inkex.addNS('image', 'svg'), inkex.addNS('use', 'svg')]: node.set('transform', formatTransform(transf)) for child in node.getchildren(): self.recursiveFuseTransform(child, transf)
def recursivelyTraverseSvg(self, aNodeList, matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): for node in aNodeList: # first apply the current matrix transform to this node's transform matNew = composeTransform(matCurrent, parseTransform(node.get("transform"))) if node.tag == inkex.addNS('g', 'svg') or node.tag == 'g': self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('symbol', 'svg') or node.tag == 'symbol': if (self.useTagNestLevel > 0): self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('a', 'svg') or node.tag == 'a': self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('use', 'svg') or node.tag == 'use': refid = node.get(inkex.addNS('href', 'xlink')) if refid is not None: # [1:] to ignore leading '#' in reference path = '//*[@id="%s"]' % refid[1:] refnode = node.xpath(path) if refnode is not None: x = float(node.get('x', '0')) y = float(node.get('y', '0')) # Note: the transform has already been applied if (x != 0) or (y != 0): t = parseTransform('translate(%f,%f)' % (x, y)) matNew2 = composeTransform(matNew, t) else: matNew2 = matNew self.useTagNestLevel = self.useTagNestLevel + 1 self.recursivelyTraverseSvg(refnode, matNew2) self.useTagNestLevel = self.useTagNestLevel - 1 else: continue else: continue elif node.tag == inkex.addNS('image', 'svg') or node.tag == 'image': self.gcode += self.imageToGcode(node, matNew) else: continue
def effect(self): """ This method is called first, and sets up the self.commands list for later output. """ svg = self.document.getroot() # find document width and height, used to scale down self.doc_width = inkex.unittouu(svg.get('width')) self.doc_height = inkex.unittouu(svg.get('height')) # add header self.commands.append("^DF;") self.commands.append("! 1;") self.commands.append("H;") self.commands.append("@ %d %d;" % (self.options.z_down, self.options.z_up)) self.commands.append("V {0};F {0};\n".format(self.options.feed_rate_moving)) self.commands.append("Z 0 0 %d;" % self.options.z_up) # mostly borrowed from hgpl_output.py lastX = 0 lastY = 0 # find paths in layers i = 0 layerPath = '//svg:g[@inkscape:groupmode="layer"]' for layer in svg.xpath(layerPath, namespaces=inkex.NSS): i += 1 nodePath = ('//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path') % i for node in svg.xpath(nodePath, namespaces=inkex.NSS): # these next lines added from this patch to fix the transformation issues - http://launchpadlibrarian.net/36269154/hpgl_output.py.patch # possibly also want to try this code: https://bugs.launchpad.net/inkscape/+bug/600472/+attachment/1475310/+files/hpgl_output.py transforms = node.xpath("./ancestor-or-self::svg:*[@transform]",namespaces=inkex.NSS) matrix = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] for parenttransform in transforms: newmatrix = simpletransform.parseTransform(parenttransform.get("transform")) matrix = simpletransform.composeTransform(matrix, newmatrix) d = node.get('d') if len(simplepath.parsePath(d)): p = cubicsuperpath.parsePath(d) simpletransform.applyTransformToPath(matrix, p) # this line is also from the transform-fixing patch mentioned above cspsubdiv.cspsubdiv(p, self.options.flat) for sp in p: first = True for csp in sp: if first: x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1]) self.commands.append("Z %d %d %d;" % (x, y, self.options.z_up)) self.commands.append("V {0};F {0};".format(self.options.feed_rate_cutting)) first = False x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1]) self.commands.append("Z %d %d %d;" % (x, y, self.options.z_down)) lastX = x lastY = y self.commands.append("V {0};F {0};".format(self.options.feed_rate_moving)) self.commands.append("Z %d %d %d;" % (lastX, lastY, self.options.z_up)) self.commands.append("Z 0 0 %d;" % self.options.z_up) self.commands.append("H;")
def get_ancestor_transform(self, elem): """ Returns the cumulative transform of all this element's ancestors (excluding this element's own transform) """ transform = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] for a in self.ancestors(elem): transform = simpletransform.composeTransform( transform, self.get_transform(a)) return transform
def process_shape(self, node, mat): rgb = (0, 0, 0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(), rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0) self.closed = 0 # only for LWPOLYLINE self.color = 7 # default is black if hsl[2]: self.color = 1 + (int(6 * hsl[0] + 0.5) % 6) # use 6 hues if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: return if (d[-1] == 'z' or d[-1] == 'Z'): self.closed = 1 p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): self.closed = 1 x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y], [x, y], [x, y]]] p.append([[x + width, y], [x + width, y], [x + width, y]]) p.append([[x + width, y + height], [x + width, y + height], [x + width, y + height]]) p.append([[x, y + height], [x, y + height], [x, y + height]]) p.append([[x, y], [x, y], [x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) for sub in p: for i in range(len(sub) - 1): s = sub[i] e = sub[i + 1] if s[1] == s[2] and e[0] == e[1]: if (self.options.POLY == 'true'): self.LWPOLY_line([s[1], e[1]]) else: self.dxf_line([s[1], e[1]]) elif (self.options.ROBO == 'true'): self.ROBO_spline([s[1], s[2], e[0], e[1]]) else: self.dxf_spline([s[1], s[2], e[0], e[1]])
def recursivelyTraverseSvg(self, nodeList=None, matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], parent_visibility='visible' ): """ Based on the Eggbot extension for Inkscape. Recursively traverse the svg file to plot out all the paths. Keeps track of the composite transformation that should be applied to each path. Handles path, group. Doesn't yet handle line, text, rect, polyline, polygon, circle, ellipse and use (clone) elements. Unhandled elements should be converted to paths in Inkscape. Probably want to avoid paths with holes inside. """ if not nodeList: nodeList = self.svgRoot # get svg document width and height width, units_width = self.parseLengthAndUnits(nodeList.get("width")) height, units_height = self.parseLengthAndUnits(nodeList.get("height")) if units_width != units_height: print "Weird, units for SVG root document width and height differ..." print nodeList.get("width") print nodelist.get("height") sys.exit(1) # set initial viewbox from document root viewbox = nodeList.get("viewBox") print "Document size: %f x %f (%s)" % (width, height, units_width) if viewbox: vinfo = viewbox.strip().replace(',', ' ').split(' ') if (vinfo[2] != 0) and (vinfo[3] != 0): sx = width / float(vinfo[2]) sy = height / float(vinfo[3]) matCurrent = simpletransform.parseTransform("scale(%f, %f) translate(%f, %f)" % (sx, sy, -float(vinfo[0]), -float(vinfo[1]))) print "Initial transformation matrix:", matCurrent for node in nodeList: # Ignore invisible nodes v = node.get('visibility', parent_visibility) if v == 'inherit': v = parent_visibility if v == 'hidden' or v == 'collapse': pass # first apply the current matrix transform to this node's transform matNew = simpletransform.composeTransform( matCurrent, simpletransform.parseTransform(node.get("transform")) ) if node.tag in [self.svgQName("g"), "g"]: print "group tag - Might not be handled right!" self.recursivelyTraverseSvg( list(node), matNew, v ) elif node.tag in [self.svgQName("path")]: self.plotPath( node, matNew ) else: print "Other tag: '%s'" % node.tag
def effect(self): if len(self.options.ids) < 2: inkex.debug("This extension requires that you select two paths.") return self.prepareSelectionList() #center at (0,0) bbox = pathmodifier.computeBBox([self.patternNode]) mat = [[1, 0, -(bbox[0] + bbox[1]) / 2], [0, 1, -(bbox[2] + bbox[3]) / 2]] if self.options.vertical: bbox = [-bbox[3], -bbox[2], bbox[0], bbox[1]] mat = simpletransform.composeTransform([[0, -1, 0], [1, 0, 0]], mat) mat[1][2] += self.options.noffset simpletransform.applyTransformToNode(mat, self.patternNode) width = bbox[1] - bbox[0] dx = width + self.options.space for skelnode in self.skeletons.itervalues(): self.curSekeleton = cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: self.skelcomp, self.lengths = linearize(comp) #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! self.skelcompIsClosed = (self.skelcomp[0] == self.skelcomp[-1]) length = sum(self.lengths) if self.options.stretch: dx = width + self.options.space n = int( (length - self.options.toffset + self.options.space) / dx) if n > 0: dx = (length - self.options.toffset) / n xoffset = self.skelcomp[0][0] - bbox[0] + self.options.toffset yoffset = self.skelcomp[0][1] - ( bbox[2] + bbox[3]) / 2 - self.options.noffset s = self.options.toffset while s <= length: mat = self.localTransformAt(s, self.options.follow) clone = copy.deepcopy(self.patternNode) #!!!--> should it be given an id? #seems to work without this!?! myid = self.patternNode.tag.split('}')[-1] clone.set("id", self.uniqueId(myid)) self.gNode.append(clone) simpletransform.applyTransformToNode(mat, clone) s += dx self.patternNode.getparent().remove(self.patternNode)
def get_transforms(self,g): root = self.document.getroot() trans = [] while (g!=root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform(t,trans) if trans != [] else t g=g.getparent() return trans
def get_transform(c1, c2, a1, a2): [c1x, c1y], [c2x, c2y] = c1, c2 # move c1 to 0 transform = [[1, 0, -c1x], [0, 1, -c1y]] # Rotate to a1 to 0 transform = simpletransform.composeTransform( [[math.cos(a1), -math.sin(a1), 0], [math.sin(a1), math.cos(a1), 0]], transform) # Move c2 to 0 transform = simpletransform.composeTransform( [[1, 0, -c2x + c1x], [0, 1, -c2y + c1y]], transform) # Rotate to a2 to 0 transform = simpletransform.composeTransform( [[math.cos(a2), -math.sin(a2), 0], [math.sin(a2), math.cos(a2), 0]], transform) # move c2 back to c2 transform = simpletransform.composeTransform( [[1, 0, c2x], [0, 1, c2y]], transform) return transform
def get_transforms(self,g): root = self.document.getroot() trans = [] while (g!=root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform(t,trans) if trans != [] else t print_(trans) g=g.getparent() return trans
def compose_parent_transforms(node, mat): # This is adapted from Inkscape's simpletransform.py's composeParents() # function. That one can't handle nodes that are detached from a DOM. trans = node.get('transform') if trans: mat = simpletransform.composeTransform(simpletransform.parseTransform(trans), mat) if node.getparent() is not None: if node.getparent().tag in [SVG_GROUP_TAG, SVG_LINK_TAG]: mat = compose_parent_transforms(node.getparent(), mat) return mat
def compose_parent_transforms(node, mat): # This is adapted from Inkscape's simpletransform.py's composeParents() # function. That one can't handle nodes that are detached from a DOM. trans = node.get('transform') if trans: mat = simpletransform.composeTransform( simpletransform.parseTransform(trans), mat) if node.getparent() is not None: if node.getparent().tag == inkex.addNS('g', 'svg'): mat = compose_parent_transforms(node.getparent(), mat) return mat
def process_shape(self, node, mat): rgb = (0,0,0) # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) if style.has_key('stroke-width'): stroke = self.unittouu(style['stroke-width']) stroke = int(stroke*self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256*fill[1] + 256*256*fill[2] color = rgb[0] + 256*rgb[1] + 256*256*rgb[2] if node.tag == inkex.addNS('path','svg'): d = node.get('d') if not d: return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect','svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y],[x, y],[x, y]]] p.append([[x + width, y],[x + width, y],[x + width, y]]) p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]]) p.append([[x, y + height],[x, y + height],[x, y + height]]) p.append([[x, y],[x, y],[x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) hPen = mygdi.CreatePen(0, stroke, color) mygdi.SelectObject(self.hDC, hPen) self.emit_path(p) if fillcolor is not None: brush = LOGBRUSH(0, fillcolor, 0) hBrush = mygdi.CreateBrushIndirect(addressof(brush)) mygdi.SelectObject(self.hDC, hBrush) mygdi.BeginPath(self.hDC) self.emit_path(p) mygdi.EndPath(self.hDC) mygdi.FillPath(self.hDC) return
def get_node_transform(node): # start with the identity transform transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] # combine this node's transform with all parent groups' transforms transform = simpletransform.composeParents(node, transform) # add in the transform implied by the viewBox viewbox_transform = get_viewbox_transform(node.getroottree().getroot()) transform = simpletransform.composeTransform(viewbox_transform, transform) return transform
def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): transf = composeTransform(transf, parseTransform(node.get("transform", None))) if 'transform' in node.attrib: del node.attrib['transform'] node = self.objectToPath(node) if 'd' in node.attrib: d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(transf, p) node.set('d', cubicsuperpath.formatPath(p)) self.scaleStrokeWidth(node, transf) elif node.tag in [ inkex.addNS('polygon', 'svg'), inkex.addNS('polyline', 'svg') ]: points = node.get('points') points = points.strip().split(' ') for k, p in enumerate(points): if ',' in p: p = p.split(',') p = [float(p[0]), float(p[1])] applyTransformToPoint(transf, p) p = [str(p[0]), str(p[1])] p = ','.join(p) points[k] = p points = ' '.join(points) node.set('points', points) self.scaleStrokeWidth(node, transf) elif node.tag in [ inkex.addNS('rect', 'svg'), inkex.addNS('text', 'svg'), inkex.addNS('image', 'svg'), inkex.addNS('use', 'svg'), inkex.addNS('circle', 'svg') ]: node.set('transform', formatTransform(transf)) else: # e.g. <g style="..."> self.scaleStrokeWidth(node, transf) for child in node.getchildren(): self.recursiveFuseTransform(child, transf)
def _get_transforms(self, g): root = self.document.getroot() trans = [[1, 0, 0], [0, 1, 0]] while (g != root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform( t, trans) if trans != [] else t self._log.debug("Found transform: " % trans) g = g.getparent() return trans
def process_shape(self, node, mat): readStrokeWidth = not self.options.ignoreStrokeWidth color = None # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! node_style = node.get('style') if node_style: style = self.groupstyle.copy() style.update(simplestyle.parseStyle(node_style)) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) color = rgb[0] + 256 * rgb[1] + 256 * 256 * rgb[2] if readStrokeWidth and style.has_key('stroke-width'): stroke = self.unittouu( style['stroke-width']) / self.unittouu('1px') stroke = int(stroke * self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][ 0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256 * fill[1] + 256 * 256 * fill[2] if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: self.not_converted.append(node.get('id')) return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = self.printer.rectangle_path(x, y, width, height) elif node.tag == inkex.addNS('defs', 'svg') or node.tag == inkex.addNS( 'metadata', 'svg'): # ignore svg:defs and svg:metadata return elif node.tag.startswith('{' + inkex.NSS['svg']) == False: # ignore non-SVG elements return else: self.not_converted.append(node.get('id')) return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) self.printer.draw_path(p, color, stroke, fillcolor)
def process_shape(self, node, mat): rgb = (0,0,0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(),rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0) self.closed = 0 # only for LWPOLYLINE self.color = 7 # default is black if hsl[2]: #self.color = 1 + (int(6*hsl[0] + 0.5) % 6) # use 6 hues self.color = 1 + (int(10*hsl[0] + 0.5) % 10) # use 6 hues if node.tag == inkex.addNS('path','svg'): d = node.get('d') if not d: return if (d[-1] == 'z' or d[-1] == 'Z'): self.closed = 1 p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect','svg'): self.closed = 1 x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y],[x, y],[x, y]]] p.append([[x + width, y],[x + width, y],[x + width, y]]) p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]]) p.append([[x, y + height],[x, y + height],[x, y + height]]) p.append([[x, y],[x, y],[x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) for sub in p: for i in range(len(sub)-1): s = sub[i] e = sub[i+1] if s[1] == s[2] and e[0] == e[1]: if (self.options.POLY == 'true'): self.LWPOLY_line([s[1],e[1]]) else: self.dxf_line([s[1],e[1]]) elif (self.options.ROBO == 'true'): self.ROBO_spline([s[1],s[2],e[0],e[1]]) else: self.dxf_spline([s[1],s[2],e[0],e[1]])
def effect(self): if len(self.options.ids)<2: inkex.debug("This extension requires that you select two paths.") return self.prepareSelectionList() #center at (0,0) bbox=pathmodifier.computeBBox([self.patternNode]) mat=[[1,0,-(bbox[0]+bbox[1])/2],[0,1,-(bbox[2]+bbox[3])/2]] if self.options.vertical: bbox=[-bbox[3],-bbox[2],bbox[0],bbox[1]] mat=simpletransform.composeTransform([[0,-1,0],[1,0,0]],mat) mat[1][2] += self.options.noffset simpletransform.applyTransformToNode(mat,self.patternNode) width=bbox[1]-bbox[0] dx=width+self.options.space for skelnode in self.skeletons.itervalues(): self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: self.skelcomp,self.lengths=linearize(comp) #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! self.skelcompIsClosed = (self.skelcomp[0]==self.skelcomp[-1]) length=sum(self.lengths) if self.options.stretch: dx=width+self.options.space n=int((length-self.options.toffset+self.options.space)/dx) if n>0: dx=(length-self.options.toffset)/n xoffset=self.skelcomp[0][0]-bbox[0]+self.options.toffset yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2-self.options.noffset s=self.options.toffset while s<=length: mat=self.localTransformAt(s,self.options.follow) clone=copy.deepcopy(self.patternNode) #!!!--> should it be given an id? #seems to work without this!?! myid = self.patternNode.tag.split('}')[-1] clone.set("id", self.uniqueId(myid)) self.gNode.append(clone) simpletransform.applyTransformToNode(mat,clone) s+=dx self.patternNode.getparent().remove(self.patternNode)
def parsePath(self, node, transforms, names): name = "" for n in names: name = n + "_" + name name = name + node.get("id") m2 = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] for t in transforms: m = simpletransform.parseTransform(t) m2 = simpletransform.composeTransform(m2, m) m = simpletransform.parseTransform(node.get("transform")) m2 = simpletransform.composeTransform(m2, m) color = self.get_color(node) path = simplepath.formatPath(simplepath.parsePath(node.get('d'))) subpaths = path.split('M') for i in range(1, len(subpaths)): subpaths[i] = 'M ' + rstrip(subpaths[i]) closed = subpaths[i][-1] in ['Z', 'z'] csp = cubicsuperpath.parsePath(subpaths[i]) simpletransform.applyTransformToPath(m2, csp) if closed: self.closed2curves(csp) else: self.opened2curves(csp) vertices = self.cast2spine(csp, closed) if len(vertices) >= 9 and closed or len(vertices) >= 6 and not closed: self.path2json(name + "_" + str(i), closed, color, vertices) else: inkex.debug("skipping " + name + "_" + str(i) + ": vertex count < 6 (" + str(len(vertices)) + ")")
def effect(self): object2path.ObjectToPath.effect(self) transformMatrix = [[1,0,0],[0,1,0]] dims = self.determine_dims(transformMatrix) [x,y,X,Y] = dims width = X - x height = Y - y # Longest side is vertical if width > height: scale = 480.0 / height if scale * width > 999.0: inkex.errormsg("Plot area is to large (%f > 999)." % scale*height) exit() transformMatrix = parseTransform('translate(%f,%f)' % (-x,-y)) transformMatrix = composeTransform(parseTransform('rotate(-90)'), transformMatrix) transformMatrix = composeTransform(parseTransform('scale(%f,%f)' % (scale,scale)), transformMatrix) else: scale = 480.0 / width if scale * height > 999.0: inkex.errormsg("Plot area is to large (%f > 999)." % scale*height) exit() transformMatrix = parseTransform('translate(%f,%f)' % (-x,-y)) transformMatrix = composeTransform(parseTransform('rotate(180)'), transformMatrix) transformMatrix = composeTransform(parseTransform('translate(%f,0)' % width), transformMatrix) transformMatrix = composeTransform(parseTransform('scale(%f,%f)' % (-scale,scale)), transformMatrix) transformMatrix = composeTransform(parseTransform('translate(480,0)'), transformMatrix) paths = [] for [path, node] in self.processPaths(transformMatrix): color = (0, 0, 0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if 'stroke' in style: if style['stroke'] and style['stroke'] != 'none': color = simplestyle.parseColor(style['stroke']) points = [] for point in self.processPath(path): points.append(point) paths.append({'color':color, 'points':points}) dims = self.determine_dims(transformMatrix) if self.options.debug: print >>sys.stderr, "VC1520 debug info" print >>sys.stderr, "-----------------" print >>sys.stderr, "plot area: minX:%d, minY:%d, maxX:%d, maxY:%d" % tuple(dims) print >>sys.stderr, "nr paths: %d" % len(paths) i = 0 print >>sys.stderr, "path;color;points" for path in paths: print >>sys.stderr, "%d;%s;%d" % (i,self.find_color(path['color']),len(path['points'])) i += 1 for path in paths: print >>sys.stderr, path else: self.plot(paths, dims[1])
def i2d_affine(self, node, use_cache=True): ''' Get the "item to document" transformation matrix. Note: use_cache showed 20% speed improvement for a big SVG document ''' if use_cache and node in self.i2d_cache: return self.i2d_cache[node] import simpletransform m2 = simpletransform.parseTransform(node.get('transform')) parent = node.getparent() if parent is not None: m1 = self.i2d_affine(parent, use_cache) m2 = simpletransform.composeTransform(m1, m2) else: m2 = simpletransform.composeTransform(self.r2d, m2) m2 = simpletransform.composeTransform([[th2pref.basescale, 0.0, 0.0], [0.0, th2pref.basescale, 0.0]], m2) self.i2d_cache[node] = m2 return m2
def get_transform(self, elem, parent_transform=None): """ Get this element's transform as a matrix. If parent_transform is specified, return the cumulative transform. """ transform = elem.attrib.get('transform', '').strip() if transform: transform = simpletransform.parseTransform(transform) else: transform = [[1,0,0], [0,1,0], [0,0,1]] if parent_transform: transform = simpletransform.composeTransform(parent_transform, transform) return transform
def processPaths(self, transformMatrix): path = '//svg:path' pm = pathmodifier.PathModifier() for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): pm.objectToPath(node, True) d = node.get('d') p = cubicsuperpath.parsePath(d) t = node.get('transform') if t is not None: transformMatrix = composeTransform(transformMatrix, parseTransform(t)) applyTransformToPath(transformMatrix, p) yield [p, node]
def get_node_transform(node): # start with the identity transform transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] # this if is because sometimes inkscape likes to create paths outside of a layer?! if node.getparent() is not None: # combine this node's transform with all parent groups' transforms transform = simpletransform.composeParents(node, transform) # add in the transform implied by the viewBox viewbox_transform = get_viewbox_transform(node.getroottree().getroot()) transform = simpletransform.composeTransform(viewbox_transform, transform) return transform
def getGlobalTransform(self,node): parent = node.getparent() myTrans = simpletransform.parseTransform(node.get('transform')) if myTrans: if parent is not None: parentTrans = self.getGlobalTransform(parent) if parentTrans: return simpletransform.composeTransform(parentTrans,myTrans) else: return myTrans else: if parent is not None: return self.getGlobalTransform(parent) else: return None
def process_path(self, node, mat): d = node.get('d') if d: 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) for sp in p: first = True for csp in sp: cmd = 'PD' if first: cmd = 'PU' first = False self.hpgl.append('%s%d,%d;' % (cmd,csp[1][0],csp[1][1]))
def process_shapes(self, shapelist, transform): """Convert the SVG shape elements to Lines and CubicBeziers, and apply object/layer transforms. Returns a list of tuples ((path-id, path), ...). """ cutpath_list = [] for node, layer_transform in shapelist: # Convert the shape element to a simplepath path = supereffect.convert_element_to_path(node) # Convert the simplepath to a 'cubicsuperpath' which is # just a list of cubic bezier curves. # This seems to be how most Inkscape plugins do things... # TODO: This is really an unnecessary step since # we could deal with SVG shapes directly... csp = cubicsuperpath.CubicSuperPath(path) # Apply the SVG element transform and it's layer transform to the # path segments so that we are working in absolute coordinates. # Transform SVG coordinates into cartesian (ie G code) coordinates # (flip the Y axis from upper left to lower left). # node_transform = simpletransform.parseTransform(node.get('transform')) # node_transform = simpletransform.composeTransform(node_transform, transform) # node_transform = simpletransform.composeTransform(node_transform, layer_transform) node_transform = simpletransform.composeTransform(transform, layer_transform) simpletransform.applyTransformToPath(node_transform, csp) # Convert cubic path segments to curves and lines # TODO: get bounding boxes and calculate offset if doc origin not used. cutpath = paths.Path(name=node.get('id')) for subcsp in csp: for i in range(1,len(subcsp)): p1 = geom.P(subcsp[i-1][1]) c1 = geom.P(subcsp[i-1][2]) p2 = geom.P(subcsp[i][0]) c2 = geom.P(subcsp[i][1]) if p1 == c1 and p2 == c2: segment = geom.Line(p1, p2) else: segment = geom.CubicBezier(p1, c1, p2, c2) cutpath.append(segment) cutpath_list.append(cutpath) return cutpath_list
def convert_url(self, url_id, mtx, d): """Return a list Synfig layers that represent the gradient with the given id""" gradient = d.get_gradient(url_id) if gradient is None: # Patterns and other URLs not supported return [None] if gradient["type"] == "linear": layer = d.create_layer( "linear_gradient", url_id, d.gradient_to_params(gradient), guids={"gradient": gradient["stops_guid"]} ) if gradient["type"] == "radial": layer = d.create_layer( "radial_gradient", url_id, d.gradient_to_params(gradient), guids={"gradient": gradient["stops_guid"]} ) return d.op_transform([layer], simpletransform.composeTransform(mtx, gradient["mtx"]))
def transform(self, elem, setval=None, parent_transform=None): """ Gets this element's transform. Use setval=matrix to set this element's transform. You can only specify parent_transform when getting. """ transform = elem.attrib.get("transform", "").strip() if transform: transform = simpletransform.parseTransform(transform) else: transform = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] if parent_transform: transform = simpletransform.composeTransform(parent_transform, transform) if setval: elem.attrib["transform"] = simpletransform.formatTransform(setval) else: return transform
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': layer = group.get(inkex.addNS('label', 'inkscape')) layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer 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('g','svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def process_group(self, group): 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 list_deep_paths(self, node, trans=None): if trans is None: trans = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] trans = simpletransform.composeTransform( trans, simpletransform.parseTransform(node.get('transform', None))) if node.tag == SVG_PATH_TAG: path = simplepath.parsePath(node.get("d")) #simpletransform.applyTransformToPath(trans, path) yield DrawItem('vector', node.get('id'), path, trans) elif node.tag == SVG_GROUP_TAG: for child in node.iterchildren(): for path in self.list_deep_paths(child, trans=trans): yield path else: inkex.errormsg("Cannot parse node with tag %s" % (node.tag))
def i2d_affine(self, node): m2 = simpletransform.parseTransform(node.get('transform')) while True: node = node.getparent() if node is None: break viewBox = node.get('viewBox') t1 = node.get('transform') if viewBox: viewBox = [float(i) for i in viewBox.split()] doc_width = self.unittouu(node.get('width', viewBox[2])) doc_height = self.unittouu(node.get('height', viewBox[3])) m1 = [[doc_width / viewBox[2], 0, -viewBox[0]], [0, doc_height / viewBox[3], -viewBox[1]]] elif t1: m1 = simpletransform.parseTransform(t1) else: continue m2 = simpletransform.composeTransform(m1, m2) return m2
def recursiveFuseTransform(node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): transf = composeTransform(transf, parseTransform(node.get("transform", None))) if "transform" in node.attrib: del node.attrib["transform"] node = ApplyTransform.objectToPath(node) if "d" in node.attrib: d = node.get("d") p = cubicsuperpath.parsePath(d) applyTransformToPath(transf, p) node.set("d", cubicsuperpath.formatPath(p)) elif node.tag == inkex.addNS("rect", "svg"): node.set("transform", formatTransform(transf)) for child in node.getchildren(): ApplyTransform.recursiveFuseTransform(child, transf)
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style['display'] == 'none' and self.visibleLayers: 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('g','svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def recursivelyGetEnclosingTransform( self, node ): ''' Determine the cumulative transform which node inherits from its chain of ancestors. ''' node = node.getparent() if node is not None: parent_transform = self.recursivelyGetEnclosingTransform( node ) node_transform = node.get( 'transform', None ) if node_transform is None: return parent_transform else: tr = simpletransform.parseTransform( node_transform ) if parent_transform is None: return tr else: return simpletransform.composeTransform( parent_transform, tr ) else: return self.docTransform