Quilting-lw/sharedviews/view/mygraphicsscene.cpp

1357 lines
43 KiB
C++
Raw Normal View History

2026-01-23 08:37:18 +00:00
#include "mygraphicsscene.h"
#include <cmath>
MyGraphicsScene::MyGraphicsScene()
{
m_selectedBrush.setColor(Qt::red);
m_defaultBrush.setColor(Qt::blue);
m_ellipseItemList.clear();
m_lineItemList.clear();
m_draggingPoint = NULL;
m_shapeType = -1;
m_addOrder = 0;
m_isAdsorption = false;
m_ArcCount = 0;
}
MyGraphicsScene::~MyGraphicsScene()
{
for(int i = 0; i < m_ellipseItemList.size(); i++)
{
if(m_ellipseItemList[i] != NULL)
{
delete m_ellipseItemList[i];
}
}
for(int i = 0; i < m_lineItemList.size(); i++)
{
if(m_lineItemList[i].item != NULL)
{
delete m_lineItemList[i].item;
}
}
}
void MyGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(m_draggingPoint)
{
m_draggingPoint->setPen(Qt::NoPen);
m_draggingPoint->setBrush(Qt::blue);
m_draggingPoint = NULL;
emit siCurrentIndex(0);
}
bool selectFlag = false;
if (event->button() != Qt::LeftButton)
{
return QGraphicsScene::mousePressEvent(event);
}
// 找到被点击的点
for (QGraphicsEllipseItem *point : m_ellipseItemList)
{
//rect是setpos之前的边框所以要加上pos坐标值
QRectF rect = point->boundingRect();
rect.setLeft(rect.left() + point->x());
rect.setRight(rect.right() + point->x());
rect.setTop(rect.top() + point->y());
rect.setBottom(rect.bottom() + point->y());
if (rect.contains(event->scenePos()))
{
if(m_draggingPoint)
{
m_draggingPoint->setPen(Qt::NoPen);
m_draggingPoint->setBrush(Qt::blue);
m_draggingPoint = NULL;
}
// 选中点
point->setPen(Qt::NoPen);
point->setBrush(Qt::red);
m_draggingPoint = point;
int index = m_ellipseItemList.indexOf(m_draggingPoint);
//qDebug()<<"index"<<index;
emit siCurrentIndex(index+1);
//qDebug()<<"m_draggingPoint->pos()"<<m_draggingPoint->pos();
m_dragOffset = event->scenePos() - point->pos();
selectFlag = true;
break;
}
}
//选中点
if(selectFlag == true)
{
return QGraphicsScene::mousePressEvent(event);
}
else
{
QPointF pressPos = event->scenePos();
//添加吸附判断
if(m_isAdsorption)
pressPos = m_grid->getClosestFocus(event->scenePos());
//画点 //重复点不要添加
if((m_shapeType == TYPE_DRAG)
|| (m_ellipseItemList.size() != 0
&& pressPos == m_ellipseItemList.last()->pos()))
return QGraphicsScene::mousePressEvent(event);
if(m_shapeType == TYPE_LINE)
{
if(m_ellipseItemList.size() <= 1)
{
//默认位置中心都是0
QGraphicsEllipseItem *ellipse = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
ellipse->setPos(pressPos);
ellipse->setPen(Qt::NoPen);
ellipse->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
ellipse->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(ellipse);
}
else
{
//先添加起点
QGraphicsEllipseItem *pointPre = m_ellipseItemList[m_ellipseItemList.size()-1];
QGraphicsEllipseItem *point = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
point->setPos(pointPre->pos());
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
//默认位置中心都是0
QGraphicsEllipseItem *ellipse = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
ellipse->setPos(pressPos);
ellipse->setPen(Qt::NoPen);
ellipse->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
ellipse->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(ellipse);
}
if(m_ellipseItemList.size() <= 1)
return;
m_addOrder++;
QPointF start = m_ellipseItemList.at(m_ellipseItemList.size() - 2)->pos();
QPointF end = pressPos;
QVector<QPointF> points;
points.append(start);
points.append(end);
QGraphicsPolygonItem *line = this->addPolygon(QPolygonF(points));
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
line->setPen(pen);
GLineItem item;
item.order = m_addOrder;
item.type = QUI_TYPE_LINE;
item.item = line;
item.points.append(start);
item.points.append(end);
m_lineItemList.append(item);
}
else if(m_shapeType == TYPE_ARC)
{
if(m_ellipseItemList.size() <= 2)
{
//默认位置中心都是0
QGraphicsEllipseItem *ellipse = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
ellipse->setPos(pressPos);
ellipse->setPen(Qt::NoPen);
ellipse->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
ellipse->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(ellipse);
}
else
{
if(m_ArcCount == 1)
{
//先添加起点
QGraphicsEllipseItem *pointPre = m_ellipseItemList[m_ellipseItemList.size()-1];
QGraphicsEllipseItem *point = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
point->setPos(pointPre->pos());
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
}
//默认位置中心都是0
QGraphicsEllipseItem *ellipse = this->addEllipse(0 - m_radius,
0 - m_radius,
2*m_radius,
2*m_radius);
ellipse->setPos(pressPos);
ellipse->setPen(Qt::NoPen);
ellipse->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
ellipse->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(ellipse);
}
m_ArcCount++;
if(m_ArcCount < 3)//三点确定一条圆弧
return QGraphicsScene::mousePressEvent(event);
QList<QPointF> points;
points.clear();
//第一个点默认为上一个点
QPointF point1 = m_ellipseItemList.at(m_ellipseItemList.size() - 3)->pos();
points.append(point1);
QPointF point2 = m_ellipseItemList.at(m_ellipseItemList.size() - 2)->pos();
points.append(point2);
QPointF point3 = m_ellipseItemList.at(m_ellipseItemList.size() - 1)->pos();
points.append(point3);
if(points.size() == 3)
{
m_addOrder++;
double threex[3], threey[3];
threex[0] = points[0].x();
threex[1] = points[1].x();
threex[2] = points[2].x();
threey[0] = points[0].y();
threey[1] = points[1].y();
threey[2] = points[2].y();
QGraphicsPathItem *arcItem = new QGraphicsPathItem();
getArcItem(points,arcItem,threex,threey);
if(arcItem != NULL)
{
this->addItem(arcItem); // 添加到场景中以显示
GPathItem item;
item.order = m_addOrder;
item.type = QUI_TYPE_ARC;
item.item = arcItem;
item.points = points;
m_pathItemList.append(item);
}
}
#if(0)
QList<QPointF> arcPoints;
QPointF center;
double radius;
// 计算圆心
bool bl = findCircleCenter(point1, point2, point3,center,radius);
if(bl == false)
{
qDebug()<<"findCircleCenter false";
}
else
{
double startAngle = atan2(point1.y() - center.y(), point1.x() - center.x());
double endAngle = atan2(point3.y() - center.y(), point3.x() - center.x());
// 生成圆弧上的点
double angleSpan = fabs(endAngle - startAngle);
double arcLength = radius * angleSpan;
// 圆弧上的点数
int segments = qMax(1, static_cast<int>(arcLength / (static_cast<double>(m_maxSegmentLength) / 10)));
QPointF v1 = point1 - center;
QPointF v2 = point2 - center;
QPointF v3 = point3 - center;
// 叉积判断方向
double cross = (v2.x() - v1.x()) * (v3.y() - v1.y()) - (v2.y() - v1.y()) * (v3.x() - v1.x());
bool clockwise = (cross < 0); // true 为顺时针false 为逆时针
if (!clockwise) {
if (endAngle < startAngle) endAngle += 2 * M_PI;
} else {
if (endAngle > startAngle) endAngle -= 2 * M_PI;
}
for (int i = 0; i <= segments; ++i)
{
double angle = startAngle + i * (endAngle - startAngle) / segments;
QPointF point(center.x() + radius * cos(angle), center.y() + radius * sin(angle));
arcPoints.append(point);
}
}
this->removeItem(m_ellipseItemList.last());
m_ellipseItemList.removeLast();
this->removeItem(m_ellipseItemList.last());
m_ellipseItemList.removeLast();
for(int i = 0; i < arcPoints.size()-1; i++)
{
QPointF start = arcPoints[i];
QPointF end = arcPoints[i+1];
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
//调整椭圆的位置,使其中心位于 points[i]
point->setPos(end.x(), end.y());
// QGraphicsLineItem *line = this->addLine(start.x(), start.y(), end.x(), end.y());
// QPen pen;
// pen.setWidthF(1);
// pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
// pen.setColor(Qt::blue);
// line->setPen(pen);
// GLineItem item;
// item.type = QUI_TYPE_ARC;
// item.item = line;
// item.points.append(start);
// item.points.append(end);
// m_lineItemList.append(item);
}
#endif
//移除前两个点
m_ArcCount = 1;
}
}
//未选中 默认最后一个点是选中点
if(selectFlag == false && m_ellipseItemList.size() != 0)
{
setLastPointSelected();
}
return QGraphicsScene::mousePressEvent(event);
}
void MyGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
//qDebug()<<"mouseMoveEvent";
if (event->buttons() & Qt::LeftButton && m_draggingPoint)
{
QPointF newPos = event->scenePos();
// 更新相关的线段
int relLine = getGLineItem(m_draggingPoint,newPos);
//如果直线和圆弧共点relLine和relArc都会 >0则先处理直线的点所以这个if的最后会return
if(relLine > 0)
{
update();
m_draggingPoint->setPos(newPos);
return QGraphicsScene::mouseMoveEvent(event);
}
int relArc = getGPathItem(m_draggingPoint,newPos);
if(relArc > 0)
{
update();
m_draggingPoint->setPos(newPos);
return QGraphicsScene::mouseMoveEvent(event);
}
}
return QGraphicsScene::mouseMoveEvent(event);
}
void MyGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
return QGraphicsScene::mouseReleaseEvent(event);
}
QPointF MyGraphicsScene::midpoint(const QPointF &p1, const QPointF &p2)
{
return QPointF((p1.x() + p2.x()) / 2.0, (p1.y() + p2.y()) / 2.0);
}
double MyGraphicsScene::slope(const QPointF &p1, const QPointF &p2)
{
if (p2.x() == p1.x()) return 1; // 避免除以零
return (p2.y() - p1.y()) / (p2.x() - p1.x());
}
bool MyGraphicsScene::findCircleCenter(const QPointF &p1, const QPointF &p2, const QPointF &p3, QPointF &center, double &radius)
{
//判断三点是否共线
double x1 = p1.x();
double y1 = p1.y();
double x2 = p2.x();
double y2 = p2.y();
double x3 = p3.x();
double y3 = p3.y();
double val = (int)(y3 - y1) * (int)(x2 - x1) - (int)(y2 - y1) * (int)(x3 - x1);
if(val == 0)//三点共线
{
return false;//三点共线
}
else//求圆心和半径
{
double a, b, c, d, e, f;
double xc, yc;
a = 2 * (x2-x1);
b = 2 * (y2-y1);
c = x2*x2 + y2*y2 - x1*x1 - y1*y1;
d = 2 * (x3-x2);
e = 2 * (y3-y2);
f = x3*x3+ y3*y3 - x2*x2 - y2*y2;
//圆心
xc = (b*f-e*c)/(b*d-e*a);
yc = (d*c-a*f)/(b*d-e*a);
center.setX(xc);
center.setY(yc);
//半径
radius = sqrt((xc-x1)*(xc-x1)+(yc-y1)*(yc-y1));
}
return true;
}
double MyGraphicsScene::findRadius(const QPointF &center, const QPointF &point)
{
return QLineF(center, point).length();
}
double MyGraphicsScene::distanceSquared(QPointF p1, QPointF p2)
{
return (p1.x() - p2.x()) * (p1.x() - p2.x()) + (p1.y() - p2.y()) * (p1.y() - p2.y());
}
void MyGraphicsScene::addItemToScene(QByteArray ary)
{
m_draggingPoint = NULL;
ViewItem * pDispBuff = (ViewItem *)ary.data();
int size = ary.size();
int stitchCount = size/sizeof(ViewItem);
if (stitchCount <= 0)
{
return;
}
double bx, by, ex, ey;
bx = by = ex = ey = 0;
QList<QPointF> points;
points.clear();
// 假设第一条线段的第一个点是起始点
bx = pDispBuff[0].bx;
by = pDispBuff[0].by;
points.append(QPointF(bx, by));
for (int i = 0; i < stitchCount; i++)
{
ex = pDispBuff[i].ex;
ey = pDispBuff[i].ey;
points.append(QPointF(ex,ey));
}
//创建点和线段
for(int i = 0; i < points.size(); i++)
{
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
// 调整椭圆的位置,使其中心位于 points[i]
point->setPos(points[i].x(), points[i].y());
if(i == points.size()-1)
{
break;
}
QPointF start = points[i];
QPointF end = points[i+1];
QVector<QPointF> vec;
vec.append(start);
vec.append(end);
QGraphicsPolygonItem *line = this->addPolygon(QPolygonF(vec));
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
line->setPen(pen);
GLineItem item;
item.order = i;
item.type = QUI_TYPE_LINE;
item.item = line;
item.points.append(start);
item.points.append(end);
m_lineItemList.append(item);
}
#if(0)
// m_linesSeg = new MultiLineSegments(points,nullptr);
// this->addItem(m_linesSeg);
// m_points.clear();
// // 创建点
// for (const auto &pointPos : points)
// {
// Endpoint *point = new Endpoint(pointPos.x(), pointPos.y(), 0.2, nullptr);
// m_points.append(point);
// this->addItem(point);
// }
// // 创建线段
// for (int i = 0; i < m_points.size() - 1; ++i)
// {
// Endpoint *start = m_points[i];
// Endpoint *end = m_points[i + 1];
// if(i == 0)
// {
// //end->setPos(QPointF(509.317,506.388));
// }
// LineSegment *line = new LineSegment(start, end, nullptr);
// start->addLineItem(line);
// end->addLineItem(line);
// m_lines.append(line);
// this->addItem(line);
// }
#endif
}
void MyGraphicsScene::addItemListToScene(QList<drawItem> list)
{
m_draggingPoint = NULL;
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
for(int i = 0; i < list.size(); i++)
{
int num = list[i].points.size();
QList<QPointF> points;
points.clear();
for(int j = 0; j < num; j++)
{
double x = list[i].points[j].x();
double y = list[i].points[j].y();
points.append(QPointF(x,y));
}
if(list[i].type == QUI_TYPE_ARC)//三点圆弧
{
//创建点和线段
for(int i = 0; i < points.size(); i++)
{
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
//调整椭圆的位置,使其中心位于 points[i]
point->setPos(points[i].x(), points[i].y());
}
if(points.size() == 3)
{
double threex[3], threey[3];
threex[0] = points[0].x();
threex[1] = points[1].x();
threex[2] = points[2].x();
threey[0] = points[0].y();
threey[1] = points[1].y();
threey[2] = points[2].y();
QGraphicsPathItem *arcItem = new QGraphicsPathItem();
getArcItem(points,arcItem,threex,threey);
if(arcItem != NULL)
{
this->addItem(arcItem); // 添加到场景中以显示
GPathItem item;
item.order = i;
item.type = QUI_TYPE_ARC;
item.item = arcItem;
item.points = points;
m_pathItemList.append(item);
}
}
}
else if(list[i].type == QUI_TYPE_BES)//贝塞尔
{
//创建点和线段
for(int i = 0; i < points.size(); i++)
{
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
//调整椭圆的位置,使其中心位于 points[i]
point->setPos(points[i].x(), points[i].y());
}
if(points.size() == 4)
{
// 创建 QPainterPath 并添加贝塞尔曲线
QPainterPath path;
path.moveTo(points[0]); // 移动到起始点
path.cubicTo(points[1], points[2], points[3]); // 添加贝塞尔曲线
// 创建 QGraphicsPathItem 并设置路径
QGraphicsPathItem *cubItem = new QGraphicsPathItem(path);
cubItem->setPen(pen); // 设置线条颜色和宽度
this->addItem(cubItem); // 添加到场景中以显示
GPathItem item;
item.order = i;
item.type = QUI_TYPE_BES;
item.item = cubItem;
item.points = points;
m_pathItemList.append(item);
}
}
else//直线
{
//创建点和线段
QVector<QPointF> pointsVec;
pointsVec.clear();
for(int m = 0; m < points.size(); m++)
{
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
m_ellipseItemList.append(point);
// 调整椭圆的位置,使其中心位于 points[i]
point->setPos(points[m].x(), points[m].y());
pointsVec.append(points[m]);
}
QGraphicsPolygonItem *poly = this->addPolygon(QPolygonF(pointsVec));
if(list[i].type != QUI_TYPE_LINE)
{
pen.setColor(Qt::green);
}
else
{
pen.setColor(Qt::blue);
}
poly->setPen(pen);
GLineItem item;
item.order = i;
item.type = list[i].type;
item.item = poly;
item.points = list[i].points;
m_lineItemList.append(item);
}
}
}
void MyGraphicsScene::addGrid(double gridSpacing, QRectF rect)
{
// m_gridSpacing = gridSpacing;
// m_gridRect = rect;
m_grid = new MyGraphicsGridItem(gridSpacing, rect);
this->addItem(m_grid);
}
void MyGraphicsScene::cleanScene()
{
m_shapeType = -1;
m_draggingPoint = NULL;
for(int i = 0 ; i < m_ellipseItemList.size(); i++)
{
this->removeItem(m_ellipseItemList[i]);
}
m_ellipseItemList.clear();
for(int i = 0 ; i < m_lineItemList.size(); i++)
{
this->removeItem(m_lineItemList[i].item);
m_lineItemList[i].points.clear();
}
m_lineItemList.clear();
for(int i = 0 ; i < m_pathItemList.size(); i++)
{
this->removeItem(m_pathItemList[i].item);
m_pathItemList[i].points.clear();
}
m_pathItemList.clear();
}
bool MyGraphicsScene::getCurSelectState()
{
bool bl = false;
if(m_draggingPoint)
{
bl = true;
}
if(m_ellipseItemList.size() <= 0)
{
bl = false;
}
return bl;
}
bool MyGraphicsScene::initAPoint()
{
bool bl = false;
if(m_draggingPoint)
{
bl = true;
}
if(m_draggingPoint == NULL)
{
if(m_ellipseItemList.size() > 0)
{
m_ellipseItemList[0]->setPen(Qt::NoPen);
m_ellipseItemList[0]->setBrush(Qt::red);
m_draggingPoint = m_ellipseItemList[0];
emit siCurrentIndex(1);
}
}
if(m_ellipseItemList.size() <= 0)
{
bl = false;
}
return bl;
}
void MyGraphicsScene::forwardAndBackward(int idx)
{
int index = m_ellipseItemList.indexOf(m_draggingPoint);
index += idx;
if(index < 0 || index >= m_ellipseItemList.size())
{
if(index < 0)
{
index = 0;
}
if(index >= m_ellipseItemList.size())
{
index = m_ellipseItemList.size()-1;
}
}
m_draggingPoint->setPen(Qt::NoPen);
m_draggingPoint->setBrush(Qt::blue);
m_draggingPoint = NULL;
// 选中点
m_ellipseItemList[index]->setPen(Qt::NoPen);
m_ellipseItemList[index]->setBrush(Qt::red);
m_draggingPoint = m_ellipseItemList[index];
emit siCurrentIndex(index+1);
}
void MyGraphicsScene::insertPoint(int dir)
{
int index = m_ellipseItemList.indexOf(m_draggingPoint);
index += dir;
if(index < 0 || index >= m_ellipseItemList.size())
{
return;
}
//默认位置中心都是0
QGraphicsEllipseItem *point = this->addEllipse(0-m_radius,
0-m_radius,
2*m_radius,
2*m_radius);
point->setPen(Qt::NoPen);
point->setBrush(Qt::blue);
//point->setFlag(QGraphicsItem::ItemIsSelectable, true);
point->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
QPointF a = m_draggingPoint->pos();
QPointF b = m_ellipseItemList[index]->pos();
// 调整椭圆的位置
QPointF m = QPointF((a.x()+b.x())/2.0,(a.y()+b.y())/2.0);
point->setPos(m.x(), m.y());
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
//向前插入点和线
if(dir < 0)
{
m_ellipseItemList.insert(index-dir,point);
//插入线,先把原来的线段删除,再插入两端线段
this->removeItem(m_lineItemList[index].item);
m_lineItemList.removeAt(index);
//先插入后半段
QPointF start = m;
QPointF end = a;
QVector<QPointF> vec;
vec.append(start);
vec.append(end);
QGraphicsPolygonItem *line = this->addPolygon(QPolygonF(vec));
line->setPen(pen);
GLineItem item;
item.item = line;
item.points.append(start);
item.points.append(end);
m_lineItemList.insert(index,item);
//再插入前半段
start = b;
end = m;
QVector<QPointF> vec1;
vec1.append(start);
vec1.append(end);
QGraphicsPolygonItem *line1 = this->addPolygon(QPolygonF(vec1));
line1->setPen(pen);
GLineItem item1;
item1.item = line1;
item1.points.append(start);
item1.points.append(end);
m_lineItemList.insert(index,item1);
emit siCurrentIndex(index-dir+2);
}
else
{
m_ellipseItemList.insert(index,point);
//插入线,先把原来的线段删除,再插入两端线段
this->removeItem(m_lineItemList[index-dir].item);
m_lineItemList.removeAt(index-dir);
//先插入后半段
QPointF start = m;
QPointF end = b;
QVector<QPointF> vec;
vec.append(start);
vec.append(end);
QGraphicsPolygonItem *line = this->addPolygon(QPolygonF(vec));
line->setPen(pen);
GLineItem item;
item.item = line;
item.points.append(start);
item.points.append(end);
m_lineItemList.insert(index-dir,item);
//再插入前半段
start = a;
end = m;
QVector<QPointF> vec1;
vec1.append(start);
vec1.append(end);
QGraphicsPolygonItem *line1 = this->addPolygon(QPolygonF(vec1));
line1->setPen(pen);
GLineItem item1;
item1.item = line1;
item1.points.append(start);
item1.points.append(end);
m_lineItemList.insert(index-dir,item1);
emit siCurrentIndex(index);
}
}
void MyGraphicsScene::removeSelectPoint()
{
int index = m_ellipseItemList.indexOf(m_draggingPoint);
qDebug() << " m_ellipseItemList.indexOf " << index;
if(m_ellipseItemList.size() > 1)
{
//将点相关的两条线段改为一条
if(index == 0)
{
this->removeItem(m_lineItemList[0].item);
m_lineItemList.removeFirst();
}
else if(index == m_ellipseItemList.size()-1)
{
this->removeItem(m_lineItemList[m_lineItemList.size()-1].item);
m_lineItemList.removeLast();
}
else
{
this->removeItem(m_lineItemList[index-1].item);
this->removeItem(m_lineItemList[index].item);
m_lineItemList.removeAt(index-1);
m_lineItemList.removeAt(index-1);
QPointF start = m_ellipseItemList[index-1]->pos();
QPointF end = m_ellipseItemList[index+1]->pos();
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
QVector<QPointF> vec;
vec.append(start);
vec.append(end);
QGraphicsPolygonItem *line = this->addPolygon(QPolygonF(vec));
line->setPen(pen);
GLineItem item;
item.item = line;
item.points.append(start);
item.points.append(end);
m_lineItemList.insert(index-1,item);
}
}
this->removeItem(m_draggingPoint);
m_ellipseItemList.removeAt(index);
setLastPointSelected();
}
void MyGraphicsScene::setShapeType(int type)
{
if(type == TYPE_LINE && m_shapeType == TYPE_ARC)
{
//上一次画直线或圆时,只画了一个点,要删除该点
if(m_ArcCount == 2)
{
QGraphicsEllipseItem *item = m_ellipseItemList.last();
this->removeItem(item);
m_ellipseItemList.removeOne(item);
m_ArcCount = 0;
}
}
//切换到了圆
else if(type == TYPE_ARC && m_shapeType == TYPE_LINE)
{
m_ArcCount = 1;
}
if(type == TYPE_ARC && m_ellipseItemList.size() <= 0)
{
m_ArcCount = 0;
}
m_shapeType = type;
setLastPointSelected();
}
void MyGraphicsScene::setAdsorption(bool adsorption)
{
m_isAdsorption = adsorption;
}
void MyGraphicsScene::setLastPointSelected()
{
if(m_ellipseItemList.size() == 0)
{
m_draggingPoint = NULL;
}
else
{
if(m_draggingPoint != NULL)
{
m_draggingPoint->setPen(Qt::NoPen);
m_draggingPoint->setBrush(Qt::blue);
}
QGraphicsEllipseItem *point = m_ellipseItemList.last();
// 选中点
point->setPen(Qt::NoPen);
point->setBrush(Qt::red);
m_draggingPoint = point;
emit siCurrentIndex(m_ellipseItemList.size());
}
}
void MyGraphicsScene::setMaxSegmentLength(int value)
{
m_maxSegmentLength = value;
}
int MyGraphicsScene::getMaxSegmentLength()
{
return m_maxSegmentLength;
}
int MyGraphicsScene::getArcItem(QList<QPointF> points, QGraphicsPathItem *item, double threex[], double threey[])
{
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
int val = isThreePointOnALine(threex, threey);
if(val == 1 || val == 2)//三个点或两个点重合
{
QPainterPath path;
path.moveTo(points[0]);
//线段
for(int i = 1; i < points.size(); i++)
{
path.lineTo(points[i].x(),points[i].y());
item->setPath(path);
item->setPen(pen); // 设置线条颜色和宽度
}
}
else
{
double xc = 0;
double yc = 0;
double r = 0;
getArcCenter(threex, threey, &xc, &yc, &r); //计算圆心和半径
QPointF center(xc,yc);
// 创建一个 QPainterPath 并添加弧线
// 2. 计算三个点的角度
qreal startAngle = QLineF(center, points[0]).angle();
qreal endAngle = QLineF(center, points[2]).angle();
// 3. 计算中间点角度,用于判断走哪一边
qreal midAngle = QLineF(center, points[1]).angle();
// 辅助函数:将角度差归一化到 [-180, 180]
auto normalizeDiff = [](qreal diff)
{
while (diff < -180) diff += 360;
while (diff > 180) diff -= 360;
return diff;
};
// 计算从 start 到 end 的两种可能跨度
qreal diff = normalizeDiff(endAngle - startAngle); // 最短角度差 [-180, 180]
qreal spanCCW, spanCW;
if (diff >= 0)
{
spanCCW = diff; // 逆时针短弧
spanCW = diff - 360; // 顺时针长弧
}
else
{
spanCCW = diff + 360; // 逆时针长弧
spanCW = diff; // 顺时针短弧
}
// 判断中间点在哪段弧上
auto isAngleInArc = [&](qreal angle, qreal span) -> bool
{
qreal rel = normalizeDiff(angle - startAngle); // 相对于起点的角度差
if (span >= 0)
{
return (rel >= -1e-3 && rel <= span + 1e-3);
}
else
{
return (rel <= 1e-3 && rel >= span - 1e-3);
}
};
qreal finalSpan;
if (isAngleInArc(midAngle, spanCCW))
{
finalSpan = spanCCW;
}
else if (isAngleInArc(midAngle, spanCW))
{
finalSpan = spanCW;
}
else
{
// fallback: 选绝对值较小的(劣弧)
finalSpan = (std::abs(spanCCW) <= std::abs(spanCW)) ? spanCCW : spanCW;
}
// 创建路径
QPainterPath path;
path.moveTo(points[0]);
path.arcTo(xc - r, yc - r, 2 * r, 2 * r, startAngle, finalSpan);
item->setPath(path);
item->setPen(pen);
}
return 1;
}
int MyGraphicsScene::getGLineItem(QGraphicsEllipseItem* p,QPointF p1)
{
int rel = 0;
if(p)
{
QPointF position = p->pos();
for(int i = 0; i < m_lineItemList.size(); i++)
{
for(int j = 0; j < m_lineItemList[i].points.size(); j++)
{
if(position == m_lineItemList[i].points[j])
{
m_lineItemList[i].points[j] = p1;
rel = 1;
QVector<QPointF> pointsVec;
pointsVec.reserve(m_lineItemList[i].points.size());
for (const QPointF &p : m_lineItemList[i].points)
{
pointsVec.append(p);
}
QGraphicsPolygonItem *pLine = m_lineItemList[i].item;
pLine->setPolygon(QPolygonF(pointsVec));
return rel;
}
}
}
}
return rel;
}
int MyGraphicsScene::getGPathItem(QGraphicsEllipseItem* p,QPointF p1)
{
int rel = 0;
if(p)
{
QPointF position = p->pos();
for(int i = 0; i < m_pathItemList.size(); i++)
{
for(int j = 0; j < m_pathItemList[i].points.size(); j++)
{
if(position == m_pathItemList[i].points[j])
{
if(m_pathItemList[i].points.size() == 3)//圆弧
{
rel = 1;
m_pathItemList[i].points[j] = p1;
QGraphicsPathItem *pPath = m_pathItemList[i].item;
QList<QPointF> points = m_pathItemList[i].points;
double threex[3], threey[3];
threex[0] = points[0].x();
threex[1] = points[1].x();
threex[2] = points[2].x();
threey[0] = points[0].y();
threey[1] = points[1].y();
threey[2] = points[2].y();
getArcItem(points,pPath,threex,threey);
return rel;
}
else if(m_pathItemList[i].points.size() == 4)//贝塞尔4个点
{
rel = 2;
m_pathItemList[i].points[j] = p1;
QGraphicsPathItem *pPath = m_pathItemList[i].item;
// 创建 QPainterPath 并添加贝塞尔曲线
QPainterPath path;
path.moveTo(m_pathItemList[i].points[0]); // 移动到起始点
path.cubicTo(m_pathItemList[i].points[1], m_pathItemList[i].points[2], m_pathItemList[i].points[3]); // 添加贝塞尔曲线
// 创建 QGraphicsPathItem 并设置路径
pPath->setPath(path);
QPen pen;
pen.setWidthF(1);
pen.setCosmetic(true); // 设置为眉笔模式,线段在缩放时保证粗细不变
pen.setColor(Qt::blue);
pPath->setPen(pen); // 设置线条颜色和宽度
return rel;
}
}
}
}
}
return rel;
}
void MyGraphicsScene::setXYMove(double valX,double valY)
{
if(m_draggingPoint == NULL)
{
return;
}
QPointF newPos(m_draggingPoint->x()+valX,m_draggingPoint->y()+valY);
int relLine = getGLineItem(m_draggingPoint,newPos);
//如果直线和圆弧共点relLine和relArc都会 > 0则先处理直线的点所以这个if的最后会return
if(relLine > 0)
{
update();
m_draggingPoint->setPos(newPos);
return;
}
int relArc = getGPathItem(m_draggingPoint,newPos);
if(relArc > 0)
{
update();
m_draggingPoint->setPos(newPos);
return;
}
}
//撤销最后一个图元
void MyGraphicsScene::revokeLastItem()
{
if(m_ellipseItemList.size() <= 0)
{
return;
}
int num = 0;//已删除的数量
int pointsNum = 0;//总共的点的个数
int order = m_lineItemList.size() + m_pathItemList.size();
for(int i = 0; i < m_lineItemList.size(); i++)
{
if(m_lineItemList[i].order == order)
{
//去掉两个点
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(m_lineItemList.size() > i)
{
this->removeItem(m_lineItemList[i].item);
m_lineItemList.removeAt(i);
num++;
}
break;
}
}
for(int i = 0; i < m_pathItemList.size(); i++)
{
if(m_pathItemList[i].order == order)
{
//去掉三个点
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(m_pathItemList.size() > i)
{
this->removeItem(m_pathItemList[i].item);
m_pathItemList.removeAt(i);
num++;
}
break;
}
}
for(int i = 0; i < m_lineItemList.size(); i++)
{
pointsNum += m_lineItemList[i].points.size();
}
for(int i = 0; i < m_pathItemList.size(); i++)
{
pointsNum += m_pathItemList[i].points.size();
}
//如果图元点总和与m_ellipseItemList的数量不一致要删除m_ellipseItemList多余点因为很可能画圆弧画了一半
if(pointsNum != m_ellipseItemList.size())
{
while(1)
{
if(m_ellipseItemList.size() > 0)
{
this->removeItem(m_ellipseItemList[m_ellipseItemList.size()-1]);
m_ellipseItemList.removeLast();
}
if(pointsNum == m_ellipseItemList.size())
{
break;
}
}
}
m_addOrder -= num;
m_shapeType = TYPE_DRAG;
setLastPointSelected();
}
QList<QGraphicsEllipseItem *> MyGraphicsScene::getPointList()
{
return m_ellipseItemList;
}
QList<GLineItem> MyGraphicsScene::getLineItemList()
{
return m_lineItemList;
}
QList<GPathItem> MyGraphicsScene::getPathItemList()
{
return m_pathItemList;
}