def generate(self): length = self.svg.unittouu(str(self.options.length) + 'px') spacing = self.svg.unittouu(str(self.options.spacing) + 'px') angle = radians(self.options.angle) # generate points: list of (x, y) pairs points = [] x = 0 tas = tan(angle) * spacing while x < length: # move along path, generating the next 'tooth' points.append((x, 0)) points.append((x + tas, spacing)) points.append((x + spacing, spacing)) points.append((x + spacing + tas, 0)) x += spacing * 2. path = points_to_svgd(points) # Create SVG Path for gear style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px')) } yield inkex.PathElement(style=str(inkex.Style(style)), d=str(path))
def draw_crop_line(self, x1, y1, x2, y2, name, parent): style = {'stroke': '#000000', 'stroke-width': str(self.stroke_width), 'fill': 'none'} line_attribs = {'style': str(inkex.Style(style)), 'id': name, 'd': 'M ' + str(x1) + ',' + str(y1) + ' L ' + str(x2) + ',' + str(y2)} parent.add(inkex.PathElement(**line_attribs))
def generate(self): # Let's simplify the variable names ht = int(self.options.height) wt = int(self.options.width) sc = int(self.options.seg_count) cp = self.svg.namedview.center # center point maxx = cp[0] + (wt / 2) maxy = cp[0] + (ht / 2) minx = cp[1] - (wt / 2) miny = cp[1] - (ht / 2) # We need to decide what the maximum length we can draw a line # maxlen is used to seed the random length of the line # It may still be too long, but we'll check on that later! if ht > wt: maxlen = ht else: maxlen = wt style = inkex.Style({ 'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu('1px')), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': '#000000', 'stroke-linecap': 'butt', 'fill': 'none' }) tur = pturtle.pTurtle() tur.pu() # Pen up tur.setpos(cp) # position to center of window def nextmove(maxlen): randdist = random.randint(0, maxlen) # how far should we draw? tur.forward(randdist) # Let's move the new distance newpos = tur.getpos() # Did we go to far? return newpos, randdist while sc > 0: turpos = tur.getpos() # where are we? randangle = random.randint(1, 360) # Let's Pick a new direction tur.rt(randangle) # Let's turn to face that new direction tur.pu() # We don't want to draw just yet, so pick up the pen/pencil newpos, randdist = nextmove(maxlen) # If we make this move will we go out of bounds? while newpos[0] > maxx or newpos[0] < minx or newpos[1] < miny or newpos[1] > maxy: tur.setpos(turpos) newpos, randdist = nextmove(maxlen) # If it all tests ok, we reset the position # and draw the line for real! tur.setpos(turpos) tur.pd() tur.forward(randdist) sc = sc - 1 return inkex.PathElement(d=tur.getPath(), style=str(style))
def csp_to_path(self, node, csp_list, transform=None): """Create new paths based on csp data, return group with paths.""" # set up stroke width, group stroke_width = self.svg.unittouu('1px') stroke_color = '#000000' style = { 'fill': 'none', 'stroke': stroke_color, 'stroke-width': str(stroke_width), } group = inkex.Group() # apply gradientTransform and node's preserved transform to group group.transform = transform * node.transform # convert each csp to path, append to group for csp in csp_list: elem = group.add(inkex.PathElement()) elem.style = style elem.path = inkex.CubicSuperPath(csp) if self.options.mode == 'outline': elem.path.close() elif self.options.mode == 'faces': if len(csp) == 1 and len(csp[0]) == 5: elem.path.close() return group
def effect(self): # get number of digits prec = int(self.options.precision) scale = self.svg.unittouu('1px') # convert to document units self.options.offset *= scale factor = 1.0 if self.svg.get('viewBox'): factor = self.svg.scale / self.svg.unittouu('1px') self.options.fontsize /= factor factor *= scale / self.svg.unittouu('1' + self.options.unit) # loop over all selected paths for node in self.svg.selection.filter(inkex.PathElement): csp = node.path.transform(node.composed_transform()).to_superpath() if self.options.mtype == "length": slengths, stotal = csplength(csp) self.group = node.getparent().add(TextElement()) elif self.options.mtype == "area": stotal = abs(csparea(csp) * factor * self.options.scale) self.group = node.getparent().add(TextElement()) else: try: xc, yc = cspcofm(csp) except ValueError as err: raise inkex.AbortExtension(str(err)) self.group = node.getparent().add(inkex.PathElement()) self.group.set('id', 'MassCenter_' + node.get('id')) self.add_cross(self.group, xc, yc, scale) continue # Format the length as string val = round(stotal * factor * self.options.scale, prec) self.options.method(node, str(val))
def generate(self, swatch): if swatch: self.draw_swatch() # Round width/height to integer number of patterns. self.e_length = self.width / \ max(round(self.width / self.e_length), 1.0) self.e_height = self.height / \ max(round(self.height / self.e_height), 1.0) self.prerender() style = { "stroke": cut_colour, "stroke-width": str(self.stroke_width), "fill": "none", } path_command = "" y = self.y while y < self.y + self.height: x = self.x while x < self.x + self.width: path_command = "%s %s " % (path_command, self.draw_one(x, y)) x += self.e_length y += self.e_height link = self.canvas.add(inkex.PathElement()) link.update(**{ "style": style, "inkscape:label": "lattice", "d": path_command })
def add_connector(document, symbol, element): # I'd like it if I could position the connector endpoint nicely but inkscape just # moves it to the element's center immediately after the extension runs. start_pos = (symbol.get('x'), symbol.get('y')) end_pos = element.shape.centroid # Make sure the element's XML node has an id so that we can reference it. if element.node.get('id') is None: element.node.set('id', document.get_unique_id("object")) path = inkex.PathElement( attrib={ "id": generate_unique_id(document, "command_connector"), "d": "M %s,%s %s,%s" % (start_pos[0], start_pos[1], end_pos.x, end_pos.y), "style": "stroke:#000000;stroke-width:1px;stroke-opacity:0.5;fill:none;", CONNECTION_START: "#%s" % symbol.get('id'), CONNECTION_END: "#%s" % element.node.get('id'), CONNECTOR_TYPE: "polyline", # l10n: the name of the line that connects a command to the object it applies to INKSCAPE_LABEL: _("connector") }) symbol.getparent().insert(0, path)
def parameters_to_path(self, svg, parameters, layerNum, isPU): """split params and sanity check them""" parameters = parameters.strip().split(',') if parameters and len(parameters) % 2 == 0: for i, param in enumerate(parameters): # convert params to document units if i % 2 == 0: parameters[i] = str(float(param) / self.scaleX) else: parameters[i] = str(297.0 - (float(param) / self.scaleY)) # create path and add it to the corresponding layer if not isPU or (self.options.showMovements and isPU): # create layer if it does not exist if layerNum not in self.layers: label = self.textPenNumber + str(layerNum - 1) self.layers[layerNum] = svg.add(inkex.Layer.new(label)) path = 'M %f,%f L %s' % (self.oldCoordinates[0], self.oldCoordinates[1], ','.join(parameters)) style = 'stroke:#' + ('ff0000' if isPU else '000000' ) + '; stroke-width:0.2; fill:none;' self.layers[layerNum].add( inkex.PathElement(d=path, style=style)) self.oldCoordinates = (float(parameters[-2]), float(parameters[-1]))
def effect(self): zoom = self.svg.unittouu(str(self.options.zoom) + 'px') if self.options.randomize: imagelist = generate_random_string(self.options.text, zoom) else: tokens = tokenize(self.options.text) imagelist = randomize_input_string(tokens, zoom) image = layoutstring(imagelist, zoom) if image: s = {'stroke': 'none', 'fill': '#000000'} new = inkex.PathElement(style=str(inkex.Style(s)), d=str(inkex.Path(image))) layer = self.svg.get_current_layer() layer.append(new) # compensate preserved transforms of parent layer if layer.getparent() is not None: mat = ( self.svg.get_current_layer().transform * inkex.Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])).matrix new.transform *= -inkex.Transform(mat)
def export_line(vals): """Draw a strait line from the dxf""" # mandatory group codes : (10, 11, 20, 21) (x1, x2, y1, y2) if vals.has_x1 and vals.has_x2 and vals.has_y1 and vals.has_y2: path = inkex.PathElement() path.style = style path.path = 'M %f,%f %f,%f' % (vals.x1, vals.y1, vals.x2, vals.y2) layer.add(path)
def draw_line(x1, y1, x2, y2, width, name, parent): elem = parent.add(inkex.PathElement()) elem.style = { 'stroke': '#000000', 'stroke-width': str(width), 'fill': 'none' } elem.set('inkscape:label', name) elem.path = [Move(x1, y1), Line(x2, y2)]
def draw_bleed_line(self, x1, y1, x2, y2, name, parent): style = {'stroke': '#000000', 'stroke-width': str(self.stroke_width), 'fill': 'none', 'stroke-miterlimit': '4', 'stroke-dasharray': '4, 2, 1, 2', 'stroke-dashoffset': '0'} line_attribs = {'style': str(inkex.Style(style)), 'id': name, 'd': 'M ' + str(x1) + ',' + str(y1) + ' L ' + str(x2) + ',' + str(y2)} parent.add(inkex.PathElement(**line_attribs))
def effect(self): # Classify path as horz or vert, ignore others horzPaths = [] vertPaths = [] for elem in self.svg.get_selected_or_all(inkex.PathElement): path = elem.path.to_absolute() if len(path) != 2: # warning: can only process singular, simple paths pass else: if path[1].letter == 'H': horzPaths.append(path) elif path[1].letter == 'V': vertPaths.append(path) else: #warning: can only process horizontal or vertical paths pass line_style = { 'stroke': '#FF0000', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('{:0.2f}mm'.format(self.options.thickness * 0.1))) } # Create Divider objects used to generate new divider paths Divider.height = self.options.depth Divider.thickness = self.options.thickness dividers = [] for hp in horzPaths: hx1 = hp[0].args[0] hx2 = hp[1].args[0] d = Divider(abs(hx1 - hx2)) for vp in vertPaths: if lines_intersect(hp, vp): vx1 = vp[0].args[0] d.notches.append(vx1 - min(hx1, hx2)) d.notches.sort() dividers.append(d) for vp in vertPaths: vy1 = vp[0].args[1] vy2 = vp[1].args[0] d = Divider(abs(vy1 - vy2)) for hp in horzPaths: if lines_intersect(hp, vp): hy1 = hp[0].args[1] d.notches.append(hy1 - min(vy1, vy2)) d.notches.sort() dividers.append(d) # Render Dividers for d in dividers: index = dividers.index(d) pe = self.svg.get_current_layer().add(inkex.PathElement(id='Divider ' + str(index))) pe.set_path(Path(d.path_string).translate(0, (index * (d.height + d.thickness))).rotate(180)) pe.style = line_style
def getLine(XYstring): line = inkex.PathElement() line.style = { 'stroke': '#000000', 'stroke-width': str(linethickness), 'fill': 'none' } line.path = XYstring #inkex.etree.SubElement(parent, inkex.addNS('path','svg'), drw) return line
def plot_beam(self, beam: List[Ray], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0].origin[0], beam[0].origin[1])] for ray in beam: p1 = ray.origin + ray.travel * ray.direction path += [Line(p1[0], p1[1])] element = self._beam_layer.add(inkex.PathElement()) # Need to convert to path to get the correct style for inkex.Use element.style = node.to_path_element().style element.path = path
def plot_beam(beam: List[Tuple[Ray, float]], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0][0].origin[0], beam[0][0].origin[1])] for ray, t in beam: p1 = ray.origin + t * ray.direction path += [Line(p1[0], p1[1])] element = node.getparent().add(inkex.PathElement()) element.style = node.get("style") element.path = path.transform(-node.composed_transform())
def plot_beam(self, beam: List[Tuple[Ray, float]], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0][0].origin[0], beam[0][0].origin[1])] for ray, t in beam: p1 = ray.origin + t * ray.direction path += [Line(p1[0], p1[1])] svg = self.document.getroot() element = svg.add(inkex.PathElement()) element.style = node.get("style") element.path = path
def generate(self): self.options.step = self.svg.unittouu(str(self.options.step) + 'px') sty = { 'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu('1px')), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': '#000000', 'stroke-linecap': 'butt', 'fill': 'none' } return inkex.PathElement(style=str(inkex.Style(sty)), d=self.iterate())
def effect(self): str_IdName = 'Arrow1Mend' str_stroke = 'rgb(255, 0, 177)' str_strokeWidth = '5px' marker_node = self.svg.getElement('/svg:svg//svg:marker[@id="%s"]' % str_IdName) if marker_node is None: """Create a marker in the defs of the svg""" marker = inkex.Marker() marker.set('inkscape:isstock', 'true') marker.set('style', str(inkex.Style({'overflow': 'visible'}))) marker.set('id', str_IdName) marker.set('refX', '0.0') marker.set('refY', '0.0') marker.set('orient', 'auto') marker.set('inkscape:stockid', str_IdName) self.svg.defs.append(marker) arrow = inkex.PathElement( d='M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z ') arrow.set( 'transform', 'scale(0.4) rotate(180) translate(10,0)' ) # <- なぜか `matrix(-0.4 4.89843e-17 -4.89843e-17 -0.4 -4 4.89843e-16)` のように変換されてしまう arrow.set( 'style', str( inkex.Style({ 'fill-rule': 'evenodd', 'stroke': '#000000', 'stroke-width': '1pt', 'stroke-opacity': '1', 'fill': '#000000', 'fill-opacity': '1' }))) marker.append(arrow) for id, node in self.svg.selected.items(): node_style = dict(inkex.Style.parse_str(node.get('style'))) node_style['stroke'] = str_stroke node_style['stroke-width'] = self.svg.unittouu(str_strokeWidth) node_style['marker-end'] = ('url(#' + str_IdName + ')') node.set('style', str(inkex.Style(node_style))) return
def draw_star_target(self, cx, cy, name, parent): r = (self.mark_size / 2) style = {'fill': '#000 device-cmyk(1,1,1,1)', 'fill-opacity': '1', 'stroke': 'none'} d = ' M 0,0' i = 0 while i < (2 * math.pi): i += math.pi / 16 d += ' L 0,0 ' + \ ' L ' + str(math.sin(i) * r) + ',' + str(math.cos(i) * r) + \ ' L ' + str(math.sin(i + 0.09) * r) + ',' + str(math.cos(i + 0.09) * r) elem = parent.add(inkex.PathElement()) elem.label = name elem.transform.add_translate(cx, cy) elem.path = d elem.style = inkex.Style(style)
def satin_to_svg_node(self, rails, rungs, correction_transform, path_style): d = "" for path in chain(rails, rungs): d += "M" for x, y in path: d += "%s,%s " % (x, y) d += " " return inkex.PathElement(attrib={ "id": self.uniqueId("path"), "style": path_style, "transform": correction_transform, "d": d, INKSTITCH_ATTRIBS['satin_column']: "true", })
def to_element(self): node = inkex.PathElement() d = str(inkex.paths.CubicSuperPath(line_strings_to_csp([self.path]))) node.set("d", d) dasharray = inkex.Style("stroke-dasharray:0.5,0.5;") style = inkex.Style(self.original_element.node.get('style', '')) + dasharray node.set("style", str(style)) node.set(INKSTITCH_ATTRIBS['running_stitch_length_mm'], self.running_stitch_length) stroke = Stroke(node) return stroke
def generate(self): r1 = self.options.r1 r2 = self.options.r2 R1 = self.options.R1 R2 = self.options.R2 a1 = self.options.a1 a2 = self.options.a2 ad1 = self.options.ad1 ad2 = self.options.ad2 # generate points: list of (x, y) pairs r1, r2 = checkSize(r1, r2) R1, R2 = checkSize(R1, R2) a1, a2 = checkSize(a1, a2) ad1, ad2 = checkSize(ad1, ad2) a = 0 oX = 0 oY = 0 style = { 'stroke': '#000000', 'fill': '#000000', 'stroke-width': str(self.svg.unittouu('1px')) } while a < 360: a = a + random.randint(a1, a2) dI = random.randint(r1, r2) dO = random.randint(R1, R2) ad = random.randint(ad1, ad2) x0 = cos(radians(a)) * dI y0 = sin(radians(a)) * dI x10 = cos(radians(a - ad / 2)) * dO y10 = sin(radians(a - ad / 2)) * dO x11 = cos(radians(a + ad / 2)) * dO y11 = sin(radians(a + ad / 2)) * dO points = [] points.append((x0, y0)) points.append((x10, y10)) points.append((x11, y11)) path = points_to_svgd(points) yield inkex.PathElement(style=str(inkex.Style(style)), d=str(path))
def draw_poly(pts, face, st, name, parent): """Draw polygone""" style = {'stroke': '#000000', 'stroke-width': str(st.th), 'stroke-linejoin': st.linejoin, 'stroke-opacity': st.s_opac, 'fill': st.fill, 'fill-opacity': st.f_opac} path = inkex.Path() for facet in face: if not path: # for first point path.append(Move(pts[facet - 1][0], -pts[facet - 1][1])) else: path.append(Line(pts[facet - 1][0], -pts[facet - 1][1])) path.close() poly = parent.add(inkex.PathElement()) poly.label = name poly.style = style poly.path = path
def _render_dividers(self): """! Renders the Divider objects into paths Inkscape can interpret """ # Set the stroke properties line_style = { 'stroke': '#FF0000', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('{:0.2f}mm'.format(self.options.thickness * 0.1))) } # Render dividers for d in self.dividers: index = self.dividers.index(d) pe = self.svg.get_current_layer().add(inkex.PathElement(id='Divider ' + str(index))) pe.set_path(Path(d.path_string).translate(0, (index * (d.height + d.thickness))).rotate(180)) pe.style = line_style
def color_block_to_realistic_stitches(color_block, svg, destination): for point_list in color_block_to_point_lists(color_block): color = color_block.color.visible_on_white.darker.to_hex_str() start = point_list[0] for point in point_list[1:]: destination.append( inkex.PathElement( attrib={ 'style': "fill: %s; stroke: none; filter: url(#realistic-stitch-filter);" % color, 'd': realistic_stitch(start, point), 'transform': get_correction_transform(svg) })) start = point
def effect(self): newpath = None for node in self.svg.selected.values(): if isinstance(node, Rectangle): # create new path with basic dimensions of selected rectangle newpath = inkex.PathElement() x = float(node.get('x')) y = float(node.get('y')) w = float(node.get('width')) h = float(node.get('height')) # copy attributes of rect newpath.style = node.style newpath.transform = node.transform # top and bottom were exchanged newpath.path = \ drawfunction(self.options.xstart, self.options.xend, self.options.ybottom, self.options.ytop, self.options.samples, w, h, x, y + h, self.options.fofx, self.options.fpofx, self.options.fponum, self.options.times2pi, self.options.polar, self.options.isoscale, self.options.drawaxis, self.options.endpts) newpath.set('title', self.options.fofx) # add path into SVG structure node.getparent().append(newpath) # option whether to clip the path with rect or not. if self.options.clip: clip = self.svg.defs.add(ClipPath()) clip.set_random_id() clip.append(node.copy()) newpath.set('clip-path', clip.get_id(as_url=2)) # option whether to remove the rectangle or not. if self.options.remove: node.getparent().remove(node) if newpath is None: raise inkex.AbortExtension(_("Please select a rectangle"))
def draw_SVG_tri(point1, point2, point3, offset, width, name, parent): style = {'stroke': '#000000', 'stroke-width': str(width), 'fill': 'none'} elem = parent.add(inkex.PathElement()) elem.update( **{ 'style': style, 'inkscape:label': name, 'd': 'M ' + str(point1[X] + offset[X]) + ',' + str(point1[Y] + offset[Y]) + ' L ' + str(point2[X] + offset[X]) + ',' + str(point2[Y] + offset[Y]) + ' L ' + str(point3[X] + offset[X]) + ',' + str(point3[Y] + offset[Y]) + ' L ' + str(point1[X] + offset[X]) + ',' + str(point1[Y] + offset[Y]) + ' z' }) return elem
def effect(self): for node in self.svg.selected: if isinstance(node, inkex.Rectangle): # create new path with basic dimensions of selected rectangle newpath = inkex.PathElement() x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) # copy attributes of rect newpath.style = node.style newpath.transform = node.transform # top and bottom were exchanged newpath.path = \ drawfunction(self.options.t_start, self.options.t_end, self.options.xleft, self.options.xright, self.options.ybottom, self.options.ytop, self.options.samples, width, height, x, y + height, self.options.fofx, self.options.fofy, self.options.times2pi, self.options.isoscale, self.options.drawaxis) newpath.set('title', self.options.fofx + " " + self.options.fofy) # newpath.set('desc', '!func;' + self.options.fofx + ';' + self.options.fofy + ';' # + `self.options.t_start` + ';' # + `self.options.t_end` + ';' # + `self.options.samples`) # add path into SVG structure node.getparent().append(newpath) # option whether to remove the rectangle or not. if self.options.remove: node.getparent().remove(node)
def color_block_to_paths(color_block, svg, destination, visual_commands): # If we try to import these above, we get into a mess of circular # imports. from ..commands import add_commands from ..elements.stroke import Stroke # We could emit just a single path with one subpath per point list, but # emitting multiple paths makes it easier for the user to manipulate them. first = True path = None for point_list in color_block_to_point_lists(color_block): if first: first = False elif visual_commands: add_commands(Stroke(destination[-1]), ["trim"]) color = color_block.color.visible_on_white.to_hex_str() path = inkex.PathElement( attrib={ 'id': svg.get_unique_id("object"), 'style': "stroke: %s; stroke-width: 0.4; fill: none;" % color, 'd': "M" + " ".join(" ".join(str(coord) for coord in point) for point in point_list), 'transform': get_correction_transform(svg), INKSTITCH_ATTRIBS['manual_stitch']: 'true' }) destination.append(path) if path is not None and visual_commands: if color_block.trim_after: add_commands(Stroke(path), ["trim"]) if color_block.stop_after: add_commands(Stroke(path), ["stop"])