def optimal_rotations(node): step = pi / float(STEPS) bbox = simpletransform.computeBBox([node]) min_width = bbox[1] - bbox[0] min_width_angle = None min_bbox_area = min_width * (bbox[3] - bbox[2]) min_bbox_area_angle = None for i in range(STEPS): angle = -pi / 2.0 + i * step rotated = simpletransform.computeBBox([node], rotate_matrix(node, angle)) width = rotated[1] - rotated[0] height = rotated[3] - rotated[2] bbox_area = width * height if width < min_width: min_width = width min_width_angle = angle if bbox_area < min_bbox_area: if width > height: # To keep results similar to min_width_angle, rotate by an # additional 90 degrees which doesn't affect bbox area. angle -= copysign(pi / 2.0, angle) min_bbox_area = bbox_area min_bbox_area_angle = angle return min_width_angle, min_bbox_area_angle
def linearizeEnvelopes(envs): bbox1 = simpletransform.computeBBox([envs[0]]) bbox2 = simpletransform.computeBBox([envs[1]]) comps1, lengths1 = linearize(modifySkeletonPath(cubicsuperpath.parsePath(envs[0].get('d')))) comps2, lengths2 = linearize(modifySkeletonPath(cubicsuperpath.parsePath(envs[1].get('d')))) correctness, shouldSwap = checkCompatibility(bbox1, bbox2, comps1, comps2) if not shouldSwap: return (comps1, lengths1, comps2, lengths2, bbox1, bbox2, correctness) else: return (comps2, lengths2, comps1, lengths1, bbox2, bbox1, correctness)
def rotate_matrix(node, a): bbox = simpletransform.computeBBox([node]) cx = (bbox[0] + bbox[1]) / 2.0 cy = (bbox[2] + bbox[3]) / 2.0 return simpletransform.composeTransform( [[cos(a), -sin(a), cx], [sin(a), cos(a), cy]], [[1, 0, -cx], [0, 1, -cy]])
def parseArc(self,node,parent): #self.parsing_context = 'arc' style = node.get('style') style = self.parseStyleAttribute(style) arc = { 'id':node.get('id',''), 'svg':'arc', 'label':str(node.get(inkex.addNS('label', 'inkscape'),'')), 'cx': node.get(inkex.addNS('cx', 'sodipodi'),''), 'cy':node.get(inkex.addNS('cy', 'sodipodi'),''), 'rx':node.get(inkex.addNS('rx', 'sodipodi'),''), 'ry':node.get(inkex.addNS('ry', 'sodipodi'),''), 'path':simplepath.parsePath(node.get('d')), 'd':node.get('d',''), 'box':list(simpletransform.computeBBox([node])), 'fill':style.get('fill',''), 'fill-opacity':style.get('fillOpacity',''), 'stroke':style.get('stroke',''), 'stroke-width':style.get('strokeWidth',''), 'stroke-opacity':style.get('strokeOpacity',''), 'transform':node.get('transform','') } if(self.reposition): arc['path'] = self.movePath(node,0,0,'tl') else: arc['path'] = arc['d'] parent.append(arc)
def movePath(self, node, x, y, origin): tagName = self.getTagName(node) if tagName != "path": inkex.debug('movePath only works on SVG Path elements. Argument was of type "' + tagName + '"') return False path = simplepath.parsePath(node.get("d")) id = node.get("id") box = list(simpletransform.computeBBox([node])) offset_x = box[0] - x offset_y = box[2] - (y) for cmd in path: params = cmd[1] i = 0 while i < len(params): if i % 2 == 0: # inkex.debug('x point at ' + str( round( params[i] ))) params[i] = params[i] - offset_x # inkex.debug('moved to ' + str( round( params[i] ))) else: # inkex.debug('y point at ' + str( round( params[i]) )) params[i] = params[i] - offset_y # inkex.debug('moved to ' + str( round( params[i] ))) i = i + 1 return simplepath.formatPath(path)
def processSelected(self): """Iterate trough nodes and find the bounding coordinates of the selected area""" startx=None starty=None endx=None endy=None nodelist=[] root=self.document.getroot(); toty=self.getUnittouu(root.attrib['height']) props=['x','y','width','height'] for id in self.selected: if self.options.fast == "true": # uses simpletransform nodelist.append(self.getElementById(id)) else: # uses command line rawprops=[] for prop in props: command=("inkscape", "--without-gui", "--query-id", id, "--query-"+prop,self.args[-1]) proc=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) proc.wait() rawprops.append(math.ceil(self.getUnittouu(proc.stdout.read()))) nodeEndX=rawprops[0]+rawprops[2] nodeStartY=toty-rawprops[1]-rawprops[3] nodeEndY=toty-rawprops[1] if rawprops[0] < startx or startx is None: startx=rawprops[0] if nodeStartY < starty or starty is None: starty = nodeStartY if nodeEndX > endx or endx is None: endx = nodeEndX if nodeEndY > endy or endy is None: endy = nodeEndY if self.options.fast == "true": # uses simpletransform bbox=simpletransform.computeBBox(nodelist) startx=math.ceil(bbox[0]) endx=math.ceil(bbox[1]) h=-bbox[2]+bbox[3] starty=toty-math.ceil(bbox[2])-h endy=toty-math.ceil(bbox[2]) coords=[startx,starty,endx,endy] return coords
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 parseGroup(self,node,parent): #inkex.debug(self.debug_tab + 'Parsing group' + node.get('id')) self.debug_tab += ' ' matrix_list = [] self.parsing_context = 'g' transform = node.get('transform','') id = node.get('id') if(transform!=''): transform = simpletransform.parseTransform(node.get('transform','')) transform = self.matrixToList(transform) transform = self.normalizeMatrix(transform) label = str(node.get(inkex.addNS('label', 'inkscape'),'')) elements = node.xpath('./*',namespaces=inkex.NSS) #box = simpletransform.computeBBox(elements) #box = list(box) if box != None else [] box =list(simpletransform.computeBBox([node])) box[1] = (box[1]-box[0]) box[3] = (box[3]-box[2]) origin_x = float(node.get(inkex.addNS('transform-center-x', 'inkscape'),0)) origin_y = float(node.get(inkex.addNS('transform-center-y', 'inkscape'),0)) origin_x = origin_x + ( box[1] / 2) origin_y = (origin_y * -1) + ( box[3] / 2) group = { 'id':id, 'name':label, 'label':label, 'svg':'g', 'transform':transform, 'origin':{ 'x':origin_x, 'y':origin_y, }, 'box':box, 'elements':[] } parent.append(group) self.parse_stack.append(group) #inkex.debug('Loop through all grouped elements') for child in elements: self.parseElement(child,group["elements"]) self.debug_tab = self.debug_tab[:-4] self.parsing_context = '' self.parse_stack.pop()
def effect(self): # if self.options.mformat == '"presets"': # self.setPreset() # njj: hack some options # get number of digits # prec = int(self.options.precision) prec = 2 self.options.fontsize = 20 self.options.unit = 'mm' self.options.scale = 1 self.options.angle = 0 self.options.offset = -6 scale = self.unittouu('1px') # convert to document units # self.options.offset *= scale factor = 1.0 doc = self.document.getroot() if doc.get('viewBox'): (viewx, viewy, vieww, viewh) = re.sub(' +|, +|,', ' ', doc.get('viewBox')).strip().split(' ', 4) factor = self.unittouu(doc.get('width')) / float(vieww) if self.unittouu(doc.get('height')) / float(viewh) < factor: factor = self.unittouu(doc.get('height')) / float(viewh) factor /= self.unittouu('1px') self.options.fontsize /= factor factor *= scale / self.unittouu('1' + self.options.unit) # Gather paths debug(dir(self)) paths = self.document.findall('.//{0}'.format(nspath)) # Act on paths for node in paths: mat = simpletransform.composeParents( node, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) p = cubicsuperpath.parsePath(node.get('d')) simpletransform.applyTransformToPath(mat, p) stotal = abs(measure.csparea(p) * factor * self.options.scale) self.group = inkex.etree.SubElement(node.getparent(), inkex.addNS('text', 'svg')) # Format the area as string resultstr = locale.format( "%(len)25." + str(prec) + "f", { 'len': round(stotal * factor * self.options.scale, prec) }).strip() # Fixed text, in the center of each path bbox = simpletransform.computeBBox([node]) tx = bbox[0] + (bbox[1] - bbox[0]) / 2.0 ty = bbox[2] + (bbox[3] - bbox[2]) / 2.0 anchor = 'middle' self.addTextWithTspan( self.group, tx, ty, resultstr + ' ' + self.options.unit + '^2', id, anchor, -int(self.options.angle), -self.options.offset + self.options.fontsize / 2)
def effect(self): distance = self.unittouu( str(self.options.distance) + self.options.unit) if len(self.options.ids) != 2: print >> sys.stderr, "you must select exactly two objects" return id1 = self.options.ids[0] id2 = self.options.ids[1] b1 = simpletransform.computeBBox([ self.selected[id1], ]) b2 = simpletransform.computeBBox([ self.selected[id2], ]) if b1[2] > b2[2]: b1, b2 = (b2, b1) id1, id2 = (id2, id1) # id1,b1 is for the top element # id2,b2 is for the bottom element if self.options.top == 't': top = b1[2] else: top = b1[3] if self.options.bottom == 't': bottom = b2[2] else: bottom = b2[3] if self.options.moving == 't': moving = self.selected[id1] delta = (bottom - top) - distance else: moving = self.selected[id2] delta = -(bottom - top) + distance #print >>sys.stderr,distance,top,bottom,delta #print >>sys.stderr,self.selected,b1,b2,delta,distance # translate #print >>sys.stderr,self.selected[id2].attrib['transform'] m = re.search('translate.*\([0-9-.]+,([0-9-.]+).*\)', moving.attrib.get('transform', '')) #print >>sys.stderr,"match is:",m if m != None: delta = delta + float(m.group(1)) #print >>sys.stderr,"delta is:",delta moving.attrib['transform'] = 'translate(0,' + str(delta) + ')'
def get_frame(self, mat=[[1,0,0],[0,1,0]]): """ Determine the node's size and position. It's accounting for the coordinates of all paths in the node's children. :return: x position, y position, width, height """ min_x, max_x, min_y, max_y = st.computeBBox([self._node], mat) width = max_x - min_x height = max_y - min_y return min_x, min_y, width, height
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): distance=self.unittouu(str(self.options.distance)+self.options.unit) if len(self.options.ids)!=2: print >>sys.stderr,"you must select exactly two objects" return id1=self.options.ids[0] id2=self.options.ids[1] b1=simpletransform.computeBBox([self.selected[id1],]) b2=simpletransform.computeBBox([self.selected[id2],]) if b1[0]>b2[0]: b1,b2=(b2,b1) id1,id2=(id2,id1) # id1,b1 is for the left element # id2,b2 is for the right element if self.options.left=='l': left=b1[0] else: left=b1[1] if self.options.right=='l': right=b2[0] else: right=b2[1] # left is the reference coord for the left element # right ..............................right....... if self.options.moving=='l': moving=self.selected[id1] delta=(right-left)-distance else: moving=self.selected[id2] delta=-(right-left)+distance #print >>sys.stderr,distance,left,right,delta #print >>sys.stderr,self.selected,b1,b2,delta,distance # translate #print >>sys.stderr,self.selected[id2].attrib['transform'] m=re.search('translate.*\(([0-9-.]+),.*',moving.attrib.get('transform','')) #print >>sys.stderr,"match is:",m if m!=None: delta=delta+float(m.group(1)) #print >>sys.stderr,"delta is:",delta moving.attrib['transform']='translate('+str(delta)+',0)'
def processSelected(self): """Iterate trough nodes and find the bounding coordinates of the selected area""" startx = None starty = None endx = None endy = None nodelist = [] root = self.document.getroot() toty = self.getUnittouu(root.attrib['height']) scale = self.getUnittouu('1px') props = ['x', 'y', 'width', 'height'] for id in self.selected: if self.options.fast == True: # uses simpletransform nodelist.append(self.getElementById(id)) else: # uses command line rawprops = [] for prop in props: command = ("inkscape", "--without-gui", "--query-id", id, "--query-" + prop, self.args[-1]) proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.wait() rawprops.append( math.ceil(self.getUnittouu(proc.stdout.read()))) nodeEndX = rawprops[0] + rawprops[2] nodeStartY = toty - rawprops[1] - rawprops[3] nodeEndY = toty - rawprops[1] if rawprops[0] < startx or startx is None: startx = rawprops[0] if nodeStartY < starty or starty is None: starty = nodeStartY if nodeEndX > endx or endx is None: endx = nodeEndX if nodeEndY > endy or endy is None: endy = nodeEndY if self.options.fast == True: # uses simpletransform bbox = simpletransform.computeBBox(nodelist) startx = math.ceil(bbox[0]) endx = math.ceil(bbox[1]) h = -bbox[2] + bbox[3] starty = toty - math.ceil(bbox[2]) - h endy = toty - math.ceil(bbox[2]) coords = [startx / scale, starty / scale, endx / scale, endy / scale] return coords
def effect(self): if len(self.options.ids) == 0: inkex.errormsg("Please select an object.") exit() # Collect document ids doc_ids = {} docIdNodes = self.document.xpath("//@id") for m in docIdNodes: doc_ids[m] = 1 grpname = "axis" # Make sure that the id/name is inique index = 0 while doc_ids.has_key(grpname): grpname = "axis" + str(index) index = index + 1 grp_name = grpname grp_attribs = {inkex.addNS("label", "inkscape"): grp_name} # The group to put everything in grp = inkex.etree.SubElement(self.current_layer, "g", grp_attribs) # Get the bounding box bbox = simpletransform.computeBBox(self.selected.values()) width = int(bbox[1] - bbox[0]) height = int(bbox[3] - bbox[2]) x_pos = bbox[0] y_pos = bbox[3] self.draw_axis( x_pos, y_pos, width, height, self.options.axis_from, self.options.axis_to, self.options.num_ticks, self.options.sub_ticks, self.options.axis_offset, self.options.decimals, self.options.text, self.options.text_font, self.options.text_size_axis, self.options.text_size_title, self.options.direction, grp, )
def translateElement(self, node, x, y, relative=False): # Grab transform attribute if it exists. transform = node.get("transform", "") # Compute the nodes bounding box box = list(simpletransform.computeBBox([node])) pos_x = box[0] pos_y = box[2] # rotation center is not a breeze to calculate from the matrix, so thanks inkscape ;) origin_x = float(node.get(inkex.addNS("transform-center-x", "inkscape"), 0)) origin_y = float(node.get(inkex.addNS("transform-center-y", "inkscape"), 0)) origin_x = origin_x + (box[1] / 2) origin_y = (origin_y * -1) + (box[3] / 2) if transform == "": # If there is no transform attribute on the node we add one node.attrib["transform"] = "" # simpletransform returns a multi dim array of matrix values transform = simpletransform.parseTransform(transform) transformObject = self.normalizeMatrix(transform) inkex.debug(transformObject) # offset_x = (transform[0][2]-pos_x) # offset_y = (transform[1][2]-pos_y) offset_x = pos_x * -1 offset_y = pos_y * -1 inkex.debug([offset_x, offset_y]) transform = simpletransform.parseTransform( ("translate(" + str(offset_x) + " " + str(offset_y) + ")"), transform ) transformObject = self.normalizeMatrix(transform) inkex.debug(transformObject) inkex.debug(transform) if relative == False: matrix = simpletransform.formatTransform(transform) node.set("transform", matrix) inkex.debug(matrix) else: simpletransform.applyTransformToNode(transform, node)
def effect(self): """ Apply the transformation. If an element already has a transformation attribute, it will be combined with the transformation matrix for the requested conversion. """ if self.options.reverse == "true": conversion = "from_" + self.options.conversion else: conversion = "to_" + self.options.conversion if len(self.selected) == 0: inkex.errormsg( _("Please select an object to perform the " + "isometric projection transformation on.")) return # Default to the flat 2D to isometric top down view conversion if an # invalid identifier is passed. effect_matrix = self.transformations.get( conversion, self.transformations.get('to_top')) for id, node in self.selected.items(): bbox = computeBBox([node]) midpoint = self.getMidPoint(bbox, node) center_old = self.getTransformCenter(midpoint, node) transform = node.get("transform") # Combine our transformation matrix with any pre-existing # transform. matrix = parseTransform(transform, effect_matrix) # Compute the location of the transformation center after applying # the transformation matrix. center_new = center_old[:] applyTransformToPoint(matrix, center_new) applyTransformToPoint(matrix, midpoint) # Add a translation transformation that will move the object to # keep its transformation center in the same place. self.translateBetweenPoints(matrix, center_new, center_old) node.set('transform', formatTransform(matrix)) # Adjust the transformation center. self.moveTransformationCenter(node, midpoint, center_new)
def effect(self): """ Apply the transformation. If an element already has a transformation attribute, it will be combined with the transformation matrix for the requested conversion. """ if self.options.reverse == "true": conversion = "from_" + self.options.conversion else: conversion = "to_" + self.options.conversion if len(self.selected) == 0: inkex.errormsg(_("Please select an object to perform the " + "isometric projection transformation on.")) return # Default to the flat 2D to isometric top down view conversion if an # invalid identifier is passed. effect_matrix = self.transformations.get( conversion, self.transformations.get('to_top')) for id, node in self.selected.iteritems(): bbox = computeBBox([node]) midpoint = self.getMidPoint(bbox, node) center_old = self.getTransformCenter(midpoint, node) transform = node.get("transform") # Combine our transformation matrix with any pre-existing # transform. matrix = parseTransform(transform, effect_matrix) # Compute the location of the transformation center after applying # the transformation matrix. center_new = center_old[:] applyTransformToPoint(matrix, center_new) applyTransformToPoint(matrix, midpoint) # Add a translation transformation that will move the object to # keep its transformation center in the same place. self.translateBetweenPoints(matrix, center_new, center_old) node.set('transform', formatTransform(matrix)) # Adjust the transformation center. self.moveTransformationCenter(node, midpoint, center_new)
def effect(self): if len(self.options.ids) == 0: inkex.errormsg("Please select an object.") exit() # Collect document ids doc_ids = {} docIdNodes = self.document.xpath('//@id') for m in docIdNodes: doc_ids[m] = 1 grpname = 'axis' # Make sure that the id/name is inique index = 0 while (doc_ids.has_key(grpname)): grpname = 'axis' + str(index) index = index + 1 grp_name = grpname grp_attribs = {inkex.addNS('label','inkscape'):grp_name} # The group to put everything in grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs) # Get the bounding box bbox = simpletransform.computeBBox(self.selected.values()) width = int(bbox[1] - bbox[0]) height = int(bbox[3] - bbox[2]) x_pos = bbox[0] y_pos = bbox[3] self.draw_axis(x_pos, y_pos, width, height, self.options.axis_from, self.options.axis_to, self.options.num_ticks, self.options.sub_ticks, self.options.axis_offset, self.options.decimals, self.options.text, self.options.text_font, self.options.text_size_axis, self.options.text_size_title, self.options.direction, grp)
def effect(self): if len(self.options.ids) != 2: inkex.errormsg(_("This extension requires two selected paths.")) return self.prepareSelectionList() envs = self.envelopes.values() s = envs[0].get('style') parent = envs[0].getparent() fstEnvComps, fstEnvLengths, sndEnvComps, sndEnvLengths, fstEnvBbox, sndEnvBbox, isCorrect = linearizeEnvelopes(envs) if not isCorrect: inkex.errormsg(_("Selected paths are not compatible.")) return areNested = isSkeletonClosed(fstEnvComps) and isSkeletonClosed(sndEnvComps) self.skelComp = None self.lengths = None countOfSkelPaths = 1 distBetweenFirstPts = 1 funcSeries = self.options.series isLine = True if self.options.patternFunction == 'line' else False if (isLine and self.options.offset > 0): distBetweenFirstPts = getDistBetweenFirstPts(fstEnvComps, sndEnvComps, fstEnvBbox, sndEnvBbox, areNested) countOfSkelPaths = int(distBetweenFirstPts / self.options.offset) funcSeries = 1 for cnt in range(0, countOfSkelPaths): curOffset = (cnt + 1) * self.options.offset / distBetweenFirstPts if areNested: self.skelComp, self.lengths = getClosedLinearizedSkeletonPath(fstEnvComps, sndEnvComps, curOffset, isLine) elif (fstEnvBbox[0] == sndEnvBbox[0] and fstEnvBbox[1] == sndEnvBbox[1]): self.skelComp, self.lengths = getHorizontalLinearizedSkeletonPath(fstEnvComps, sndEnvComps, curOffset, isLine) elif (fstEnvBbox[2] == sndEnvBbox[2] and fstEnvBbox[3] == sndEnvBbox[3]): self.skelComp, self.lengths = getVerticalLinearizedSkeletonPath(fstEnvComps, sndEnvComps, curOffset, isLine) self.skelCompIsClosed = isSkeletonClosed(self.skelComp) length = sum(self.lengths) patternWidth = length / self.options.frequency funcOffsetStep = 100 / funcSeries resPath = '' pattern = inkex.etree.Element(inkex.addNS('path','svg')) self.options.strokeHexColor, self.strokeOpacity = getColorAndOpacity(self.options.strokeColor) if s: pattern.set('style', setColorAndOpacity(s, self.options.strokeHexColor, self.strokeOpacity)) for j in range(funcSeries): selectedFunction = self.getFunction(self.options.patternFunction, j * funcOffsetStep) pattern.set('d', simplepath.formatPath(drawfunction(self.options.nodes, patternWidth, selectedFunction))) # Add path into SVG structure parent.append(pattern) # Compute bounding box bbox = simpletransform.computeBBox([pattern]) width = bbox[1] - bbox[0] height = bbox[3] - bbox[2] dx = width if dx < 0.01: exit(_("The total length of the pattern is too small.")) patternPath = cubicsuperpath.parsePath(pattern.get('d')) curPath = deepcopy(patternPath) xoffset = self.skelComp[0][0] - bbox[0] yoffset = self.skelComp[0][1] - (bbox[2] + bbox[3]) / 2 patternCopies = max(1, int(round(length / dx))) width = dx * patternCopies newPath = [] # Repeat pattern to cover whole skeleton for subPath in curPath: for i in range(0, patternCopies, 1): newPath.append(deepcopy(subPath)) offset(subPath, dx, 0) # Offset pattern to the first node of the skeleton for subPath in newPath: offset(subPath, xoffset, yoffset) curPath = deepcopy(newPath) # Stretch pattern to whole skeleton for subPath in curPath: stretch(subPath, length / width, 1, self.skelComp[0]) for subPath in curPath: for ctlpt in subPath: self.applyDiffeo(ctlpt[1], (ctlpt[0], ctlpt[2])) # Check if there is a need to close path manually if self.skelCompIsClosed: firstPtX = round(curPath[0][0][1][0], 8) firstPtY = round(curPath[0][0][1][1], 8) finalPtX = round(curPath[-1][-1][1][0], 8) finalPtY = round(curPath[-1][-1][1][1], 8) if (firstPtX != finalPtX or firstPtY != finalPtY): curPath[-1].append(curPath[0][0]) curPathComps, curPathLengths = linearize(modifySkeletonPath(curPath)) if not isLine: curPathComps = stretchComps(self.skelComp, curPathComps, fstEnvComps, sndEnvComps, fstEnvBbox, sndEnvBbox, areNested, height / 2, self.options.amplitude / 100.0, self.options.offset) resPath += compsToSVGd(curPathComps) pattern.set('d', resPath) if self.options.remove: parent.remove(envs[0]) parent.remove(envs[1])
def effect(self): thickness = self.unittouu( str(self.options.thickness) + self.options.unit) height = self.unittouu(str(self.options.height) + self.options.unit) iheight = self.unittouu(str(self.options.iheight) + self.options.unit) if len(self.options.ids) != 1: print >> sys.stderr, "you must select exactly one object" return id = self.options.ids[0] node = self.selected[id] # Element (xmin, xmax, ymin, ymax) = simpletransform.computeBBox([node]) # Tuple width = xmax - xmin depth = ymax - ymin nodes = [] if (node.tag == inkex.addNS('path', 'svg')): nodes = [simplepath.parsePath(node.get('d'))] if (node.tag == inkex.addNS('g', 'svg')): nodes = [] for n in node.getchildren(): if (n.tag == inkex.addNS('rect', 'svg')): x = float(n.get('x')) y = float(n.get('y')) h = float(n.get('height')) w = float(n.get('width')) nodes.append([['M', [x, y]], ['L', [x + w, y]], ['L', [x + w, y + h]], ['L', [x, y + h]]]) else: nodes.append(simplepath.parsePath(n.get('d'))) # inkex.debug(nodes) if (nodes == []): print >> sys.stderr, "selected object must be a path or a group of paths" return # Create main SVG element tr = 'translate(' + str(xmin + thickness) + ',' + str(ymax - thickness) + ')' g_attribs = { inkex.addNS('label', 'inkscape'): 'Boxify' + str(width) + \ "x" + str(height) , 'transform': tr } g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) # Create SVG Path for plate style = formatStyle({ 'stroke': '#000000', \ 'fill': 'none', \ 'stroke-width': str(self.unittouu('1px')) }) # Create main box vdivs = max(int(height / (2 * thickness)) - 1, 1) lc.insert_box(g, (width, depth, height), (int( width / (2 * thickness)), int(depth / (2 * thickness)), vdivs), thickness, False, False, style) # Insert remaining edges # inkex.debug(nodes) edges = lc.decompose(nodes) # Position border edges (*after* having translated) e = edges.pop(0) e.position((xmax - xmin - thickness, 0), 'w') e = edges.pop(0) e.position((-thickness, ymin - ymax + 2 * thickness), 'e') e = edges.pop(0) e.position((xmax - xmin - 2 * thickness, ymin - ymax + thickness), 's') e = edges.pop(0) e.position((0, thickness), 'n') # Handle remaining edges numedges = 0 for e in edges: # inkex.debug("==========================") # inkex.debug(str(e) + "\n") # style = formatStyle({ 'stroke': "#%06x" % random.randint(0, 0xFFFFFF), \ # 'fill': 'none', \ # 'stroke-width': str(self.unittouu('3px')) }) numedges += 1 # Determine edge direction in the main plate dir = e.getdir() # Middle holes leng = e.getlen() for (f, df) in e.touch: if not (f.bnd): leng += thickness / 2 num = int((leng - 2 * thickness) / (2 * thickness)) if (dir == 's') or (dir == 'n'): # Vertical edge dims = (thickness, (leng - 2 * thickness) / (2 * num + 1)) if (dir == 's'): st = (e.p_from[0] - xmin - thickness, e.p_from[1] - ymax - dims[1] / 2 + thickness) else: st = (e.p_from[0] - xmin - thickness, e.p_from[1] - ymax + 2 * thickness + dims[1] / 2) if not ((abs(e.p_from[1] - ymin) < 0.1) or (abs(e.p_from[1] - ymax) < 0.1)): # Is the start point on the border ? st = (st[0], st[1] - thickness / 2) else: st = (st[0], st[1]) else: # Horizontal edge dims = ((leng - 2 * thickness) / (2 * num + 1), thickness) if (dir == 'e'): st = (e.p_from[0] - xmin + dims[0] / 2, e.p_from[1] - ymax + thickness) else: st = (e.p_from[0] - xmin - 2 * thickness - dims[0] / 2, e.p_from[1] - ymax + thickness) if not ((abs(e.p_from[0] - xmin) < 0.1) or (abs(e.p_from[0] - xmax) < 0.1)): # Is the start point on the border ? if (dir == 'e'): st = (st[0] - thickness / 2, st[1]) else: st = (st[0] + thickness / 2, st[1]) lc.insert_holes(g, st, dims, num + 1, dir, style) # Do we need to split the joins of the edge ? tm_from = 0 tm_to = 0 for (f, df) in e.touch: tm_from += len( filter((lambda q: ((q[0] - e.p_from[0])**2 + (q[1] - e.p_from[1]))**2 < 0.1), f.attch)) tm_to += len( filter((lambda q: ((q[0] - e.p_to[0])**2 + (q[1] - e.p_to[1]))**2 < 0.1), f.attch)) vdivs = max(int((height - iheight) / (2 * thickness)) - 1, 1) points = lc.make_plate( (height - thickness - iheight, leng), (True, False), thickness, vdivs, num, 'm' if tm_to <= 1 else ('x' if (e.getdir() == 'w') or (e.getdir() == 'n') else 'w'), False, 'm' if tm_from <= 1 else ('x' if (e.getdir() == 'w') or (e.getdir() == 'n') else 'w'), False, '-', False, 'f', True) (dpx, dpy) = (xmax - xmin - 2 * thickness + numedges * (height - iheight) + iheight, 0) points = lc.translate_points(points, dpx, dpy) lc.insert_path(g, points, style) e.position((xmax - xmin + (height - iheight) * (numedges + 1) + iheight - 2 * thickness, thickness), 'n') # Left parts for (f, df) in e.touch: # inkex.debug("Touch " + str(f) + " -- DIST= " + str(df) + "\n") vdir = lc.rotatedir(f.dir) if (vdir == 's') or (vdir == 'n'): xdim = thickness ydim = (height - iheight - thickness) / (2 * vdivs + 1.) dyf = -2 * thickness - 3 * ydim / 2 if vdir == 'n' else +3 * ydim / 2 df = 1 - df stf = (f.r_from[0] + df * (f.r_to[0] - f.r_from[0]), f.r_from[1] + df * (f.r_to[1] - f.r_from[1]) + thickness + dyf) vdir = 's' if vdir == 'n' else 'n' else: ydim = thickness xdim = (height - iheight - thickness) / (2 * vdivs + 1.) df = 1 - df dxf = 2 * thickness + 3 * xdim / 2 if vdir == 'e' else -3 * xdim / 2 stf = (f.r_from[0] + df * (f.r_to[0] - f.r_from[0]) - thickness + dxf, f.r_from[1] + df * (f.r_to[1] - f.r_from[1])) lc.insert_holes(g, stf, (xdim, ydim), vdivs, vdir, style)
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): if len(self.options.ids) < 1 and len(self.options.ids) > 1: inkex.errormsg( _("This extension requires only one selected paths.")) return #liste des chemins, preparation idList = self.options.ids idList = pathmodifier.zSort(self.document.getroot(), idList) id = idList[-1] idpoint = id + '-' + str(random.randint( 1, 99)) #id du paterns creer a partir du chemin selectionner for id, node in self.selected.iteritems(): style = simplestyle.parseStyle( node.get('style')) #je recupere l'ancien style style['stroke'] = '#00ff00' #je modifie la valeur node.set('style', simplestyle.formatStyle(style)) #j'applique la modifi #gestion du skelte (le chemin selectionner) self.skeletons = self.selected self.expandGroupsUnlinkClones(self.skeletons, True, False) self.objectsToPaths(self.skeletons) for skelnode in self.skeletons.itervalues( ): #calcul de la longeur du chemin self.curSekeleton = cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: self.skelcomp, self.lengths = linearize(comp) longeur = sum(self.lengths) distance = self.unittouu(self.options.space) taille = self.unittouu(self.options.diamlong) if self.options.autoRepeat: #gestion du calcul auto nbrRepeat = int(round((longeur) / distance)) else: nbrRepeat = self.options.nrepeat if self.options.autoOffset: #gestion du decallage automatique tOffset = ((longeur - (nbrRepeat - 1) * distance) / 2) - taille / 2 else: tOffset = self.unittouu(self.options.toffset) #gestion du paterns labelpoint = 'Point:' + self.options.diamlong + ' Ecart:' + self.options.space + ' Decallage:' + str( round(self.uutounit(tOffset, 'mm'), 2)) + 'mm' + ' Nbr:' + str(nbrRepeat) + ' longueur:' + str( round(self.uutounit(longeur, 'mm'), 2)) + 'mm' addDot(self, idpoint, labelpoint, self.options.diamlong, self.options.typePoint) #creation du cercle de base self.patterns = { idpoint: self.getElementById(idpoint) } #ajout du point dans le paterns de base bbox = simpletransform.computeBBox(self.patterns.values()) #liste des chemins, fin de preparation if distance < 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) #!!!!>----> 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] + tOffset yoffset = self.skelcomp[0][1] - (bbox[2] + bbox[3]) / 2 if self.options.textInfos: addText(self, xoffset, yoffset, labelpoint) MaxCopies = max( 1, int(round((length + distance) / distance))) NbCopies = nbrRepeat #nombre de copie desirer a intergrer dans les choix a modifier pour ne pas depasser les valeurs maxi if NbCopies > MaxCopies: NbCopies = MaxCopies #on limitte le nombre de copie au maxi possible sur le chemin width = distance * NbCopies if not self.skelcompIsClosed: width -= distance new = [] for sub in p: #creation du nombre de patern for i in range(0, NbCopies, 1): new.append( copy.deepcopy(sub) ) #realise une copie de sub pour chaque nouveau element du patern offset(sub, distance, 0) p = new for sub in p: offset(sub, xoffset, yoffset) for sub in p: #une fois tous creer, on les mets en place for ctlpt in sub: #pose le patern sur le chemin self.applyDiffeo(ctlpt[1], (ctlpt[0], ctlpt[2])) newp += p node.set('d', cubicsuperpath.formatPath(newp))
def _process_bbox(self): left, right, top, bottom = simpletransform.computeBBox(self.node.iterdescendants()) self.width = right - left self._min_x = left
def effect(self): if len(self.options.ids) < 1 and len(self.options.ids) > 1: inkex.errormsg("This extension requires only one selected paths.") return #liste des chemins, preparation idList = self.options.ids idList = pathmodifier.zSort(self.document.getroot(), idList) id = idList[-1] idpoint = id + '-' + str(random.randint( 1, 99)) #id du paterns creer a partir du chemin selectionner idpointMark = id + '-' + str(random.randint(1, 99)) for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): style = simplestyle.parseStyle( node.get('style')) #je recupere l'ancien style style['stroke'] = '#00ff00' #je modifie la valeur if self.options.autoMask == True: style['display'] = 'none' node.set('style', simplestyle.formatStyle(style)) #j'applique la modifi #gestion du skelete (le chemin selectionner) self.skeletons = self.selected self.expandGroupsUnlinkClones(self.skeletons, True, False) self.objectsToPaths(self.skeletons) for skelnode in self.skeletons.itervalues( ): #calcul de la longeur du chemin self.curSekeleton = cubicsuperpath.parsePath( skelnode.get('d')) for comp in self.curSekeleton: self.skelcomp, self.lengths = linearize(comp) longeur = sum(self.lengths) distance = self.unittouu(self.options.space) taille = self.unittouu(self.options.diamlong) MaxCopies = max(1, int(round((longeur + distance) / distance))) NbCopies = self.options.nrepeat #nombre de copie desirer a integrer dans les choix a modifier pour ne pas depasser les valeurs maxi if NbCopies > MaxCopies: NbCopies = MaxCopies #on limitte le nombre de copie au maxi possible sur le chemin if self.options.autoRepeat: #gestion du calcul auto NbCopies = MaxCopies if self.options.autoOffset: #gestion du decallage automatique tOffset = ((longeur - (NbCopies - 1) * distance) / 2) - taille / 2 else: tOffset = self.unittouu(self.options.toffset) #gestion du paterns labelpoint = 'Point: ' + idpoint + ' Nbr:' + str( NbCopies) + ' longueur:' + str( round(self.uutounit(longeur, 'mm'), 2)) + 'mm' addDot(self, idpoint, labelpoint, self.options.diamlong, self.options.typePoint, 0) #creation du cercle de base self.patterns = { idpoint: self.getElementById(idpoint) } #ajout du point dans le paterns de base bbox = simpletransform.computeBBox(self.patterns.values()) #liste des chemins, fin de preparation if distance < 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) #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! self.skelcompIsClosed = ( self.skelcomp[0] == self.skelcomp[-1]) xoffset = self.skelcomp[0][0] - bbox[ 0] + tOffset yoffset = self.skelcomp[0][1] - (bbox[2] + bbox[3]) / 2 if self.options.textInfos: addText(self, xoffset, yoffset, labelpoint) width = distance * NbCopies if not self.skelcompIsClosed: width -= distance new = [] for sub in p: #creation du nombre de patern for i in range(0, NbCopies, 1): new.append( copy.deepcopy(sub) ) #realise une copie de sub pour chaque nouveau element du patern offset(sub, distance, 0) p = new for sub in p: offset(sub, xoffset, yoffset) for sub in p: #une fois tous creer, on les mets en place for ctlpt in sub: #pose le patern sur le chemin self.applyDiffeo( ctlpt[1], (ctlpt[0], ctlpt[2])) newp += p node.set('d', cubicsuperpath.formatPath(newp)) else: inkex.errormsg( "This extension need a path, not groups.") if self.options.autoMark: if self.options.typeMark == "markFraction": Fraction = self.options.nrepeat2 #en mode fraction 1= au debut et a la fin, 2= un demi, 3= 1/3 etc distance = (width) / Fraction #distance inter point NbrMark = max(1, int(round((width + distance) / distance))) infos = " Marquage 1/" + str(Fraction) couleur = '#ff0000' else: Repeat = self.options.nrepeat2 #en mode fraction 1= au debut et a la fin, 2= un demi, 3= 1/3 etc NbrMark = max(1, int(round((NbCopies / Repeat)))) distance = distance * Repeat #distance inter point infos = " Marquage tous les " + str(Repeat) + " points" couleur = '#ffaa00' labelMark = "Mark: " + idpoint + infos addMark(self, 0, 0, idpointMark, labelMark, self.options.diamlong, couleur) self.patternsMark = { idpointMark: self.getElementById(idpointMark) } #ajout du point dans le paterns de base bbox = simpletransform.computeBBox(self.patternsMark.values()) #liste des chemins, fin de preparation if distance < 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.patternsMark.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) #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! self.skelcompIsClosed = ( self.skelcomp[0] == self.skelcomp[-1]) # a tester si les point au dessus sont utilisable pour positionner les autres a upoi ressemble skelcomp ?? xoffset = self.skelcomp[0][0] - bbox[ 0] + tOffset + taille / 2 yoffset = self.skelcomp[0][1] - (bbox[2] + bbox[3]) / 2 width = distance * NbrMark if not self.skelcompIsClosed: width -= distance new = [] for sub in p: #creation du nombre de patern for i in range(0, NbrMark, 1): new.append( copy.deepcopy(sub) ) #realise une copie de sub pour chaque nouveau element du patern offset(sub, distance, 0) p = new for sub in p: offset(sub, xoffset, yoffset) for sub in p: #une fois tous creer, on les mets en place for ctlpt in sub: #pose le patern sur le chemin self.applyDiffeo(ctlpt[1], (ctlpt[0], ctlpt[2])) newp += p node.set('d', cubicsuperpath.formatPath(newp)) else: inkex.errormsg("This extension need a path, not groups.")
def effect(self): thickness=self.unittouu(str(self.options.thickness)+self.options.unit) height=self.unittouu(str(self.options.height)+self.options.unit) iheight=self.unittouu(str(self.options.iheight)+self.options.unit) if len(self.options.ids)!=1: print >> sys.stderr,"you must select exactly one object" return id=self.options.ids[0] node=self.selected[id] # Element (xmin,xmax,ymin,ymax)=simpletransform.computeBBox([node]) # Tuple width=xmax-xmin depth=ymax-ymin nodes=[] if (node.tag == inkex.addNS('path','svg')): nodes = [simplepath.parsePath(node.get('d'))] if (node.tag == inkex.addNS('g','svg')): nodes = [] for n in node.getchildren(): if (n.tag == inkex.addNS('rect','svg')): x = float(n.get('x')) y = float(n.get('y')) h = float(n.get('height')) w = float(n.get('width')) nodes.append([['M', [x,y]],['L', [x+w,y]],['L', [x+w,y+h]],['L', [x,y+h]]]) else: nodes.append(simplepath.parsePath(n.get('d'))) # inkex.debug(nodes) if (nodes == []): print >> sys.stderr,"selected object must be a path or a group of paths" return # Create main SVG element tr= 'translate(' + str(xmin+thickness) + ',' + str(ymax-thickness) + ')' g_attribs = { inkex.addNS('label', 'inkscape'): 'Boxify' + str(width) + \ "x" + str(height) , 'transform': tr } g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) # Create SVG Path for plate style = formatStyle({ 'stroke': '#000000', \ 'fill': 'none', \ 'stroke-width': str(self.unittouu('1px')) }) # Create main box vdivs = max(int(height/(2*thickness))-1,1) lc.insert_box(g, (width, depth, height), (int(width/(2*thickness)), int(depth/(2*thickness)), vdivs), thickness, False, False, style) # Insert remaining edges # inkex.debug(nodes) edges = lc.decompose(nodes) # Position border edges (*after* having translated) e = edges.pop(0); e.position((xmax-xmin-thickness,0),'w') e = edges.pop(0); e.position((-thickness,ymin-ymax+2*thickness),'e') e = edges.pop(0); e.position((xmax-xmin-2*thickness,ymin-ymax+thickness),'s') e = edges.pop(0); e.position((0,thickness),'n') # Handle remaining edges numedges = 0 for e in edges: # inkex.debug("==========================") # inkex.debug(str(e) + "\n") # style = formatStyle({ 'stroke': "#%06x" % random.randint(0, 0xFFFFFF), \ # 'fill': 'none', \ # 'stroke-width': str(self.unittouu('3px')) }) numedges += 1 # Determine edge direction in the main plate dir = e.getdir() # Middle holes leng = e.getlen() for (f,df) in e.touch: if not(f.bnd): leng += thickness/2 num = int((leng-2*thickness)/(2*thickness)) if (dir == 's') or (dir == 'n'): # Vertical edge dims = (thickness,(leng-2*thickness)/(2*num+1)) if (dir == 's'): st = (e.p_from[0]-xmin-thickness, e.p_from[1]-ymax-dims[1]/2+thickness) else: st = (e.p_from[0]-xmin-thickness, e.p_from[1]-ymax+2*thickness+dims[1]/2) if not((abs(e.p_from[1]-ymin) < 0.1) or (abs(e.p_from[1]-ymax) < 0.1)): # Is the start point on the border ? st = (st[0],st[1]-thickness/2) else: st = (st[0],st[1]) else: # Horizontal edge dims = ((leng-2*thickness)/(2*num+1),thickness) if (dir == 'e'): st = (e.p_from[0]-xmin+dims[0]/2, e.p_from[1]-ymax+thickness) else: st = (e.p_from[0]-xmin-2*thickness-dims[0]/2, e.p_from[1]-ymax+thickness) if not((abs(e.p_from[0]-xmin) < 0.1) or (abs(e.p_from[0]-xmax) < 0.1)): # Is the start point on the border ? if (dir == 'e'): st = (st[0]-thickness/2,st[1]) else: st = (st[0]+thickness/2,st[1]) lc.insert_holes(g, st, dims, num+1, dir, style) # Do we need to split the joins of the edge ? tm_from = 0; tm_to = 0 for (f,df) in e.touch: tm_from += len(filter ((lambda q: ((q[0]-e.p_from[0])**2+(q[1]-e.p_from[1]))**2 < 0.1), f.attch)) tm_to += len(filter ((lambda q: ((q[0]-e.p_to[0])**2+(q[1]-e.p_to[1]))**2 < 0.1), f.attch)) vdivs = max(int((height-iheight)/(2*thickness))-1,1) points=lc.make_plate((height-thickness-iheight,leng),(True,False), thickness,vdivs,num, 'm' if tm_to <= 1 else ('x' if (e.getdir() == 'w') or (e.getdir() == 'n') else 'w'),False, 'm' if tm_from <= 1 else ('x' if (e.getdir() == 'w') or (e.getdir() == 'n') else 'w'),False, '-',False, 'f',True) (dpx,dpy) = (xmax-xmin-2*thickness+numedges*(height-iheight)+iheight,0) points = lc.translate_points(points,dpx,dpy) lc.insert_path(g, points, style) e.position((xmax-xmin+(height-iheight)*(numedges+1)+iheight-2*thickness, thickness), 'n') # Left parts for (f,df) in e.touch: # inkex.debug("Touch " + str(f) + " -- DIST= " + str(df) + "\n") vdir = lc.rotatedir(f.dir) if (vdir == 's') or (vdir == 'n'): xdim = thickness ydim = (height-iheight-thickness)/(2*vdivs+1.) dyf = -2*thickness-3*ydim/2 if vdir == 'n' else +3*ydim/2 df = 1-df stf = (f.r_from[0]+df*(f.r_to[0]-f.r_from[0]), f.r_from[1]+df*(f.r_to[1]-f.r_from[1])+thickness+dyf) vdir = 's' if vdir == 'n' else 'n' else: ydim = thickness xdim = (height-iheight-thickness)/(2*vdivs+1.) df = 1-df dxf = 2*thickness+3*xdim/2 if vdir == 'e' else -3*xdim/2 stf = (f.r_from[0]+df*(f.r_to[0]-f.r_from[0])-thickness+dxf, f.r_from[1]+df*(f.r_to[1]-f.r_from[1])) lc.insert_holes(g, stf, (xdim,ydim), vdivs, vdir, style)
def calculate_bboxes(self, nodes): bboxes = [(id, node, computeBBox([node])) for id, node in nodes.items()] return bboxes
def center(self, source_node): xmin, xmax, ymin, ymax = computeBBox([source_node]) point = [(xmax - ((xmax - xmin) / 2)), (ymax - ((ymax - ymin) / 2))] transform = get_node_transform(self.node) applyTransformToPoint(transform, point) return point
def effect(self): # Get script's options values. # Factor to multiply in order to get user units (pixels) factor = self.unittouu('1' + self.options.unit) # document or selection target = self.options.target # boolean same_margins = self.options.same_margins # convert string to integer, in user units (pixels) top_margin = float(self.options.top_margin) * factor right_margin = float(self.options.right_margin) * factor bottom_margin = float(self.options.bottom_margin) * factor left_margin = float(self.options.left_margin) * factor # getting parent tag of the guides namedview = self.document.xpath( '/svg:svg/sodipodi:namedview', namespaces=inkex.NSS)[0] # getting the main SVG document element (canvas) svg = self.document.getroot() # if same margins, set them all to same value if same_margins: right_margin = top_margin bottom_margin = top_margin left_margin = top_margin # getting the width and height attributes of the canvas canvas_width = self.unittouu(svg.get('width')) canvas_height = self.unittouu(svg.get('height')) # If selection, draw around selection. Otherwise use document. if (target == "selection"): # If there is no selection, quit with message if not self.options.ids: inkex.errormsg(_("Please select an object first")) exit() # get bounding box obj_x1, obj_x2, obj_y1, obj_y2 = simpletransform.computeBBox([self.getElementById(id) for id in self.options.ids]) # start position of guides top_pos = canvas_height - obj_y1 - top_margin right_pos = obj_x2 - right_margin bottom_pos = canvas_height - obj_y2 + bottom_margin left_pos = obj_x1 + left_margin # Draw the four margin guides # TODO: only draw if not on border guidetools.drawGuide(top_pos, "horizontal", namedview) guidetools.drawGuide(right_pos, "vertical", namedview) guidetools.drawGuide(bottom_pos, "horizontal", namedview) guidetools.drawGuide(left_pos, "vertical", namedview) else: # draw margin guides (if not zero) if same_margins: right_margin = top_margin bottom_margin = top_margin left_margin = top_margin # start position of guides top_pos = canvas_height - top_margin right_pos = canvas_width - right_margin bottom_pos = bottom_margin left_pos = left_margin # Draw the four margin guides (if margin exists) if top_pos != canvas_height: guidetools.drawGuide(top_pos, "horizontal", namedview) if right_pos != canvas_width: guidetools.drawGuide(right_pos, "vertical", namedview) if bottom_pos != 0: guidetools.drawGuide(bottom_pos, "horizontal", namedview) if left_pos != 0: guidetools.drawGuide(left_pos, "vertical", namedview)
def effect(self): if self.options.mformat == '"presets"': self.setPreset() # get number of digits prec = int(self.options.precision) scale = self.unittouu('1px') # convert to document units self.options.offset *= scale factor = 1.0 doc = self.document.getroot() if doc.get('viewBox'): [viewx, viewy, vieww, viewh] = doc.get('viewBox').split(' ') factor = self.unittouu(doc.get('width'))/float(vieww) if self.unittouu(doc.get('height'))/float(viewh) < factor: factor = self.unittouu(doc.get('height'))/float(viewh) factor /= self.unittouu('1px') self.options.fontsize /= factor factor *= scale/self.unittouu('1'+self.options.unit) # loop over all selected paths for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): mat = simpletransform.composeParents(node, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) p = cubicsuperpath.parsePath(node.get('d')) simpletransform.applyTransformToPath(mat, p) if self.options.mtype == "length": slengths, stotal = csplength(p) self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg')) elif self.options.mtype == "area": stotal = abs(csparea(p)*factor*self.options.scale) self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg')) else: xc, yc = cspcofm(p) self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('path','svg')) self.group.set('id', 'MassCenter_' + node.get('id')) self.addCross(self.group, xc, yc, scale) continue # 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.mformat == '"textonpath"': startOffset = self.options.startOffset if startOffset == "custom": startOffset = str(self.options.startOffsetCustom) + '%' if self.options.mtype == "length": self.addTextOnPath(self.group, 0, 0, lenstr+' '+self.options.unit, id, self.options.anchor, startOffset, self.options.offset) else: self.addTextOnPath(self.group, 0, 0, lenstr+' '+self.options.unit+'^2', id, self.options.anchor, startOffset, self.options.offset) elif self.options.mformat == '"fixedtext"': if self.options.position == "mass": tx, ty = cspcofm(p) anchor = 'middle' elif self.options.position == "center": bbox = simpletransform.computeBBox([node]) tx = bbox[0] + (bbox[1] - bbox[0])/2.0 ty = bbox[2] + (bbox[3] - bbox[2])/2.0 anchor = 'middle' else: # default tx = p[0][0][1][0] ty = p[0][0][1][1] anchor = 'start' if self.options.mtype == "length": self.addTextWithTspan(self.group, tx, ty, lenstr+' '+self.options.unit, id, anchor, -int(self.options.angle), self.options.offset + self.options.fontsize/2) else: self.addTextWithTspan(self.group, tx, ty, lenstr+' '+self.options.unit+'^2', id, anchor, -int(self.options.angle), -self.options.offset + self.options.fontsize/2) else: # center of mass, no text pass
def effect(self): """ Effect behaviour. """ self.where = self.options.where self.base64Encode = self.options.encode self.viewResult = self.options.viewresult self.resizeDrawing = self.options.resize self.reposition = self.options.reposition self.scour = self.options.scour self.renderSass = True self.includeJS = self.options.includejs self.CSSSource = [] self.getselected() self.svgDoc = self.document.xpath("//svg:svg", namespaces=inkex.NSS)[0] self.svgWidth = inkex.unittouu(self.svgDoc.get("width")) self.svgHeight = inkex.unittouu(self.svgDoc.get("height")) overideElementDim = False # Temporary solution where I grab all defs, regardless of if they are actually used or not # defs = self.document.xpath('//svg:svg/svg:defs',namespaces=inkex.NSS)[0] layers = self.document.xpath('//svg:svg/svg:g[@style!="display:none"]', namespaces=inkex.NSS) """ if(len(defs) > 0): defs = inkex.etree.tostring(defs) else: defs = '<defs/>' """ # If no elements where selected we default to exporting every visible layer in the drawing if self.selected.__len__() <= 0: self.selected = layers # As we are exporting whole layers we assume that the resulting SVG drawings has the # same dimensions as the source document and thus overide the elements bounding box. overideElementDim = True else: self.selected = self.selected.values() if self.selected.__len__() > 0: selected = [] # Iterate through all selected elements for element in self.selected: elementLabel = str(element.get(inkex.addNS("label", "inkscape"), "")) elementId = element.get("id") if elementLabel != "": element.set("label", elementLabel) element.set("class", elementLabel) else: pass tagName = self.getTagName(element) if tagName == "path": # Paths can easily be moved by recalculating their d attributes if self.reposition or self.resizeDrawing: pathData = self.movePath(element, 0, 0, "tl") if pathData: element.set("d", pathData) elif tagName == "g": # Groups however are best "transformed" into place using translate # self.translateElement(element,0,0,False) pass elementBox = list(simpletransform.computeBBox([element])) elementBox[1] = elementBox[1] - elementBox[0] elementBox[3] = elementBox[3] - elementBox[2] if overideElementDim == False: elementWidth = elementBox[1] elementHeight = elementBox[3] else: elementWidth = self.svgWidth elementHeight = self.svgHeight elementSource = inkex.etree.tostring(element) if elementSource != "": # Wrap the node in an SVG doc if self.resizeDrawing: tplResult = string.replace(self.exportTemplate, "{{element.width}}", str(elementWidth)) tplResult = string.replace(tplResult, "{{element.height}}", str(elementHeight)) else: tplResult = string.replace(self.exportTemplate, "{{element.width}}", str(self.svgWidth)) tplResult = string.replace(tplResult, "{{element.height}}", str(self.svgHeight)) # tplResult = string.replace(tplResult,'{{document.defs}}',defs) tplResult = string.replace(tplResult, "{{element.source}}", elementSource) if self.includeJS: tplResult = string.replace(tplResult, "{{js}}", self.js) else: tplResult = string.replace(tplResult, "{{js}}", "") if self.scour: tplResult = self.scourDoc(tplResult) # If the result of the operation is valid, add the SVG source to the selected array if tplResult: selected.append( {"id": elementId, "label": elementLabel, "source": tplResult, "box": elementBox} ) for node in selected: # Cache these in local vars content = node["source"] id = node["id"] label = node["label"] or node["id"] if content != "": if self.base64Encode: if self.renderSass: content = ( "$data-url-" + label + ':"data:image/svg+xml;name=' + label + ";base64," + (base64.b64encode(content)) + '";' ) # node['source'] = ('data:image/svg+xml;name='+label+';base64,'+(base64.b64encode(content))) # content = self.renderSassStyle(node) else: pass # content = ('data:image/svg+xml;name='+label+';base64,'+(base64.b64encode(content))) if self.where != "": # The easiest way to name rendered elements is by using their id since we can trust that this is always unique. filename = os.path.join(self.where, (id + "-" + label + ".svg")) success = self.saveToFile(content, filename) if success: if self.viewResult: self.viewOutput(filename) else: inkex.debug('Unable to write to file "' + filename + '"') else: if self.viewResult: if self.base64Encode: inkex.debug(content) inkex.debug("") # self.viewOutput('data:image/svg+xml;base64,'+content) else: inkex.debug(content) inkex.debug("") # self.viewOutput('data:image/svg+xml,'+content) else: inkex.debug(content) else: inkex.debug("No SVG source available for element " + id) else: inkex.debug("No SVG elements or layers to extract.")
def effect(self): #{{{ Check that elements have been selected if len(self.options.ids) == 0: inkex.errormsg(_("Please select objects!")) return #}}} #{{{ Drawing styles linestyle = { 'stroke': '#000000', 'stroke-width': str(self.unittouu('1px')), 'fill': 'none' } facestyle = { 'stroke': '#000000', 'stroke-width':'0px',# str(self.unittouu('1px')), 'fill': 'none' } #}}} #{{{ Handle the transformation of the current group parentGroup = self.getParentNode(self.selected[self.options.ids[0]]) svg = self.document.getroot() children =svg.getchildren() fp=open("log.txt","w") img=None width_in_svg=1 height_in_svg=1 for child in children: if child.tag=="{http://www.w3.org/2000/svg}g": ccc=child.getchildren() for c in ccc: if c.tag=="{http://www.w3.org/2000/svg}image": href=c.attrib["{http://www.w3.org/1999/xlink}href"] fp.write(href) img = Image.open(href) width_in_svg=child.attrib['width'] height_in_svg=child.attrib['height'] elif child.tag=="{http://www.w3.org/2000/svg}image": href=child.attrib["{http://www.w3.org/1999/xlink}href"] width_in_svg=child.attrib['width'] height_in_svg=child.attrib['height'] if "file://" in href: href=href[7:] fp.write(href+"\n") img = Image.open(href).convert("RGB") width=-1 height=-1 if img!=None: imagesize = img.size width=img.size[0] height=img.size[1] fp.write("imageSize="+str(imagesize)) trans = self.getGlobalTransform(parentGroup) invtrans = None if trans: invtrans = self.invertTransform(trans) #}}} #{{{ Recovery of the selected objects pts = [] nodes = [] seeds = [] fp.write('num:'+str(len(self.options.ids))+'\n') for id in self.options.ids: node = self.selected[id] nodes.append(node) if(node.tag=="{http://www.w3.org/2000/svg}path"):#pathだった場合 #パスの頂点座標を取得 points = cubicsuperpath.parsePath(node.get('d')) fp.write(str(points)+"\n") for p in points[0]: pt=[p[1][0],p[1][1]] if trans: simpletransform.applyTransformToPoint(trans, pt) pts.append(Point(pt[0], pt[1])) seeds.append(Point(p[1][0], p[1][1])) else:#その他の図形の場合 bbox = simpletransform.computeBBox([node]) if bbox: cx = 0.5 * (bbox[0] + bbox[1]) cy = 0.5 * (bbox[2] + bbox[3]) pt = [cx, cy] if trans: simpletransform.applyTransformToPoint(trans, pt) pts.append(Point(pt[0], pt[1])) seeds.append(Point(cx, cy)) pts.sort() seeds.sort() fp.write("*******sorted!***********"+str(len(seeds))+"\n") #}}} #{{{ Creation of groups to store the result # Delaunay groupDelaunay = inkex.etree.SubElement(parentGroup, inkex.addNS('g', 'svg')) groupDelaunay.set(inkex.addNS('label', 'inkscape'), 'Delaunay') #}}} scale_x=float(width_in_svg)/float(width) scale_y=float(height_in_svg)/float(height) fp.write('width='+str(width)+', height='+str(height)+'\n') fp.write('scale_x='+str(scale_x)+', scale_y='+str(scale_y)+'\n') #{{{ Voronoi diagram generation triangles = voronoi.computeDelaunayTriangulation(seeds) for triangle in triangles: p1 = seeds[triangle[0]] p2 = seeds[triangle[1]] p3 = seeds[triangle[2]] cmds = [['M', [p1.x, p1.y]], ['L', [p2.x, p2.y]], ['L', [p3.x, p3.y]], ['Z', []]] path = inkex.etree.Element(inkex.addNS('path', 'svg')) path.set('d', simplepath.formatPath(cmds)) middleX=(p1.x+p2.x+p3.x)/3.0/scale_x middleY=(p1.y+p2.y+p3.y)/3.0/scale_y fp.write("x:"+str(middleX)+" y:"+str(middleY)+"\n") if img!=None and imagesize[0]>middleX and imagesize[1]>middleY and middleX>=0 and middleY>=0: r,g,b = img.getpixel((middleX,middleY)) facestyle["fill"]=simplestyle.formatColor3i(r,g,b) else: facestyle["fill"]="black" path.set('style', simplestyle.formatStyle(facestyle)) groupDelaunay.append(path) fp.close()
def parsePath(self,node,parent): #self.parsing_context = 'path' style = node.get('style') style = self.parseStyleAttribute(style) transform = node.get('transform','') box =list(simpletransform.computeBBox([node])) box[1] = (box[1]-box[0]) box[3] = (box[3]-box[2]) origin_x = float(node.get(inkex.addNS('transform-center-x', 'inkscape'),0)) origin_y = float(node.get(inkex.addNS('transform-center-y', 'inkscape'),0)) origin_x = origin_x + ( box[1] / 2) origin_y = (origin_y * -1) + ( box[3] / 2) if(transform!=''): transform = simpletransform.parseTransform(node.get('transform','')) transform = self.matrixToList(transform) transform = self.normalizeMatrix(transform) path_array = simplepath.parsePath(node.get('d')) path = { 'id':node.get('id'), 'svg':'path', 'label':str(node.get(inkex.addNS('label', 'inkscape'),'')), 'box':box, 'transform':transform, 'origin':{ 'x':origin_x, 'y':origin_y, }, 'path':path_array, #'d':node.get('d',''), 'attr':{ 'fillColor':style.get('fill',''), 'fillGradient':style.get('fillGradient',''), 'fillOpacity':style.get('fillOpacity','1'), 'opacity':style.get('opacity','1'), 'strokeColor':style.get('stroke',''), 'strokeGradient':style.get('strokeGradient',''), 'strokeWidth':style.get('strokeWidth','0'), 'strokeOpacity':style.get('strokeOpacity','1'), 'filters':style.get('filter','') } } #inkex.debug('Path resides in group ' + self.parse_stack[len(self.parse_stack)-1]['id']) if(self.reposition): path['path'] = self.movePath(path,0,0,'tl') else: path['path'] = simplepath.formatPath(path_array) path['box'] = list(path['box']) if path['box'] != None else [] parent.append(path)
def effect(self): if self.options.mformat == '"presets"': self.setPreset() # get number of digits prec = int(self.options.precision) scale = self.unittouu('1px') # convert to document units self.options.offset *= scale factor = 1.0 doc = self.document.getroot() if doc.get('viewBox'): [viewx, viewy, vieww, viewh] = doc.get('viewBox').split(' ') factor = self.unittouu(doc.get('width')) / float(vieww) if self.unittouu(doc.get('height')) / float(viewh) < factor: factor = self.unittouu(doc.get('height')) / float(viewh) factor /= self.unittouu('1px') self.options.fontsize /= factor factor *= scale / self.unittouu('1' + self.options.unit) # loop over all selected paths for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path', 'svg'): mat = simpletransform.composeParents( node, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) p = cubicsuperpath.parsePath(node.get('d')) simpletransform.applyTransformToPath(mat, p) if self.options.mtype == "length": slengths, stotal = csplength(p) self.group = inkex.etree.SubElement( node.getparent(), inkex.addNS('text', 'svg')) elif self.options.mtype == "area": stotal = abs(csparea(p) * factor * self.options.scale) self.group = inkex.etree.SubElement( node.getparent(), inkex.addNS('text', 'svg')) else: xc, yc = cspcofm(p) self.group = inkex.etree.SubElement( node.getparent(), inkex.addNS('path', 'svg')) self.group.set('id', 'MassCenter_' + node.get('id')) self.addCross(self.group, xc, yc, scale) continue # 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.mformat == '"textonpath"': startOffset = self.options.startOffset if startOffset == "custom": startOffset = str(self.options.startOffsetCustom) + '%' if self.options.mtype == "length": self.addTextOnPath(self.group, 0, 0, lenstr + ' ' + self.options.unit, id, self.options.anchor, startOffset, self.options.offset) else: self.addTextOnPath( self.group, 0, 0, lenstr + ' ' + self.options.unit + '^2', id, self.options.anchor, startOffset, self.options.offset) elif self.options.mformat == '"fixedtext"': if self.options.position == "mass": tx, ty = cspcofm(p) anchor = 'middle' elif self.options.position == "center": bbox = simpletransform.computeBBox([node]) tx = bbox[0] + (bbox[1] - bbox[0]) / 2.0 ty = bbox[2] + (bbox[3] - bbox[2]) / 2.0 anchor = 'middle' else: # default tx = p[0][0][1][0] ty = p[0][0][1][1] anchor = 'start' if self.options.mtype == "length": self.addTextWithTspan( self.group, tx, ty, lenstr + ' ' + self.options.unit, id, anchor, -int(self.options.angle), self.options.offset + self.options.fontsize / 2) else: self.addTextWithTspan( self.group, tx, ty, lenstr + ' ' + self.options.unit + '^2', id, anchor, -int(self.options.angle), -self.options.offset + self.options.fontsize / 2) else: # center of mass, no text pass
def effect(self): if len(self.options.ids) < 1: inkex.errormsg(_("This extension requires one selected path.")) return self.prepareSelectionList() for skeleton in self.skeletons.itervalues(): resPath = [] pattern = inkex.etree.Element(inkex.addNS('path','svg')) self.options.strokeHexColor, self.strokeOpacity = getColorAndOpacity(self.options.strokeColor) # Copy style of skeleton with setting color and opacity s = skeleton.get('style') if s: pattern.set('style', setColorAndOpacity(s, self.options.strokeHexColor, self.strokeOpacity)) skeletonPath = modifySkeletonPath(getSkeletonPath(skeleton.get('d'), self.options.offset)) self.skelComp, self.lengths = self.linearizePath(skeletonPath, self.options.offset) length = sum(self.lengths) patternWidth = length / self.options.frequency selectedFunction = self.getFunction(self.options.contourFunction) pattern.set('d', simplepath.formatPath(drawfunction(self.options.nodes, patternWidth, selectedFunction))) # Add path into SVG structure skeleton.getparent().append(pattern) if self.options.remove: skeleton.getparent().remove(skeleton) # Compute bounding box bbox = simpletransform.computeBBox([pattern]) width = bbox[1] - bbox[0] dx = width if dx < 0.01: exit(_("The total length of the pattern is too small.")) patternPath = cubicsuperpath.parsePath(pattern.get('d')) curPath = deepcopy(patternPath) xoffset = self.skelComp[0][0] - bbox[0] yoffset = self.skelComp[0][1] - (bbox[2] + bbox[3]) / 2 patternCopies = max(1, int(round(length / dx))) width = dx * patternCopies newPath = [] # Repeat pattern to cover whole skeleton for subPath in curPath: for i in range(0, patternCopies, 1): newPath.append(deepcopy(subPath)) offset(subPath, dx, 0) curPath = newPath # Offset pattern to the first node of the skeleton for subPath in curPath: offset(subPath, xoffset, yoffset) # Stretch pattern to whole skeleton for subPath in curPath: stretch(subPath, length / width, 1, self.skelComp[0]) for subPath in curPath: for ctlpt in subPath: self.applyDiffeo(ctlpt[1], (ctlpt[0], ctlpt[2])) # Check if there is a need to close path manually if self.skelCompIsClosed: firstPtX = round(curPath[0][0][1][0], 8) firstPtY = round(curPath[0][0][1][1], 8) finalPtX = round(curPath[-1][-1][1][0], 8) finalPtY = round(curPath[-1][-1][1][1], 8) if (firstPtX != finalPtX or firstPtY != finalPtY): curPath[-1].append(curPath[0][0]) resPath += curPath pattern.set('d', cubicsuperpath.formatPath(resPath))
def effect(self): # search for pattern layer triangle_layer = self.document.xpath('//svg:g[@id="triangle_layer"]', namespaces=inkex.NSS) if len(triangle_layer) == 0: # append pattern layer triangle_layer = self.createLayer("triangle_layer", "Triangle Boundary") self.document.getroot().append(triangle_layer) inkex.debug( "1. draw exactly one triangle in Triangle Boundary layer\n" "2. create a pattern composed of only paths\n" "3. select triangles that you want to apply pattern to\n" "4. enter pattern id (or default to use first pattern), then apply" ) else: triangle_layer = triangle_layer[0] # find triangle in the triangle_layer trngl_lyr_children = triangle_layer.getchildren() if not len(trngl_lyr_children) == 1: inkex.debug( "more or less than 1 element in Triangle Boundary layer: " + str(len(trngl_lyr_children))) return else: bndry_trngle = triangle_layer.getchildren()[0] # seems like a path if isPath(bndry_trngle): path_string = bndry_trngle.attrib[u'd'] svg_path = simplepath.parsePath(path_string) # verified to be triangle if pathIsTriangle(svg_path): self.bndry_trngle_verts = getTriangleVerts(svg_path) self.bndry_trngle_matrx = formMatrix( self.bndry_trngle_verts) # find pattern self.defs = self.document.xpath( '//svg:defs', namespaces=inkex.NSS)[0] # get first pattern is default if self.options.pattern_name == "default": patterns = self.defs.xpath('./svg:pattern', namespaces=inkex.NSS) # find pattern with name else: patterns = self.defs.xpath( './svg:pattern[@id="' + self.options.pattern_name + '"]', namespaces=inkex.NSS) if len(patterns) > 0: self.pattern = patterns[0] # calculate the size of the pattern so that the pattern repeats exactly once in the bounding triangle # get the union of all paths in pattern and boundary triangle pattern_trngle_union = self.pattern.xpath( './/svg:path', namespaces=inkex.NSS) pattern_trngle_union.append(bndry_trngle) # get bounding box of the union bb_x_min, bb_x_max, bb_y_min, bb_y_max = simpletransform.computeBBox( pattern_trngle_union) # calculate size of union pattern_width = bb_x_max - bb_x_min pattern_height = bb_y_max - bb_y_min # get scaling factor of pattern pattern_trnsfrm = simpletransform.parseTransform( self.pattern.attrib[u'patternTransform']) scale_x = pattern_trnsfrm[0][0] scale_y = pattern_trnsfrm[1][1] # set size of pattern self.pattern.attrib[u'width'] = str(pattern_width / scale_x) self.pattern.attrib[u'height'] = str( pattern_height / scale_y) else: inkex.debug("cannot find pattern") return else: inkex.debug( "the shape in triangle boundary layer is not a triangle" ) return for id, node in self.selected.iteritems(): if isPath(node): path_string = node.attrib[u'd'] svg_path = simplepath.parsePath(path_string) if pathIsTriangle(svg_path): trngle_verts = getTriangleVerts(svg_path) trngle_matrx = formMatrix(trngle_verts) # apply affine transform pattern_trnsform = three.multiply( trngle_matrx, three.getInverse(self.bndry_trngle_matrx)) # compose with initial transform of pattern initial_trnsform = simpletransform.parseTransform( self.pattern.attrib[u'patternTransform']) final_trnsform = simpletransform.composeTransform( pattern_trnsform, initial_trnsform) # if pattern for triangle exists, use it pattern_name = "pattern_for_" + str(id) existing_patterns = self.defs.xpath('./svg:pattern[@id="' + pattern_name + '"]', namespaces=inkex.NSS) if len(existing_patterns) > 0: pattern_transformed = existing_patterns[0] else: # create transformed pattern pattern_transformed = etree.Element("{%s}pattern" % inkex.NSS[u'svg']) # fill in the attributes for pattern pattern_transformed.attrib[u'id'] = "pattern_for_" + str( id) pattern_transformed.attrib[ "{%s}collect" % inkex.NSS[u'inkscape']] = "always" pattern_transformed.attrib[ "{%s}href" % inkex.NSS[u'xlink']] = '#' + self.pattern.attrib[u'id'] pattern_transformed.attrib[ u'patternTransform'] = simpletransform.formatTransform( final_trnsform) # append transformed pattern self.defs.append(pattern_transformed) # fill triangle with pattern trngle_styles = simplestyle.parseStyle( node.attrib[u'style']) trngle_styles[u'fill'] = u'url(#' + str( pattern_transformed.attrib[u'id']) + ')' node.attrib[u'style'] = simplestyle.formatStyle( trngle_styles) else: inkex.debug("not triangle")
def effect(self): #{{{ Check that elements have been selected if len(self.options.ids) == 0: inkex.errormsg(_("Please select objects!")) return #}}} #{{{ Drawing styles linestyle = { 'stroke' : '#000000', 'stroke-width' : str(self.unittouu('1px')), 'fill' : 'none' } facestyle = { 'stroke' : '#ff0000', 'stroke-width' : str(self.unittouu('1px')), 'fill' : 'none' } #}}} #{{{ Handle the transformation of the current group parentGroup = self.getParentNode(self.selected[self.options.ids[0]]) trans = self.getGlobalTransform(parentGroup) invtrans = None if trans: invtrans = simpletransform.invertTransform(trans) #}}} #{{{ Recovery of the selected objects pts = [] nodes = [] seeds = [] for id in self.options.ids: node = self.selected[id] nodes.append(node) bbox = simpletransform.computeBBox([node]) if bbox: cx = 0.5*(bbox[0]+bbox[1]) cy = 0.5*(bbox[2]+bbox[3]) pt = [cx,cy] if trans: simpletransform.applyTransformToPoint(trans,pt) pts.append(Point(pt[0],pt[1])) seeds.append(Point(cx,cy)) #}}} #{{{ Creation of groups to store the result if self.options.diagramType != 'Delaunay': # Voronoi groupVoronoi = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg')) groupVoronoi.set(inkex.addNS('label', 'inkscape'), 'Voronoi') if invtrans: simpletransform.applyTransformToNode(invtrans,groupVoronoi) if self.options.diagramType != 'Voronoi': # Delaunay groupDelaunay = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg')) groupDelaunay.set(inkex.addNS('label', 'inkscape'), 'Delaunay') #}}} #{{{ Clipping box handling if self.options.diagramType != 'Delaunay': #Clipping bounding box creation gBbox = simpletransform.computeBBox(nodes) #Clipbox is the box to which the Voronoi diagram is restricted clipBox = () if self.options.clipBox == 'Page': svg = self.document.getroot() w = self.unittouu(svg.get('width')) h = self.unittouu(svg.get('height')) clipBox = (0,w,0,h) else: clipBox = (2*gBbox[0]-gBbox[1], 2*gBbox[1]-gBbox[0], 2*gBbox[2]-gBbox[3], 2*gBbox[3]-gBbox[2]) #Safebox adds points so that no Voronoi edge in clipBox is infinite safeBox = (2*clipBox[0]-clipBox[1], 2*clipBox[1]-clipBox[0], 2*clipBox[2]-clipBox[3], 2*clipBox[3]-clipBox[2]) pts.append(Point(safeBox[0],safeBox[2])) pts.append(Point(safeBox[1],safeBox[2])) pts.append(Point(safeBox[1],safeBox[3])) pts.append(Point(safeBox[0],safeBox[3])) if self.options.showClipBox: #Add the clip box to the drawing rect = inkex.etree.SubElement(groupVoronoi,inkex.addNS('rect','svg')) rect.set('x',str(clipBox[0])) rect.set('y',str(clipBox[2])) rect.set('width',str(clipBox[1]-clipBox[0])) rect.set('height',str(clipBox[3]-clipBox[2])) rect.set('style',simplestyle.formatStyle(linestyle)) #}}} #{{{ Voronoi diagram generation if self.options.diagramType != 'Delaunay': vertices,lines,edges = voronoi.computeVoronoiDiagram(pts) for edge in edges: line = edge[0] vindex1 = edge[1] vindex2 = edge[2] if (vindex1 <0) or (vindex2 <0): continue # infinite lines have no need to be handled in the clipped box else: segment = self.clipEdge(vertices,lines,edge,clipBox) #segment = [vertices[vindex1],vertices[vindex2]] # deactivate clipping if len(segment)>1: v1 = segment[0] v2 = segment[1] cmds = [['M',[v1[0],v1[1]]],['L',[v2[0],v2[1]]]] path = inkex.etree.Element(inkex.addNS('path','svg')) path.set('d',simplepath.formatPath(cmds)) path.set('style',simplestyle.formatStyle(linestyle)) groupVoronoi.append(path) if self.options.diagramType != 'Voronoi': triangles = voronoi.computeDelaunayTriangulation(seeds) for triangle in triangles: p1 = seeds[triangle[0]] p2 = seeds[triangle[1]] p3 = seeds[triangle[2]] cmds = [['M',[p1.x,p1.y]], ['L',[p2.x,p2.y]], ['L',[p3.x,p3.y]], ['Z',[]]] path = inkex.etree.Element(inkex.addNS('path','svg')) path.set('d',simplepath.formatPath(cmds)) path.set('style',simplestyle.formatStyle(facestyle)) groupDelaunay.append(path)
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 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) 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: if not width: exit( _("The 'stretch' option requires that the pattern must have non-zero width :\nPlease edit the pattern width." )) 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))