Exemple #1
0
 def draw_arrow(self, line, width, color):
     (x1, y1), (x2, y2) = line
     # compute points
     line = QLineF(x1, y1, x2, y2)
     # If the line is very small, we make our arrowhead smaller
     arrowsize = min(14, line.length())
     lineangle = radians(line.angle())
     arrowpt1 = line.p2() + QPointF(sin(lineangle - (pi/3)) * arrowsize, cos(lineangle - (pi/3)) * arrowsize)
     arrowpt2 = line.p2() + QPointF(sin(lineangle - pi + (pi/3)) * arrowsize, cos(lineangle - pi + (pi/3)) * arrowsize)
     head = QPolygonF([line.p2(), arrowpt1, arrowpt2])
     # We have to draw the actual line a little short for the tip of the arrowhead not to be too wide
     adjustedLine = QLineF(line)
     adjustedLine.setLength(line.length() - arrowsize/2)
     
     # draw line
     painter = self.current_painter
     color = COLORS[color]
     painter.save()
     pen = QPen(painter.pen())
     pen.setColor(color)
     pen.setWidthF(width)
     painter.setPen(pen)
     painter.drawLine(adjustedLine)
     
     # draw arrowhead
     painter.setPen(Qt.NoPen)
     brush = painter.brush()
     brush.setColor(color)
     brush.setStyle(Qt.SolidPattern)
     painter.setBrush(brush)
     painter.drawPolygon(head)
     painter.restore()
    def paintArc(self, painter, option, widget):
        assert self.source is self.dest
        node = self.source

        def best_angle():
            """...is the one furthest away from all other angles"""
            angles = [
                QLineF(node.pos(), other.pos()).angle() for other in chain((
                    edge.source for edge in node.edges
                    if edge.dest == node and edge.source != node), (
                        edge.dest for edge in node.edges
                        if edge.dest != node and edge.source == node))
            ]
            angles.sort()
            if not angles:  # If this self-constraint is the only edge
                return 225
            deltas = np.array(angles[1:] + [360 + angles[0]]) - angles
            return (angles[deltas.argmax()] + deltas.max() / 2) % 360

        angle = best_angle()
        inf = QPointF(-1e20, -1e20)  # Doesn't work with real -np.inf!
        line0 = QLineF(node.pos(), inf)
        line1 = QLineF(node.pos(), inf)
        line2 = QLineF(node.pos(), inf)
        line0.setAngle(angle)
        line1.setAngle(angle - 13)
        line2.setAngle(angle + 13)

        p0 = shape_line_intersection(node.shape(), node.pos(), line0)
        p1 = shape_line_intersection(node.shape(), node.pos(), line1)
        p2 = shape_line_intersection(node.shape(), node.pos(), line2)
        path = QtGui.QPainterPath()
        path.moveTo(p1)
        line = QLineF(node.pos(), p0)
        line.setLength(3 * line.length())
        pt = line.p2()
        path.quadTo(pt, p2)

        line = QLineF(node.pos(), pt)
        self.setLine(line)  # This invalidates DeviceCoordinateCache
        painter.drawPath(path)

        # Draw arrow head
        line = QLineF(pt, p2)
        self.arrowHead.clear()
        for point in self._arrowhead_points(line):
            self.arrowHead.append(point)
        painter.setBrush(self.pen().color())
        painter.drawPolygon(self.arrowHead)

        # Update label position
        self.label.setPos(path.pointAtPercent(.5))
        if 90 < angle < 270:  # Right-align the label
            pos = self.label.pos()
            x, y = pos.x(), pos.y()
            self.label.setPos(x - self.label.boundingRect().width(), y)
        self.squares.placeBelow(self.label)
    def paintArc(self, painter, option, widget):
        assert self.source is self.dest
        node = self.source

        def best_angle():
            """...is the one furthest away from all other angles"""
            angles = [
                QLineF(node.pos(), other.pos()).angle()
                for other in chain(
                    (edge.source for edge in node.edges if edge.dest == node and edge.source != node),
                    (edge.dest for edge in node.edges if edge.dest != node and edge.source == node),
                )
            ]
            angles.sort()
            if not angles:  # If this self-constraint is the only edge
                return 225
            deltas = np.array(angles[1:] + [360 + angles[0]]) - angles
            return (angles[deltas.argmax()] + deltas.max() / 2) % 360

        angle = best_angle()
        inf = QPointF(-1e20, -1e20)  # Doesn't work with real -np.inf!
        line0 = QLineF(node.pos(), inf)
        line1 = QLineF(node.pos(), inf)
        line2 = QLineF(node.pos(), inf)
        line0.setAngle(angle)
        line1.setAngle(angle - 13)
        line2.setAngle(angle + 13)

        p0 = shape_line_intersection(node.shape(), node.pos(), line0)
        p1 = shape_line_intersection(node.shape(), node.pos(), line1)
        p2 = shape_line_intersection(node.shape(), node.pos(), line2)
        path = QtGui.QPainterPath()
        path.moveTo(p1)
        line = QLineF(node.pos(), p0)
        line.setLength(3 * line.length())
        pt = line.p2()
        path.quadTo(pt, p2)

        line = QLineF(node.pos(), pt)
        self.setLine(line)  # This invalidates DeviceCoordinateCache
        painter.drawPath(path)

        # Draw arrow head
        line = QLineF(pt, p2)
        self.arrowHead.clear()
        for point in self._arrowhead_points(line):
            self.arrowHead.append(point)
        painter.setBrush(self.pen().color())
        painter.drawPolygon(self.arrowHead)

        # Update label position
        self.label.setPos(path.pointAtPercent(0.5))
        if 90 < angle < 270:  # Right-align the label
            pos = self.label.pos()
            x, y = pos.x(), pos.y()
            self.label.setPos(x - self.label.boundingRect().width(), y)
        self.squares.placeBelow(self.label)
