예제 #1
0
    def __init__( self, edge, modObj, connObj ):
        QGraphicsPathItem.__init__( self )
        self.__edge = edge
        self.__modObj = modObj
        self.__connObj = connObj

        startPoint = QPointF( edge.points[ 0 ][ 0 ], edge.points[ 0 ][ 1 ] )
        painterPath = QPainterPath( startPoint )

        index = 1
        while index + 3 <= len( edge.points ):
            painterPath.cubicTo(edge.points[index][0],  edge.points[index][1],
                                edge.points[index+1][0],edge.points[index+1][1],
                                edge.points[index+2][0],edge.points[index+2][1])
            index = index + 3
        if index + 2 <= len( edge.points ):
            painterPath.quadTo(edge.points[index+1][0], edge.points[index+1][1],
                               edge.points[index+2][0], edge.points[index+2][1])
            index = index + 2

        if index + 1 <= len( edge.points ):
            painterPath.lineTo(edge.points[index+1][0], edge.points[index+1][1])

        lastIndex = len( edge.points ) - 1
        self.addArrow( painterPath,
                       edge.points[lastIndex-1][0],
                       edge.points[lastIndex-1][1],
                       edge.points[lastIndex][0],
                       edge.points[lastIndex][1] )

        self.setPath( painterPath )
        return
예제 #2
0
    def __init__(self, edge, modObj):
        QGraphicsPathItem.__init__(self)
        self.__edge = edge
        self.__modObj = modObj

        startPoint = QPointF(edge.points[0][0], edge.points[0][1])
        painterPath = QPainterPath(startPoint)

        index = 1
        while index + 3 <= len(edge.points):
            painterPath.cubicTo(edge.points[index][0], edge.points[index][1],
                                edge.points[index + 1][0],
                                edge.points[index + 1][1],
                                edge.points[index + 2][0],
                                edge.points[index + 2][1])
            index = index + 3
        if index + 2 <= len(edge.points):
            painterPath.quadTo(edge.points[index + 1][0],
                               edge.points[index + 1][1],
                               edge.points[index + 2][0],
                               edge.points[index + 2][1])
            index = index + 2

        if index + 1 <= len(edge.points):
            painterPath.lineTo(edge.points[index + 1][0],
                               edge.points[index + 1][1])

        self.setPath(painterPath)
        return
예제 #3
0
    def __init__(self, edge):
        QGraphicsPathItem.__init__(self)
        self.__edge = edge

        startPoint = QPointF(edge.points[0][0], edge.points[0][1])
        painterPath = QPainterPath(startPoint)

        index = 1
        while index + 3 <= len(edge.points):
            painterPath.cubicTo(edge.points[index][0], edge.points[index][1],
                                edge.points[index + 1][0],
                                edge.points[index + 1][1],
                                edge.points[index + 2][0],
                                edge.points[index + 2][1])
            index = index + 3
        if index + 2 <= len(edge.points):
            painterPath.quadTo(edge.points[index + 1][0],
                               edge.points[index + 1][1],
                               edge.points[index + 2][0],
                               edge.points[index + 2][1])
            index = index + 2

        if index + 1 <= len(edge.points):
            painterPath.lineTo(edge.points[index + 1][0],
                               edge.points[index + 1][1])

        if edge.head != edge.tail:
            lastIndex = len(edge.points) - 1
            self.addArrow(painterPath, edge.points[lastIndex - 1][0],
                          edge.points[lastIndex - 1][1],
                          edge.points[lastIndex][0], edge.points[lastIndex][1])

        self.setPath(painterPath)
        return
