def effect(self): # get number of digits prec = int(self.options.precision) # loop over all selected paths for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg')) t = node.get('transform') # Removed to fix LP #308183 # (Measure Path text shifted when used with a copied object) #if t: # self.group.set('transform', t) a =[] p = cubicsuperpath.parsePath(node.get('d')) num = 1 factor = 1.0/inkex.unittouu('1'+self.options.unit) if self.options.type == "length": slengths, stotal = csplength(p) else: stotal,x0,y0 = csparea(p) stotal *= factor*self.options.scale # Format the length as string lenstr = locale.format("%(len)25."+str(prec)+"f",{'len':round(stotal*factor*self.options.scale,prec)}).strip() if self.options.type == "length": self.addTextOnPath(self.group,0, 0,lenstr+' '+self.options.unit, id, self.options.offset) else: self.addTextWithTspan(self.group,x0,y0,lenstr+' '+self.options.unit+'^2', id, self.options.offset)
def effect(self): if len(self.options.ids)<2: inkex.errormsg(_("This extension requires two selected paths.")) return self.prepareSelectionList() self.tolerance=math.pow(10,self.options.space); for id, node in self.patterns.iteritems(): if node.tag == inkex.addNS('path','svg') or node.tag=='path': d = node.get('d') p0 = cubicsuperpath.parsePath(d) origin = p0[0][0][1]; newp=[] for skelnode in self.skeletons.itervalues(): self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: self.skelcomp=linearize(comp,self.tolerance) for comp in self.skelcomp: p=copy.deepcopy(p0) for sub in p: xoffset=comp[0]-origin[0]+self.options.xoffset yoffset=comp[1]-origin[1]+self.options.yoffset offset(sub,xoffset,yoffset) newp+=p node.set('d', cubicsuperpath.formatPath(newp))
def effect(self): if len(self.options.ids)!=1: inkex.errormsg(_("This extension requires one selected path.")) return self.prepareSelectionList() bbox=simpletransform.computeBBox(self.patterns.values()) width=bbox[1]-bbox[0] dx=width+self.options.padding if dx < 0.01: exit(_("The total length of the pattern is too small :\nPlease choose a larger object or set 'Space between copies' > 0")) for id, node in self.patterns.iteritems(): if node.tag == inkex.addNS('path','svg') or node.tag=='path': d = node.get('d') p0 = cubicsuperpath.parsePath(d) newp=[] for skelnode in self.skeletons.itervalues(): self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: p=copy.deepcopy(p0) self.skelcomp,self.lengths=linearize(comp) self.skelcompIsClosed = (self.skelcomp[0]==self.skelcomp[-1]) length=sum(self.lengths) xoffset=self.skelcomp[0][0]-bbox[0] yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2 NbCopies=max(1,int(round((length+self.options.padding)/dx))) width=dx*NbCopies if not self.skelcompIsClosed: width-=self.options.padding bbox=bbox[0],bbox[0]+width, bbox[2],bbox[3] new=[] for sub in p: for i in range(0,NbCopies,1): new.append(copy.deepcopy(sub)) offset(sub,dx,0) p=new for sub in p: offset(sub,xoffset,yoffset) for sub in p: for ctlpt in sub: self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) newp+=p node.set('d', cubicsuperpath.formatPath(newp)) for selected_element in self.selected.itervalues(): self.remove(selected_element)
def effect(self): sep = self.options.seperator f = open( os.path.join(self.options.output_dir, self.options.output_filename), "w") x_off = self.options.x_offset y_off = self.options.y_offset # Get document height and trim the units string off the end doc_h = float(self.getDocumentHeight()[:-2]) for node in self.selected.values(): if node.tag == inkex.addNS("path", "svg"): # Make sure the path is in absolute coords simpletransform.fuseTransform(node) path = cubicsuperpath.parsePath(node.get("d")) for sub_path in path: # sub_path represents a list of all nodes in the path for node in sub_path: # node type is SubPath[(point_a, bezier, point_b) # We dont want the control points, we only want the bezier # point_a, bezier, and point_b is a list of length 2 and type float x = node[1][0] y = node[1][1] x = x + x_off if self.options.origin == "south_west_corner": y = doc_h - y + y_off else: y = y + y_off f.write(str(x) + sep + str(y) + sep + "\n") f.close()
def plotPath(self, node, matTransform): """ Plot the path while applying the transformation defined by the matrix matTransform. """ filledPath = (simplestyle.parseStyle(node.get("style")).get("fill", "none") != "none") # Plan: Turn this path into a cubicsuperpath (list of beziers)... d = node.get("d") if len(simplepath.parsePath(d)) == 0: return p = cubicsuperpath.parsePath(d) # ... and apply the transformation to each point. simpletransform.applyTransformToPath(matTransform, p) # p is now a list of lists of cubic beziers [cp1, cp2, endp] # where the start-point is the last point of the previous segment. # For some reason the inkscape extensions uses csp[1] as the coordinates of each point, # but that makes it seem like they are using control point 2 as line points. # Maybe that is a side-effect of the CSP subdivion process? TODO realPoints = [] for sp in p: cspsubdiv.subdiv(sp, self.smoothness) for csp in sp: realPoints.append( (csp[1][0], csp[1][1]) ) self.rawObjects.append( (filledPath, realPoints) )
def load(self, node, mat): #JiB #split the syle in separate tuples and assign to path s = node.get('style') if s: self.style = s for item in s.split(';'): attribute , value = item.split(':') #print attribute, value value = value.replace('px', '') setattr(self, attribute.replace('-','') , value) #print getattr(self, attribute.replace('-','') ) #print ";" + self.strokewidth #print attribute.replace('-','') d = node.get('d') if len(simplepath.parsePath(d)) == 0: return p = cubicsuperpath.parsePath(d) applyTransformToPath(mat, p) # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint] # where the start-point is the last point in the previous segment self.segments = [] for sp in p: points = [] subdivideCubicPath(sp,0.2) # TODO: smoothness preference for csp in sp: points.append((csp[1][0],csp[1][1])) self.segments.append(points)
def effect(self): scale = self.options.scale scaleFrom = self.options.scaleFrom tolerance = 10**(-1 * self.options.precision) printOut = False selections = self.selected pathNodes = self.document.xpath('//svg:path', namespaces=inkex.NSS) outStrs = [str(len(pathNodes))] paths = [(pathNode.get('id'), cubicsuperpath.parsePath(pathNode.get('d'))) \ for pathNode in pathNodes if (pathNode.get('id') in selections.keys())] if (len(paths) > 1): srcPath = paths[-1][1] srclen = self.getLength(srcPath, tolerance) paths = paths[:len(paths) - 1] for key, cspath in paths: curveLen = self.getLength(cspath, tolerance) self.scaleCubicSuper(cspath, scaleFactor = scale * (srclen / curveLen), \ scaleFrom = scaleFrom) selections[key].set('d', cubicsuperpath.formatPath(cspath)) else: inkex.errormsg( _("Please select at least two paths, with the path whose \ length is to be copied at the top. You may have to convert the shape \ to path with path->Object to Path."))
def effect(self): for node in self.selected.items(): output_all = output_nodes = "" output_nodes_xy = {'x': "", 'y': ""} float_value = 2 for id, node in self.selected.items(): if node.tag == inkex.addNS('path', 'svg'): output_all += "" output_nodes += "" simpletransform.fuseTransform(node) d = node.get('d') p = cubicsuperpath.parsePath(d) for subpath in p: for csp in subpath: output_nodes_xy['x'] += str( round(csp[1][0], float_value)) + ", " output_nodes_xy['y'] += str( round(csp[1][1], float_value)) + ", " output_nodes += str(csp[1][0]) + "\t" + str( csp[1][1]) + "\n" sys.stderr.write("XY list:\n") sys.stderr.write(output_nodes) sys.stderr.write("\n\nPython dict:\n") sys.stderr.write("{\n'x':[" + output_nodes_xy['x'][:-2] + "],\n'y':[" + output_nodes_xy['y'][:-2] + "]\n}\n")
def effect(self): gcode = "" i = 0 doc = self.document.getroot() factor = self.unittouu(doc.get('width')) inkex.debug(factor) for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') p = cubicsuperpath.parsePath(d) cspsubdiv.cspsubdiv(p, self.options.flat) np = [] first = True gcode = "M3 S255(colona " + str(i) + ") \n" #+"G01 F500.000\n" for csp in p[0]: cmd = 'L' if first: cmd = 'M' first = False np.append([cmd, [csp[1][0], csp[1][1]]]) gcode += "G01 X" + str( round(self.uutounit(csp[1][0], "mm"), 2)) + " Y" + str( round(self.uutounit(csp[1][1], "mm"), 2)) + "\n" node.set('d', simplepath.formatPath(np)) f = open("costycnc.nc", 'w') f.write(str(gcode)) f.close()
def effect(self): self.dxf_insert_code('999', '"DXF R12 Output" (www.mydxf.blogspot.com)') self.dxf_add(r12_header) scale = 25.4 / 90.0 h = self.unittouu(self.getDocumentHeight()) path = '//svg:path' for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): layer = node.getparent().get(inkex.addNS('label', 'inkscape')) if layer == None: layer = 'Layer 1' d = node.get('d') p = cubicsuperpath.parsePath(d) t = node.get('transform') if t != None: m = simpletransform.parseTransform(t) simpletransform.applyTransformToPath(m, p) m = [[scale, 0, 0], [0, -scale, h * scale]] simpletransform.applyTransformToPath(m, p) if re.search('drill$', layer, re.I) == None: #if layer == 'Brackets Drill': self.dxf_path_to_lines(layer, p) else: self.dxf_path_to_point(layer, p) self.dxf_add(r12_footer)
def combine_many_paths(path_list): """Combine paths in path_list to single compound path.""" if len(path_list): csp = [] first = path_list[0] for path in path_list: csp_path = cubicsuperpath.parsePath(path.get('d')) mat.apply_to(mat.copy_from(path), csp_path) if path == first: csp.append(csp_path) else: # transform csp_path into first coords mat.apply_to(mat.absolute_diff(first, path), csp_path) # compensate preserved transform of first in csp_path mat.apply_to(mat.invert(mat.copy_from(first)), csp_path) csp[0].append(csp_path[0]) # insert as new path into document path = inkex.etree.Element(inkex.addNS('path', 'svg')) path.set('d', cubicsuperpath.formatPath(csp[0])) # insert before source path index = first.getparent().index(first) first.getparent().insert(index, path) # return new path return path else: return None
def combine_two_paths(path0_path1): """Combine two paths into a new one. Combine the transformed csp representations as sub-paths, insert new path element with path data from csp path into document and return the etree element. """ path0, path1 = path0_path1 csp = [] for path in (path0, path1): csp_path = cubicsuperpath.parsePath(path.get('d')) mat.apply_to(mat.copy_from(path), csp_path) csp.append(csp_path) # transform path1 into path0 coords mat.apply_to(mat.absolute_diff(path0, path1), csp[1]) # compensate preserved transform of path0 in csp1 mat.apply_to(mat.invert(mat.copy_from(path0)), csp[1]) # combine the two csp paths (append csp1 as sub-path to csp0) csp[0].append(csp[1][0]) # insert as new path into document path = inkex.etree.Element(inkex.addNS('path', 'svg')) path.set('d', cubicsuperpath.formatPath(csp[0])) # insert before source path index = path0.getparent().index(path0) path0.getparent().insert(index, path) # return new path return path
def process_layer(self, layer_element, layer_name): #For each layer group, get each path. for element in layer_element.iter(tag_path): log("Found path: " + str(element.attrib['d'])) #Get the point transform at node svg_transforms = self.get_transform_list(element) #Parse path parsed_path = cubicsuperpath.parsePath(element.attrib['d']) #Convert into polyline cspsubdiv.cspsubdiv(parsed_path, self.resolution) #At this point, parsed_path contains a list of list of points (yes, I know) #so for each "path", each "subpath" we should get an array of points for subpath in parsed_path: log(" Subpath (%d points)" % len(subpath)) #Write footprint path begining self.out_file.write(polygon_header) for point in subpath: point = list(point[1]) for transform in svg_transforms: log("Applying transform: " + str(transform)) simpletransform.applyTransformToPoint(transform, point) log(" Point: " + str(point)) #transform point using self.transform matrix #write individual point self.out_file.write("(xy %f %f) " % (point[0], point[1])) self.out_file.write(polygon_footer.format(layer=layer_name))
def effect(self): for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) #lens, total = csplength(p) #avg = total/numlengths(lens) #inkex.debug("average segment length: %s" % avg) new = [] for sub in p: new.append([sub[0][:]]) i = 1 while i <= len(sub)-1: length = cspseglength(new[-1][-1], sub[i]) if length > self.options.max: splits = math.ceil(length/self.options.max) for s in xrange(int(splits),1,-1): new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s) new[-1].append(next[:]) new[-1].append(sub[i]) i+=1 d.value = cubicsuperpath.formatPath(new)
def effect(self): for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) #lens, total = csplength(p) #avg = total/numlengths(lens) #inkex.debug("average segment length: %s" % avg) new = [] for sub in p: new.append([sub[0][:]]) i = 1 while i <= len(sub) - 1: length = cspseglength(new[-1][-1], sub[i]) if length > self.options.max: splits = math.ceil(length / self.options.max) for s in xrange(int(splits), 1, -1): new[-1][-1], next, sub[ i] = cspbezsplitatlength( new[-1][-1], sub[i], 1.0 / s) new[-1].append(next[:]) new[-1].append(sub[i]) i += 1 d.value = cubicsuperpath.formatPath(new)
def computeBBox(aList, mat=[[1, 0, 0], [0, 1, 0]]): bbox = None for node in aList: m = parseTransform(node.get('transform')) m = composeTransform(mat, m) #TODO: text not supported! if node.tag == inkex.addNS('rect', 'svg'): A = [0, 0] B = [0, 0] A[0] = float(node.get('x')) A[1] = float(node.get('y')) B[0] = A[0] + float(node.get('width')) B[1] = A[1] + float(node.get('height')) applyTransformToPoint(mat, A) applyTransformToPoint(mat, B) bbox = min(A[0], B[0]), max(A[0], B[0]), min(A[1], B[1]), max(A[1], B[1]) if node.get("d"): d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(m, p) bbox = boxunion(roughBBox(p), bbox) if node.tag == inkex.addNS('use', 'svg') or node.tag == 'use': refid = node.get(inkex.addNS('href', 'xlink')) path = '//*[@id="%s"]' % refid[1:] refnode = node.getroottree().xpath(path, namespaces=inkex.NSS) bbox = boxunion(computeBBox(refnode, m), bbox) bbox = boxunion(computeBBox(node, m), bbox) return bbox
def effect(self): view_center = computePointInNode(list(self.view_center), self.current_layer) for id, node in self.selected.iteritems(): rotation = -1 if self.options.rotation == True: rotation = 1 whirl = self.options.whirl / 1000 if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') p = cubicsuperpath.parsePath(d) for sub in p: for csp in sub: for point in csp: point[0] -= view_center[0] point[1] -= view_center[1] dist = math.sqrt((point[0]**2) + (point[1]**2)) if dist != 0: a = rotation * dist * whirl theta = math.atan2(point[1], point[0]) + a point[0] = (dist * math.cos(theta)) point[1] = (dist * math.sin(theta)) point[0] += view_center[0] point[1] += view_center[1] node.set('d', cubicsuperpath.formatPath(p))
def computeBBox(aList,mat=[[1,0,0],[0,1,0]]): bbox=None for node in aList: m = parseTransform(node.get('transform')) m = composeTransform(mat,m) #TODO: text not supported! if node.get("d"): d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(m,p) bbox=boxunion(roughBBox(p),bbox) elif node.tag == inkex.addNS('rect','svg') or node.tag=='rect': w = float(node.get('width'))/2. h = float(node.get('height'))/2. x = float(node.get('x')) y = float(node.get('y')) C = [x + w , y + h ] applyTransformToPoint(mat,C) xmin = C[0] - abs(m[0][0]) * w - abs(m[0][1]) * h xmax = C[0] + abs(m[0][0]) * w + abs(m[0][1]) * h ymin = C[1] - abs(m[1][0]) * w - abs(m[1][1]) * h ymax = C[1] + abs(m[1][0]) * w + abs(m[1][1]) * h bbox = xmin,xmax,ymin,ymax elif node.tag == inkex.addNS('use','svg') or node.tag=='use': refid=node.get(inkex.addNS('href','xlink')) path = '//*[@id="%s"]' % refid[1:] refnode = node.xpath(path) bbox=boxunion(computeBBox(refnode,m),bbox) bbox=boxunion(computeBBox(node,m),bbox) return bbox
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): p = cubicsuperpath.parsePath(node.get('d')) coords = [] openPath = False for sub in p: if sub[0][0] == sub[-1][2]: p0 = sub[0][1] i = 0 while i < len(sub) - 1: p1 = sub[i][2] p2 = sub[i + 1][0] p3 = sub[i + 1][1] bez = (p0, p1, p2, p3) coords.extend( bezlinearize(bez, self.options.num_points)) p0 = p3 i += 1 else: openPath = True inkex.errormsg("Path doesn't appear to be closed") if not openPath: c = centroid(coords) ## debug linearization # many_lines(coords, self.current_layer) # draw_SVG_dot(c, self.options.centroid_radius, "centroid-dot", self.current_layer)
def computeBBox(aList,mat=[[1,0,0],[0,1,0]]): bbox=None for node in aList: m = parseTransform(node.get('transform')) m = composeTransform(mat,m) #TODO: text not supported! if node.tag == inkex.addNS('rect','svg'): A=[0,0] B=[0,0] A[0] = float(node.get('x')) A[1] = float(node.get('y')) B[0] = A[0]+float(node.get('width')) B[1] = A[1]+float(node.get('height')) applyTransformToPoint(mat, A) applyTransformToPoint(mat, B) bbox = min(A[0], B[0]), max(A[0], B[0]), min(A[1], B[1]), max(A[1], B[1]) if node.get("d"): d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(m,p) bbox=boxunion(roughBBox(p),bbox) if node.tag == inkex.addNS('use','svg') or node.tag=='use': refid=node.get(inkex.addNS('href','xlink')) path = '//*[@id="%s"]' % refid[1:] refnode = node.getroottree().xpath(path, namespaces=inkex.NSS) bbox=boxunion(computeBBox(refnode,m),bbox) bbox=boxunion(computeBBox(node,m),bbox) return bbox
def get_paths(self, use_symmetry=True): if self.paths is not None: if use_symmetry: return [item for sublist in self.paths for item in sublist] else: return self.paths[0] # simplify / rotate shape self.paths = [] for i in xrange(self.symmetry): self.paths.append([]) xform = ( TransformMatrix.translate(self.origin) * TransformMatrix.rotateAxis( Point(0,0,1), angle=2*pi*i/self.symmetry ) * TransformMatrix.translate(-self.origin) ) for node in self.effect.layer_contents(self.layer): if node.tag == inkex.addNS('path', 'svg'): xform2 = xform * TransformMatrix.fromSVG( simpletransform.parseTransform(node.get('transform')) ) d = node.get('d') p = cubicsuperpath.parsePath(d) cspsubdiv.cspsubdiv(p, FLATNESS) for sp in p: thisPath = [] for csp in sp: thisPath.append( Point(csp[1][0],csp[1][1],0).transform(xform2) ) self.paths[i].append(thisPath) return self.get_paths(use_symmetry)
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): p = cubicsuperpath.parsePath(node.get('d')) coords = [] openPath = False for sub in p: if sub[0][0] == sub[-1][2]: p0 = sub[0][1] i = 0 while i < len(sub)-1: p1 = sub[i][2] p2 = sub[i+1][0] p3 = sub[i+1][1] bez = (p0, p1, p2, p3) coords.extend(bezlinearize(bez, self.options.num_points)) p0 = p3 i+=1 else: openPath = True inkex.errormsg("Path doesn't appear to be closed") if not openPath: c = centroid(coords) ## debug linearization # many_lines(coords, self.current_layer) # draw_SVG_dot(c, self.options.centroid_radius, "centroid-dot", self.current_layer)
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): p = cubicsuperpath.parsePath(node.get('d')) #lens, total = csplength(p) #avg = total/numlengths(lens) #inkex.debug("average segment length: %s" % avg) new = [] for sub in p: new.append([sub[0][:]]) i = 1 while i <= len(sub)-1: length = cspseglength(new[-1][-1], sub[i]) if self.options.method == 'bynum': splits = self.options.segments else: splits = math.ceil(length/self.options.max) for s in xrange(int(splits),1,-1): new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s) new[-1].append(next[:]) new[-1].append(sub[i]) i+=1 node.set('d',cubicsuperpath.formatPath(new))
def computeBBox(self, aList): bbox=None for id, node in aList.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) bbox=boxunion(roughBBox(p),bbox) return bbox
def effect(self): if len(self.options.ids) < 2: inkex.errormsg(_("This extension requires two selected paths. \nThe second path must be exactly four nodes long.")) exit() #obj is selected second scale = self.unittouu('1px') # convert to document units obj = self.selected[self.options.ids[0]] trafo = self.selected[self.options.ids[1]] if obj.get(inkex.addNS('type','sodipodi')): inkex.errormsg(_("The first selected object is of type '%s'.\nTry using the procedure Path->Object to Path." % obj.get(inkex.addNS('type','sodipodi')))) exit() if obj.tag == inkex.addNS('path','svg') or obj.tag == inkex.addNS('g','svg'): if trafo.tag == inkex.addNS('path','svg'): #distil trafo into four node points mat = simpletransform.composeParents(trafo, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) trafo = cubicsuperpath.parsePath(trafo.get('d')) if len(trafo[0]) < 4: inkex.errormsg(_("This extension requires that the second selected path be four nodes long.")) exit() simpletransform.applyTransformToPath(mat, trafo) trafo = [[Point(csp[1][0],csp[1][1]) for csp in subs] for subs in trafo][0][:4] #vectors pointing away from the trafo origin self.t1 = Segment(trafo[0],trafo[1]) self.t2 = Segment(trafo[1],trafo[2]) self.t3 = Segment(trafo[3],trafo[2]) self.t4 = Segment(trafo[0],trafo[3]) #query inkscape about the bounding box of obj self.q = {'x':0,'y':0,'width':0,'height':0} file = self.args[-1] id = self.options.ids[0] for query in self.q.keys(): if bsubprocess: p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query,id,file), shell=True, stdout=PIPE, stderr=PIPE) rc = p.wait() self.q[query] = scale*float(p.stdout.read()) err = p.stderr.read() else: f,err = os.popen3('inkscape --query-%s --query-id=%s "%s"' % (query,id,file))[1:] self.q[query] = scale*float(f.read()) f.close() err.close() if obj.tag == inkex.addNS("path",'svg'): self.process_path(obj) if obj.tag == inkex.addNS("g",'svg'): self.process_group(obj) else: if trafo.tag == inkex.addNS('g','svg'): inkex.errormsg(_("The second selected object is a group, not a path.\nTry using the procedure Object->Ungroup.")) else: inkex.errormsg(_("The second selected object is not a path.\nTry using the procedure Path->Object to Path.")) exit() else: inkex.errormsg(_("The first selected object is not a path.\nTry using the procedure Path->Object to Path.")) exit()
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 process_path(self,path,m): d = path.get('d') p = cubicsuperpath.parsePath(d) for subs in p: for csp in subs: csp[0] = self.project_point(csp[0],m) csp[1] = self.project_point(csp[1],m) csp[2] = self.project_point(csp[2],m) path.set('d',cubicsuperpath.formatPath(p))
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 process_path(self,path,m): d = path.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) for subs in p: for csp in subs: csp[0] = self.project_point(csp[0],m) csp[1] = self.project_point(csp[1],m) csp[2] = self.project_point(csp[2],m) d.value = cubicsuperpath.formatPath(p)
def process_path(self,path): d = path.get('d') p = cubicsuperpath.parsePath(d) for subs in p: for csp in subs: csp[0] = self.trafopoint(csp[0]) csp[1] = self.trafopoint(csp[1]) csp[2] = self.trafopoint(csp[2]) path.set('d',cubicsuperpath.formatPath(p))
def fuseTransform(node): m=parseTransform(node.getAttributeNS(None,"transform")) d = node.getAttributeNS(None,'d') p=cubicsuperpath.parsePath(d) for comp in p: for ctl in comp: for pt in ctl: applyTransformToPoint(m,pt) node.setAttributeNS(None,'d', cubicsuperpath.formatPath(p)) node.removeAttributeNS(None,"transform")
def effect(self): paths = [] for id, node in self.selected.iteritems(): if node.tag == '{http://www.w3.org/2000/svg}path': paths.append(node) if len(paths) == 2: break else: sys.stderr.write('Need 2 paths selected\n') return pts = [cubicsuperpath.parsePath(paths[i].get('d')) for i in (0,1)] for i in (0,1): if 'transform' in paths[i].keys(): trans = paths[i].get('transform') trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) verts = [] for i in range(0, min(map(len, pts))): comp = [] for j in range(0, min(len(pts[0][i]), len(pts[1][i]))): comp.append([pts[0][i][j][1][-2:], pts[1][i][j][1][-2:]]) verts.append(comp) if self.options.mode.lower() == 'lines': line = [] for comp in verts: for n,v in enumerate(comp): line += [('M', v[0])] line += [('L', v[1])] ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') paths[0].xpath('..')[0].append(ele) ele.set('d', simplepath.formatPath(line)) ele.set('style', 'fill:none;stroke:#000000;stroke-opacity:1;stroke-width:1;') elif self.options.mode.lower() == 'polygons': g = inkex.etree.Element('{http://www.w3.org/2000/svg}g') g.set('style', 'fill:#000000;stroke:#000000;fill-opacity:0.3;stroke-width:2;stroke-opacity:0.6;') paths[0].xpath('..')[0].append(g) for comp in verts: for n,v in enumerate(comp): nn = n+1 if nn == len(comp): nn = 0 line = [] line += [('M', comp[n][0])] line += [('L', comp[n][1])] line += [('L', comp[nn][1])] line += [('L', comp[nn][0])] line += [('L', comp[n][0])] ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') g.append(ele) ele.set('d', simplepath.formatPath(line))
def load(self, node, mat): self.id = node.get('id') d = node.get('d') if len(simplepath.parsePath(d)) == 0: return p = cubicsuperpath.parsePath(d) applyTransformToPath(mat, p) # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint] # where the start-point is the last point in the previous segment self.points = [] self.paths = [] for sp in p: path = [] subdivide_cubic_path(sp, 0.2) # TODO: smoothness preference for csp in sp: point = [csp[1][0], csp[1][1]] if point not in self.points: self.points.append(point) path.append(self.points.index(point)) self.paths.append(path) # get color style = node.get('style') try: hexcolor = re.search('fill:#([0-9a-fA-f]{6})', style).group(1) rgb = [ int(hexcolor[0:2], 16), int(hexcolor[2:4], 16), int(hexcolor[4:6], 16) ] except (TypeError, AttributeError): rgb = None # get optional opacity try: opacity = float(re.search('(?:^|;)opacity:([0-9]*\.?[0-9]+)', style).group(1)) except (TypeError, AttributeError): opacity = 1.0 # get optional fill-opacity (of course there is more than one way to set opacity of paths...) try: fill_opacity = float(re.search('(?:^|;)fill-opacity:([0-9]*\.?[0-9]+)', style).group(1)) except (TypeError, AttributeError): fill_opacity = 1.0 if rgb: self.color = [ rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0, opacity * fill_opacity ] else: self.color = None
def effect(self): for id, node in self.selected.iteritems(): if node.tag == '{http://www.w3.org/2000/svg}path': path=node break else: sys.stderr.write('Need one path selected\n') return pts = cubicsuperpath.parsePath(path.get('d')) if 'transform' in path.keys(): trans = path.get('transform') trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) gtext = inkex.etree.SubElement(path.xpath('..')[0], inkex.addNS('g','svg'), {} ) gdots = inkex.etree.SubElement(path.xpath('..')[0], inkex.addNS('g','svg'), {} ) size = 10 if 'style' in path.attrib: style=path.get('style') if style!='': styles=style.split(';') for i in range(len(styles)): if styles[i].startswith('stroke-width'): if ( styles[i].endswith('px') or styles[i].endswith('cm') ) : size=float(styles[i][len('stroke-width:'):-2])*2 else: size=float(styles[i][len('stroke-width:'):])*2 # if len(pts[0])>2: # size = math.sqrt(math.pow(pts[0][0][0][0]-pts[0][1][0][0],2)+math.pow(pts[0][0][0][1]-pts[0][1][0][1],2))/10 it = 0 for sub in pts: for p in sub: if it == 0: style = { 'stroke': 'none', 'fill': 'black' } x0 = p[0][0] y0 = p[0][1] circ_attribs = {'id':'pt0','style':simplestyle.formatStyle(style),'cx':str(x0), 'cy':str(y0),'r':str(size)} circle = inkex.etree.SubElement(gdots, inkex.addNS('circle','svg'), circ_attribs ) else: clone_attribs = { 'x':'0', 'y':'0', 'transform':'translate(%f,%f)' % (p[0][0]-x0,p[0][1]-y0) } clone = inkex.etree.SubElement(gdots, inkex.addNS('use','svg'), clone_attribs ) xlink = inkex.addNS('href','xlink') clone.set(xlink, '#pt0') text_style = { 'font-size':'%dpx' % (size*2.4), 'fill':'black', 'font-family':'DejaVu Sans', 'text-anchor':'middle' } text_attribs = { 'x':str(p[0][0]), 'y':str(p[0][1]-size*1.8), 'style':simplestyle.formatStyle(text_style) } text = inkex.etree.SubElement(gtext, inkex.addNS('text','svg'), text_attribs) tspan = inkex.etree.SubElement(text , 'tspan', {inkex.addNS('role','sodipodi'): 'line'}) tspan.text = '%d' % ( it+1 ) it+=1
def effect(self): paths = [] for id, node in self.selected.iteritems(): if node.tag == "{http://www.w3.org/2000/svg}path": paths.append(node) if len(paths) == 2: break else: sys.stderr.write("Need 2 paths selected\n") return pts = [cubicsuperpath.parsePath(paths[i].get("d")) for i in (0, 1)] for i in (0, 1): if "transform" in paths[i].keys(): trans = paths[i].get("transform") trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) verts = [] for i in range(0, min(map(len, pts))): comp = [] for j in range(0, min(len(pts[0][i]), len(pts[1][i]))): comp.append([pts[0][i][j][1][-2:], pts[1][i][j][1][-2:]]) verts.append(comp) if self.options.mode.lower() == "lines": line = [] for comp in verts: for n, v in enumerate(comp): line += [("M", v[0])] line += [("L", v[1])] ele = inkex.etree.Element("{http://www.w3.org/2000/svg}path") paths[0].xpath("..")[0].append(ele) ele.set("d", simplepath.formatPath(line)) ele.set("style", "fill:none;stroke:#000000;stroke-opacity:1;stroke-width:1;") elif self.options.mode.lower() == "polygons": g = inkex.etree.Element("{http://www.w3.org/2000/svg}g") g.set("style", "fill:#000000;stroke:#000000;fill-opacity:0.3;stroke-width:2;stroke-opacity:0.6;") paths[0].xpath("..")[0].append(g) for comp in verts: for n, v in enumerate(comp): nn = n + 1 if nn == len(comp): nn = 0 line = [] line += [("M", comp[n][0])] line += [("L", comp[n][1])] line += [("L", comp[nn][1])] line += [("L", comp[nn][0])] line += [("L", comp[n][0])] ele = inkex.etree.Element("{http://www.w3.org/2000/svg}path") g.append(ele) ele.set("d", simplepath.formatPath(line))
def findCandidatesForStyleChange(self, skip): """ collect the document items that are a Bezier curve """ self.candidates = [] for item in self.document.getiterator(): if self.isBezier(item) and item != skip: csp = cubicsuperpath.parsePath(item.get('d')) s = self.startPoint(csp) e = self.endPoint(csp) self.candidates.append({'s':s, 'e':e, 'i':item})
def list_all(self, nodes): ''' Walks through nodes, building a list of all cables found, then reports to the user with that list ''' rpt = [] cables = {} cnt = 0 for node in nodes: if is_path(node): style = get_style(node) p = cubicsuperpath.parsePath(node.get('d')) slengths, stotal = measure.csplength(p) cable_length = ('{0:8.'+str(self.options.precision)+'f}').format(stotal*self.factor()*self.options.scale) description = self.find_desc(node) try: #rpt.append("path %s x %d" % (cable_length, int(description))) if cable_length in cables.keys(): cables[cable_length] += int(description) else: cables[cable_length] = int(description) except: style['stroke'] = "#ff0000" style['stroke-width'] = "10px" #style['marker-start'] = "url(#DotL)" set_style(node, style) cnt += 1 sorted_cables = cables.items() sorted_cables.sort( key=lambda cables:cables[0]) #rpt.append("%s" % (cables)) rpt.append("%s" % (sorted_cables)) min_length = 10000 max_length = 0 t_length = 0 t_count_cables = 0 for c_length, c_number in sorted_cables: # duzina kabla l = float(c_length) if l < min_length: min_length = l if l > max_length: max_length = l t_length += l * c_number t_count_cables += c_number rpt.append("Broj path-ova = %s" % (cnt)) rpt.append("min duzina kabla %s, max duzina kabla = %s" % (min_length, max_length)) rpt.append("Broj kablova = %s, ukupna duzina = %s" % (t_count_cables, t_length)) report_findings(rpt)
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 addLeaves(path, n, offset, slideRatio, document): # Creates the Leaf Constructors points = dformer.generatePoints(path, slideRatio, 2 * n) pt_pairs = dformer.findPointPairs(points) p = cubicsuperpath.parsePath(path.get('d'))[0] i = 1 for a, b in pt_pairs: # Get center point of leaf slope = dformer.computeSlope(a, b) p_slope = dformer.perpendicularSlope(slope) tmp = offset * math.tan(math.radians(0)) dist = math.sqrt(tmp ** 2 + offset ** 2) ab_MidPoint = dformer.getMidPoint(a, b) c = dformer.computePointAlongLine(p_slope, ab_MidPoint, -dist) ctrl1 = dformer.computePointAlongLine(p_slope, a, -dist) ctrl2 = dformer.computePointAlongLine(p_slope, b, -dist) start_pt = p[i - 1][1] # Check that start_pt is viable while not(dformer.checkRelativeDifference(start_pt[0], a[0]) and dformer.checkRelativeDifference(start_pt[1], a[1])): i += 1 start_pt = p[i - 1][1] begin_idx = i end_pt = p[i][1] # Check that end_pt is viable while not(dformer.checkRelativeDifference(end_pt[0], b[0]) and dformer.checkRelativeDifference(end_pt[1], b[1])): i += 1 end_pt = p[i][1] end_idx = i before = p[:begin_idx] after = p[end_idx:] # Create Leaf before[-1][1] = list(a) leafMidPoint = dformer.getMidPoint(ab_MidPoint, ctrl1) leftSidePoint = dformer.computePointAlongLine(slope, leafMidPoint, -dist/2) before[-1][2] = list(leftSidePoint) curve_at_c = [list(ctrl1), list(c), list(ctrl2)] rightMidPoint = dformer.getMidPoint(ab_MidPoint, ctrl2) rightSidePoint = dformer.computePointAlongLine(dformer.negateSlope(slope), rightMidPoint, -dist/2) after[0][0] = list(rightSidePoint) after[0][1] = list(b) after[0][2] = after[1][0] p = before + [curve_at_c] + after path.set('d', cubicsuperpath.formatPath([p]))
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 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 fuseTransform(node): if node.get('d')==None: #FIX ME: how do you raise errors? raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute' t = node.get("transform") if t == None: return m = parseTransform(t) d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(m,p) node.set('d', cubicsuperpath.formatPath(p)) del node.attrib["transform"]
def process_path(self,path): mat = simpletransform.composeParents(path, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) d = path.get('d') p = cubicsuperpath.parsePath(d) simpletransform.applyTransformToPath(mat, p) for subs in p: for csp in subs: csp[0] = self.trafopoint(csp[0]) csp[1] = self.trafopoint(csp[1]) csp[2] = self.trafopoint(csp[2]) mat = simpletransform.invertTransform(mat) simpletransform.applyTransformToPath(mat, p) path.set('d',cubicsuperpath.formatPath(p))