def effect(self): if len(self.svg.selected) == 0: inkex.errormsg("Please select some paths first.") exit() path_attribute = self.options.path_attribute is_text_attribute = path_attribute in ['id', 'label'] for id, node in self.svg.selection.filter(inkex.PathElement).items(): to_show = self.extract_path_attribute(path_attribute, node) node.path.transform(node.composed_transform()).to_superpath() bbox = node.bounding_box() tx, ty = bbox.center if self.options.group: group_element = node.getparent().add(inkex.Group()) group_element.add(node) group_element.set('id', node.get('id') + "_group") text_element = group_element.add(inkex.TextElement()) else: text_element = node.getparent().add(inkex.TextElement()) tspan_element = text_element.add(inkex.Tspan()) tspan_element.set('sodipodi:role', 'line') styles = { 'text-align': 'center', 'vertical-align': 'bottom', 'text-anchor': 'middle', 'font-size': str(self.options.fontsize) + 'px', 'font-weight': self.options.fontweight, 'font-style': 'normal', 'font-family': self.options.font, 'fill': str(self.options.color) } tspan_element.set('style', str(inkex.Style(styles))) tspan_element.set('dy', '0') if is_text_attribute: if self.options.capitals: to_show = to_show.upper() if self.options.matchre != '': matches = re.findall(self.options.matchre, to_show) if len(matches) > 0: to_show = matches[0] if self.options.replaced != '': to_show = to_show.replace(self.options.replaced, self.options.replacewith) tspan_element.text = to_show tspan_element.set('id', node.get('id') + "_tspan") text_element.set('id', node.get('id') + "_text") text_element.set('x', str(tx)) text_element.set('y', str(ty)) text_element.set( 'transform', 'rotate(%s, %s, %s)' % (-int(self.options.angle), tx, ty))
def insert_pointer(self, problem): correction_transform = get_correction_transform(self.troubleshoot_layer) if isinstance(problem, ValidationWarning): fill_color = "#ffdd00" layer = self.warning_group elif isinstance(problem, ValidationError): fill_color = "#ff0000" layer = self.error_group elif isinstance(problem, ObjectTypeWarning): fill_color = "#ff9900" layer = self.type_warning_group pointer_style = "stroke:#000000;stroke-width:0.2;fill:%s;" % (fill_color) text_style = "fill:%s;stroke:#000000;stroke-width:0.2;font-size:8px;text-align:center;text-anchor:middle" % (fill_color) path = inkex.PathElement(attrib={ "id": self.uniqueId("inkstitch__invalid_pointer__"), "d": "m %s,%s 4,20 h -8 l 4,-20" % (problem.position.x, problem.position.y), "style": pointer_style, INKSCAPE_LABEL: _('Invalid Pointer'), "transform": correction_transform }) layer.insert(0, path) text = inkex.TextElement(attrib={ INKSCAPE_LABEL: _('Description'), "x": str(problem.position.x), "y": str(float(problem.position.y) + 30), "transform": correction_transform, "style": text_style }) layer.append(text) tspan = inkex.Tspan() tspan.text = problem.name if problem.label: tspan.text += " (%s)" % problem.label text.append(tspan)
def export_mtext(vals): # mandatory group codes : (1 or 3, 10, 20) (text, x, y) if (vals.has_text or vals.has_mtext) and vals.has_x1 and vals.has_y1: x = vals.x1 y = vals.y1 # optional group codes : (21, 40, 50) (direction, text height mm, text angle) size = 12 # default fontsize in px if vals.has_scale: size = scale * textscale * vals.scale attribs = {'x': '%f' % x, 'y': '%f' % y, 'style': 'font-size: %.3fpx; fill: %s; font-family: %s' % (size, color, options.font)} angle = 0 # default angle in degrees if vals.has_angle: angle = vals.angle attribs.update({'transform': 'rotate (%f %f %f)' % (-angle, x, y)}) elif vals.has_y2: if vals.y2 == 1.0: attribs.update({'transform': 'rotate (%f %f %f)' % (-90, x, y)}) elif vals.y2 == -1.0: attribs.update({'transform': 'rotate (%f %f %f)' % (90, x, y)}) node = layer.add(inkex.TextElement(**attribs)) node.set('sodipodi:linespacing', '125%') text = '' if vals.has_mtext: text = ''.join(vals.mtext_list) if vals.has_text: text = vals.text found = text.find(r'\P') # new line while found > -1: tspan = node.add(inkex.Tspan()) tspan.set('sodipodi:role', 'line') tspan.text = text[:found] text = text[(found + 2):] found = text.find(r'\P') tspan = node.add(inkex.Tspan()) tspan.set('sodipodi:role', 'line') tspan.text = text
def draw_swatch(self): border = self.canvas.add(inkex.PathElement()) # Curve radius cr = self.svg.unittouu('10mm') # Swatch padding sp = self.svg.unittouu('30mm') # Handle length hl = cr / 2 path_command = ('m %f,%f l %f,%f c %f,%f %f,%f %f,%f' 'l %f,%f c %f,%f %f,%f %f,%f ' 'l %f,%f c %f,%f %f,%f %f,%f ' 'l %f,%f c %f,%f %f,%f %f,%f ') % ( cr, 0, self.width - 2 * cr, 0, hl, 0, cr, cr - hl, cr, cr, 0, self.height - 2 * cr + 1.5 * sp, 0, cr / 2, 0 - cr + hl, cr, 0 - cr, cr, 0 - self.width + 2 * cr, 0, 0 - hl, 0, 0 - cr, 0 - cr + hl, 0 - cr, 0 - cr, 0, 0 - self.height - 1.5 * sp + 2 * cr, 0, 0 - hl, cr - hl, 0 - cr, cr, 0 - cr) style = { "stroke": cut_colour, "stroke-width": str(self.stroke_width), "fill": "none", } border.update(**{ "style": style, "inkscape:label": "lattice_border", "d": path_command }) c = self.canvas.add( inkex.Circle(style=str(inkex.Style(style)), cx=str(cr), cy=str(cr), r=str(self.svg.unittouu('4mm')))) self.y += sp text_style = { 'fill': engrave_colour, 'font-size': '9px', 'font-family': 'sans-serif', 'text-anchor': 'middle', 'text-align': 'center', } text = self.canvas.add( inkex.TextElement(style=str(inkex.Style(text_style)), x=str(self.x + self.width / 2), y=str(self.y - sp / 2))) text.text = "Style: %s" % self.name text_style['font-size'] = "3px" text = self.canvas.add( inkex.TextElement(style=str(inkex.Style(text_style)), x=str(self.x + self.width / 2), y=str(self.y - sp / 4))) text.text = self.parameter_text() text = self.canvas.add( inkex.TextElement(style=str(inkex.Style(text_style)), x=str(self.x + self.width / 2), y=str(self.y + self.height + sp / 4))) text.text = "https://github.com/buxtronix/living-hinge"
def generate(self): size = self.svg.unittouu(str(self.options.size) + 'px') head = self.svg.unittouu(str(self.options.head) + 'px') width = self.svg.unittouu(str(self.options.width) + 'pt') medium = self.svg.unittouu('10pt') # font sizes, ... large = self.svg.unittouu('12pt') # ... could be options tsector, survey_title = analyse3d(self.options.file, self.options.nsector) tmax = max(tsector) thoriz = 0.5 * sum(tsector) # each leg is counted twice ns = len(tsector) tmean = 2 * thoriz / ns # Inner group to contain all the rose diagram elements rose_diagram = inkex.Group() elements = [''] * (2*ns) # list of lines and arc elements for i, v in enumerate(tsector): alo = 2 * m.pi * (i - 0.5) / ns ahi = 2 * m.pi * (i + 0.5) / ns rad = size * tsector[i] / tmax xx0 = rad * m.sin(alo) yy0 = - rad * m.cos(alo) xx1 = rad * m.sin(ahi) yy1 = - rad * m.cos(ahi) elements[2*i] = ('L' if i else 'M') + '%7.2f, %7.2f ' % (xx0, yy0) elements[2*i+1] = 'A %6.2f, %6.2f 0 0,1 %7.2f, %7.2f' % (rad, rad, xx1, yy1) # Add the lines and arc elements - 'z' closes the path zigzag = inkex.PathElement(d=' '.join(elements) + ' z') zigzag.style = {'stroke': 'black', 'fill': 'none' if self.options.bw else 'yellow', 'stroke-width': width} rose_diagram.add(zigzag) # Adjust the scale circle radius, rounding down if necessary scale_rad = fancy_round(tmean) if scale_rad > tmax: scale_rad = fancy_round(tmean, offset=0.0) # Add the scale circle circle = inkex.Circle(r=str(size * scale_rad / tmax)) circle.style = {'stroke': 'black' if self.options.bw else 'blue', 'fill': 'none', 'stroke-width': width} if self.options.bw: circle.style['stroke-dasharray'] = '{step} {step}'.format(step=4*width) rose_diagram.add(circle) # Add N-S, E-W, NW-SE, NE-SW lines; the N has a half-arrow style = {'stroke': 'black', 'fill': 'none', 'stroke-width': width} style = str(inkex.Style(style)) length = 1.05 * size rose_diagram.add(inkex.PathElement(d=f'M0,{-length+2*head} L{-head},{-length+2*head} L0,-{length} L0,{length}', style=style)) rose_diagram.add(inkex.PathElement(d=f'M-{length},0 L{length},0', style=style)) length = m.sqrt(0.5) * 1.05 * size rose_diagram.add(inkex.PathElement(d=f'M-{length},-{length} L{length},{length}', style=style)) rose_diagram.add(inkex.PathElement(d=f'M{length},-{length} L-{length},{length}', style=style)) # Add a 'N' to the north arrow north = inkex.TextElement(x=str(head), y=str(-1.05*size+head)) north.style = {'font-family': 'Verdana', 'font-size': large, 'fill': 'black', 'text-anchor': 'middle', 'text-align': 'center'} north.text = 'N' rose_diagram.add(north) yield rose_diagram # Add annotation for cave length and circle radius annotation = inkex.TextElement(x=str(0), y=str(1.3*size)) annotation.style = {'font-family': 'Verdana', 'font-size': medium, 'fill': 'black', 'text-anchor': 'middle', 'text-align': 'center'} cave_length = f'{round(thoriz/1000, 1)} km' if thoriz > 10000 else f'{round(thoriz)} m' circle_radius = f'{scale_rad/1000} km' if scale_rad > 1000 else f'{scale_rad} m' annotation.text = f'length {cave_length}, circle radius is {circle_radius}' yield annotation # Add a title title = inkex.TextElement(x=str(0), y=str(-1.3*size)) title.style = {'font-family': 'Verdana', 'font-size': large, 'fill': 'black', 'text-anchor': 'middle', 'text-align': 'center'} title.text = self.options.title or survey_title yield title
def add_descriptions(self, problem_types): svg = self.document.getroot() # We could use svg.viewport_width, but then we would need to do unit conversions, # so let's stay with parsing the viewbox by ourselves # viewbox values are either separated through white space or commas text_x = str(float(svg.get('viewBox', '0 0 800 0').replace(",", " ").split()[2]) + 5.0) text_container = inkex.TextElement(attrib={ "x": text_x, "y": str(5), "style": "fill:#000000;font-size:5px;line-height:1;" }) self.troubleshoot_layer.append(text_container) text = [ [_("Troubleshoot"), "font-weight: bold; font-size: 8px;"], ["", ""] ] for problem_type, problems in list(problem_types.items()): if problem_type == "error": text_color = "#ff0000" problem_type_header = _("Errors") problem_type_description = _("Problems that will prevent the shape from being embroidered.") elif problem_type == "warning": text_color = "#ffdd00" problem_type_header = _("Warnings") problem_type_description = _("These are problems that won't prevent the shape from being embroidered. " "You should consider to fix the warning, but if you don't, " "Ink/Stitch will do its best to process the object.") elif problem_type == "type_warning": text_color = "#ff9900" problem_type_header = _("Object Type Warnings") problem_type_description = _("These objects may not work properly with Ink/Stitch. " "Follow the instructions to correct unwanted behaviour.") if problems: text.append([problem_type_header, "font-weight: bold; fill: %s; text-decoration: underline; font-size: 7px;" % text_color]) text.append(["", ""]) text.append([problem_type_description, "fill:%s;" % text_color]) text.append(["", ""]) for problem in problems: text.append([problem.name, "font-weight: bold; fill: %s;" % text_color]) text.append([problem.description, "font-size: 3px;"]) text.append(["", ""]) for step in problem.steps_to_solve: text.append([step, "font-size: 4px;"]) text.append(["", ""]) explain_layer = _('It is possible, that one object contains more than one error, ' + 'yet there will be only one pointer per object. Run this function again, ' + 'when further errors occur. Remove pointers by deleting the layer named ' '"Troubleshoot" through the objects panel (Object -> Objects...).') explain_layer_parts = textwrap.wrap(explain_layer, 60) for description in explain_layer_parts: text.append([description, "font-style: italic; font-size: 4px;"]) text = self.split_text(text) for text_line in text: tspan = inkex.Tspan(attrib={ SODIPODI_ROLE: "line", "style": text_line[1] }) tspan.text = text_line[0] text_container.append(tspan)