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 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 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 groupToPath(self, node, doReplace=True): if node.tag == inkex.addNS('g', 'svg'): newNode = inkex.etree.SubElement(self.current_layer, inkex.addNS('path', 'svg')) newstyle = simplestyle.parseStyle(node.get('style') or "") newp = [] for child in node: childstyle = simplestyle.parseStyle(child.get('style') or "") childstyle.update(newstyle) newstyle.update(childstyle) childAsPath = self.objectToPath(child, False) newp += cubicsuperpath.parsePath(childAsPath.get('d')) newNode.set('d', cubicsuperpath.formatPath(newp)) newNode.set('style', simplestyle.formatStyle(newstyle)) self.current_layer.remove(newNode) if doReplace: parent = node.getparent() parent.insert(parent.index(node), newNode) parent.remove(node) return newNode else: raise AssertionError
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 _process_group(self, group): new_group = copy(group) new_group.attrib.pop('transform', None) del new_group[:] # delete references to the original group's children for node in group: if node.tag == SVG_GROUP_TAG: new_group.append(self._process_group(node)) else: node_copy = copy(node) if "d" in node.attrib: # Convert the path to absolute coordinates, incorporating all # nested transforms. path = cubicsuperpath.parsePath(node.get("d")) apply_transforms(path, node) node_copy.set("d", cubicsuperpath.formatPath(path)) # Delete transforms from paths and groups, since we applied # them to the paths already. node_copy.attrib.pop('transform', None) new_group.append(node_copy) return new_group
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 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) < 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 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 effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') p = cubicsuperpath.parsePath(d) for subpath in p: for csp in subpath: if self.options.end: delta = randomize([0, 0], self.options.radiusx, self.options.radiusy, self.options.dist) csp[0][0] += delta[0] csp[0][1] += delta[1] csp[1][0] += delta[0] csp[1][1] += delta[1] csp[2][0] += delta[0] csp[2][1] += delta[1] if self.options.ctrl: csp[0] = randomize(csp[0], self.options.radiusx, self.options.radiusy, self.options.dist) csp[2] = randomize(csp[2], self.options.radiusx, self.options.radiusy, self.options.dist) node.set('d', cubicsuperpath.formatPath(p))
def flip(self, satin): csp = satin.path if len(csp) > 1: first, second = satin.rail_indices csp[first], csp[second] = csp[second], csp[first] satin.node.set("d", cubicsuperpath.formatPath(csp))
def csp_to_bbox(csp, parent): """Return simpletransform geom bbox of csp path.""" clip_path = inkex.etree.Element(inkex.addNS('path', 'svg')) parent.append(clip_path) clip_path.set('d', cubicsuperpath.formatPath(csp)) clip_bbox = mat.st.computeBBox([clip_path]) parent.remove(clip_path) return clip_bbox
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.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, 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 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 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 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 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 convert2dash(self, node): if node.tag == inkex.addNS('g', 'svg'): for child in node: self.convert2dash(child) else: if node.tag == inkex.addNS('path', 'svg'): dashes = [] offset = 0 style = simplestyle.parseStyle(node.get('style')) if style.has_key('stroke-dasharray'): if style['stroke-dasharray'].find(',') > 0: dashes = [ float(dash) for dash in style['stroke-dasharray'].split(',') ] if style.has_key('stroke-dashoffset'): offset = style['stroke-dashoffset'] if dashes: p = cubicsuperpath.parsePath(node.get('d')) new = [] for sub in p: idash = 0 dash = dashes[0] length = float(offset) while dash < length: length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[ i] = cspbezsplitatlength( new[-1][-1], sub[i], dash / length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i += 1 node.set('d', cubicsuperpath.formatPath(new)) del style['stroke-dasharray'] node.set('style', simplestyle.formatStyle(style)) if node.get(inkex.addNS('type', 'sodipodi')): del node.attrib[inkex.addNS('type', 'sodipodi')] else: self.not_converted.append(node.get('id'))
def _csp_to_satin(self, csp): node = deepcopy(self.node) d = cubicsuperpath.formatPath(csp) node.set("d", d) # we've already applied the transform, so get rid of it if node.get("transform"): del node.attrib["transform"] return SatinColumn(node)
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 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): 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): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): dashes = [] offset = 0 style = simplestyle.parseStyle(node.get('style')) if style.has_key('stroke-dasharray'): if style['stroke-dasharray'].find(',') > 0: dashes = [ float(dash) for dash in style['stroke-dasharray'].split(',') ] if style.has_key('stroke-dashoffset'): offset = style['stroke-dashoffset'] if dashes: p = cubicsuperpath.parsePath(node.get('d')) new = [] for sub in p: idash = 0 dash = dashes[0] length = float(offset) while dash < length: length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[ i] = cspbezsplitatlength( new[-1][-1], sub[i], dash / length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i += 1 node.set('d', cubicsuperpath.formatPath(new)) del style['stroke-dasharray'] node.set('style', simplestyle.formatStyle(style)) if node.get(inkex.addNS('type', 'sodipodi')): del node.attrib[inkex.addNS('type', 'sodipodi')] else: inkex.errormsg( _("The selected object is not a path.\nTry using the procedure Path->Object to Path." ))
def splitPath(inkex, node): dashes = [] try: # inkscape 1.0 style = dict(Style(node.get('style'))) except: # inkscape 0.9x style = simplestyle.parseStyle(node.get('style')) if 'stroke-dasharray' in style: if style['stroke-dasharray'].find(',') > 0: dashes = [ float(dash) for dash in style['stroke-dasharray'].split(',') if dash ] if dashes: try: # inkscape 1.0 p = CubicSuperPath(node.get('d')) except: # inkscape 0.9x p = cubicsuperpath.parsePath(node.get('d')) new = [] for sub in p: idash = 0 dash = dashes[0] length = 0 new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[i] = cspbezsplitatlength( new[-1][-1], sub[i], dash / length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i += 1 try: # inkscape 1.0 node.set('d', CubicSuperPath(new)) except: # inkscape 0.9x node.set('d', cubicsuperpath.formatPath(new)) del style['stroke-dasharray'] try: # inkscape 1.0 node.set('style', Style(style)) except: # inkscape 0.9x node.set('style', simplestyle.formatStyle(style)) if node.get(inkex.addNS('type', 'sodipodi')): del node.attrib[inkex.addNS('type', 'sodipodi')]
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 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 _path_lists_to_satins(self, path_lists): transform = get_correction_transform(self.node) satins = [] for path_list in path_lists: node = deepcopy(self.node) csp = line_strings_to_csp(path_list) d = cubicsuperpath.formatPath(csp) node.set("d", d) node.set("transform", transform) satins.append(SatinColumn(node)) return satins
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 effect(self): #self.duplicateNodes(self.selected) #self.expandGroupsUnlinkClones(self.selected, True) self.objectsToPaths(self.selected, True) self.bbox=computeBBox(self.selected.values()) for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): d = node.get('d') p = cubicsuperpath.parsePath(d) #do what ever you want with p! node.set('d',cubicsuperpath.formatPath(p))
def effect(self): #self.duplicateNodes(self.selected) self.expandGroupsUnlinkClones(self.selected, True) self.objectsToPaths(self.selected, True) self.bbox=self.computeBBox(self.selected) for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) #do what ever you want with p! d.value = cubicsuperpath.formatPath(p)
def effect(self): #self.duplicateNodes(self.selected) self.expandGroupsUnlinkClones(self.selected, True) self.objectsToPaths(self.selected, True) self.bbox = self.computeBBox(self.selected) for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) #do what ever you want with p! d.value = cubicsuperpath.formatPath(p)
def fuseTransform(node): if node.get('d') == None: #FIXME: 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))
def to_element(self): node = inkex.etree.Element(SVG_PATH_TAG) node.set("d", cubicsuperpath.formatPath( line_strings_to_csp([self.path]))) style = simplestyle.parseStyle(self.style) style['stroke-dasharray'] = "0.5,0.5" style = simplestyle.formatStyle(style) node.set("style", style) node.set("embroider_running_stitch_length_mm", self.running_stitch_length) stroke = Stroke(node) return stroke
def flip(self, satin): csp = satin.path if len(csp) > 1: flattened = satin.flatten(csp) # find the rails (the two longest paths) and swap them indices = range(len(csp)) indices.sort(key=lambda i: shgeo.LineString(flattened[i]).length, reverse=True) first = indices[0] second = indices[1] csp[first], csp[second] = csp[second], csp[first] satin.node.set("d", cubicsuperpath.formatPath(csp))
def to_element(self): node = inkex.etree.Element(SVG_PATH_TAG) node.set("d", cubicsuperpath.formatPath(line_strings_to_csp([self.path]))) style = self.original_element.parse_style() style['stroke-dasharray'] = "0.5,0.5" style = simplestyle.formatStyle(style) node.set("style", style) node.set(INKSTITCH_ATTRIBS['running_stitch_length_mm'], self.running_stitch_length) stroke = Stroke(node) return stroke
def addNotches(path, n, offset, slideRatio, angle, document): # Creates the Notch 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 tooth slope = dformer.computeSlope(a, b) p_slope = dformer.perpendicularSlope(slope) ac_slope = dformer.rotateSlope(p_slope, 360 - angle) bd_slope = dformer.rotateSlope(p_slope, angle) tmp = offset * math.tan(math.radians(angle)) dist = math.sqrt(tmp ** 2 + offset ** 2) c = dformer.computePointAlongLine(ac_slope, a, -dist) d = dformer.computePointAlongLine(bd_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+1:] # Create Tooth before[-1][1] = list(a) before[-1][2] = list(a) line_to_c = [list(c)] * 3 line_to_d = [list(d)] * 3 line_to_b = [list(b)] * 3 p = before + [line_to_c] + [line_to_d] + [line_to_b] + after path.set('d', cubicsuperpath.formatPath([p]) + 'Z')
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): dashes = [] offset = 0 style = simplestyle.parseStyle(node.get('style')) if style.has_key('stroke-dasharray'): if style['stroke-dasharray'].find(',') > 0: dashes = [float (dash) for dash in style['stroke-dasharray'].split(',')] if style.has_key('stroke-dashoffset'): offset = style['stroke-dashoffset'] if dashes: p = cubicsuperpath.parsePath(node.get('d')) new = [] for sub in p: idash = 0 dash = dashes[0] length = float (offset) while dash < length: length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], dash/length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i+=1 node.set('d',cubicsuperpath.formatPath(new)) del style['stroke-dasharray'] node.set('style', simplestyle.formatStyle(style)) if node.get(inkex.addNS('type','sodipodi')): del node.attrib[inkex.addNS('type', 'sodipodi')] else: inkex.errormsg(_("The selected object is not a path.\nTry using the procedure Path->Object to Path."))
def effect(self): #self.duplicateNodes(self.selected) self.expandGroupsUnlinkClones(self.selected, True) self.expandGroups(self.selected, True) self.objectsToPaths(self.selected, True) self.bbox=self.computeBBox(self.selected) for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) for sub in p: for ctlpt in sub: self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) d.value = cubicsuperpath.formatPath(p)
def effect(self): #self.duplicateNodes(self.selected) self.expandGroupsUnlinkClones(self.selected, True) self.expandGroups(self.selected, True) self.objectsToPaths(self.selected, True) self.bbox=computeBBox(self.selected.values()) for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg') or node.tag=='path': d = node.get('d') p = cubicsuperpath.parsePath(d) for sub in p: for ctlpt in sub: self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) node.set('d',cubicsuperpath.formatPath(p))
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 effect(self): for id, node in self.selected.iteritems(): if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) for subpath in p: for csp in subpath: if self.options.end: delta=randomize([0,0], self.options.radius, self.options.norm) csp[0][0]+=delta[0] csp[0][1]+=delta[1] csp[1][0]+=delta[0] csp[1][1]+=delta[1] csp[2][0]+=delta[0] csp[2][1]+=delta[1] if self.options.ctrl: csp[0]=randomize(csp[0], self.options.radius, self.options.norm) csp[2]=randomize(csp[2], self.options.radius, self.options.norm) d.value = cubicsuperpath.formatPath(p)
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): d = node.get('d') p = cubicsuperpath.parsePath(d) for subpath in p: for csp in subpath: if self.options.end: delta=randomize([0,0], self.options.radiusx, self.options.radiusy, self.options.norm) csp[0][0]+=delta[0] csp[0][1]+=delta[1] csp[1][0]+=delta[0] csp[1][1]+=delta[1] csp[2][0]+=delta[0] csp[2][1]+=delta[1] if self.options.ctrl: csp[0]=randomize(csp[0], self.options.radiusx, self.options.radiusy, self.options.norm) csp[2]=randomize(csp[2], self.options.radiusx, self.options.radiusy, self.options.norm) node.set('d',cubicsuperpath.formatPath(p))
def effect(self): for id, node in self.selected.iteritems(): rotation = -1 if self.options.rotation == True: rotation = 1 whirl = self.options.whirl / 1000 if node.tagName == 'path': d = node.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) for sub in p: for csp in sub: for point in csp: point[0] -= self.options.centerx point[1] -= self.options.centery 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] += self.options.centerx point[1] += self.options.centery d.value = cubicsuperpath.formatPath(p)
def effect(self): 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] -= self.view_center[0] point[1] -= self.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] += self.view_center[0] point[1] += self.view_center[1] node.set('d',cubicsuperpath.formatPath(p))
def effect(self): if len(self.options.ids) < 2: inkex.debug("Requires two selected paths. The second must be exactly four nodes long.") exit() #obj is selected second obj = self.selected[self.options.ids[0]] trafo = self.selected[self.options.ids[1]] if obj.tagName == 'path' and trafo.tagName == 'path': #distil trafo into four node points trafo = cubicsuperpath.parsePath(trafo.attributes.getNamedItem('d').value) 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(): f = os.popen("inkscape --query-%s --query-id=%s %s" % (query,id,file)) self.q[query] = float(f.read()) f.close() #process path d = obj.attributes.getNamedItem('d') p = cubicsuperpath.parsePath(d.value) 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]) d.value = cubicsuperpath.formatPath(p)
def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS("path", "svg"): dashes = [] style = simplestyle.parseStyle(node.get("style")) if style.has_key("stroke-dasharray"): if style["stroke-dasharray"].find(",") > 0: dashes = [float(dash) for dash in style["stroke-dasharray"].split(",")] if dashes: p = cubicsuperpath.parsePath(node.get("d")) new = [] for sub in p: idash = 0 dash = dashes[0] length = 0 new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], dash / length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i += 1 node.set("d", cubicsuperpath.formatPath(new)) del style["stroke-dasharray"] node.set("style", simplestyle.formatStyle(style))
def splitPath(inkex, node): dashes = [] style = simplestyle.parseStyle(node.get('style')) if style.has_key('stroke-dasharray'): if style['stroke-dasharray'].find(',') > 0: dashes = [float (dash) for dash in style['stroke-dasharray'].split(',') if dash] if dashes: p = cubicsuperpath.parsePath(node.get('d')) new = [] for sub in p: idash = 0 dash = dashes[0] length = 0 new.append([sub[0][:]]) i = 1 while i < len(sub): dash = dash - length length = cspseglength(new[-1][-1], sub[i]) while dash < length: new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], dash/length) if idash % 2: # create a gap new.append([next[:]]) else: # splice the curve new[-1].append(next[:]) length = length - dash idash = (idash + 1) % len(dashes) dash = dashes[idash] if idash % 2: new.append([sub[i]]) else: new[-1].append(sub[i]) i+=1 node.set('d',cubicsuperpath.formatPath(new)) del style['stroke-dasharray'] node.set('style', simplestyle.formatStyle(style)) if node.get(inkex.addNS('type','sodipodi')): del node.attrib[inkex.addNS('type', 'sodipodi')]
def groupToPath(self,node,doReplace=True): if node.tag == inkex.addNS('g','svg'): newNode = inkex.etree.SubElement(self.current_layer,inkex.addNS('path','svg')) newstyle = simplestyle.parseStyle(node.get('style') or "") newp = [] for child in node: childstyle = simplestyle.parseStyle(child.get('style') or "") childstyle.update(newstyle) newstyle.update(childstyle) childAsPath = self.objectToPath(child,False) newp += cubicsuperpath.parsePath(childAsPath.get('d')) newNode.set('d',cubicsuperpath.formatPath(newp)) newNode.set('style',simplestyle.formatStyle(newstyle)) self.current_layer.remove(newNode) if doReplace: parent=node.getparent() parent.insert(parent.index(node),newNode) parent.remove(node) return newNode else: raise AssertionError
def draw(self, near=None, group=None, style_from=None, layer=None, transform=None, stroke=None, fill=None, width=None, text="", gcodetools_tag = None) : # near mean draw net to element # style should be an element to copy style from # TODO rewrite layers assignment if near!=None : group = near.getparent() layer = gcodetools.get_layer(near) if style_from == None : style_from = near #layer, group, transform, reverse_angle = gcodetools.get_preview_group(layer, group, transform) #if style_from!=None and "style" in style_from.keys() : # style = simplestyle.parseStyle(style_from.get("style")) #else : # style = {} style = {} if width != None : style['stroke-width'] = "%s"%width if stroke != None : style['stroke'] = "%s"%stroke if fill != None : style['fill'] = "%s"%fill if style == {} : style = { 'stroke': '#0072a7', 'fill': 'none', 'stroke-width':'1'} style = simplestyle.formatStyle(style) csp = self.copy() #csp.transform(layer,True) if text!="" : st = csp.items[0].points[0][1] draw_text(text, st.x+10,st.y , group = group) attr = { "style": style, "d": cubicsuperpath.formatPath(csp.to_list()), "gcodetools": "Preview %s"%self, } if transform != [] and transform != None : attr["transform"] = transform return inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr)
def effect(self): if len(self.options.ids)<2: inkex.errormsg(_("This extension requires two selected paths.")) return self.prepareSelectionList() self.options.wave = (self.options.kind=="Ribbon") if self.options.copymode=="Single": self.options.repeat =False self.options.stretch=False elif self.options.copymode=="Repeated": self.options.repeat =True self.options.stretch=False elif self.options.copymode=="Single, stretched": self.options.repeat =False self.options.stretch=True elif self.options.copymode=="Repeated, stretched": self.options.repeat =True self.options.stretch=True bbox=simpletransform.computeBBox(self.patterns.values()) if self.options.vertical: #flipxy(bbox)... bbox=(-bbox[3],-bbox[2],-bbox[1],-bbox[0]) width=bbox[1]-bbox[0] dx=width+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) if self.options.vertical: flipxy(p0) newp=[] for skelnode in self.skeletons.itervalues(): self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) if self.options.vertical: flipxy(self.curSekeleton) for comp in self.curSekeleton: p=copy.deepcopy(p0) 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) xoffset=self.skelcomp[0][0]-bbox[0]+self.options.toffset yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2-self.options.noffset if self.options.repeat: NbCopies=max(1,int(round((length+self.options.space)/dx))) width=dx*NbCopies if not self.skelcompIsClosed: width-=self.options.space 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) if self.options.stretch: for sub in p: stretch(sub,length/width,1,self.skelcomp[0]) for sub in p: for ctlpt in sub: self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) if self.options.vertical: flipxy(p) newp+=p node.set('d', cubicsuperpath.formatPath(newp))
def effect(self): exponent = self.options.exponent if exponent>= 0: exponent = 1.0 + exponent else: exponent = 1.0/(1.0 - exponent) steps = [1.0/(self.options.steps + 1.0)] for i in range(self.options.steps - 1): steps.append(steps[0] + steps[-1]) steps = [step**exponent for step in steps] paths = {} styles = {} for id in self.options.ids: node = self.selected[id] if node.tag ==inkex.addNS('path','svg'): paths[id] = cubicsuperpath.parsePath(node.get('d')) styles[id] = simplestyle.parseStyle(node.get('style')) trans = node.get('transform') if trans: simpletransform.applyTransformToPath(simpletransform.parseTransform(trans), paths[id]) else: self.options.ids.remove(id) for i in range(1,len(self.options.ids)): start = copy.deepcopy(paths[self.options.ids[i-1]]) end = copy.deepcopy(paths[self.options.ids[i]]) sst = copy.deepcopy(styles[self.options.ids[i-1]]) est = copy.deepcopy(styles[self.options.ids[i]]) basestyle = copy.deepcopy(sst) if basestyle.has_key('stroke-width'): basestyle['stroke-width'] = self.tweenstyleunit('stroke-width',sst,est,0) #prepare for experimental style tweening if self.options.style: dostroke = True dofill = True styledefaults = {'opacity':'1.0', 'stroke-opacity':'1.0', 'fill-opacity':'1.0', 'stroke-width':'1.0', 'stroke':'none', 'fill':'none'} for key in styledefaults.keys(): sst.setdefault(key,styledefaults[key]) est.setdefault(key,styledefaults[key]) isnotplain = lambda x: not (x=='none' or x[:1]=='#') if isnotplain(sst['stroke']) or isnotplain(est['stroke']) or (sst['stroke']=='none' and est['stroke']=='none'): dostroke = False if isnotplain(sst['fill']) or isnotplain(est['fill']) or (sst['fill']=='none' and est['fill']=='none'): dofill = False if dostroke: if sst['stroke']=='none': sst['stroke-width'] = '0.0' sst['stroke-opacity'] = '0.0' sst['stroke'] = est['stroke'] elif est['stroke']=='none': est['stroke-width'] = '0.0' est['stroke-opacity'] = '0.0' est['stroke'] = sst['stroke'] if dofill: if sst['fill']=='none': sst['fill-opacity'] = '0.0' sst['fill'] = est['fill'] elif est['fill']=='none': est['fill-opacity'] = '0.0' est['fill'] = sst['fill'] if self.options.method == 2: #subdivide both paths into segments of relatively equal lengths slengths, stotal = csplength(start) elengths, etotal = csplength(end) lengths = {} t = 0 for sp in slengths: for l in sp: t += l / stotal lengths.setdefault(t,0) lengths[t] += 1 t = 0 for sp in elengths: for l in sp: t += l / etotal lengths.setdefault(t,0) lengths[t] += -1 sadd = [k for (k,v) in lengths.iteritems() if v < 0] sadd.sort() eadd = [k for (k,v) in lengths.iteritems() if v > 0] eadd.sort() t = 0 s = [[]] for sp in slengths: if not start[0]: s.append(start.pop(0)) s[-1].append(start[0].pop(0)) for l in sp: pt = t t += l / stotal if sadd and t > sadd[0]: while sadd and sadd[0] < t: nt = (sadd[0] - pt) / (t - pt) bezes = cspbezsplitatlength(s[-1][-1][:],start[0][0][:], nt) s[-1][-1:] = bezes[:2] start[0][0] = bezes[2] pt = sadd.pop(0) s[-1].append(start[0].pop(0)) t = 0 e = [[]] for sp in elengths: if not end[0]: e.append(end.pop(0)) e[-1].append(end[0].pop(0)) for l in sp: pt = t t += l / etotal if eadd and t > eadd[0]: while eadd and eadd[0] < t: nt = (eadd[0] - pt) / (t - pt) bezes = cspbezsplitatlength(e[-1][-1][:],end[0][0][:], nt) e[-1][-1:] = bezes[:2] end[0][0] = bezes[2] pt = eadd.pop(0) e[-1].append(end[0].pop(0)) start = s[:] end = e[:] else: #which path has fewer segments? lengthdiff = numsegs(start) - numsegs(end) #swap shortest first if lengthdiff > 0: start, end = end, start #subdivide the shorter path for x in range(abs(lengthdiff)): maxlen = 0 subpath = 0 segment = 0 for y in range(len(start)): for z in range(1, len(start[y])): leng = bezlenapprx(start[y][z-1], start[y][z]) if leng > maxlen: maxlen = leng subpath = y segment = z sp1, sp2 = start[subpath][segment - 1:segment + 1] start[subpath][segment - 1:segment + 1] = cspbezsplit(sp1, sp2) #if swapped, swap them back if lengthdiff > 0: start, end = end, start #break paths so that corresponding subpaths have an equal number of segments s = [[]] e = [[]] while start and end: if start[0] and end[0]: s[-1].append(start[0].pop(0)) e[-1].append(end[0].pop(0)) elif end[0]: s.append(start.pop(0)) e[-1].append(end[0][0]) e.append([end[0].pop(0)]) elif start[0]: e.append(end.pop(0)) s[-1].append(start[0][0]) s.append([start[0].pop(0)]) else: s.append(start.pop(0)) e.append(end.pop(0)) if self.options.dup: steps = [0] + steps + [1] #create an interpolated path for each interval group = inkex.etree.SubElement(self.current_layer,inkex.addNS('g','svg')) for time in steps: interp = [] #process subpaths for ssp,esp in zip(s, e): if not (ssp or esp): break interp.append([]) #process superpoints for sp,ep in zip(ssp, esp): if not (sp or ep): break interp[-1].append([]) #process points for p1,p2 in zip(sp, ep): if not (sp or ep): break interp[-1][-1].append(interppoints(p1, p2, time)) #remove final subpath if empty. if not interp[-1]: del interp[-1] #basic style tweening if self.options.style: basestyle['opacity'] = tweenstylefloat('opacity',sst,est,time) if dostroke: basestyle['stroke-opacity'] = tweenstylefloat('stroke-opacity',sst,est,time) basestyle['stroke-width'] = self.tweenstyleunit('stroke-width',sst,est,time) basestyle['stroke'] = tweenstylecolor('stroke',sst,est,time) if dofill: basestyle['fill-opacity'] = tweenstylefloat('fill-opacity',sst,est,time) basestyle['fill'] = tweenstylecolor('fill',sst,est,time) attribs = {'style':simplestyle.formatStyle(basestyle),'d':cubicsuperpath.formatPath(interp)} new = inkex.etree.SubElement(group,inkex.addNS('path','svg'), attribs)