def test_group_with_number_of_rects_translated(self): group = Group() dx, dy = 5, 10 xmin, ymin = 1000, 1000 xmax, ymax = -1000, -1000 rects = [] for x, y, w, h in [ (10, 20, 5, 7), (30, 40, 5, 7), ]: rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y)) rects.append(rect) xmin = min(xmin, x) xmax = max(xmax, x + w) ymin = min(ymin, y) ymax = max(ymax, y + h) group.add(rect) group.transform = Transform(translate=(dx, dy)) self.assert_bounding_box_is_equal(group, (dx + xmin, dx + xmax), (dy + ymin, dy + ymax))
def test_group_with_regular_rect(self): group = Group() x, y = 10, 20 w, h = 7, 20 rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y)) group.add(rect) self.assert_bounding_box_is_equal(group, (x, x + w), (y, y + h))
def getNumbers( self, ticks: int, fmtstr: str, intan: float, inrad: float, style: Style ): "The numbers at the main-ticks. intan: shift perpendicular to axis, inrad: shift in axis." group = Group() if ticks <= 0: return group step = (self.max-self.min) / ticks for i in range(ticks+1): val = self.min + i * step point = self.transform(val) group.add( textAt( point.x-intan*self.sin+inrad*self.cos, point.y+intan*self.cos+inrad*self.sin, ("{0:"+fmtstr+"}").format(val), style) ) return group
def _create_lines(self, triangles): 'Render triangles as individual SVG lines.' # First, find all unique lines. lines = set() for tri in triangles: if len(tri) != 3: sys.exit( inkex.utils.errormsg( _('Internal error: Encountered a non-triangle.'))) for i, j in [(0, 1), (0, 2), (1, 2)]: xy1 = tuple(tri[i]) xy2 = tuple(tri[j]) if xy1 < xy2: lines.update([(xy1, xy2)]) else: lines.update([(xy2, xy1)]) # Then, create SVG line elements. styles = self._create_styles(len(lines)) group = self.svg.get_current_layer().add(Group()) for ([(x1, y1), (x2, y2)], style) in zip(lines, styles): line = Line() line.set('x1', x1) line.set('y1', y1) line.set('x2', x2) line.set('y2', y2) line.style = style group.add(line)
def generateSecureCircles(): def generateSecureCircle(row, column): isSecureBox = getIsSecureBox(row, column) if (isSecureBox): isHomeBox = getIsHomeBox(row, column) fillSecure = getFillColor(isHomeBox, self.secureNotHomeBoxFillColor) xBox = initialX + column * xBoxSize yBox = initialY - (row + 1) * yBoxSize centerX = xBox + xBoxSize / 2 centerY = yBox + yBoxSize / 2 radius = yBoxSize * .5 / 2 name = 'secure-circle-{}-{}'.format(nSector + 1, column) circle = self.generateCircle(centerX, centerY, radius, strokeWidth, stroke, fillSecure, name) secureCircles.add(circle) secureCircles = Group.new('secure-circles-{}'.format(nSector + 1)) row = 4 for column in range(0, nColumns): generateSecureCircle(row, column) row = 0 column = nColumns - 2 generateSecureCircle(row, column) return secureCircles
def generate(self): if numpy is None: raise inkex.AbortExtension("numpy is required.") so = self.options obj = WavefrontObj(self.get_filename()) scale = self.svg.unittouu('1px') # convert to document units st = Style(so) # initialise style # we will put all the rotations in the object name, so it can be repeated in poly = Group.new(obj.name + ':' + make_rotation_log(so)) (pos_x, pos_y) = self.svg.namedview.center poly.transform.add_translate(pos_x, pos_y) poly.transform.add_scale(scale) # TRANSFORMATION OF THE OBJECT (ROTATION, SCALE, ETC) trans_mat = numpy.identity(3, float) # init. trans matrix as identity matrix for i in range(1, 7): # for each rotation axis = getattr(so, 'r{}_ax'.format(i)) angle = getattr(so, 'r{}_ang'.format(i)) * pi / 180 trans_mat = rotate(trans_mat, angle, axis) # scale by linear factor (do this only after the transforms to reduce round-off) trans_mat = trans_mat * so.scl # the points as projected in the z-axis onto the viewplane transformed_pts = obj.get_transformed_pts(trans_mat) so.show(obj, st, poly, transformed_pts) return poly
def effect(self): """Performs the effect.""" # Determine common properties. width = self.options.width style = inkex.Style({'stroke-width': width}) style.set_color(self.options.fill_color, 'fill') style.set_color(self.options.stroke_color, 'stroke') layer = self.svg.get_current_layer() for node in self.svg.selected.values(): box = node.bounding_box() if self.options.position == 'outside': box = size_box(box, (width / 2)) else: box = size_box(box, -(width / 2)) frame = self.add_frame("Frame", box, style, self.options.corner_radius) if self.options.clip: self.add_clip(node, frame) if self.options.group: group = layer.add(Group()) group.append(node) group.append(frame) else: layer.append(frame) return None
def generateVerticalLines(): nSectorPlusOne = nSector + 1 lines = Group.new('vlines-{}'.format(nSectorPlusOne)) for column in range(1, nColumns): x = initialX + xBoxSize * (column) name = 'vline-{}-{}'.format(nSectorPlusOne, column) line = self.generateLine(x, initialY, x, 0, strokeWidth, stroke, name) lines.add(line) return lines
def generateHorizontalLines(): nSectorPlusOne = nSector + 1 lines = Group.new('hlines-{}'.format(nSectorPlusOne)) for row in range(1, nBoxesPerColumn): y = initialY - yBoxSize * (row) name = 'hline-{}-{}'.format(nSectorPlusOne, row) line = self.generateLine(initialX, y, -initialX, y, strokeWidth, stroke, name) lines.append(line) return lines
def prepareSelectionList(self): # first selected->pattern, all but first selected-> skeletons pattern_node = self.svg.selected.pop() self.gNode = Group() pattern_node.getparent().append(self.gNode) if self.options.copymode == "copy": self.patternNode = pattern_node.duplicate() elif self.options.copymode == "clone": # TODO: allow 4th option: duplicate the first copy and clone the next ones. self.patternNode = self.gNode.add(Use()) self.patternNode.href = pattern_node else: self.patternNode = pattern_node self.skeletons = self.svg.selected self.expand_clones(self.skeletons, True, False) self.objects_to_paths(self.skeletons, False)
def _create_polygons(self, triangles): 'Render triangles as SVG polygons.' styles = self._create_styles(len(triangles)) group = self.svg.get_current_layer().add(Group()) for tri, style in zip(triangles, styles): tri_str = ' '.join(['%.10g %.10g' % (pt[0], pt[1]) for pt in tri]) poly = Polygon() poly.set('points', tri_str) poly.style = style group.add(poly)
def effect(self): if len(self.svg.selected) != 2: errormsg( _("Please select exact two objects:\n1. object representing path,\n2. object representing dots." )) return (iddot, dot) = self.svg.selected.popitem() (idpath, path) = self.svg.selected.popitem() bb = dot.bounding_box() parent = path.find('..') group = Group() parent.add(group) for point in path.path.end_points: clone = Use() clone.set('xlink:href', '#' + iddot) clone.set('x', point.x - bb.center.x) clone.set('y', point.y - bb.center.y) group.add(clone)
def getTicks( self, ticks: int, linevon: float, linebis: float, style: Style): "The main ticks, linevon and linebis are the start- and end-point perpendicular to the axis in svg-coordinates." group = Group() if ticks <= 0: return group step = (self.max-self.min) / ticks for i in range(ticks+1): val = self.min + i * step point = self.transform(val) line = Line( x1=str(point.x-linevon*self.sin), y1=str(point.y+linevon*self.cos), x2=str(point.x-linebis*self.sin), y2=str(point.y+linebis*self.cos) ) line.style = style group.add(line) return group
def test_group_nested_transform(self): group = Group() x, y = 10, 20 w, h = 7, 20 scale = 2 rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y)) rect.transform = Transform(rotate=45, scale=scale) group.add(rect) group.transform = Transform(rotate=-45) # rotation is compensated, but scale is not a = rect.composed_transform() self.assert_bounding_box_is_equal(group, (scale * x, scale * (x + w)), (scale * y, scale * (y + h)))
def effect(self): if len(self.svg.selected) != 2: errormsg( _("Please select exact two objects:\n1. object representing path,\n2. object representing dots." )) return (iddot, dot) = self.svg.selected.popitem() (idpath, path) = self.svg.selected.popitem() bb = dot.bounding_box() parent = path.find('..') group = Group() parent.add(group) end_points = list(path.path.end_points) control_points = [] for cp in path.path.control_points: is_endpoint = False for ep in end_points: if cp.x == ep.x and cp.y == ep.y: is_endpoint = True break if not is_endpoint: control_points.append(cp) pointlist = [] if self.options.endpoints: pointlist += end_points if self.options.controlpoints: pointlist += control_points for point in pointlist: clone = Use() clone.set('xlink:href', '#' + iddot) clone.set('x', point.x - bb.center.x) clone.set('y', point.y - bb.center.y) group.add(clone)
def generate(self): self.parse_arguments units = self.options.units boardSize = self.svg.unittouu(str(self.options.boardSize) + units) boardMargin = self.svg.unittouu(str(self.options.boardMargin) + units) self.useLaser = self.options.useLaser self.nPlayers = self.options.nPlayers nBoxesPerColumn = self.options.nBoxesPerColumn nColumns = self.options.nColumns self.generateCenter = self.options.generateCenter self.generateNumbers = self.options.generateNumbers self.useImages = self.options.useImages fill = (self.getColorString(self.options.fillColor), 'none')[self.useLaser] # inkex.utils.debug(fill) strokeWidth = self.options.strokeWidth sectorStroke = ('black', 'red')[self.useLaser] boardStroke = ('gray', 'black')[self.useLaser] homeSafeStroke = (sectorStroke, 'yellow')[self.useImages and self.useLaser] self.sectorColors = [ 'yellow', 'royalblue', 'red', 'green', 'orange', 'hotpink', 'gold', 'darkkhaki' ] self.regularBoxFillColor = ('white', 'none')[self.useLaser] self.secureNotHomeBoxFillColor = 'gray' # Generate Board board = Group.new('board') # Generate Border border = self.generateRectangle(0, 0, boardSize, boardSize, strokeWidth, boardStroke, fill, 'border') board.add(border) # Generate Sectors sectors = self.generateSectors(nBoxesPerColumn, nColumns, boardSize, boardMargin, strokeWidth, sectorStroke, homeSafeStroke) board.add(sectors) return board
def test_group_with_number_of_rects(self): group = Group() xmin, ymin = 1000, 1000 xmax, ymax = -1000, -1000 rects = [] for x, y, w, h in [ (10, 20, 5, 7), (30, 40, 5, 7), ]: rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y)) rects.append(rect) xmin = min(xmin, x) xmax = max(xmax, x + w) ymin = min(ymin, y) ymax = max(ymax, y + h) group.append(rect) self.assert_bounding_box_is_equal(group, (xmin, xmax), (ymin, ymax))
def load(self, stream): """Load the steam as if it were an open DHW file""" header = list(struct.unpack('<32sBHHBxx', stream.read(40))) doc = header.pop(0).decode() if doc != 'ACECAD_DIGIMEMO_HANDWRITING_____': raise AbortExtension('Could not load file, not a ACECAD DHW file!') height = int(header[2]) doc = self.get_template(**dict(zip(('v', 'w', 'h', 'p'), header))) svg = doc.getroot() timestamp = 0 layer = svg.getElementById('layer1') while True: tag = stream.read(1) if tag == b'': break if ord(tag) <= 128: errormsg('Unsupported tag: {}\n'.format(tag)) continue if tag == b'\x90': # New Layer element timestamp = 0 name = 'layer{:d}'.format(ord(stream.read(1)) + 1) layer = svg.add(Group(inkscape_groupmode="layer", id=name)) elif tag == b'\x88': # Read the timestamp next timestamp += ord(stream.read(1)) * 20 else: # Pen down coords = [ p for p in iter(lambda: read_point(stream, height), None) ] # Pen up coords.append(read_point(stream, height)) poly = layer.add(Polyline()) poly.path = coords poly.set('dm:timestamp', timestamp) return doc
def render_svg(self, grp, drawtype): """Render to svg""" drawer = getattr(self, f"render_{drawtype}", self.render_obsolete) if drawer is None: raise Exception("Unknown draw type: " + drawtype) canvas_width = (self.draw.col_count() + 2 * self.margin) * self.boxsize canvas_height = (self.draw.row_count() + 2 * self.margin) * self.boxsize # white background providing margin: rect = grp.add(Rectangle.new(0, 0, canvas_width, canvas_height)) rect.style['stroke'] = 'none' rect.style['fill'] = "black" if self.invert_code else "white" qrg = grp.add(Group()) qrg.style['stroke'] = 'none' qrg.style['fill'] = "white" if self.invert_code else "black" qrg.add(drawer())
def get_slicer_layer(self, force_creation=False): # Test if webslicer-layer layer existis layer = self.svg.getElement( '//*[@id="webslicer-layer" and @inkscape:groupmode="layer"]') if layer is None: if force_creation: # Create a new layer layer = Group(id='webslicer-layer') layer.set('inkscape:label', 'Web Slicer') layer.set('inkscape:groupmode', 'layer') self.document.getroot().append(layer) else: layer = None return layer
def generateSectors(self, nBoxesPerColumn, nColumns, boardSize, boardMargin, strokeWidth, stroke, homeSafeStroke): sectors = Group.new('sectors') for nSector in range(self.nPlayers): sector = self.generateSector(nSector, nBoxesPerColumn, nColumns, boardSize, strokeWidth, stroke, homeSafeStroke) sectors.add(sector) ((x1, x2), (y1, y2)) = sectors.bounding_box() sizeX = x2 - x1 sizeY = y2 - y1 sizeMinusMargin = boardSize - 2 * boardMargin scaleX = sizeMinusMargin / sizeX scaleY = sizeMinusMargin / sizeY sectors.transform.add_scale(scaleX, scaleY) translateX = -x1 + boardMargin / scaleX translateY = -y1 + boardMargin / scaleY sectors.transform.add_translate(translateX, translateY) return sectors
def generate(self): scale = self.svg.unittouu('1px') # convert to document units opt = self.options if not opt.text: raise inkex.AbortExtension('Please enter an input text') elif opt.drawtype == "symbol" and opt.symbolid == "": raise inkex.AbortExtension('Please enter symbol id') # for Python 3 ugly hack to represent bytes as str for Python2 compatibility text_bytes = bytes(opt.text, opt.encoding).decode("latin_1") text_str = str(opt.text) grp = Group() grp.set('inkscape:label', 'QR Code: ' + text_str) if opt.groupid: grp.set('id', opt.groupid) pos_x, pos_y = self.svg.namedview.center grp.transform.add_translate(pos_x, pos_y) if scale: grp.transform.add_scale(scale) # GENERATE THE QRCODE if opt.typenumber == 0: # Automatic QR code size` code = QRCode.getMinimumQRCode(text_bytes, opt.correctionlevel) else: # Manual QR code size code = QRCode(correction=opt.correctionlevel) code.setTypeNumber(int(opt.typenumber)) code.addData(text_bytes) code.make() self.boxsize = opt.modulesize self.invert_code = opt.invert self.margin = 4 self.draw = GridDrawer(opt.invert, opt.smoothval) self.draw.set_grid(code.modules) self.render_svg(grp, opt.drawtype) return grp
def generate(self): """Generate the actual svg from the coding""" string = self.encode(self.text) if string == 'ERROR': return name = self.get_id('barcode') # use an svg group element to contain the barcode barcode = Group() barcode.set('id', name) barcode.set('style', 'fill: black;') barcode.transform.add_translate(self.pos_x, self.pos_y) if self.scale: barcode.transform.add_scale(self.scale) bar_id = 1 bar_offset = 0 tops = set() for datum in self.graphical_array(string): # Datum 0 tells us what style of bar is to come next style = self.get_style(int(datum[0])) # Datum 1 tells us what width in units, # style tells us how wide a unit is width = int(datum[1]) * int(style['width']) if style['write']: tops.add(style['top']) rect = Rectangle() rect.set('x', str(bar_offset)) rect.set('y', str(style['top'])) if self.pos_text == TEXT_POS_TOP: rect.set('y', str(style['top'] + self.font_size)) rect.set('id', "{}_bar{:d}".format(name, bar_id)) rect.set('width', str(width)) rect.set('height', str(style['height'])) barcode.append(rect) bar_offset += width bar_id += 1 for extra in self._extra: if extra is not None: barcode.append(extra) bar_width = bar_offset # Add text at the bottom of the barcode text = TextElement() text.set('x', str(int(bar_width / 2))) text.set('y', str(min(tops) + self.font_size - 1)) if self.pos_text == TEXT_POS_BOTTOM: text.set('y', str(self.height + max(tops) + self.font_size)) text.set('style', TEXT_TEMPLATE % self.font_size) text.set('xml:space', 'preserve') text.set('id', '{}_text'.format(name)) text.text = str(self.text) barcode.append(text) return barcode
def test_empty_group_with_translation(self): group = Group() group.transform = Transform(translate=(10, 15)) self.assert_bounding_box_is_equal(group, None, None)
def test_empty_group(self): group = Group() self.assert_bounding_box_is_equal(group, None, None)
def split_fill_and_stroke(path_node): """Split a path into two paths, one filled and one stroked Returns a the list [fill, stroke], where each is the XML element of the fill or stroke, or None. """ style = dict(inkex.Style.parse_str(path_node.get("style", ""))) # If there is only stroke or only fill, don't split anything if "fill" in style and style["fill"] == "none": if "stroke" not in style or style["stroke"] == "none": return [None, None] # Path has neither stroke nor fill else: return [None, path_node] if "stroke" not in style.keys() or style["stroke"] == "none": return [path_node, None] group = Group() fill = group.add(PathElement()) stroke = group.add(PathElement()) d = path_node.pop('d') if d is None: raise AssertionError("Cannot split stroke and fill of non-path element") nodetypes = path_node.pop('sodipodi:nodetypes', None) path_id = path_node.pop('id', str(id(path_node))) transform = path_node.pop('transform', None) path_node.pop('style') # Pass along all remaining attributes to the group for attrib_name, attrib_value in path_node.attrib.items(): group.set(attrib_name, attrib_value) group.set("id", path_id) # Next split apart the style attribute style_group = {} style_fill = {"stroke": "none", "fill": "#000000"} style_stroke = {"fill": "none", "stroke": "none"} for key in style.keys(): if key.startswith("fill"): style_fill[key] = style[key] elif key.startswith("stroke"): style_stroke[key] = style[key] elif key.startswith("marker"): style_stroke[key] = style[key] elif key.startswith("filter"): style_group[key] = style[key] else: style_fill[key] = style[key] style_stroke[key] = style[key] if len(style_group) != 0: group.set("style", str(inkex.Style(style_group))) fill.set("style", str(inkex.Style(style_fill))) stroke.set("style", str(inkex.Style(style_stroke))) # Finalize the two paths fill.set("d", d) stroke.set("d", d) if nodetypes is not None: fill.set('sodipodi:nodetypes', nodetypes) stroke.set('sodipodi:nodetypes', nodetypes) fill.set("id", path_id + "-fill") stroke.set("id", path_id + "-stroke") if transform is not None: fill.set("transform", transform) stroke.set("transform", transform) # Replace the original node with the group path_node.getparent().replace(path_node, group) return [fill, stroke]
def test_bounding_box(self): """A group returns a bounding box""" empty = self.svg.add(Group(Group())) self.assertEqual(empty.bounding_box(), None) self.assertEqual(int(self.svg.getElementById('A').bounding_box().width), 783) self.assertEqual(int(self.svg.getElementById('B').bounding_box().height), 114)
def test_new_group(self): """Test creating groups""" svg = Layer.new('layerA', Group.new('groupA', Rectangle())) self.assertElement(svg,\ b'<g inkscape:groupmode="layer" inkscape:label="layerA">'\ b'<g inkscape:label="groupA"><rect/></g></g>')
def effect(self): self.is_installed() for name in list(self.options.__dict__): if '_' in name: self.set_options(self.options, name, self.options.__dict__.pop(name)) # Remove old master slide property for node in self.svg.xpath( "//svg:g[@jessyink:customKeyBindings='customKeyBindings']"): node.delete() # Set custom key bindings. node_text = """function getCustomKeyBindingsSub() { var keyDict = new Object(); keyDict[SLIDE_MODE] = new Object(); keyDict[INDEX_MODE] = new Object(); keyDict[DRAWING_MODE] = new Object(); """ for key, value in self.options.slideKeyCodes.items(): node_text += f" keyDict[SLIDE_MODE][{key}] = function() {{ {value} }};\n" for key, value in self.options.drawingKeyCodes.items(): node_text += f" keyDict[DRAWING_MODE][{key}] = function() {{ {value} }};\n" for key, value in self.options.indexKeyCodes.items(): node_text += f" keyDict[INDEX_MODE][{key}] = function() {{ {value} }};\n" # Set custom char bindings. node_text += """ return keyDict; } function getCustomCharBindingsSub() { var charDict = new Object(); charDict[SLIDE_MODE] = new Object(); charDict[INDEX_MODE] = new Object(); charDict[DRAWING_MODE] = new Object(); """ for key, value in self.options.slideCharCodes.items(): node_text += f' charDict[SLIDE_MODE]["{key}"] = function() {{ {value} }};\n' for key, value in self.options.drawingCharCodes.items(): node_text += f' charDict[DRAWING_MODE]["{key}"] = function() {{ {value} }};\n' for key, value in self.options.indexCharCodes.items(): node_text += f' charDict[INDEX_MODE]["{key}"] = function() {{ {value} }};\n' node_text += " return charDict;" + "\n" node_text += "}" + "\n" # Create new script node group = self.svg.add(Group()) script = group.add(Script()) script.text = node_text group.set("jessyink:customKeyBindings", "customKeyBindings") group.set("onload", "this.getCustomCharBindings = function() { "\ "return getCustomCharBindingsSub(); }; "\ "this.getCustomKeyBindings = function() { return getCustomKeyBindingsSub(); };")
def effect(self): # Check that elements have been selected if not self.svg.selected: inkex.errormsg(_("Please select objects!")) return linestyle = { 'stroke': '#000000', 'stroke-width': str(self.svg.unittouu('1px')), 'fill': 'none', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' } facestyle = { 'stroke': '#000000', 'stroke-width': str(self.svg.unittouu('1px')), 'fill': 'none', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' } parent_group = self.svg.selection.first().getparent() trans = parent_group.composed_transform() invtrans = None if trans: invtrans = -trans # Recovery of the selected objects pts = [] nodes = [] seeds = [] fills = [] for node in self.svg.selected.values(): nodes.append(node) bbox = node.bounding_box() if bbox: center_x, center_y = bbox.center point = [center_x, center_y] if trans: point = trans.apply_to_point(point) pts.append(Point(*point)) if self.options.delaunayFillOptions != "delaunay-no-fill": fills.append(node.style.get('fill', 'none')) seeds.append(Point(center_x, center_y)) # Creation of groups to store the result if self.options.diagramType != 'Delaunay': # Voronoi group_voronoi = parent_group.add(Group()) group_voronoi.set('inkscape:label', 'Voronoi') if invtrans: group_voronoi.transform *= invtrans if self.options.diagramType != 'Voronoi': # Delaunay group_delaunay = parent_group.add(Group()) group_delaunay.set('inkscape:label', 'Delaunay') # Clipping box handling if self.options.diagramType != 'Delaunay': # Clipping bounding box creation group_bbox = sum([node.bounding_box() for node in nodes], None) # Clipbox is the box to which the Voronoi diagram is restricted if self.options.clip_box == 'Page': svg = self.document.getroot() width = self.svg.unittouu(svg.get('width')) height = self.svg.unittouu(svg.get('height')) clip_box = (0, width, 0, height) else: clip_box = (group_bbox.left, group_bbox.right, group_bbox.top, group_bbox.bottom) # Safebox adds points so that no Voronoi edge in clip_box is infinite safe_box = (2 * clip_box[0] - clip_box[1], 2 * clip_box[1] - clip_box[0], 2 * clip_box[2] - clip_box[3], 2 * clip_box[3] - clip_box[2]) pts.append(Point(safe_box[0], safe_box[2])) pts.append(Point(safe_box[1], safe_box[2])) pts.append(Point(safe_box[1], safe_box[3])) pts.append(Point(safe_box[0], safe_box[3])) if self.options.showClipBox: # Add the clip box to the drawing rect = group_voronoi.add(Rectangle()) rect.set('x', str(clip_box[0])) rect.set('y', str(clip_box[2])) rect.set('width', str(clip_box[1] - clip_box[0])) rect.set('height', str(clip_box[3] - clip_box[2])) rect.style = linestyle # Voronoi diagram generation if self.options.diagramType != 'Delaunay': vertices, lines, edges = voronoi.computeVoronoiDiagram(pts) for edge in edges: vindex1, vindex2 = edge[1:] if (vindex1 < 0) or (vindex2 < 0): continue # infinite lines have no need to be handled in the clipped box else: segment = self.clip_edge(vertices, lines, edge, clip_box) # segment = [vertices[vindex1],vertices[vindex2]] # deactivate clipping if len(segment) > 1: x1, y1 = segment[0] x2, y2 = segment[1] cmds = [['M', [x1, y1]], ['L', [x2, y2]]] path = group_voronoi.add(PathElement()) path.set('d', str(inkex.Path(cmds))) path.style = linestyle if self.options.diagramType != 'Voronoi': triangles = voronoi.computeDelaunayTriangulation(seeds) i = 0 if self.options.delaunayFillOptions == "delaunay-fill": random.seed("inkscape") for triangle in triangles: pt1 = seeds[triangle[0]] pt2 = seeds[triangle[1]] pt3 = seeds[triangle[2]] cmds = [['M', [pt1.x, pt1.y]], ['L', [pt2.x, pt2.y]], ['L', [pt3.x, pt3.y]], ['Z', []]] if self.options.delaunayFillOptions == "delaunay-fill" \ or self.options.delaunayFillOptions == "delaunay-fill-random": facestyle = { 'stroke': fills[triangle[random.randrange(0, 2)]], 'stroke-width': str(self.svg.unittouu('0.005px')), 'fill': fills[triangle[random.randrange(0, 2)]], 'stroke-linecap': 'round', 'stroke-linejoin': 'round' } path = group_delaunay.add(PathElement()) path.set('d', str(inkex.Path(cmds))) path.style = facestyle i += 1