Arc in QGraphicsScene

前端 未结 2 839
梦如初夏
梦如初夏 2020-12-04 00:37

I want to implement arc in QGraphicsScene. I want that on clicking of three points my arc should be drawn such that on clicking of three points arc is drawn where first poin

相关标签:
2条回答
  • 2020-12-04 01:24

    This sounds like it could be solved with some relatively simple math:

    https://www.google.com/search?q=define%20circle%20three%20points

    https://math.stackexchange.com/a/213678

    https://www.khanacademy.org/math/geometry/triangle-properties/perpendicular_bisectors/v/three-points-defining-a-circle

    Here is my translation of the math into Qt goodness

    // m_points is a QList<QPointF>
    // use math to define the circle
    QLineF lineBC(m_points.at(1), m_points.at(2));
    QLineF lineAC(m_points.at(0), m_points.at(2));
    QLineF lineBA(m_points.at(1), m_points.at(0));
    qreal rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
    
    QLineF bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
    bisectorBC.setAngle(lineBC.normalVector().angle());
    
    QLineF bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
    bisectorBA.setAngle(lineBA.normalVector().angle());
    
    QPointF center;
    bisectorBA.intersect(bisectorBC, &center);
    
    qDebug() << rad << center;
    

    QT QGraphicsScene Drawing Arc

    QPainterPath* path = new QPainterPath();
    path->arcMoveTo(0,0,50,50,20);
    path->arcTo(0,0,50,50,20, 90);
    scene.addPath(*path);
    

    Putting all of this together into a nice little project turns into this:

    https://github.com/peteristhegreat/ThreePointsCircle

    qt graphics scene three points circle

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include "graphicsscene.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        QGraphicsView * view = new QGraphicsView;
    
        GraphicsScene * scene = new GraphicsScene();
        view->setScene(scene);
    
        view->setSceneRect(-300,-300, 300, 300);
        this->resize(600, 600);
    
        this->setCentralWidget(view);
    }
    
    MainWindow::~MainWindow()
    {
    
    }
    

    graphicsscene.h

    #ifndef GRAPHICSSCENE_H
    #define GRAPHICSSCENE_H
    
    #include <QGraphicsScene>
    #include <QGraphicsSceneMouseEvent>
    #include <QPointF>
    #include <QList>
    
    class GraphicsScene : public QGraphicsScene
    {
        Q_OBJECT
    public:
        explicit GraphicsScene(QObject *parent = 0);
        virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent);
        virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
        virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
        virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
    signals:
    
    public slots:
    
    private:
        QList <QPointF> m_points;
    };
    
    #endif // GRAPHICSSCENE_H
    

    graphicsscene.cpp

    #include "graphicsscene.h"
    #include <QDebug>
    #include <QGraphicsEllipseItem>
    #include <QGraphicsPathItem>
    #include <QPainterPath>
    #include "qmath.h"
    
    GraphicsScene::GraphicsScene(QObject *parent) :
        QGraphicsScene(parent)
    {
        this->setBackgroundBrush(Qt::gray);
    }
    
    void GraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)
    {
        qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
        QGraphicsScene::mouseDoubleClickEvent(mouseEvent);
    }
    
    void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
    {
        qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
        QGraphicsScene::mouseMoveEvent(mouseEvent);
    }
    
    void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
    {
        qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
        QGraphicsScene::mousePressEvent(mouseEvent);
    }
    
    void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * me)
    {
        qDebug() << Q_FUNC_INFO << me->scenePos();
        int radius = 20;
        QGraphicsEllipseItem * ellipse = this->addEllipse(me->scenePos().x() - radius, me->scenePos().y() - radius, radius*2, radius*2);
    
        ellipse->setBrush(Qt::white);
        m_points.append(me->scenePos());
        if(m_points.size() == 3)
        {
            // use math to define the circle
            QLineF lineBC(m_points.at(1), m_points.at(2));
            QLineF lineAC(m_points.at(0), m_points.at(2));
            QLineF lineBA(m_points.at(1), m_points.at(0));
            qreal rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
    
            QLineF bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
            bisectorBC.setAngle(lineBC.normalVector().angle());
    
            QLineF bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
            bisectorBA.setAngle(lineBA.normalVector().angle());
    
            QPointF center;
            bisectorBA.intersect(bisectorBC, &center);
    
            qDebug() << rad << center;
    
            bool drawCircle = true;
    
            QGraphicsEllipseItem * ellipse = new QGraphicsEllipseItem(center.x() - rad, center.y() - rad, rad*2, rad*2);
            if(drawCircle)
                this->addItem(ellipse);
    
            // add arc
            // this->addItem(path);
            QPainterPath path;
            QLineF lineOA(center, m_points.at(0));
            QLineF lineOC(center, m_points.at(2));
            path.arcMoveTo(ellipse->boundingRect(),lineOA.angle());
            path.arcTo(ellipse->boundingRect(), lineOA.angle(), lineOC.angle() - lineOA.angle());
            QGraphicsPathItem * pathItem = new QGraphicsPathItem(path);
            pathItem->setPen(QPen(Qt::red,10));
            this->addItem(pathItem);
    
            if(!drawCircle)
                delete ellipse;
            m_points.clear();
        }
    
        QGraphicsScene::mouseReleaseEvent(me);
    }
    
    0 讨论(0)
  • 2020-12-04 01:32

    A Subclass of QGraphicsItem, that takes 3 points, and intersects the three with an arc of a circle. The second point is always in the middle. (Selectablity and other properties haven't been fully implemented or tested).

    Note: Qt Creator includes more advanced examples of subclassed QGraphicsItems such as Colliding Mice, and 40,000 chips examples.

    http://qt-project.org/doc/qt-5/examples-graphicsview.html

    Also to enable QObject signals and slots and properties from a QGraphicsItem, you should use QGraphicsObject.

    Note: added onto github here.

    arcgraphicsitem.h

    #ifndef ARCGRAPHICSITEM_H
    #define ARCGRAPHICSITEM_H
    
    #include <QGraphicsItem>
    #include <QLineF>
    #include <QPointF>
    #include <QPainter>
    #include <QStyleOptionGraphicsItem>
    #include <QWidget>
    
    class ArcGraphicsItem : public QGraphicsItem
    {
    
    public:
        ArcGraphicsItem();
        ArcGraphicsItem(int i, QPointF point0, QPointF point1, QPointF point2);
        ~ArcGraphicsItem();
    
        QRectF boundingRect() const;
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    
        int type() const { return Type;}
        int id() {return m_id;}
    
        QPainterPath shape() const;
    protected:
    
    private:
        void init();
    
        enum { Type = UserType + 6 };
        int m_id;
    
        QPointF startP, midP, endP, p1, p2, p3, center;
        QLineF lineBC;
        QLineF lineAC;
        QLineF lineBA;
        QLineF lineOA;
        QLineF lineOB;
        QLineF lineOC;
        QLineF bisectorBC;
        QLineF bisectorBA;
        qreal startAngle;
        qreal spanAngle;
    
        QRectF circle;
        QRectF boundingRectTemp;
        qreal rad;
    };
    
    #endif // ARCGRAPHICSITEM_H
    

    arcgraphicsitem.cpp

    #include "arcgraphicsitem.h"
    #include "qmath.h"
    #include <QPen>
    #include <QDebug>
    #include <QPainterPath>
    
    ArcGraphicsItem::ArcGraphicsItem(int i,
                                     QPointF point1,
                                     QPointF point2,
                                     QPointF point3)
        : m_id(i), p1(point1), p2(point2), p3(point3)
    
    {
        init();
    }
    
    
    ArcGraphicsItem::ArcGraphicsItem()
    {
        p1 = QPointF(0,0);
        p2 = QPointF(0,1);
        p3 = QPointF(1,1);
        m_id = -1;
        init();
    }
    
    ArcGraphicsItem::~ArcGraphicsItem()
    {
    
    }
    
    void ArcGraphicsItem::init()
    {
        lineBC = QLineF(p2, p3);
        lineAC = QLineF(p1, p3);
        lineBA = QLineF(p2, p1);
    
        rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
    
        bisectorBC = QLineF(lineBC.pointAt(0.5), lineBC.p2());
        bisectorBC.setAngle(lineBC.normalVector().angle());
    
        bisectorBA = QLineF(lineBA.pointAt(0.5), lineBA.p2());
        bisectorBA.setAngle(lineBA.normalVector().angle());
        bisectorBA.intersect(bisectorBC, &center);
    
        circle = QRectF(center.x() - rad, center.y() - rad, rad*2, rad*2);
    
        lineOA = QLineF(center, p1);
        lineOB = QLineF(center, p2);
        lineOC = QLineF(center, p3);
    
    
        startAngle = lineOA.angle();
        spanAngle = lineOA.angleTo(lineOC);
        // Make sure that the span angle covers all three points with the second point in the middle
        if(qAbs(spanAngle) < qAbs(lineOA.angleTo(lineOB)) || qAbs(spanAngle) < qAbs(lineOB.angleTo(lineOC)))
        {
            // swap the end point and invert the spanAngle
            startAngle = lineOC.angle();
            spanAngle = 360 - spanAngle;
        }
    
        int w = 10;
        boundingRectTemp = circle.adjusted(-w, -w, w, w);
    }
    
    QRectF ArcGraphicsItem::boundingRect() const
    {
        // outer most edges
        return boundingRectTemp;
    }
    
    void ArcGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        QPen paintpen;
        painter->setRenderHint(QPainter::Antialiasing);
        paintpen.setWidth(1);
        // Draw arc
    
        if(isSelected())
        {
            painter->setBrush(Qt::SolidPattern);
            paintpen.setColor(Qt::black);
            painter->setPen(paintpen);
        }
        else
        {
            paintpen.setStyle(Qt::DashLine);
            paintpen.setColor(Qt::black);
            painter->setPen(paintpen);
        }
    
        QPainterPath path;
        path.arcMoveTo(circle,startAngle);
        path.arcTo(circle, startAngle, spanAngle);
    
        // Draw points
    
        if (isSelected())
        {
            // sets brush for end points
            painter->setBrush(Qt::SolidPattern);
            paintpen.setColor(Qt::red);
            painter->setPen(paintpen);
    
            qreal ptRad = 10;
            painter->drawEllipse(p1, ptRad, ptRad);
            painter->drawEllipse(p2, ptRad, ptRad);
            painter->drawEllipse(p3, ptRad, ptRad);
        }
    
        painter->setBrush(Qt::NoBrush);
        painter->drawPath(path);
    }
    
    QPainterPath ArcGraphicsItem::shape() const
    {
        QPainterPath path;
        path.arcMoveTo(circle,startAngle);
        path.arcTo(circle, startAngle, spanAngle);
        return path;
    }
    

    Hope that helps

    0 讨论(0)
提交回复
热议问题