def layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning kernlist = [] length = zoom for entry in imagelist: if (entry == " "): # leaving room for " " space characters length = length + (zoom * render_alphabetsoup_config.space) else: image, width, height = entry length = length + width + zoom # add letter length to overall length kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image workspace = None position = zoom for i in range(0, len(kernlist)): while(imagelist[i] == " "): position = position + (zoom * render_alphabetsoup_config.space ) imagelist.pop(i) image, width, height = imagelist[i] # set the kerning if i == 0: kern = 0 # for first image, kerning is zero else: kerncompare = [] # kerning comparison array for j in range( 0, len(kernlist[i][0])): kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] ) kern = min( kerncompare ) position = position - kern # move position back by kern amount thisimage = copy.deepcopy(image) simplepath.translatePath(thisimage, position, 0) workspace = combinePaths(workspace, thisimage) position = position + width + zoom # advance position by letter width return workspace
def test_simplepath(self): """Test simplepath API""" import simplepath data = 'M12 34L56 78Z' path = simplepath.parsePath(data) self.assertEqual(path, [['M', [12., 34.]], ['L', [56., 78.]], ['Z', []]]) d_out = simplepath.formatPath(path) d_out = d_out.replace('.0', '') self.assertEqual(data.replace(' ', ''), d_out.replace(' ', '')) simplepath.translatePath(path, -3, -4) self.assertEqual(path, [['M', [9., 30.]], ['L', [53., 74.]], ['Z', []]]) simplepath.scalePath(path, 10, 20) self.assertEqual(path, [['M', [90., 600.]], ['L', [530., 1480.]], ['Z', []]]) simplepath.rotatePath(path, math.pi / 2.0, cx=5, cy=7) approxed = [[code, approx(coords)] for (code, coords) in path] self.assertEqual( approxed, [['M', [-588., 92.]], ['L', [-1468., 532.]], ['Z', []]])
def inkscape(hpgl, svg, inkex): layer = inkex.etree.SubElement(svg, 'g') layer.set(inkex.addNS('label', 'inkscape'), 'InkCut Preview Layer') layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') spPU = [['M', [0, 0]]] spPD = [] for c in hpgl.split(';'): if c[:2] == "PU": p = map(int, c[2:].split(',')) spPD.append(['M', p]) spPU.append(['L', p]) elif c[:2] == "PD": p = map(int, c[2:].split(',')) spPU.append(['M', p]) spPD.append(['L', p]) pu = inkex.etree.Element(inkex.addNS('path', 'svg')) simplepath.scalePath(spPU, 0.088582677, -0.088582677) simplepath.translatePath(spPU, 0, float(svg.get('height'))) style = {'fill': 'none', 'stroke-opacity': '.8', 'stroke': '#116AAB'} pu.set('style', simplestyle.formatStyle(style)) pu.set('d', simplepath.formatPath(spPU)) pd = inkex.etree.Element(inkex.addNS('path', 'svg')) style = {'fill': 'none', 'stroke-opacity': '.8', 'stroke': '#AB3011'} pd.set('style', simplestyle.formatStyle(style)) pd.set('d', simplepath.formatPath(spPD)) # Connect elements together. layer.append(pu) layer.append(pd)
def effect(self): #References: Minimum Requirements for Creating a DXF File of a 3D Model By Paul Bourke # NURB Curves: A Guide for the Uninitiated By Philip J. Schneider # The NURBS Book By Les Piegl and Wayne Tiller (Springer, 1995) self.dxf_add("999\nDXF created by Inkscape\n") self.dxf_add(dxf_templates.r14_header) scale = 25.4/90.0 h = inkex.unittouu(self.document.getroot().xpath('@height', namespaces=inkex.NSS)[0]) path = '//svg:path' for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): d = node.get('d') sim = simplepath.parsePath(d) if len(sim): simplepath.scalePath(sim,scale,-scale) simplepath.translatePath(sim,0,h*scale) p = cubicsuperpath.CubicSuperPath(sim) 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]: 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]]) if self.options.ROBO == 'true': self.ROBO_output() self.LWPOLY_output() self.dxf_add(dxf_templates.r14_footer)
def inkscape(hpgl,svg,inkex): layer = inkex.etree.SubElement(svg, 'g') layer.set(inkex.addNS('label', 'inkscape'), 'InkCut Preview Layer') layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') spPU = [['M',[0,0]]] spPD = [] for c in hpgl.split(';'): if c[:2] == "PU": p = map(int,c[2:].split(',')) spPD.append(['M',p]) spPU.append(['L',p]) elif c[:2] == "PD": p = map(int,c[2:].split(',')) spPU.append(['M',p]) spPD.append(['L',p]) pu = inkex.etree.Element(inkex.addNS('path','svg')) simplepath.scalePath(spPU,0.088582677,-0.088582677) simplepath.translatePath(spPU,0,float(svg.get('height'))) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#116AAB'} pu.set('style', simplestyle.formatStyle(style)) pu.set('d',simplepath.formatPath(spPU)) pd = inkex.etree.Element(inkex.addNS('path','svg')) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#AB3011'} pd.set('style', simplestyle.formatStyle(style)) pd.set('d',simplepath.formatPath(spPD)) # Connect elements together. layer.append(pu) layer.append(pd)
def realistic_stitch(start, end): """Generate a stitch vector path given a start and end point.""" end = Point(*end) start = Point(*start) stitch_length = (end - start).length() stitch_center = (end + start) / 2.0 stitch_direction = (end - start) stitch_angle = math.atan2(stitch_direction.y, stitch_direction.x) stitch_length = max(0, stitch_length - 0.2 * PIXELS_PER_MM) # create the path by filling in the length in the template path = simplepath.parsePath(stitch_path % stitch_length) # rotate the path to match the stitch rotation_center_x = -stitch_length / 2.0 rotation_center_y = stitch_height / 2.0 simplepath.rotatePath(path, stitch_angle, cx=rotation_center_x, cy=rotation_center_y) # move the path to the location of the stitch simplepath.translatePath(path, stitch_center.x - rotation_center_x, stitch_center.y - rotation_center_y) return simplepath.formatPath(path)
def getTranslatedPath(d, posX, posY): if(CommonDefs.inkVer == 1.0): path = Path(d) path.translate(posX, posY, inplace = True) return path.to_superpath().__str__() else: path = simplepath.parsePath(d) simplepath.translatePath(path, posX, posY) return simplepath.formatPath(path)
def place(self, nodes): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = 0 line_nodes = [] group = etree.SubElement(self.current_layer, addNS('g', 'svg')) for id, node, bbox in nodes: x, _, y, _ = bbox node_width = x_gap + self.width(bbox) # reached end of line, reset, move higher, start new group if total_width + node_width > max_line_width: group = etree.SubElement(self.current_layer, addNS('g', 'svg')) total_width = 0 total_height += self.height( self.computeBBox(line_nodes)) + y_gap line_nodes = [] group.append(node) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) if node.tag == addNS('path', 'svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node.attrib['d']) translatePath(path, x_delta, y_delta) node.attrib['d'] = formatPath(path) elif node.tag == addNS('g', 'svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node) else: node.attrib['x'] = str(x_dest) node.attrib['y'] = str(y_dest) total_width += node_width line_nodes.append(node)
def place(self, nodes): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = 0 line_nodes = [] group = etree.SubElement(self.current_layer, addNS('g','svg')) for id, node, bbox in nodes: x, _, y, _ = bbox node_width = x_gap + self.width(bbox) # reached end of line, reset, move higher, start new group if total_width + node_width > max_line_width: group = etree.SubElement(self.current_layer, addNS('g','svg')) total_width = 0 total_height += self.height(self.computeBBox(line_nodes)) + y_gap line_nodes = [] group.append(node) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) if node.tag == addNS('path','svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node.attrib['d']) translatePath(path, x_delta, y_delta) node.attrib['d'] = formatPath(path) elif node.tag == addNS('g','svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node) else: node.attrib['x'] = str(x_dest) node.attrib['y'] = str(y_dest) total_width += node_width line_nodes.append(node)
def hpgl(plot): #create a preview svg svg = etree.Element(inkex.addNS('svg', 'svg')) svg.set('height', str(plot.dimensions[1])) svg.set( 'width', str(plot.getSize()[0] + plot.startPosition[0] + plot.finishPosition[0])) svg.set('version', '1.1') """ bg = inkex.etree.Element(inkex.addNS('rect','svg')) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#212425','stroke-width':'10'} bg.set('style', simplestyle.formatStyle(style)) bg.set('x','0') bg.set('y','0') bg.set('width',str(plot.dimensions[0])) bg.set('height',svg.get('height')) svg.append(bg) """ spPU = [['M', [0, 0]]] spPD = [] for c in plot.toHPGL().split(';'): if c[:2] == "PU": p = map(int, c[2:].split(',')) spPD.append(['M', p]) spPU.append(['L', p]) elif c[:2] == "PD": p = map(int, c[2:].split(',')) spPU.append(['M', p]) spPD.append(['L', p]) pu = inkex.etree.Element(inkex.addNS('path', 'svg')) simplepath.scalePath(spPU, 0.088582677, -0.088582677) simplepath.translatePath(spPU, 0, float(svg.get('height'))) style = {'fill': 'none', 'stroke-opacity': '.8', 'stroke': '#116AAB'} pu.set('style', simplestyle.formatStyle(style)) pu.set('d', simplepath.formatPath(spPU)) pd = inkex.etree.Element(inkex.addNS('path', 'svg')) style = {'fill': 'none', 'stroke-opacity': '.8', 'stroke': '#AB3011'} pd.set('style', simplestyle.formatStyle(style)) pd.set('d', simplepath.formatPath(spPD)) # Connect elements together. svg.append(pu) svg.append(pd) return svg
def hpgl(plot): #create a preview svg svg = etree.Element(inkex.addNS('svg','svg')) svg.set('height',str(plot.dimensions[1])) svg.set('width',str(plot.getSize()[0]+plot.startPosition[0]+plot.finishPosition[0])) svg.set('version','1.1') """ bg = inkex.etree.Element(inkex.addNS('rect','svg')) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#212425','stroke-width':'10'} bg.set('style', simplestyle.formatStyle(style)) bg.set('x','0') bg.set('y','0') bg.set('width',str(plot.dimensions[0])) bg.set('height',svg.get('height')) svg.append(bg) """ spPU = [['M',[0,0]]] spPD = [] for c in plot.toHPGL().split(';'): if c[:2] == "PU": p = map(int,c[2:].split(',')) spPD.append(['M',p]) spPU.append(['L',p]) elif c[:2] == "PD": p = map(int,c[2:].split(',')) spPU.append(['M',p]) spPD.append(['L',p]) pu = inkex.etree.Element(inkex.addNS('path','svg')) simplepath.scalePath(spPU,0.088582677,-0.088582677) simplepath.translatePath(spPU,0,float(svg.get('height'))) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#116AAB'} pu.set('style', simplestyle.formatStyle(style)) pu.set('d',simplepath.formatPath(spPU)) pd = inkex.etree.Element(inkex.addNS('path','svg')) style = {'fill' : 'none','stroke-opacity': '.8','stroke':'#AB3011'} pd.set('style', simplestyle.formatStyle(style)) pd.set('d',simplepath.formatPath(spPD)) # Connect elements together. svg.append(pu) svg.append(pd) return svg
def fill_row(self, node): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = self.total_height group = etree.SubElement(self.current_layer, addNS('g','svg')) bbox = computeBBox([node]) x, _, y, _ = bbox node_width = x_gap + self.width(bbox) while total_width + node_width < max_line_width: node_copy = deepcopy(node) group.append(node_copy) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) # translation logic if node_copy.tag == addNS('path','svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node_copy.attrib['d']) translatePath(path, x_delta, y_delta) node_copy.attrib['d'] = formatPath(path) elif node_copy.tag == addNS('g','svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node_copy) else: node_copy.attrib['x'] = str(x_dest) node_copy.attrib['y'] = str(y_dest) total_width += node_width self.total_height += self.height(computeBBox(group)) + y_gap
def fill_row(self, node): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = self.total_height group = etree.SubElement(self.current_layer, addNS('g', 'svg')) bbox = computeBBox([node]) x, _, y, _ = bbox node_width = x_gap + self.width(bbox) while total_width + node_width < max_line_width: node_copy = deepcopy(node) group.append(node_copy) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) # translation logic if node_copy.tag == addNS('path', 'svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node_copy.attrib['d']) translatePath(path, x_delta, y_delta) node_copy.attrib['d'] = formatPath(path) elif node_copy.tag == addNS('g', 'svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node_copy) else: node_copy.attrib['x'] = str(x_dest) node_copy.attrib['y'] = str(y_dest) total_width += node_width self.total_height += self.height(computeBBox(group)) + y_gap
def draw(stack): # draw a character based on a tree stack state = stack.pop(0) #print state, image, width, height = loadPath(font + syntax[state][0]) # load the image if (stack[0] != "["): # terminal stack element if (len(syntax[state]) == 1): # this state is a terminal node return image, width, height else: substack = generate(state) # generate random substack return draw(substack) # draw random substack else: #inkex.debug("[") stack.pop(0) images = [] # list of daughter images nodes = [] # list of daughter names while (stack[0] != "]"): # for all nodes in stack newstate = stack[0] # the new state newimage, width, height = draw(stack) # draw the daughter state if (newimage): tfimage = mxfm(newimage, width, height, stack) # maybe transform daughter state images.append([tfimage, width, height]) # list of daughter images nodes.append(newstate) # list of daughter nodes else: #inkex.debug(("recurse on",newstate,"failed")) # this should never happen return None, 0, 0 rule = findrule(state, nodes) # find the rule for this subtree for i in range(0, len(images)): currimg, width, height = images[i] if currimg: #box = getPathBoundingBox(currimg) dx = rule[i][1] * units dy = rule[i][2] * units #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy)) simplepath.translatePath(currimg, dx, dy) image = combinePaths(image, currimg) stack.pop(0) return image, width, height
def draw(stack): # draw a character based on a tree stack state = stack.pop(0) # print state, image, width, height = loadPath(font + syntax[state][0]) # load the image if stack[0] != "[": # terminal stack element if len(syntax[state]) == 1: # this state is a terminal node return image, width, height else: substack = generate(state) # generate random substack return draw(substack) # draw random substack else: # inkex.debug("[") stack.pop(0) images = [] # list of daughter images nodes = [] # list of daughter names while stack[0] != "]": # for all nodes in stack newstate = stack[0] # the new state newimage, width, height = draw(stack) # draw the daughter state if newimage: tfimage = mxfm(newimage, width, height, stack) # maybe transform daughter state images.append([tfimage, width, height]) # list of daughter images nodes.append(newstate) # list of daughter nodes else: # inkex.debug(("recurse on",newstate,"failed")) # this should never happen return None, 0, 0 rule = findrule(state, nodes) # find the rule for this subtree for i in range(0, len(images)): currimg, width, height = images[i] if currimg: # box = getPathBoundingBox(currimg) dx = rule[i][1] * units dy = rule[i][2] * units # newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy)) simplepath.translatePath(currimg, dx, dy) image = combinePaths(image, currimg) stack.pop(0) return image, width, height
def resolve_path(node, transform=False): path = simplepath.parsePath(node.attrib['d']) if transform and 'transform' in node.attrib: transforms = re.findall( "([a-z,A-Z]+)\(([0-9,\s,.,-]*)\)", node.attrib['transform']) for k, vs in transforms: sc = ' ' if ',' in vs: sc = ',' args = map(lambda v: float(v.strip()), vs.split(sc)) if k == 'translate': simplepath.translatePath(path, *args) elif k == 'scale': simplepath.scalePath(path, *args) elif k == 'rotate': simplepath.rotatePath(path, *args) else: error( "Invalid path data: contains unsupported transform %s" % k) return path
def effect(self): #References: Minimum Requirements for Creating a DXF File of a 3D Model By Paul Bourke # NURB Curves: A Guide for the Uninitiated By Philip J. Schneider self.dxf_add("999\nDXF created by Inkscape\n0\nSECTION\n2\nENTITIES") scale = 25.4/90.0 h = inkex.unittouu(inkex.xml.xpath.Evaluate('/svg/@height',self.document)[0].value) path = '//path' for node in inkex.xml.xpath.Evaluate(path,self.document): d = node.attributes.getNamedItem('d').value sim = simplepath.parsePath(d) simplepath.scalePath(sim,scale,-scale) simplepath.translatePath(sim,0,h*scale) p = cubicsuperpath.CubicSuperPath(sim) 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]: self.dxf_line([s[1],e[1]]) else: self.dxf_spline([s[1],s[2],e[0],e[1]]) self.dxf_add("\n0\nENDSEC\n0\nEOF\n")
def draw_crop_scale(stack, zoom): # draw, crop and scale letter image image, width, height = draw(stack) bbox = getPathBoundingBox(image) simplepath.translatePath(image, -bbox[0], 0) simplepath.scalePath(image, zoom / units, zoom / units) return image, bbox[1] - bbox[0], bbox[3] - bbox[2]
def translatePath(self,x,y): simplepath.translatePath(self.data,x,y)
def flip_cordinate_system(self, d, emsize, baseline): pathdata = simplepath.parsePath(d) simplepath.scalePath(pathdata, 1,-1) simplepath.translatePath(pathdata, 0, int(emsize) - int(baseline)) return simplepath.formatPath(pathdata)
def flip_cordinate_system(self, d, emsize, baseline): pathdata = simplepath.parsePath(d) simplepath.scalePath(pathdata, 1, -1) simplepath.translatePath(pathdata, 0, int(emsize) - int(baseline)) return simplepath.formatPath(pathdata)
def effect(self): # get user-entered params x_scale = self.options.x_scale y_scale = self.options.y_scale t_start = self.options.t_start t_end = self.options.t_end n_steps = self.options.n_steps fps = self.options.fps dt = self.options.dt x_eqn = self.options.x_eqn y_eqn = self.options.y_eqn x_size_eqn = self.options.x_size_eqn y_size_eqn = self.options.y_size_eqn theta_eqn = self.options.theta_eqn # get doc root svg = self.document.getroot() doc_w = self.unittouu(svg.get('width')) doc_h = self.unittouu(svg.get('height')) # get selected items and validate selected = pathmodifier.zSort(self.document.getroot(), self.selected.keys()) if not selected: inkex.errormsg( 'Exactly two objects must be selected: a rect and a template. See "help" for details.' ) return elif len(selected) != 2: inkex.errormsg( 'Exactly two objects must be selected: a rect and a template. See "help" for details.' ) return # rect rect = self.selected[selected[0]] if not rect.tag.endswith('rect'): inkex.errormsg('Bottom object must be rect. See "help" for usage.') return # object obj = self.selected[selected[1]] if not (obj.tag.endswith('path') or obj.tag.endswith('g')): inkex.errormsg( 'Template object must be path or group of paths. See "help" for usage.' ) return if obj.tag.endswith('g'): children = obj.getchildren() if not all([ch.tag.endswith('path') for ch in children]): msg = 'All elements of group must be paths, but they are: ' msg += ', '.join(['{}'.format(ch) for ch in children]) inkex.errormsg(msg) return objs = children is_group = True else: objs = [obj] is_group = False # get rect params w = float(rect.get('width')) h = float(rect.get('height')) x_rect = float(rect.get('x')) y_rect = float(rect.get('y')) # lower left corner x_0 = x_rect y_0 = y_rect + h # get object path(s) obj_ps = [simplepath.parsePath(obj_.get('d')) for obj_ in objs] n_segs = [len(obj_p_) for obj_p_ in obj_ps] obj_p = sum(obj_ps, []) # compute travel parameters if not n_steps: # compute dt if dt == 0: dt = 1. / fps ts = np.arange(t_start, t_end, dt) else: ts = np.linspace(t_start, t_end, n_steps) # compute xs, ys, stretches, and rotations in arbitrary coordinates xs = np.nan * np.zeros(len(ts)) ys = np.nan * np.zeros(len(ts)) x_sizes = np.nan * np.zeros(len(ts)) y_sizes = np.nan * np.zeros(len(ts)) thetas = np.nan * np.zeros(len(ts)) for ctr, t in enumerate(ts): xs[ctr] = eval(x_eqn) ys[ctr] = eval(y_eqn) x_sizes[ctr] = eval(x_size_eqn) y_sizes[ctr] = eval(y_size_eqn) thetas[ctr] = eval(theta_eqn) * pi / 180 # ensure no Infs if np.any(np.isinf(xs)): raise Exception('Inf detected in x(t), please remove.') return if np.any(np.isinf(ys)): raise Exception('Inf detected in y(t), please remove.') return if np.any(np.isinf(x_sizes)): raise Exception('Inf detected in x_size(t), please remove.') return if np.any(np.isinf(y_sizes)): raise Exception('Inf detected in y_size(t), please remove.') return if np.any(np.isinf(thetas)): raise Exception('Inf detected in theta(t), please remove.') return # convert to screen coordinates xs *= (w / x_scale) xs += x_0 ys *= (-h / y_scale) # neg sign to invert y for inkscape screen ys += y_0 # get obj center b_box = simpletransform.refinedBBox( cubicsuperpath.CubicSuperPath(obj_p)) c_x = 0.5 * (b_box[0] + b_box[1]) c_y = 0.5 * (b_box[2] + b_box[3]) # get rotation anchor if any([k.endswith('transform-center-x') for k in obj.keys()]): k_r_x = [ k for k in obj.keys() if k.endswith('transform-center-x') ][0] k_r_y = [ k for k in obj.keys() if k.endswith('transform-center-y') ][0] r_x = c_x + float(obj.get(k_r_x)) r_y = c_y - float(obj.get(k_r_y)) else: r_x, r_y = c_x, c_y paths = [] # compute new paths for x, y, x_size, y_size, theta in zip(xs, ys, x_sizes, y_sizes, thetas): path = deepcopy(obj_p) # move to origin simplepath.translatePath(path, -x_0, -y_0) # move rotation anchor accordingly r_x_1 = r_x - x_0 r_y_1 = r_y - y_0 # scale simplepath.scalePath(path, x_size, y_size) # scale rotation anchor accordingly r_x_2 = r_x_1 * x_size r_y_2 = r_y_1 * y_size # move to final location simplepath.translatePath(path, x, y) # move rotation anchor accordingly r_x_3 = r_x_2 + x r_y_3 = r_y_2 + y # rotate simplepath.rotatePath(path, -theta, cx=r_x_3, cy=r_y_3) paths.append(path) parent = self.current_layer group = inkex.etree.SubElement(parent, inkex.addNS('g', 'svg'), {}) for path in paths: if is_group: group_ = inkex.etree.SubElement(group, inkex.addNS('g', 'svg'), {}) path_components = split(path, n_segs) for path_component, child in zip(path_components, children): attribs = {k: child.get(k) for k in child.keys()} attribs['d'] = simplepath.formatPath(path_component) child_copy = inkex.etree.SubElement( group_, child.tag, attribs) else: attribs = {k: obj.get(k) for k in obj.keys()} attribs['d'] = simplepath.formatPath(path) obj_copy = inkex.etree.SubElement(group, obj.tag, attribs)
def translatePath(self, x, y): simplepath.translatePath(self.data, x, y)