예제 #4
0
    def calculateDatasets(self, scene, axes, datasets):
        """
        Builds the datasets for this renderer.  Each renderer will need to
        subclass and implemenent this method, otherwise, no data will be
        shown in the chart.
        
        :param      scene | <XChartScene>
                    axes | [<
                    datasets | [<XChartDataset>, ..]
        """
        items = self.calculateDatasetItems(scene, datasets)
        if not items:
            scene.clear()
            return

        rect = self.buildData('axis_rect')
        half_size = self.maximumBarSize() / 2.0

        for dataset, item in items.items():
            path = QPainterPath()
            subpaths = []

            for value in dataset.values():
                pos = self.pointAt(axes, value)

                radius = min(rect.bottom() - pos.y(), 8)

                subpath = QPainterPath()

                # create a vertical bar graph
                if self.orientation() == Qt.Vertical:
                    subpath.moveTo(pos.x() - half_size, rect.bottom())
                    subpath.lineTo(pos.x() - half_size, pos.y() + radius)
                    subpath.quadTo(pos.x() - half_size, pos.y(),
                                   pos.x() - half_size + radius, pos.y())
                    subpath.lineTo(pos.x() + half_size - radius, pos.y())
                    subpath.quadTo(pos.x() + half_size, pos.y(),
                                   pos.x() + half_size,
                                   pos.y() + radius)
                    subpath.lineTo(pos.x() + half_size, rect.bottom())
                    subpath.lineTo(pos.x() - half_size, rect.bottom())

                # create a horizontal bar graph
                else:
                    subpath.moveTo(rect.left(), pos.y() - half_size)
                    subpath.lineTo(pos.x(), pos.y() - half_size)
                    subpath.lineTo(pos.x(), pos.y() + half_size)
                    subpath.lineTo(rect.left(), pos.y() + half_size)
                    subpath.lineTo(rect.left(), pos.y() - half_size)

                path.addPath(subpath)
                subpaths.append(subpath)

            item.setPath(path)
            item.setBuildData('subpaths', subpaths)
예제 #5
0
 def calculateDatasets(self, scene, axes, datasets):
     """
     Builds the datasets for this renderer.  Each renderer will need to
     subclass and implemenent this method, otherwise, no data will be
     shown in the chart.
     
     :param      scene | <XChartScene>
                 axes | [<
                 datasets | [<XChartDataset>, ..]
     """
     items = self.calculateDatasetItems(scene, datasets)
     if not items:
         scene.clear()
         return
     
     rect = self.buildData('axis_rect')
     half_size = self.maximumBarSize() / 2.0
     
     for dataset, item in items.items():
         path = QPainterPath()
         subpaths = []
         
         for value in dataset.values():
             pos = self.pointAt(axes, value)
             
             radius = min(rect.bottom() - pos.y(), 8)
             
             subpath = QPainterPath()
             
             # create a vertical bar graph
             if self.orientation() == Qt.Vertical:
                 subpath.moveTo(pos.x() - half_size, rect.bottom())
                 subpath.lineTo(pos.x() - half_size, pos.y() + radius)
                 subpath.quadTo(pos.x() - half_size, pos.y(),
                                pos.x() - half_size + radius, pos.y())
                 subpath.lineTo(pos.x() + half_size - radius, pos.y())
                 subpath.quadTo(pos.x() + half_size, pos.y(),
                                pos.x() + half_size, pos.y() + radius)
                 subpath.lineTo(pos.x() + half_size, rect.bottom())
                 subpath.lineTo(pos.x() - half_size, rect.bottom())
             
             # create a horizontal bar graph
             else:
                 subpath.moveTo(rect.left(), pos.y() - half_size)
                 subpath.lineTo(pos.x(),     pos.y() - half_size)
                 subpath.lineTo(pos.x(),     pos.y() + half_size)
                 subpath.lineTo(rect.left(), pos.y() + half_size)
                 subpath.lineTo(rect.left(), pos.y() - half_size)
             
             path.addPath(subpath)
             subpaths.append(subpath)
         
         item.setPath(path)
         item.setBuildData('subpaths', subpaths)
