Exemple #1
0
 def drawScale(self, painter, center, radius):
     offset = 4.0
     p0 = self.qwtPolar2Pos(center, offset, 1.5 * M_PI)
     w = self.innerRect().width()
     path = QPainterPath()
     path.moveTo(Qwt.qwtPolar2Pos(p0, w, 0.0))
     path.lineTo(Qwt.qwtPolar2Pos(path.currentPosition(), 2 * w, M_PI))
     path.lineTo(Qwt.qwtPolar2Pos(path.currentPosition(), w, 0.5 * M_PI))
     path.lineTo(Qwt.qwtPolar2Pos(path.currentPosition(), w, 0.0))
     painter.save()
     painter.setClipPath(path)  # swallow 180 - 360 degrees
     Qwt.QwtDial.drawScale(painter, center, radius)
     painter.restore()
Exemple #2
0
    def paintEvent(self, event):
        # Draw backgrounds according to css
        styleOpt = QStyleOption()
        styleOpt.initFrom(self)
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)
        self.style().drawPrimitive(QStyle.PE_Widget, styleOpt, p, self)

        if self.values == None or len(self.values) == 0: return

        # print(len(self.values))

        r = self.rect()
        dx = r.width() / float(self.datapoints - 1)

        # Build a path from the readings
        path = QPainterPath()
        path.moveTo(r.bottomRight())
        i = 0
        for reading in reversed(self.values):
            pt = QPointF(r.width() - i*dx, (1.0 - reading) * r.height())
            path.lineTo(pt)
            i = i + 1
        path.lineTo(path.currentPosition().x(), r.height())
        path.closeSubpath()

        # Use foreground color for graph
        gcolor = styleOpt.palette.color(QPalette.Text)
        p.setBrush(gcolor)
        p.setPen(gcolor)
        p.drawPath(path)
Exemple #3
0
    def reshape(self):
        ''' Update the shape of the edge (redefined function) '''
        path = QPainterPath()
        # If there is a starting point, draw a line to the first curve point
        if self.start_point:
            path.moveTo(self.source_connection.center)
            path.lineTo(self.bezier[0])
        else:
            path.moveTo(self.source_connection.center)
        # Loop over the curve points:
        for group in self.bezier[1:]:
            path.cubicTo(*[point.center for point in group])

        # If there is an ending point, draw a line to it
        if self.end_point:
            path.lineTo(self.end_connection.center)

        end_point = path.currentPosition()
        arrowhead = self.angle_arrow(path)
        path.lineTo(arrowhead[0])
        path.moveTo(end_point)
        path.lineTo(arrowhead[1])
        path.moveTo(end_point)
        try:
            # Add the transition label, if any (none for the START edge)
            font = QFont('arial', pointSize=8)
            metrics = QFontMetrics(font)
            label = self.edge.get('label', '')
            lines = label.split('\n')
            width = metrics.width(max(lines)) # longest line
            height = metrics.height() * len(lines)
            # lp is the position of the center of the text
            pos = self.mapFromScene(*self.edge['lp'])
            if not self.text_label:
                self.text_label = QGraphicsTextItem(
                                 self.edge.get('label', ''), parent=self)
            self.text_label.setX(pos.x() - width / 2)
            self.text_label.setY(pos.y() - height / 2)
            self.text_label.setFont(font)
            # Make horizontal center alignment, as dot does
            self.text_label.setTextWidth(self.text_label.boundingRect().width())
            fmt = QTextBlockFormat()
            fmt.setAlignment(Qt.AlignHCenter)
            cursor = self.text_label.textCursor()
            cursor.select(QTextCursor.Document)
            cursor.mergeBlockFormat(fmt)
            cursor.clearSelection()
            self.text_label.setTextCursor(cursor)
            self.text_label.show()
        except KeyError:
            # no label
            pass
        self.setPath(path)