Exemple #4
0
    def overlay_for(pt1, pt2, frequency):
        # Construct the line-geometry, we'll use this to construct the ellipsoid
        line = QLineF(pt1, pt2)

        # Determine the radius for the ellipsoid
        radius = fresnel_radius(line.length(), frequency)

        # Draw the ellipsoid
        zone = QPainterPath()
        zone.addEllipse(QPointF(0., 0.), line.length() / 2, radius)

        # Rotate the ellipsoid - same angle as the line
        transform = QTransform()
        transform.rotate(-line.angle())
        zone = transform.map(zone)

        # Center the zone over the line
        lc = QRectF(pt1, pt2).center()
        zc = zone.boundingRect().center()
        zone.translate(lc.x() - zc.x(), lc.y() - zc.y())

        return line, zone
Exemple #5
0
    def draw_arrow(self, line, width, color):
        (x1, y1), (x2, y2) = line
        # compute points
        line = QLineF(x1, y1, x2, y2)
        # If the line is very small, we make our arrowhead smaller
        arrowsize = min(14, line.length())
        lineangle = radians(line.angle())
        arrowpt1 = line.p2() + QPointF(
            sin(lineangle - (pi / 3)) * arrowsize,
            cos(lineangle - (pi / 3)) * arrowsize)
        arrowpt2 = line.p2() + QPointF(
            sin(lineangle - pi + (pi / 3)) * arrowsize,
            cos(lineangle - pi + (pi / 3)) * arrowsize)
        head = QPolygonF([line.p2(), arrowpt1, arrowpt2])
        # We have to draw the actual line a little short for the tip of the arrowhead not to be too wide
        adjustedLine = QLineF(line)
        adjustedLine.setLength(line.length() - arrowsize / 2)

        # draw line
        painter = self.current_painter
        color = COLORS[color]
        painter.save()
        pen = QPen(painter.pen())
        pen.setColor(color)
        pen.setWidthF(width)
        painter.setPen(pen)
        painter.drawLine(adjustedLine)

        # draw arrowhead
        painter.setPen(Qt.NoPen)
        brush = painter.brush()
        brush.setColor(color)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.drawPolygon(head)
        painter.restore()
