def arrow_path_concave(line, width): """ Return a :class:`QPainterPath` of a pretty looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) start, end = baseline.p1(), baseline.p2() mid = (start + end) / 2.0 normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2() path.moveTo(start) path.lineTo(start + (normal * width / 4.0)) path.quadTo(mid + (normal * width / 4.0), end + (normal * width / 1.5)) path.lineTo(end - (normal * width / 1.5)) path.quadTo(mid - (normal * width / 4.0), start - (normal * width / 4.0)) path.closeSubpath() arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), baseline.p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def arrow_path_concave(line, width): """ Return a :class:`QPainterPath` of a pretty looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) start, end = baseline.p1(), baseline.p2() mid = (start + end) / 2.0 normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2() path.moveTo(start) path.lineTo(start + (normal * width / 4.0)) path.quadTo(mid + (normal * width / 4.0), end + (normal * width / 1.5)) path.lineTo(end - (normal * width / 1.5)) path.quadTo(mid - (normal * width / 4.0), start - (normal * width / 4.0)) path.closeSubpath() arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), baseline.p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2 ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def arrow_path_plain(line, width): """ Return an :class:`QPainterPath` of a plain looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) path.moveTo(baseline.p1()) path.lineTo(baseline.p2()) stroker = QPainterPathStroker() stroker.setWidth(width) path = stroker.createStroke(path) arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2, ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def arrow_path_plain(line, width): """ Return an :class:`QPainterPath` of a plain looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) path.moveTo(baseline.p1()) path.lineTo(baseline.p2()) stroker = QPainterPathStroker() stroker.setWidth(width) path = stroker.createStroke(path) arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2 ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def _write(self, shapes, svg_file, width, height, stroke_colour = None, stroke_width = None, background_colour = None): svg_file.write('<?xml version="1.0" standalone="no"?>\n' '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n' ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n') svg_file.write('<svg width="%.6fcm" height="%.6fcm" ' % (width, height)) svg_file.write('viewBox="%.6f %.6f %.6f %.6f" ' 'xmlns="http://www.w3.org/2000/svg" ' 'version="1.1">\n' % (0.0, 0.0, width, height)) if stroke_width is None: stroke_width = "0.1%" if background_colour is not None: svg_file.write('<polygon fill="%s" ' % background_colour) svg_file.write('points="%.6f,%.6f %.6f,%.6f %.6f,%.6f %.6f,%.6f" />\n' % ( 0.0, 0.0, width, 0.0, width, height, 0.0, height)) path = QPainterPath() shapes.reverse() new_shapes = {} for points, polygon in shapes: rgb = self.parts.colours.get(polygon.colour, "#ffffff") new_points = [] for x, y in points: new_points.append(QPointF(x + width/2.0, height/2.0 - y)) new_polygon = QPolygonF(new_points) new_path = QPainterPath() new_path.addPolygon(new_polygon) if path.contains(new_path): continue inter = path.intersected(new_path) remaining = new_path.subtracted(inter) # Combine the new path with the accumulated path and simplify # the result. path = path.united(new_path) path = path.simplified() piece_dict = new_shapes.setdefault(polygon.piece, {}) colour_path = piece_dict.get(polygon.colour, QPainterPath()) piece_dict[polygon.colour] = colour_path.united(remaining) for piece, piece_dict in new_shapes.items(): svg_file.write('<g>\n') for colour, colour_path in piece_dict.items(): if colour_path.isEmpty(): continue rgb = self.parts.colours.get(colour, "#ffffff") shape = '<path style="fill:%s; opacity:%f" d="' % ( rgb, self._opacity_from_colour(colour)) i = 0 in_path = False while i < colour_path.elementCount(): p = colour_path.elementAt(i) if p.type == QPainterPath.MoveToElement: if in_path: shape += 'Z ' shape += 'M %.6f %.6f ' % (p.x, p.y) in_path = True elif p.type == QPainterPath.LineToElement: shape += 'L %.6f %.6f ' % (p.x, p.y) i += 1 if in_path: shape += 'Z' shape += '" />\n' svg_file.write(shape) svg_file.write('</g>\n') svg_file.write("</svg>\n") svg_file.close()