Exemple #4
0
class SortingBox(QWidget):
    circle_count = square_count = triangle_count = 1

    def __init__(self):
        super(SortingBox, self).__init__()

        self.circlePath = QPainterPath()
        self.squarePath = QPainterPath()
        self.trianglePath = QPainterPath()
        self.shapeItems = []

        self.previousPosition = QPoint()

        self.setMouseTracking(True)
        self.setBackgroundRole(QPalette.Base)

        self.itemInMotion = None

        self.newCircleButton = self.createToolButton(
            "New Circle", QIcon(':/images/circle.png'), self.createNewCircle)
        self.newSquareButton = self.createToolButton(
            "New Square", QIcon(':/images/square.png'), self.createNewSquare)
        self.newTriangleButton = self.createToolButton(
            "New Triangle", QIcon(':/images/triangle.png'),
            self.createNewTriangle)

        self.circlePath.addEllipse(0, 0, 100, 100)
        self.squarePath.addRect(0, 0, 100, 100)

        x = self.trianglePath.currentPosition().x()
        y = self.trianglePath.currentPosition().y()
        self.trianglePath.moveTo(x + 120 / 2, y)
        self.trianglePath.lineTo(0, 100)
        self.trianglePath.lineTo(120, 100)
        self.trianglePath.lineTo(x + 120 / 2, y)

        self.setWindowTitle("Tooltips")
        self.resize(500, 300)

        self.createShapeItem(self.circlePath, "Circle",
                             self.initialItemPosition(self.circlePath),
                             self.initialItemColor())
        self.createShapeItem(self.squarePath, "Square",
                             self.initialItemPosition(self.squarePath),
                             self.initialItemColor())
        self.createShapeItem(self.trianglePath, "Triangle",
                             self.initialItemPosition(self.trianglePath),
                             self.initialItemColor())

    def event(self, event):
        if event.type() == QEvent.ToolTip:
            helpEvent = event
            index = self.itemAt(helpEvent.pos())
            if index != -1:
                QToolTip.showText(helpEvent.globalPos(),
                                  self.shapeItems[index].toolTip())
            else:
                QToolTip.hideText()
                event.ignore()

            return True

        return super(SortingBox, self).event(event)

    def resizeEvent(self, event):
        margin = self.style().pixelMetric(QStyle.PM_DefaultTopLevelMargin)
        x = self.width() - margin
        y = self.height() - margin

        y = self.updateButtonGeometry(self.newCircleButton, x, y)
        y = self.updateButtonGeometry(self.newSquareButton, x, y)
        self.updateButtonGeometry(self.newTriangleButton, x, y)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        for shapeItem in self.shapeItems:
            painter.translate(shapeItem.position())
            painter.setBrush(shapeItem.color())
            painter.draw_path(shapeItem.path())
            painter.translate(-shapeItem.position())

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            index = self.itemAt(event.pos())
            if index != -1:
                self.itemInMotion = self.shapeItems[index]
                self.previousPosition = event.pos()

                value = self.shapeItems[index]
                del self.shapeItems[index]
                self.shapeItems.insert(len(self.shapeItems) - 1, value)

                self.update()

    def mouseMoveEvent(self, event):
        if (event.buttons() & Qt.LeftButton) and self.itemInMotion:
            self.moveItemTo(event.pos())

    def mouseReleaseEvent(self, event):
        if (event.button() == Qt.LeftButton) and self.itemInMotion:
            self.moveItemTo(event.pos())
            self.itemInMotion = None

    def createNewCircle(self):
        SortingBox.circle_count += 1
        self.createShapeItem(self.circlePath,
                             "Circle <%d>" % SortingBox.circle_count,
                             self.randomItemPosition(), self.randomItemColor())

    def createNewSquare(self):
        SortingBox.square_count += 1
        self.createShapeItem(self.squarePath,
                             "Square <%d>" % SortingBox.square_count,
                             self.randomItemPosition(), self.randomItemColor())

    def createNewTriangle(self):
        SortingBox.triangle_count += 1
        self.createShapeItem(self.trianglePath,
                             "Triangle <%d>" % SortingBox.triangle_count,
                             self.randomItemPosition(), self.randomItemColor())

    def itemAt(self, pos):
        for i in range(len(self.shapeItems) - 1, -1, -1):
            item = self.shapeItems[i]
            if item.path().contains(QPointF(pos - item.position())):
                return i

        return -1

    def moveItemTo(self, pos):
        offset = pos - self.previousPosition
        self.itemInMotion.setPosition(self.itemInMotion.position() + offset)
        self.previousPosition = QPoint(pos)
        self.update()

    def updateButtonGeometry(self, button, x, y):
        size = button.sizeHint()
        button.setGeometry(x - size.width(), y - size.height(), size.width(),
                           size.height())

        return y - size.height() - self.style().pixelMetric(
            QStyle.PM_DefaultLayoutSpacing)

    def createShapeItem(self, path, toolTip, pos, color):
        shapeItem = ShapeItem()
        shapeItem.setPath(path)
        shapeItem.setToolTip(toolTip)
        shapeItem.setPosition(pos)
        shapeItem.setColor(color)
        self.shapeItems.append(shapeItem)
        self.update()

    def createToolButton(self, toolTip, icon, member):
        button = QToolButton(self)
        button.setToolTip(toolTip)
        button.setIcon(icon)
        button.setIconSize(QSize(32, 32))
        button.clicked.connect(member)

        return button

    def initialItemPosition(self, path):
        y = (self.height() - path.controlPointRect().height()) / 2

        if len(self.shapeItems) == 0:
            x = ((3 * self.width()) / 2 - path.controlPointRect().width()) / 2
        else:
            x = (self.width() / len(self.shapeItems) -
                 path.controlPointRect().width()) / 2

        return QPoint(x, y)

    def randomItemPosition(self):
        x = random.randint(0, self.width() - 120)
        y = random.randint(0, self.height() - 120)

        return QPoint(x, y)

    def initialItemColor(self):
        hue = ((len(self.shapeItems) + 1) * 85) % 256
        return QColor.fromHsv(hue, 255, 190)

    def randomItemColor(self):
        return QColor.fromHsv(random.randint(0, 256), 255, 190)