Exemple #6
0
class MyArrow(QGraphicsLineItem):
    def __init__(self):
        super(MyArrow, self).__init__()
        self.source = QPointF(0, 250)
        self.dest = QPointF(120, 120)
        self.line = QLineF(self.source, self.dest)
        self.line.setLength(self.line.length() - 20)

    def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None):
        # setPen
        pen = QPen()
        pen.setWidth(5)
        pen.setJoinStyle(Qt.MiterJoin)  #让箭头变尖
        QPainter.setPen(pen)

        # draw line
        QPainter.drawLine(self.line)
    def adjust(self):
        if not self.source or not self.dest:
            return

        line = QLineF(self.mapFromItem(self.source, 0, 0),
                      self.mapFromItem(self.dest, 0, 0))
        length = line.length()

        self.prepareGeometryChange()

        if length > 20.0:
            edgeOffset = QPointF((line.dx() * 10) / length,
                                 (line.dy() * 10) / length)

            self.sourcePoint = line.p1() + edgeOffset
            self.destPoint = line.p2() - edgeOffset
        else:
            self.sourcePoint = line.p1()
            self.destPoint = line.p1()
    def __init__(self, sourceNode, destNode, state=1, text=""):
        super(Edge, self).__init__()

        self.arrowSize = 15.0
        self.sourcePoint = QPointF()
        self.destPoint = QPointF()

        self.setAcceptedMouseButtons(Qt.NoButton)
        self.source = sourceNode
        self.dest = destNode
        self.source.addEdge(self)
        self.dest.addEdge(self)
        self.adjust()

        self.state = state
        self.text = text

        line = QLineF(sourceNode.pos(), destNode.pos())
        self.weight = line.length()
Exemple #9
0
class Line( QGraphicsLineItem ):
    """Defines a line by two points. If points are moved, line follows these movements."""
    
    def __init__( self, startPoint, endPoint, ccs, paintToBorder = False, showIncline = False, color = 'orange', minLength = 0 ):
        super( Line, self ).__init__( ccs )
        
        self.startPoint     = startPoint
        self.endPoint       = endPoint
        self.ccs            = ccs
        self.paintToBorder  = paintToBorder
        self.showIncline    = showIncline
        self.color          = color
        
        self.visible        = True
        
        # by default we only want to draw lines if its two
        # defining points are not too close together
        self.drawAlways     = False
        self.minLength      = minLength # pixel
        
        # grmbl. Line was designed to be defined by two Point.Points. Now I want to be able to define
        # lines as well from QPointFs. 
        try:
            self.Rect = QRectF( self.startPoint.x, self.startPoint.y, self.endPoint.x, self.endPoint.y )
        except:
            self.Rect = QRectF( self.startPoint.x(), self.startPoint.y(), self.endPoint.x(), self.endPoint.y() )

    def boundingRect( self ):
        return self.Rect

    def paint( self, painter, option, widget=None ):
        if self.visible == True:
            painter.setPen( QColor( self.color ) )
            
            # see try-catch (pardon me) above
            try:
                self.sp = CST.toCcsCoord( self.ccs, self.startPoint.x, self.startPoint.y )
                self.ep = CST.toCcsCoord( self.ccs, self.endPoint.x, self.endPoint.y )
            except:
                self.sp = CST.toCcsCoord( self.ccs, self.startPoint.x(), self.startPoint.y() )
                self.ep = CST.toCcsCoord( self.ccs, self.endPoint.x(), self.endPoint.y() )
            
            self.Rect = QRectF( self.sp, self.ep )
            self.line = QLineF( self.sp, self.ep )
            
            if self.line.length() > self.minLength or self.drawAlways == True:
                
                painter.drawLine( self.line )
            
                if self.paintToBorder == True:

                    # paint line to approximately the edge of the ccs.
                    ep2 = self.line.pointAt( self.ccs.width / self.line.length() * 2)
                    painter.drawLine(self.ep,ep2)
                    sp2 = self.line.pointAt(-self.ccs.width / self.line.length() * 2)
                    painter.drawLine(self.sp,sp2)
            
                if self.showIncline == True:
                    incline = ( self.endPoint.y - self.startPoint.y ) / ( self.endPoint.x - self.startPoint.x )
                    # print text limited to 2 decimal digits.
                    painter.setBackground ( QBrush ( QColor( 'lightGrey' ) ) )
                    painter.setBackgroundMode (Qt.BGMode(1))
                    painter.setPen( QColor( 'black' ) )
                    #~ painter.drawText( self.ep.x() + 10, self.ep.y() + 10, QString ( '%.2f' %(incline) ) )
                
    def setVisible( self, value ):
        self.visible = value
        
    def setPosition( self, startPoint, endPoint ):
        self.startPoint = startPoint
        self.endPoint   = endPoint
        
    def updateYourself( self, xDelta, yDelta ):
        # There is no action needed, as a line gets its information
        # from startPoint and endPoint
        # Just adjust self.Rect to avoid case where line disappears mysteriously and after then,
        # paint() is never called again
        self.Rect = QRectF( self.startPoint.x, self.startPoint.y, self.endPoint.x, self.endPoint.y )
