#include "mygraphicsscene.h" #include 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"<pos()"<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 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 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 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(arcLength / (static_cast(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 ¢er, 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 ¢er, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 MyGraphicsScene::getPointList() { return m_ellipseItemList; } QList MyGraphicsScene::getLineItemList() { return m_lineItemList; } QList MyGraphicsScene::getPathItemList() { return m_pathItemList; }