Exemple #5
0
class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):

        self.circlePath = QPainterPath()
        self.squarePath = QPainterPath()
        self.trianglePath = QPainterPath()
        self.pentagonPath = QPainterPath()
        self.shapes = []

        self.circlePath.addEllipse(30, 50, 100, 100)
        self.squarePath.addRect(180, 50, 100, 100)

        x = self.trianglePath.currentPosition().x()
        y = self.trianglePath.currentPosition().y()

        self.trianglePath.moveTo(320, 150)
        self.trianglePath.lineTo(450, 150)
        self.trianglePath.lineTo(415, 50)
        self.trianglePath.lineTo(320, 150)

        polygon = QPolygonF()
        polygon.append(QPoint(130, 240))
        polygon.append(QPoint(100, 280))
        polygon.append(QPoint(50, 280))
        polygon.append(QPoint(20, 240))
        polygon.append(QPoint(75, 200))

        self.pentagonPath.addPolygon(polygon)

        self.createShape(self.circlePath, 'Circle', QColor('#c72602'))
        self.createShape(self.squarePath, 'Square', QColor('#32a852'))
        self.createShape(self.trianglePath, 'Triangle', QColor('#205f6e'))
        self.createShape(self.pentagonPath, 'Pentagon', QColor('#e0b107'))

        self.setWindowTitle('Shapes')
        self.resize(480, 300)
        self.show()

    def event(self, e):

        if e.type() == QEvent.ToolTip:

            index = self.itemIndexAt(e.pos())

            if index != -1:
                QToolTip.showText(e.globalPos(), self.shapes[index].toolTip())
            else:
                QToolTip.hideText()
                e.ignore()

            return True

        return super(Example, self).event(e)

    def paintEvent(self, e):

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)

        for shape in self.shapes:

            painter.setBrush(shape.color())
            painter.drawPath(shape.path())

    def itemIndexAt(self, pos):

        for i in range(len(self.shapes)):

            item = self.shapes[i]

            if item.path().contains(QPointF(pos)):

                return i

        return -1

    def createShape(self, path, toolTip, color):

        shape = Shape()
        shape.setPath(path)
        shape.setToolTip(toolTip)
        shape.setColor(color)

        self.shapes.append(shape)
