我想在QGraphicsScene中实现弧。我希望在点击三点时,我的弧线应该被画出来,在点击三点时,画出第一个点是弧线的起点,第二个点是弧线上的任意点,第三个点是弧的终点。我曾试过研究drawArc函数,但却把它弄糊涂了。我无法动态地设置它们。请建议我怎么做。
我尝试将该解决方案添加到我的项目中,但得到了以下错误:
error: cannot allocate an object of abstract type 'arc'
arcItem = new arc(++id, startP, midP, endP);
你能帮我解决这个问题吗?我为我的项目提供了一部分代码。在按摩器事件中,我做了下面的事情。
cadgraphicsscene.cpp
void CadGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// mousePressEvent in the graphicsScene
if(mouseEvent->button() == Qt::LeftButton)
{
switch (entityMode)
{
case ArcMode:
if (mFirstClick)
{
startP = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
midP = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = false;
mThirdClick = true;
}
else if (!mSecondClick && mThirdClick)
{
endP = mouseEvent->scenePos();
mThirdClick = false;
mPaintFlag = true;
}
if (mPaintFlag)
{
arcItem = new arc(++id, startP, midP, endP);
itemList.append(arcItem);
mUndoStack->push(new CadCommandAdd(this, arcItem));
setFlags();
}
}
}
}
arc.cpp
#include "arc.h"
arc::arc(int i, QPointF point1, QPointF point2, QPointF point3)
{
// assigns id
id = i;
p1 = point1;
p2 = point2;
p3 = point3;
lineBC(point2, point3);
lineAC(point1, point3);
lineBA(point2, point1);
rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
bisectorBA.intersect(bisectorBC, ¢er);
ellipse = new QGraphicsEllipseItem(center.x() - rad, center.y() - rad, rad*2, rad*2);
lineOA(center, point1);
lineOC(center, point3);
}
arc::arc(int i, QLineF start, QLineF end)
{
// assigns id
id = i;
lineOA.angle() = start;
lineOC.angle() - lineOA.angle() = end;
}
int arc::type() const
{
// Enable the use of qgraphicsitem_cast with arc item.
return Type;
}
void arc::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QPen paintpen;
painter->setRenderHint(QPainter::Antialiasing);
paintpen.setWidth(1);
if (isSelected())
{
// sets brush for end points
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawArc(ellipse->boundingRect(),lineOA.angle(),lineOC.angle() - lineOA.angle());
}
else
{
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawArc(ellipse->boundingRect(),lineOA.angle(),lineOC.angle() - lineOA.angle());
}
}
arc.h
include <QGraphicsItem>
#include "qmath.h"
class arc : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
arc(int, QPointF, QPointF, QPointF);
arc(int, QLineF, QLineF);
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
enum { Type = UserType + 6 };
int type() const;
int id;
QPointF startP, midP, endP, p1, p2, p3,center;
QLineF lineBC;
QLineF lineAC;
QLineF lineBA;
QLineF lineOA;
QLineF lineOC;
QLineF bisectorBC;
QLineF bisectorBA;
QGraphicsEllipseItem *ellipse;
qreal rad;
private:
QVector<QPointF> stuff;
};
#endif // ARC_H
请帮我解决这个错误。
发布于 2014-11-14 20:10:24
QGraphicsItem的一个子类,它取3个点,并将这三个点与一个圆弧相交。第二点总是在中间。(可选性和其他属性尚未完全实现或测试)。
注意: Qt包含更高级的子类QGraphicsItem
示例,例如碰撞鼠标,以及40000个芯片示例。
http://qt-project.org/doc/qt-5/examples-graphicsview.html
另外,要启用来自QObject
的QGraphicsItem
信号、插槽和属性,您应该使用QGraphicsObject
。
注意:添加到github 这里中。
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, ¢er);
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;
}
希望这有帮助
发布于 2014-11-13 07:36:06
这听起来似乎可以用一些相对简单的数学来解决:
https://www.google.com/search?q=define%20circle%20three%20points
https://math.stackexchange.com/a/213678
这是我把数学转化为Qt善良的地方
// 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, ¢er);
qDebug() << rad << center;
QPainterPath* path = new QPainterPath();
path->arcMoveTo(0,0,50,50,20);
path->arcTo(0,0,50,50,20, 90);
scene.addPath(*path);
把所有这些放在一个很好的小项目中,就会变成这样:
https://github.com/peteristhegreat/ThreePointsCircle
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, ¢er);
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);
}
https://stackoverflow.com/questions/26901540
复制相似问题