Quilting-lw/sharedviews/view/mygraphicsscene.cpp
2026-01-23 16:37:18 +08:00

1357 lines
43 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}