Exemple #6
0
    def paintEvent(self, evt):
        x1 = QPoint(0, -70)
        x2 = QPoint(0, -90)
        x3 = QPoint(-90, 0)
        x4 = QPoint(-70, 0)
        extRect = QRectF(-90, -90, 180, 180)
        intRect = QRectF(-70, -70, 140, 140)
        midRect = QRectF(-44, -80, 160, 160)
        unitRect = QRectF(-50, 60, 110, 50)

        speedInt = self.speed
        #speedDec = (self.speed * 10.0) - (speedInt * 10)
        s_SpeedInt = speedInt.__str__()[0:4]

        powerAngle = self.power * 270.0 / 100.0

        dummyPath = QPainterPath()
        dummyPath.moveTo(x1)
        dummyPath.arcMoveTo(intRect, 90 - powerAngle)
        powerPath = QPainterPath()
        powerPath.moveTo(x1)
        powerPath.lineTo(x2)
        powerPath.arcTo(extRect, 90, -1 * powerAngle)
        powerPath.lineTo(dummyPath.currentPosition())
        powerPath.arcTo(intRect, 90 - powerAngle, powerAngle)

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        side = min(self.width(), self.height())
        painter.scale(side / 200.0, side / 200.0)

        painter.save()
        painter.rotate(-135)

        if self.displayPowerPath:
            externalPath = QPainterPath()
            externalPath.moveTo(x1)
            externalPath.lineTo(x2)
            externalPath.arcTo(extRect, 90, -270)
            externalPath.lineTo(x4)
            externalPath.arcTo(intRect, 180, 270)

            painter.setPen(self.powerPathColor)
            painter.drawPath(externalPath)

        painter.setBrush(self.powerGradient)
        painter.setPen(Qt.NoPen)
        painter.drawPath(powerPath)
        painter.restore()
        painter.save()

        painter.translate(QPointF(0, -50))

        painter.setPen(self.unitTextColor)
        fontFamily = self.font().family()
        unitFont = QFont(fontFamily, 9)
        painter.setFont(unitFont)
        painter.drawText(unitRect, Qt.AlignCenter, "{}".format(self.unit))

        painter.restore()

        painter.setPen(self.unitTextColor)
        fontFamily = self.font().family()
        unitFont = QFont(fontFamily, 12)
        painter.setFont(unitFont)
        painter.drawText(unitRect, Qt.AlignCenter, "{}".format(self.title))

        speedColor = QColor(0, 0, 0)
        speedFont = QFont(fontFamily, 30)
        fm1 = QFontMetrics(speedFont)
        speedWidth = fm1.width(s_SpeedInt)

        #speedDecFont = QFont(fontFamily, 23)
        #fm2 = QFontMetrics(speedDecFont)
        #speedDecWidth = fm2.width(s_SpeedDec)

        leftPos = -1 * speedWidth + 40
        leftDecPos = leftPos + speedWidth
        topPos = 10
        topDecPos = 10
        painter.setPen(self.speedTextColor)
        painter.setFont(speedFont)
        painter.drawText(leftPos, topPos, s_SpeedInt)