Exemple #10
0
    def render(o):
        path = QPainterPath()

        # unit_x gives offset and direction of the x base vector. Start and end should be the grid points.

        # move the endpoints inwards an unnoticable bit, so that the intersection detector
        # won't trip on the common endpoint.
        u_x = QLineF(o.unit_x.pointAt(0.0001), o.unit_x.pointAt(0.9999))

        path.moveTo(u_x.p1())

        if o.is_straight:
            path.lineTo(u_x.p2())
            return path

        if o.flipped:
            u_x = QLineF(u_x.p2(), u_x.p1())

        u_y = u_x.normalVector()
        # move y unit to start at (0,0).
        u_y.translate(-u_y.p1())

        scaling = o.length_base / u_x.length() * o.size_correction
        if o.basewidth * scaling > 0.8:
            # Plug is too large for the edge length. Make it smaller.
            scaling = 0.8 / o.basewidth

        # some magic numbers here... carefully fine-tuned, better leave them as they are.
        ends_ctldist = 0.4
        #base_lcdist = 0.1 * scaling
        base_ucdist = 0.05 * scaling
        knob_lcdist = 0.6 * o.knobsize * scaling
        knob_ucdist = 0.8 * o.knobsize * scaling

        # set up piece -- here is where the really interesting stuff happens.
        # We will work from the ends inwards, so that symmetry counterparts are adjacent.
        # The QLine.pointAt function is used to transform everything into the coordinate
        # space defined by the us.
        # -- end points

        r1y = ends_ctldist * o.basepos * dsin(o.startangle)
        q6y = ends_ctldist * (1. - o.basepos) * dsin(o.endangle)
        p1 = u_x.p1()
        p6 = u_x.p2()
        r1 = u_x.pointAt(
            ends_ctldist * o.basepos * dcos(o.startangle)) + u_y.pointAt(r1y)
        q6 = u_x.pointAt(1. - ends_ctldist * (1. - o.basepos) *
                         dcos(o.endangle)) + u_y.pointAt(q6y)

        # -- base points
        p2x = o.basepos - 0.5 * o.basewidth * scaling
        p5x = o.basepos + 0.5 * o.basewidth * scaling

        if p2x < 0.1 or p5x > 0.9:
            # knob to large. center knob on the edge. (o.basewidth * scaling < 0.8 -- see above)
            p2x = 0.5 - 0.5 * o.basewidth * scaling
            p5x = 0.5 + 0.5 * o.basewidth * scaling

        #base_y = r1y > q6y ? r1y : q6y
        #base_y = 0.5*(r1y + q6y)
        base_y = -o.baseroundness * ends_ctldist * min(p2x, 1. - p5x)
        if base_y > 0:
            base_y = 0

        base_lcy = base_y * 2.0

        base_y += base_ucdist / 2
        base_lcy -= base_ucdist / 2
        #base_lcy = r1y
        #if (q6y < r1y): base_lcy = q6y

        # at least -base_ucdist from base_y
        #if (base_lcy > base_y - base_ucdist): base_lcy = base_y-base_ucdist

        q2 = u_x.pointAt(p2x) + u_y.pointAt(base_lcy)
        r5 = u_x.pointAt(p5x) + u_y.pointAt(base_lcy)
        p2 = u_x.pointAt(p2x) + u_y.pointAt(base_y)
        p5 = u_x.pointAt(p5x) + u_y.pointAt(base_y)
        r2 = u_x.pointAt(p2x) + u_y.pointAt(base_y + base_ucdist)
        q5 = u_x.pointAt(p5x) + u_y.pointAt(base_y + base_ucdist)

        if o._is_plugless:
            if not o.flipped:
                path.cubicTo(r1, q2, p2)
                path.cubicTo(r2, q5, p5)
                path.cubicTo(r5, q6, p6)
            else:
                path.cubicTo(q6, r5, p5)
                path.cubicTo(q5, r2, p2)
                path.cubicTo(q2, r1, p1)
            return path

        # -- knob points
        p3x = p2x - o.knobsize * scaling * dsin(o.knobangle - o.knobtilt)
        p4x = p5x + o.knobsize * scaling * dsin(o.knobangle + o.knobtilt)
        # for the y coordinate, knobtilt sign was swapped. Knobs look better this way...
        # like x offset from base points y, but that is 0.
        p3y = o.knobsize * scaling * dcos(o.knobangle + o.knobtilt) + base_y
        p4y = o.knobsize * scaling * dcos(o.knobangle - o.knobtilt) + base_y

        q3 = u_x.pointAt(p3x) + u_y.pointAt(p3y - knob_lcdist)
        r4 = u_x.pointAt(p4x) + u_y.pointAt(p4y - knob_lcdist)
        p3 = u_x.pointAt(p3x) + u_y.pointAt(p3y)
        p4 = u_x.pointAt(p4x) + u_y.pointAt(p4y)
        r3 = u_x.pointAt(p3x) + u_y.pointAt(p3y + knob_ucdist)
        q4 = u_x.pointAt(p4x) + u_y.pointAt(p4y + knob_ucdist)

        # done setting up. construct path.
        # if flipped, add points in reverse.
        if not o.flipped:
            path.cubicTo(r1, q2, p2)
            path.cubicTo(r2, q3, p3)
            path.cubicTo(r3, q4, p4)
            path.cubicTo(r4, q5, p5)
            path.cubicTo(r5, q6, p6)
        else:
            path.cubicTo(q6, r5, p5)
            path.cubicTo(q5, r4, p4)
            path.cubicTo(q4, r3, p3)
            path.cubicTo(q3, r2, p2)
            path.cubicTo(q2, r1, p1)
        return path
    def paint(self, painter, option, widget):
        if not self.source or not self.dest:
            return

        # Draw the line itself.
        line = QLineF(self.sourcePoint, self.destPoint)

        if line.length() == 0.0:
            return

        palette = QPalette()

        self.setZValue(self.state)

        if self.state == 3:
            pen = QPen(Qt.red, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        if self.state == 2:
            pen = QPen(Qt.red, 2, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin)
        elif self.state == 1:
            pen = QPen(palette.color(QPalette.Disabled, QPalette.WindowText),
                       0, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        elif self.state == 0:
            pen = QPen()
            pen.setBrush(QBrush(Qt.NoBrush))

        painter.setPen(pen)

        painter.drawLine(line)

        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = Edge.TwoPi - angle

        # draw arrowheads
        if self.state == 2 or self.state == 3:

            # Draw the arrows if there's enough room.
            sourceArrowP1 = self.sourcePoint + QPointF(
                math.sin(angle + Edge.Pi / 3) * self.arrowSize,
                math.cos(angle + Edge.Pi / 3) * self.arrowSize)
            sourceArrowP2 = self.sourcePoint + QPointF(
                math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize,
                math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize)
            destArrowP1 = self.destPoint + QPointF(
                math.sin(angle - Edge.Pi / 3) * self.arrowSize,
                math.cos(angle - Edge.Pi / 3) * self.arrowSize)
            destArrowP2 = self.destPoint + QPointF(
                math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize,
                math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize)

            painter.setPen(
                QPen(Qt.red, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            painter.setBrush(QBrush(Qt.red, Qt.SolidPattern))
            painter.drawPolygon(
                QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]))
            #painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2]))

        if self.state > 0 and self.source > self.dest:
            point = QPointF((self.sourcePoint.x() + self.destPoint.x()) / 2,
                            (self.sourcePoint.y() + self.destPoint.y()) / 2)
            point = QPointF(point.x() + math.sin(angle) * 16,
                            point.y() + math.cos(angle) * 16)
            painter.drawText(point, self.text)
 def __len__(self):
     line = QLineF(self.sourceNode().pos(), self.destNode().pos())
     return line.length()