예제 #6
0
 def rebuildSmooth( self ):
     """
     Rebuilds a smooth path based on the inputed points and set \
     parameters for this item.
     
     :return     <QPainterPath>
     """
     # collect the control points
     points = self.controlPoints()
     
     # create the path
     path = QPainterPath()
     
     if ( len(points) == 3 ):
         x0, y0 = points[0]
         x1, y1 = points[1]
         xN, yN = points[2]
         
         path.moveTo(x0, y0)
         path.quadTo(x1, y1, xN, yN)
     
     elif ( len(points) == 4 ):
         x0, y0 = points[0]
         x1, y1 = points[1]
         x2, y2 = points[2]
         xN, yN = points[3]
         
         path.moveTo(x0, y0)
         path.cubicTo(x1, y1, x2, y2, xN, yN)
         
     elif ( len(points) == 6 ):
         x0, y0 = points[0]
         x1, y1 = points[1]
         x2, y2 = points[2]
         x3, y3 = points[3]
         x4, y4 = points[4]
         xN, yN = points[5]
         
         xC      = (x2+x3) / 2.0
         yC      = (y2+y3) / 2.0
         
         path.moveTo(x0, y0)
         path.cubicTo(x1, y1, x2, y2, xC, yC)
         path.cubicTo(x3, y3, x4, y4, xN, yN)
         
     else:
         x0, y0 = points[0]
         xN, yN = points[-1]
         
         path.moveTo(x0, y0)
         path.lineTo(xN, yN)
     
     return path