Exemple #7
0
def svgToPath(filename):
    """Return QPainterPath instance from an svg file.
       No colors will be included. If the file contains multiple paths,
       they will be connected to form one single path.
       It will also return a boolean indicates if the path is closed or not."""
    path = QPainterPath()
    info = findPath(filename)
    start = QPointF(0, 0)
    last_cp = start     # last control point, for S cubic bezier curve.
    last_qp = start     # last control point, for T quadratic bezier curve.
    for idx in range(len(info)):
        line = info[idx]
        cmd = line[0]
        if (cmd.upper() == 'Z'):
            path.closeSubpath()
            continue

        coords = re.split(r'\s+|,|(?<=\d)(?=-)', line[1])
        if (cmd.upper() == 'V'):
            # only last coordinate matters.
            coord = eval(coords[-1])
            verticalLineTo(path, coord, cmd)
            continue

        if (cmd.upper() == 'H'):
            # only last coordinate matters.
            coord = eval(coords[-1])
            horizontalLineTo(path, coord, cmd)
            continue

        # pair two values into one
        coords = [x+','+y for x, y in zip(coords[::2], coords[1::2])]
        coords = list(map(getPoint, coords))

        if (cmd.upper() == 'M'):
            # if m is at the start of the path
            if (line == info[0]):
                start = coords[0]
                moveTo(path, start, 'M')
            # m is not at the start of the path
            else:
                path.closeSubpath()
                lineTo(path, coords[0], cmd)
            for i in range(1, len(coords)):
                lineTo(path, coords[i], cmd)
            continue

        if (cmd.upper() == 'L'):
            for coord in coords:
                lineTo(path, coord, cmd)
            continue

        if (cmd.upper() == 'C'):
            for i in range(len(coords)//3):
                # Saving coordinates for smoothcurve command
                last_cp = cubicTo(path, *coords[i*3:i*3+3], absolute=cmd)
            continue

        if (cmd.upper() == 'S'):
            if not (info[idx-1][0].upper() in 'SC'):
                last_cp = path.currentPoint()
            for i in range(len(coords)//2):
                last_cp = smoothCubicTo(path, last_cp,
                                        *coords[i*2:i*2+2], absolute=cmd)
            continue

        if (cmd.upper() == 'Q'):
            for i in range(len(coords)//2):
                # Saving coordinates for T smooth curve command
                last_qp = quadTo(path, *coords[i*2:i*2+2], absolute=cmd)
            continue

        if (cmd.upper() == 'T'):
            if not (info[idx-1][0].upper() in 'QT'):
                last_qp = path.currentPoint()
            for coord in coords:
                last_qp = smoothQuadTo(path, last_qp, coord, absolute=cmd)
            continue
        raise Exception('svg file contains command {}, which is not supported'
                        .format(cmd))

    closed = True
    if ((abs((path.currentPosition() - start).x()) > 1) and
       (abs((path.currentPosition() - start).y()) > 1)):
        closed = False
    path.translate(-start)
    path.translate(-path.boundingRect().center())
    return path, closed
Exemple #8
0
class SortingBox(QWidget):
    circle_count = square_count = triangle_count = 1

    def __init__(self,parent=None):
        super().__init__(parent)

        self.circlePath = QPainterPath()
        self.squarePath = QPainterPath()
        self.trianglePath = QPainterPath()
        self.shapeItems = []

        self.previousPosition = QPoint()

        self.setMouseTracking(True)
        self.setBackgroundRole(QPalette.Base)

        self.itemInMotion = None

        self.newCircleButton = self.createToolButton("New Circle",
                QIcon(':/images/circle.png'), self.createNewCircle)
        self.newSquareButton = self.createToolButton("New Square",
                QIcon(':/images/square.png'), self.createNewSquare)
        self.newTriangleButton = self.createToolButton("New Triangle",
                QIcon(':/images/triangle.png'), self.createNewTriangle)

        self.circlePath.addEllipse(0, 0, 100, 100)
        self.squarePath.addRect(0, 0, 100, 100)

        x = self.trianglePath.currentPosition().x()
        y = self.trianglePath.currentPosition().y()
        self.trianglePath.moveTo(x + 120 / 2, y)
        self.trianglePath.lineTo(0, 100)
        self.trianglePath.lineTo(120, 100)
        self.trianglePath.lineTo(x + 120 / 2, y)

        self.setWindowTitle("Tooltips")
        self.resize(500, 300)

        self.createShapeItem(self.circlePath, "Circle",
                self.initialItemPosition(self.circlePath),
                self.initialItemColor())
        self.createShapeItem(self.squarePath, "Square",
                self.initialItemPosition(self.squarePath),
                self.initialItemColor())
        self.createShapeItem(self.trianglePath, "Triangle",
                self.initialItemPosition(self.trianglePath),
                self.initialItemColor())

    def event(self, event):
        if event.type() == QEvent.ToolTip:
            helpEvent = event
            index = self.itemAt(helpEvent.pos())
            if index != -1:
                QToolTip.showText(helpEvent.globalPos(),
                        self.shapeItems[index].toolTip())
            else:
                QToolTip.hideText()
                event.ignore()

            return True

        return super(SortingBox, self).event(event)

    def resizeEvent(self, event):
        margin = self.style().pixelMetric(QStyle.PM_DefaultTopLevelMargin)
        x = self.width() - margin
        y = self.height() - margin

        y = self.updateButtonGeometry(self.newCircleButton, x, y)
        y = self.updateButtonGeometry(self.newSquareButton, x, y)
        self.updateButtonGeometry(self.newTriangleButton, x, y)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        for shapeItem in self.shapeItems:
            painter.translate(shapeItem.position())
            painter.setBrush(shapeItem.color())
            painter.drawPath(shapeItem.path())
            painter.translate(-shapeItem.position())

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            index = self.itemAt(event.pos())
            if index != -1:
                self.itemInMotion = self.shapeItems[index]
                self.previousPosition = event.pos()

                value = self.shapeItems[index]
                del self.shapeItems[index]
                self.shapeItems.insert(len(self.shapeItems) - 1, value)

                self.update()

    def mouseMoveEvent(self, event):
        if (event.buttons() & Qt.LeftButton) and self.itemInMotion:
            self.moveItemTo(event.pos())

    def mouseReleaseEvent(self, event):
        if (event.button() == Qt.LeftButton) and self.itemInMotion:
            self.moveItemTo(event.pos())
            self.itemInMotion = None

    def createNewCircle(self):
        SortingBox.circle_count += 1
        self.createShapeItem(self.circlePath,
                "Circle <%d>" % SortingBox.circle_count,
                self.randomItemPosition(), self.randomItemColor())

    def createNewSquare(self):
        SortingBox.square_count += 1
        self.createShapeItem(self.squarePath,
                "Square <%d>" % SortingBox.square_count,
                self.randomItemPosition(), self.randomItemColor())

    def createNewTriangle(self):
        SortingBox.triangle_count += 1
        self.createShapeItem(self.trianglePath,
                "Triangle <%d>" % SortingBox.triangle_count,
                self.randomItemPosition(), self.randomItemColor())

    def itemAt(self, pos):
        for i in range(len(self.shapeItems) - 1, -1, -1):
            item = self.shapeItems[i]
            if item.path().contains(QPointF(pos - item.position())):
                return i

        return -1

    def moveItemTo(self, pos):
        offset = pos - self.previousPosition
        self.itemInMotion.setPosition(self.itemInMotion.position() + offset)
        self.previousPosition = QPoint(pos)
        self.update()

    def updateButtonGeometry(self, button, x, y):
        size = button.sizeHint()
        button.setGeometry(x - size.width(), y - size.height(),
                size.width(), size.height())

        return y - size.height() - self.style().pixelMetric(QStyle.PM_DefaultLayoutSpacing)

    def createShapeItem(self, path, toolTip, pos, color):
        shapeItem = ShapeItem()
        shapeItem.setPath(path)
        shapeItem.setToolTip(toolTip)
        shapeItem.setPosition(pos)
        shapeItem.setColor(color)
        self.shapeItems.append(shapeItem)
        self.update()

    def createToolButton(self, toolTip, icon, member):
        button = QToolButton(self)
        button.setToolTip(toolTip)
        button.setIcon(icon)
        button.setIconSize(QSize(32, 32))
        button.clicked.connect(member)

        return button

    def initialItemPosition(self, path):
        y = (self.height() - path.controlPointRect().height()) / 2

        if len(self.shapeItems) == 0:
            x = ((3 * self.width()) / 2 - path.controlPointRect().width()) / 2
        else:
            x = (self.width() / len(self.shapeItems) - path.controlPointRect().width()) / 2

        return QPoint(x, y)

    def randomItemPosition(self):
        x = random.randint(0, self.width() - 120)
        y = random.randint(0, self.height() - 120)

        return QPoint(x, y)

    def initialItemColor(self):
        hue = ((len(self.shapeItems) + 1) * 85) % 256
        return QColor.fromHsv(hue, 255, 190)

    def randomItemColor(self):
        return QColor.fromHsv(random.randint(0, 256), 255, 190)
Exemple #9
0
    def create_path(self, start_point, end_point, directed):
        """Creeaza path-ul muchiei

        Path-ul muchiei este o curba Bezier. In cazul in care nici-un nod nu se intersecteaza
        cu path-ul direct dintre noduri, punctele de control ale curbei vor fi la centrul de
        greutate al dreptei date de cele 2 noduri, astfel creeandu-se o linie dreapta. In caz contrar,
        daca un nod se intersecteaza cu path-ul direct, pucntele de control ale curbei se vor situa pe
        dreapta perpendiculara pe path-ul direct, ce trece centrul de greutate al acestuia
        (dat de punctul de control initial) la o distanta egala dublul razei nodului. Aceste pucnte
        se pot situa in 2 pozitii, una la 'stanga' path-ului, iar cealalta la 'dreaptea' acestuia.
        Pozitia finala a punctului de control se determina 'trasand' 2 linii de la nodul care se
        intersecteaza la cele 2 posibile puncte de control. Verificand lungimea celor 2 linii
        se alege locatia punctului de control.

        panta dreptei : m = (y2 - y1) / (x2 - x1)
        ecuatia dreptei : y - y1 = m(x - x1)
        panta drepntei perpendiculare pe o dreapta : m' = -1 / m
        lungimea unei drepte : AB ^ 2 = (x2 - x1) ^ 2 + (y2 - y1) ^ 2

        => primul pas pentru a afla pucntele de control in cazul unei intersectii este:
        de a calula panta dreptei perpendiculara pe path-ul direct
            => m' = -1 / (node2.y - node1.y) / (node2.x - node1.x)
                => m' = -1 * (node2.x - node1.x) / (node2.y - node1.y)
        => cel de-al doilea pas este calcularea ecuatiei dreptei de panta m' ce trece prin pucntul de control (not G)
            => y - G.y = m'(x - G.x) => y = m'(x - G.x) + G.y
        => cel de-al treilea pas este inlocuirea lui y in lungimea dreptei ( lungimea dreptei dorita este dublul razei
            nodului) pentru a afla cele 2 coordonate x posibile (la 'stanga' si la 'dreapta' path-ului direct)
            => (x2 - G.x) ^ 2 + (m'(x2 - G.x) + G.y - G.y) ^ 2 = (2raza) ^ 2
            => x2 ^ 2 - 2 x2 G.x + G.x ^ 2 + (m' x2) ^ 2 - 2 (m' ^ 2) x2 G.x + (m' G.x) ^ 2 - (2raza) ^ 2 = 0
            => (x2 ^ 2)(1 + m' ^ 2) + x2(2 G.x (1 + m' ^ 2)) + (G.x ^ 2)(1 + m' ^ 2) - (2raza) ^ 2 = 0
                => cele 2 coordonate pe Ox ale punctului de control, prentu a afla cele 2 coordonate pe Oy
                se inlocuiesc valorie obtinute in ecuatia dreptei.


        Parametrii
        ----------
        start_point : QPointF
            punctul de start al path-ului
        end_point : QPointF
            punctul de final al path-ului
        directed : bool
            orientarea grafului

        Returneaza
        ----------
        path : QPainterPath
            path-ul final al muchiei
        """

        # Centrul de greutate al dreptei formata de cele 2 noduri
        control_point = QPointF((start_point.x() + end_point.x()) / 2,
                                (start_point.y() + end_point.y()) / 2)

        path = QPainterPath(start_point)
        node_radius = self.engine.node_radius
        point1 = point2 = None

        # Creearea path-ului direct
        _path = QPainterPath(start_point)
        _path.lineTo(end_point)
        self.direct_path.setPath(_path)

        # Verificarea pentru intersectii cu path-ul direct
        intersecting_items = self.engine.view.scene.collidingItems(
            self.direct_path)
        intersecting_items.remove(self.node1)
        intersecting_items.remove(self.node2)

        # Calcularea coordonatelor pe Ox a punctelor de control in cazul unei intersectii
        try:
            m = -1 * (self.node2.x() - self.node1.x()) / (self.node2.y() -
                                                          self.node1.y())
            agent = 1 + (m**2)
            factors = [
                agent, -2 * control_point.x() * agent,
                (control_point.x()**2) * agent - (node_radius * 2)**2
            ]
            roots = np.roots(factors)
        # In cazul in care nodurile au acceleasi coordonate pe Ox sau Oy panta
        # dreptei nu exista. Atunci se va trata cazul de ZeroDivisionError
        except ZeroDivisionError:
            point1 = control_point + QPointF(0, node_radius * 2)
            point2 = control_point - QPointF(0, node_radius * 2)

        for item in intersecting_items:
            if isinstance(item, Node):
                # Daca exista o intersectie si exista si panta dreptei atunci se calculeaza
                # si coordonatele pe Oy ale posibilelor puncte de control
                if (point1 and point2) is None:
                    point1 = QPointF(
                        roots[0],
                        m * (roots[0] - control_point.x()) + control_point.y())
                    point2 = QPointF(
                        roots[1],
                        m * (roots[1] - control_point.x()) + control_point.y())
                # Cele 2 linii de la nod la posibilele puncte de control
                line1 = QLineF(item.pos(), point1)
                line2 = QLineF(item.pos(), point2)
                # Daca lungimea primei linii este mai mica decat lungimea celei de-a doua linie
                # inseamna ca nodul este mai aproape de prima linie deci path-ul va trebui sa se
                # curbeze in partea opusa => se alege cel de-al doilea punct
                control_point = point2 if line1.length() <= line2.length(
                ) else point1
                break

        # Creearea curbei Bezier
        path.cubicTo(control_point, control_point, end_point)

        # Daca graful este orientat se adauga la capatul muchiei o sageata pentru
        # a reprezenta orientarea acestuia
        if directed:
            pos = path.currentPosition()
            dx, dy, angle = self.engine.get_angle(control_point, end_point)

            path.lineTo(
                QPointF(pos.x() + self.arrow_length * math.cos(angle + 60),
                        pos.y() + self.arrow_length * math.sin(angle + 60)))
            path.moveTo(end_point)
            path.lineTo(
                QPointF(pos.x() + self.arrow_length * math.cos(angle - 60),
                        pos.y() + self.arrow_length * math.sin(angle - 60)))

        # In cazul in care muchia are un cost acesta va fi afisat la mijlocul muchiei
        font_metrics = QFontMetrics(TEXT_FONT)
        font_offset = QPointF(font_metrics.height(),
                              font_metrics.horizontalAdvance(self.cost))
        path.addText(control_point - font_offset / 2, TEXT_FONT, self.cost)

        return path