def test_regular_circle(self): r = 5 cx = 10 cy = 20 circle = Circle(r=str(r), cx=str(cx), cy=str(cy)) self.assert_bounding_box_is_equal(circle, (cx - r, cx + r), (cy - r, cy + r))
def draw_reg_circles(self, cx, cy, r, name, colours, parent): for i in range(len(colours)): style = {'stroke': colours[i], 'stroke-width': str(r / len(colours)), 'fill': 'none'} circle_attribs = {'style': str(inkex.Style(style)), 'inkscape:label': name, 'cx': str(cx), 'cy': str(cy), 'r': str((r / len(colours)) * (i + 0.5))} parent.add(Circle(**circle_attribs))
def drawCircle(self, group, color, point): style = inkex.Style({'stroke': 'none', 'fill': color}) startCircle = group.add( Circle(cx=str(point[0]), cy=str(point[1]), r=str( self.svg.unittouu(str(self.options.dotsize / 2) + "px")))) startCircle.style = style
def test_parse(self): """Test Circle parsed from XML""" circle = Circle(attrib={"cx": "10px", "cy": "20px", "r": "30px"}) self.assertEqual(circle.center.x, 10) self.assertEqual(circle.center.y, 20) self.assertEqual(circle.radius, 30) ellipse = Ellipse(attrib={"cx": "10px", "cy": "20px", "rx": "30px", "ry": "40px"}) self.assertEqual(ellipse.center.x, 10) self.assertEqual(ellipse.center.y, 20) self.assertEqual(ellipse.radius.x, 30) self.assertEqual(ellipse.radius.y, 40)
def generateCircle(self, x, y, r, strokeWidth, stroke, fill, name): circle = Circle() circle.center = (x, y) circle.radius = r circle.style = { 'stroke': stroke, 'stroke-width': strokeWidth, 'fill': fill } circle.label = name return circle
def test_circle_with_stroke(self): r = 5 cx = 10 cy = 20 stroke_half_width = 1.0 circle = Circle(r=str(r), cx=str(cx), cy=str(cy)) circle.style = Style("stroke-width:{};stroke:red".format(stroke_half_width * 2)) self.assert_bounding_box_is_equal(circle, (cx - (r + stroke_half_width), cx + (r + stroke_half_width)), (cy - (r + stroke_half_width), cy + (r + stroke_half_width)))
def add_dot(self, node): """Add a dot label for this path element""" group = node.getparent().add(inkex.Group()) dot_group = group.add(inkex.Group()) num_group = group.add(inkex.Group()) group.transform = node.transform style = inkex.Style({'stroke': 'none', 'fill': '#000'}) for step, (x, y) in enumerate(node.path.end_points): circle = dot_group.add(Circle(cx=str(x), cy=str(y),\ r=str(self.svg.unittouu(self.options.dotsize) / 2))) circle.style = style num_group.append( self.add_text( x + (self.svg.unittouu(self.options.dotsize) / 2), y - (self.svg.unittouu(self.options.dotsize) / 2), self.options.start + (self.options.step * step))) node.delete()
def test_circle_with_stroke_scaled(self): r = 5 cx = 10 cy = 20 scale_x = 2 scale_y = 3 stroke_half_width = 1.0 circle = Circle(r=str(r), cx=str(cx), cy=str(cy)) circle.style = Style("stroke-width:{};stroke:red".format(stroke_half_width * 2)) circle.transform = Transform(scale=(scale_x, scale_y)) self.assert_bounding_box_is_equal(circle, (scale_x * (cx - (r + stroke_half_width)), scale_x * (cx + (r + stroke_half_width))), (scale_y * (cy - (r + stroke_half_width)), scale_y * (cy + (r + stroke_half_width))))
def draw_SVG_circle( rad, centre, params, style, name, parent ): # draw an SVG circle with a given radius as trilinear coordinates if rad == 0: # we want a dot r = style.d_rad # get the dot width from the style circ_style = { 'stroke': style.d_col, 'stroke-width': str(style.d_th), 'fill': style.d_fill } else: r = rad # use given value circ_style = { 'stroke': style.c_col, 'stroke-width': str(style.c_th), 'fill': style.c_fill } cx, cy = get_cartesian_pt(centre, params) circ_attribs = {'cx': str(cx), 'cy': str(cy), 'r': str(r)} elem = parent.add(Circle(**circ_attribs)) elem.style = circ_style elem.label = name
def test_circle_without_center(self): r = 10 circle = Circle(r=str(r)) self.assert_bounding_box_is_equal(circle, (-r, r), (-r, r))
def test_circle_with_cy(self): cy = 10 circle = Circle(cy=str(cy)) self.assert_bounding_box_is_equal(circle, (0, 0), (cy, cy))
def test_circle_with_cx(self): cx = 10 circle = Circle(cx=str(cx)) self.assert_bounding_box_is_equal(circle, (cx, cx), (0, 0))
def test_circle_without_attributes(self): circle = Circle() self.assert_bounding_box_is_equal(circle, (0, 0), (0, 0))
def render_pie(self, keys, values, pie_abs=False): """Draw pie chart""" pie_radius = self.options.pie_radius # Iterate all values to draw the different slices color = 0 x = float(self.width) / 2 y = float(self.height) / 2 # Create the shadow first (if it should be created): if self.blur: shadow = Circle(cx=str(x), cy=str(y)) shadow.set('r', str(pie_radius)) shadow.style = self.blur + inkex.Style(fill='#000000') yield shadow # Add a grey background circle with a light stroke background = Circle(cx=str(x), cy=str(y)) background.set("r", str(pie_radius)) background.set("style", "stroke:#ececec;fill:#f9f9f9") yield background # create value sum in order to divide the slices try: valuesum = sum(values) except ValueError: valuesum = 0 if pie_abs: valuesum = 100 # Set an offsetangle offset = 0 # Draw single slices for cnt, value in enumerate(values): # Calculate the PI-angles for start and end angle = (2 * 3.141592) / valuesum * float(value) start = offset end = offset + angle # proper overlapping if self.options.segment_overlap: if cnt != len(values) - 1: end += 0.09 # add a 5° overlap if cnt == 0: start -= 0.09 # let the first element overlap into the other direction # then add the slice pieslice = inkex.PathElement() pieslice.set('sodipodi:type', 'arc') pieslice.set('sodipodi:cx', x) pieslice.set('sodipodi:cy', y) pieslice.set('sodipodi:rx', pie_radius) pieslice.set('sodipodi:ry', pie_radius) pieslice.set('sodipodi:start', start) pieslice.set('sodipodi:end', end) pieslice.set( "style", "fill:" + self.get_color() + ";stroke:none;fill-opacity:1") ang = angle / 2 + offset # If text is given, draw short paths and add the text if keys: elem = inkex.PathElement() elem.path = [ Move( (self.width / 2) + pie_radius * math.cos(ang), (self.height / 2) + pie_radius * math.sin(ang), ), line( (self.options.text_offset - 2) * math.cos(ang), (self.options.text_offset - 2) * math.sin(ang), ), ] elem.style = { 'fill': 'none', 'stroke': self.options.font_color, 'stroke-width': self.options.stroke_width, 'stroke-linecap': 'butt', } yield elem label = keys[cnt] if self.options.show_values: label += ' ({}{})'.format(str(value), ('', '%')[pie_abs]) # check if it is right or left of the Pie anchor = 'start' if math.cos(ang) > 0 else 'end' text = self.draw_text(label, anchor=anchor) off = pie_radius + self.options.text_offset text.set("x", (self.width / 2) + off * math.cos(ang)) text.set("y", (self.height / 2) + off * math.sin(ang) + self.fontoff) yield text # increase the rotation-offset and the colorcycle-position offset = offset + angle color = (color + 1) % 8 # append the objects to the extension-layer yield pieslice yield self.draw_header(self.width / 2 - pie_radius)
def scanContours(self, node): if node.tag == inkex.addNS('path', 'svg'): if self.options.removefillsetstroke: self.adjustStyle(node) intersectionGroup = node.getparent().add(inkex.Group()) raw = (Path(node.get('d')).to_arrays()) subPaths, prev = [], 0 for i in range( len(raw)): # Breaks compound paths into simple paths if raw[i][0] == 'M' and i != 0: subPaths.append(raw[prev:i]) prev = i subPaths.append(raw[prev:]) for simpath in subPaths: closed = False if simpath[-1][0] == 'Z': closed = True if simpath[-2][0] == 'L': simpath[-1][1] = simpath[0][1] else: simpath.pop() points = [] for i in range(len(simpath)): if simpath[i][ 0] == 'V': # vertical and horizontal lines only have one point in args, but 2 are required simpath[i][ 0] = 'L' #overwrite V with regular L command add = simpath[i - 1][1][ 0] #read the X value from previous segment simpath[i][1].append( simpath[i][1][0] ) #add the second (missing) argument by taking argument from previous segment simpath[i][1][ 0] = add #replace with recent X after Y was appended if simpath[i][ 0] == 'H': # vertical and horizontal lines only have one point in args, but 2 are required simpath[i][ 0] = 'L' #overwrite H with regular L command simpath[i][1].append( simpath[i - 1][1][1] ) #add the second (missing) argument by taking argument from previous segment points.append(simpath[i][1][-2:]) if points[0] == points[ -1]: #if first is last point the path is also closed. The "Z" command is not required closed = True if closed == False: if self.options.highlight_opened: style = { 'stroke-linejoin': 'miter', 'stroke-width': str( self.svg.unittouu( str(self.options.strokewidth) + "px")), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': self.options.color_opened, 'stroke-linecap': 'butt', 'fill': 'none' } node.attrib['style'] = Style(style).to_str() if self.options.remove_opened: try: node.delete() except AttributeError: pass #we ignore that parent can be None if closed == True: if self.options.highlight_closed: style = { 'stroke-linejoin': 'miter', 'stroke-width': str( self.svg.unittouu( str(self.options.strokewidth) + "px")), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': self.options.color_closed, 'stroke-linecap': 'butt', 'fill': 'none' } node.attrib['style'] = Style(style).to_str() if self.options.remove_closed: try: node.delete() except AttributeError: pass #we ignore that parent can be None #if one of the options is activated we also check for self-intersecting if self.options.highlight_selfintersecting or self.options.highlight_intersectionpoints: #Style definitions closingLineStyle = Style({ 'stroke-linejoin': 'miter', 'stroke-width': str( self.svg.unittouu( str(self.options.strokewidth) + "px")), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': self.options.color_intersectionpoints, 'stroke-linecap': 'butt', 'fill': 'none' }).to_str() intersectionPointStyle = Style({ 'stroke': 'none', 'fill': self.options.color_intersectionpoints }).to_str() intersectionStyle = Style({ 'stroke-linejoin': 'miter', 'stroke-width': str( self.svg.unittouu( str(self.options.strokewidth) + "px")), 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': self.options.color_selfintersecting, 'stroke-linecap': 'butt', 'fill': 'none' }).to_str() try: if len( points ) > 2: #try to find self-intersecting /overlapping polygons. We need at least 3 points to detect for intersections (only possible if first points matched last point) isect = poly_point_isect.isect_polygon(points) if len(isect) > 0: if closed == False and self.options.addlines == True: #if contour is open and we found intersection points those points might be not relevant closingLine = intersectionGroup.add( inkex.PathElement()) closingLine.set( 'id', self.svg.get_unique_id('closingline-')) closingLine.path = [[ 'M', [points[0][0], points[0][1]] ], ['L', [points[-1][0], points[-1][1]]], ['Z', []]] closingLine.attrib[ 'style'] = closingLineStyle #draw polylines if option is enabled if self.options.polypaths == True: polyNode = intersectionGroup.add( inkex.PathElement()) polyNode.set( 'id', self.svg.get_unique_id('polypath-')) polyNode.set('d', str(self.getPolyline(node))) polyNode.attrib['style'] = closingLineStyle #make dot markings at the intersection points if self.options.highlight_intersectionpoints: for xy in isect: #Add a dot label for this path element intersectionPoint = intersectionGroup.add( Circle(cx=str(xy[0]), cy=str(xy[1]), r=str( self.svg.unittouu( str(self.options. dotsize / 2) + "px")))) intersectionPoint.set( 'id', self.svg.get_unique_id( 'intersectionpoint-')) intersectionPoint.style = intersectionPointStyle if self.options.highlight_selfintersecting: node.attrib['style'] = intersectionStyle if self.options.remove_selfintersecting: if node.getparent( ) is not None: #might be already been deleted by previously checked settings so check again node.delete() #draw intersections segment lines - useless at the moment. We could use this information to cut the original polyline to get a new curve path which included the intersection points #isectSegs = poly_point_isect.isect_polygon_include_segments(points) #for seg in isectSegs: # isectSegsPath = [] # isecX = seg[0][0] #the intersection point - X # isecY = seg[0][1] #the intersection point - Y # isecSeg1X = seg[1][0][0][0] #the first intersection point segment - X # isecSeg1Y = seg[1][0][0][1] #the first intersection point segment - Y # isecSeg2X = seg[1][1][0][0] #the second intersection point segment - X # isecSeg2Y = seg[1][1][0][1] #the second intersection point segment - Y # isectSegsPath.append(['L', [isecSeg2X, isecSeg2Y]]) # isectSegsPath.append(['L', [isecX, isecY]]) # isectSegsPath.append(['L', [isecSeg1X, isecSeg1Y]]) # #fix the really first point. Has to be an 'M' command instead of 'L' # isectSegsPath[0][0] = 'M' # polySegsNode = intersectionGroup.add(inkex.PathElement()) # polySegsNode.set('id', self.svg.get_unique_id('intersectsegments-')) # polySegsNode.set('d', str(Path(isectSegsPath))) # polySegsNode.attrib['style'] = closingLineStyle except AssertionError as e: # we skip AssertionError if self.options.show_debug is True: inkex.utils.debug("AssertionError at " + node.get('id')) continue except IndexError as i: # we skip IndexError if self.options.show_debug is True: inkex.utils.debug("IndexError at " + node.get('id')) continue #if the intersectionGroup was created but nothing attached we delete it again to prevent messing the SVG XML tree if len(intersectionGroup.getchildren()) == 0: intersectionGroupParent = intersectionGroup.getparent() if intersectionGroupParent is not None: intersectionGroup.delete() #put the node into the intersectionGroup to bundle the path with it's error markers. If removal is selected we need to avoid intersectionGroup.insert(), because it will break the removal elif self.options.remove_selfintersecting == False: intersectionGroup.insert(0, node) children = node.getchildren() if children is not None: for child in children: self.scanContours(child)
def draw_circle(r, cx, cy, width, fill, name, parent): """Draw an SVG circle""" circle = parent.add(Circle(cx=str(cx), cy=str(cy), r=str(r))) circle.style = {'stroke': '#000000', 'stroke-width': str(width), 'fill': fill} circle.label = name