예제 #7
0
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
예제 #8
0
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
예제 #9
0
    def rebuild(self):
        """
        Rebuilds the item based on the current points.
        """
        scene = self.scene()
        if not scene:
            return

        self._subpaths = []

        grid = scene.gridRect()
        typ = self.chartType()

        hruler = scene.horizontalRuler()
        vruler = scene.verticalRuler()

        path = QPainterPath()
        area = QPainterPath()

        self._buildData.clear()
        self._buildData['path_area'] = area

        self.setPos(0, 0)

        # draw a line item
        if typ == XChartScene.Type.Line:
            first = True
            pos = None
            home = None
            self._ellipses = []

            points = self.points()
            if (self.orientation() == Qt.Horizontal):
                points.sort(hruler.compareValues, key=lambda x: x[0])
            else:
                points.sort(vruler.compareValues, key=lambda y: y[1])
                points.reverse()

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                if first:
                    home = QPointF(pos.x(), grid.bottom())
                    area.moveTo(home)
                    area.lineTo(pos)
                    path.moveTo(pos)

                    self._ellipses.append(pos)

                    first = False
                else:
                    path.lineTo(pos)
                    area.lineTo(pos)

                    self._ellipses.append(pos)

            if pos and home:
                area.lineTo(pos.x(), grid.bottom())
                area.lineTo(home)

        # draw a bar item
        elif typ == XChartScene.Type.Bar:
            barsize = self.barSize()
            horiz = self.orientation() == Qt.Horizontal

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                subpath = QPainterPath()
                if horiz:
                    r = min(grid.bottom() - pos.y(), 8)

                    subpath.moveTo(pos.x() - barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, pos.y() + r)
                    subpath.quadTo(pos.x() - barsize / 2.0, pos.y(),
                                   pos.x() - barsize / 2.0 + r, pos.y())

                    subpath.lineTo(pos.x() + barsize / 2.0 - r, pos.y())
                    subpath.quadTo(pos.x() + barsize / 2.0, pos.y(),
                                   pos.x() + barsize / 2.0,
                                   pos.y() + r)

                    subpath.lineTo(pos.x() + barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, grid.bottom())
                else:
                    subpath.moveTo(grid.left(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() - barsize / 2.0)

                path.addPath(subpath)
                self._subpaths.append((x, y, subpath))

        # draw a pie chart
        elif typ == XChartScene.Type.Pie:
            if self.orientation() == Qt.Horizontal:
                key_index = 0
                value_index = 1
                value_ruler = self.verticalRuler()
            else:
                key_index = 1
                value_index = 0
                value_ruler = self.horizontalRuler()

            pie_values = {}

            for point in self.points():
                key = point[key_index]
                value = point[value_index]

                pie_values.setdefault(key, [])
                pie_values[key].append(value)

            for key, values in pie_values.items():
                pie_values[key] = value_ruler.calcTotal(values)

            total = max(1, value_ruler.calcTotal(pie_values.values()))

            # calculate drawing parameters
            center = self.pieCenter()
            radius = self.radius()
            diameter = radius * 2
            angle = 0
            bound = QRectF(-radius, -radius, diameter, diameter)

            for key, value in sorted(pie_values.items(), key=lambda x: x[1]):
                # calculate the percentage
                perc = float(value) / total

                # calculate the angle as the perc * 360
                item_angle = perc * 360
                self.setPos(center)

                sub_path = QPainterPath()
                sub_path.arcTo(bound, angle, item_angle)
                sub_path.lineTo(0, 0)

                path.addPath(sub_path)
                self._subpaths.append((key, value, sub_path))

                angle += item_angle

        self.setPath(path)
        self._dirty = False
    def drawClassicPath(self, v1, sepInput, v2, sepOutput, cl):
        """
        Trace d'un arc reliant les noeuds node1 et node2 dans le plan.
        Attention, puisque dans le plan de l'interface, l'axe des ordonnees est invere,
        mais pas l'axe des abscisses la rotation dans le sens trigonometrique et le sens horaire sont inverses.
        """

        # Il est conseille de prendre une feuille est un stylo pour dessiner en lisant les commentaires
        # de cette methode

        u = v2 - v1  # Vecteur reliant v1 à v2
        n = (u.rotate(pi / 2)).normalize()  # Vecteur unitaire perpendiculaire à u

        # Point sur la mediatrice de [v1,v2] situe a une distance cl
        # Il servira (presque) de point de controle pour les courbes de Beziers traçant les deux bords de l'arc.
        c = v1 + u / 2 + cl * n

        v1m1norm = (c - v1).normalize()  # Vecteur unitaire de la droite (v1,c), de v1 vers c
        v2m2norm = (c - v2).normalize()  # Vecteur unitaire de la droite (v2,c), de v2 vers c

        # m1 est le point du cercle node1 situé sur la droite (v1,c) entre ces deux points.
        # c'est également le milieu du départ de l'arc sur node1
        v1m1 = NodeItem.NodeWidth * v1m1norm  # Vecteur v1m1
        # Point sur le cercle node1 à une distance angulaire -alpha de m1
        m1m = v1 + v1m1.rotate(-ArcItem.endingsAlpha)
        # Point sur le cercle node1 à une distance angulaire alpha de m1
        m1p = v1 + v1m1.rotate(ArcItem.endingsAlpha)

        # m2 est le point du cercle node2 situé sur la droite (v2,c) entre ces deux points.
        # c'est également la pointe de la flêche de l'arc
        v2m2 = NodeItem.NodeWidth * v2m2norm  # Vecteur v2m2
        m2 = v2 + v2m2  # Point m2
        a2 = v2 + 2 * v2m2  # a2 est le milieu du segment central de la pointe de la flêche de l'arc
        # a2m est l'extrêmité droite de la pointe de la flêche
        a2m = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(-ArcItem.arrowBeta)
        # a2p est l'extrêmité gauche de la pointe de la flêche
        a2p = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(ArcItem.arrowBeta)
        # m2m est le point sur le cercle node2 à une distance angulaire -alpha de m2
        v2m2m = v2m2.rotate(-ArcItem.endingsAlpha)  # Vecteur v2 m2m
        # m2p est le point sur le cercle node2 à une distance angulaire alpha de m2
        v2m2p = v2m2.rotate(ArcItem.endingsAlpha)  # Vecteur v2 m2p
        # m2mp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2m parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2mp = a2 + v2m2m.project(a2m - a2)
        # m2pp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2p parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2pp = a2 + v2m2p.project(a2p - a2)

        w = (m1p - m1m).magnitude() / 2  # eviron la demi largeur de l'arc
        c1 = c - w * n  # point  de contrôle de la courbe de bézier du bord gauche de l'arc
        c2 = c + w * n  # point  de contrôle de la courbe de bézier du bord droit de l'arc

        # Tracé de l'arc
        path = QPainterPath()
        if sepInput:
            path.moveTo(v1.x + NodeItem.NodeWidth, v1.y)
            path.arcTo(v1.x - NodeItem.NodeWidth, v1.y - NodeItem.NodeWidth,
                           2 * NodeItem.NodeWidth, 2 * NodeItem.NodeWidth, 0, 360)
        path.moveTo(m1m.x, m1m.y)
        path.quadTo(c1.x, c1.y, m2pp.x, m2pp.y)
        path.lineTo(m2mp.x, m2mp.y)
        path.quadTo(c2.x, c2.y, m1p.x, m1p.y)
        path.closeSubpath()
        path.moveTo(m2.x, m2.y)
        path.lineTo(a2p.x, a2p.y)
        path.lineTo(a2m.x, a2m.y)
        path.closeSubpath()
        if sepOutput:
            path.moveTo(v2.x + NodeItem.NodeWidth, v2.y)
            path.arcTo(v2.x - NodeItem.NodeWidth, v2.y - NodeItem.NodeWidth,
                           2 * NodeItem.NodeWidth, 2 * NodeItem.NodeWidth, 0, 360)
        self.setPath(path)

        textCenter = v1 + u / 2  # position normale
        labelItem = self.getLabelItem()
        offset = 0.5 * cl * n
        labelItem.setArcVectorCenterAndOffset(u, textCenter, offset)
예제 #11
0
    def getXover(self, phg, strandtype, fromHelix,\
                       fromIndex, toHelix, toIndex):
        """
        Draws a line from the center of the fromBase (pA) to the
        top or bottom of that same base, depending on its direction (qA),
        then a quad curve to the top or bottom of the toBase (qB), and
        finally to the center of the toBase (pB).
        """
        # if we need to speed this up, we could keep track if pA changed?
        pA = QPointF(*fromHelix.baseLocation(strandtype,\
                                             fromIndex,\
                                             center=True))
        pA = phg.mapFromItem(fromHelix, pA)
        pB = QPointF(*toHelix.baseLocation(strandtype,\
                                           toIndex,\
                                           center=True))
        pB = phg.mapFromItem(toHelix, pB)
        yA = yB = self._baseWidth / 2
        if fromHelix.vhelix().directionOfStrandIs5to3(strandtype):
            orientA = HandleOrient.LeftUp
            yA = -yA
        else:
            orientA = HandleOrient.RightDown
        if toHelix.vhelix().directionOfStrandIs5to3(strandtype):
            orientB = HandleOrient.RightUp
            yB = -yB
        else:
            orientB = HandleOrient.LeftDown

        # Determine start and end points of quad curve
        qA = QPointF(pA.x(), pA.y() + yA)
        qB = QPointF(pB.x(), pB.y() + yB)

        # Determine control point of quad curve
        c1 = QPointF()
        # case 1: same strand
        if fromHelix.number() == toHelix.number():
            if pA.x() < pB.x():  # draw only from left
                if orientA == HandleOrient.LeftUp or \
                   orientA == HandleOrient.RightUp:
                    dx = abs(pB.x() - pA.x())
                    c1.setX(0.5 * (pA.x() + pB.x()))
                    c1.setY(pA.y() - self.yScale * dx)
                # end if
            # end if
        # case 2: same parity
        elif fromHelix.evenParity() == toHelix.evenParity():
            dy = abs(pB.y() - pA.y())
            c1.setX(pA.x() + self.xScale * dy)
            c1.setY(0.5 * (pA.y() + pB.y()))
        # case 3: default
        else:
            if orientA == HandleOrient.LeftUp:
                c1.setX(pA.x() - self.xScale * abs(pB.y() - pA.y()))
            else:
                c1.setX(pA.x() + self.xScale * abs(pB.y() - pA.y()))
            c1.setY(0.5 * (pA.y() + pB.y()))

        # Construct painter path
        painterpath = QPainterPath()
        painterpath.moveTo(pA)
        painterpath.lineTo(qA)
        painterpath.quadTo(c1, qB)
        painterpath.lineTo(pB)
        return painterpath