#include "graphicsItem/electricConnectLineItem.h" #include #include #include ElectricConnectLineItem::ElectricConnectLineItem(QGraphicsItem *parent) : GraphicsProjectModelItem(parent) { initial(); } ElectricConnectLineItem::ElectricConnectLineItem(const ElectricConnectLineItem& obj) : GraphicsProjectModelItem(obj) { initial(); m_lstPoints = obj.m_lstPoints; } ElectricConnectLineItem::~ElectricConnectLineItem() { } ElectricConnectLineItem* ElectricConnectLineItem::clone() const { return new ElectricConnectLineItem(*this); } void ElectricConnectLineItem::initial() { m_boundingRect = QRectF(); m_pen = QPen(Qt::black); m_brush = QBrush(Qt::NoBrush); setHandleVisible(false); setFunctionHandleIfShow(false); setFunctionHandleEnaable(false); m_lstPoints.push_back(QPointF()); //起点 m_lstPoints.push_back(QPointF()); //终点 _curLine = QPoint(); } void ElectricConnectLineItem::setStartPoint(const QPointF& p) { int n = m_lstPoints.size(); if(n) { if(n >2) { if(m_lstPoints[0].x() == m_lstPoints[1].x()) //相邻点在垂直方向,水平移动,否则垂直移动 { m_lstPoints[1].setX(p.x()); } else { m_lstPoints[1].setY(p.y()); } } m_lstPoints[0] = p; } } void ElectricConnectLineItem::setEndPoint(const QPointF& p) { int n = m_lstPoints.size(); if(n) { if(n >2) { if(m_lstPoints[n-1].x() == m_lstPoints[n-2].x()) //相邻点在垂直方向,水平移动,否则垂直移动 { m_lstPoints[n-2].setX(p.x()); } else { m_lstPoints[n-2].setY(p.y()); } } m_lstPoints[n-1] = p; } } QPainterPath ElectricConnectLineItem::shape() const { QPainterPath path; //path.addPath(m_points); path.addPath(m_pointsBoundingRect); return path; } QRectF ElectricConnectLineItem::boundingRect() const { return m_boundingRect; } void ElectricConnectLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { if (option->state & QStyle::State_Selected) { painter->setPen(Qt::red); } else { if(_curMonitorStateEnable){ //当前状态被设置 painter->setPen(QPen(_curMonitorStateColor)); } else painter->setPen(m_pen); } painter->setBrush(m_brush); painter->drawPath(m_points); } void ElectricConnectLineItem::moveLine(QPointF pos) { QPointF delta = pos - m_lastPoint; if(_curLine.isNull()) { if(m_lstPoints.size() > 1) { int n = m_lstPoints.size(); for(int i = 0;i < m_lstPoints.size() -1;++i) { QPointF p1 = m_lstPoints[i]; QPointF p2 = m_lstPoints[i+1]; if(p1.x() == p2.x() && abs(p1.x() - pos.x()) < 2) //在相同竖线 { if(p1.y() > p2.y()) { if(pos.y() > p2.y() && pos.y() < p1.y()) //在竖线上 { if(i == 0 ) //起点是连接点,创建复制点 { m_lstPoints.prepend(p1); m_lstPoints.prepend(p1); i+=2; if(m_lstPoints.size() < 6) //补齐后端 { m_lstPoints.append(m_lstPoints.last()); } } if(i+1 == n-1) //终点是连接点,创建复制点 { m_lstPoints.append(p2); m_lstPoints.append(p2); m_lstPoints[i+1] = p2; if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点 { m_lstPoints.prepend(m_lstPoints.first()); i+=1; } } //qDebug() << 1 <<" "< p1.y()) //在竖线上 { if(i == 0) //起点是连接点,创建复制点 { m_lstPoints.prepend(p1); m_lstPoints.prepend(p1); i+=2; if(m_lstPoints.size() < 6) //补齐后端 { m_lstPoints.append(m_lstPoints.last()); } } if(i+1 == n-1) //终点是连接点,创建复制点 { m_lstPoints.append(p2); m_lstPoints.append(p2); m_lstPoints[i+1] = p2; if(m_lstPoints.size() < 6) //补齐前端 { m_lstPoints.prepend(m_lstPoints.first()); i+=1; } } //qDebug() << 2 <<" "< p2.x()) { if(pos.x() > p2.x() && pos.x() < p1.x()) { if(i == 0) //起点是连接点,创建复制点 { m_lstPoints.prepend(p1); m_lstPoints.prepend(p1); i+=2; if(m_lstPoints.size() < 6) //补齐后端 { m_lstPoints.append(m_lstPoints.last()); } } if(i+1 == n-1) //终点是连接点,创建复制点 { m_lstPoints.append(p2); m_lstPoints.append(p2); if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点 { m_lstPoints.prepend(m_lstPoints.first()); i+=1; } } //qDebug() << 3 <<" "< p1.x()) { if(i == 0) //起点是连接点,创建复制点 { m_lstPoints.prepend(p1); m_lstPoints.prepend(p1); i+=2; m_lstPoints[i] = p1; if(m_lstPoints.size() < 6) //补齐后端 { m_lstPoints.append(m_lstPoints.last()); } } if(i+1 == n-1) //终点是连接点,创建复制点 { m_lstPoints.append(p2); m_lstPoints.append(p2); if(m_lstPoints.size() < 6) //补齐前端 { m_lstPoints.prepend(m_lstPoints.first()); i+=1; } } //qDebug() << 4 <<" "< 3) { if(_curLine.y() == 1) //竖线 { if(n == 0) //起点是原点 { QPointF p(0,delta.y()); //原点不动 m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动 m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只竖直移动 } else if(n == 1) { QPointF p(delta.x(),0); m_lstPoints[n] += p; //第一个点只水平移动 m_lstPoints[n +1] += p; //第二个点只水平移动 } else if(n == m_lstPoints.size()-2) //起点是倒数第二个点 { QPointF p(0,delta.y()); m_lstPoints[n] += p; //起点只上下移动 m_lstPoints[n-1] += p; //上个点只竖直移动 } else if(n == m_lstPoints.size()-3) //起点是倒数第三个点 { QPointF py(0,delta.y()); QPointF px(delta.x(),0); m_lstPoints[n-1] += py; //上个点只垂直移动 m_lstPoints[n] += delta; //起点任意动 m_lstPoints[n+1] += px; //第二个点只水平移动 } else { m_lstPoints[n -1].setY(m_lstPoints[n ].y()); m_lstPoints[n] += delta; m_lstPoints[n +1] += delta; m_lstPoints[n +2].setY(m_lstPoints[n +1].y()); } } else //横线 { if(n == 0) //起点是原点 { QPointF p(delta.x(),0); //原点不动 m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只水平移动 m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只水平移动 } else if(n == 1) { QPointF p(0,delta.y()); m_lstPoints[n] = m_lstPoints[n] + p; //第一个点只竖直移动 m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动 } else if(n == m_lstPoints.size()-2) //起点是倒数第二个点 { QPointF p(delta.x(),0); m_lstPoints[n] += p; //起点水平移动 m_lstPoints[n-1] += p; //上个点只水平移动 } else if(n == m_lstPoints.size()-3) //起点是倒数第三个点 { QPointF py(0,delta.y()); QPointF px(delta.x(),0); m_lstPoints[n-1] += px; //上个点只水平移动 m_lstPoints[n] += delta; //起点任意动 m_lstPoints[n+1] += py; //第二个点只上下移动 } else { m_lstPoints[n -1].setX(m_lstPoints[n].x()); m_lstPoints[n] += delta; m_lstPoints[n +1] += delta; m_lstPoints[n +2].setX(m_lstPoints[n +1].x()); } } } calculatePath(); } m_lastPoint = pos; } void ElectricConnectLineItem::calculatePath() { if (m_lstPoints.size() < 2) return; QPointF start = m_lstPoints.first(); QPointF end = m_lstPoints.last(); qDebug() << "\n=== calculatePath ==="; qDebug() << "Start:" << start << "End:" << end; // 创建新路径 m_points = QPainterPath(); m_points.moveTo(start); qDebug() << "Initialized path, current position:" << m_points.currentPosition(); // 获取元件 QList components = getComponentCollisionRects(); qDebug() << "Found" << components.size() << "components"; // 检查起点终点距离 qDebug() << "Distance:" << QLineF(start, end).length(); // 如果距离很近,直接连接 if (QLineF(start, end).length() < 10) { qDebug() << "Points are very close, direct connection"; m_points.lineTo(end); } else { // 生成路径 generateAvoidancePath(start, end, components); } // 验证路径 qDebug() << "After generation - Path element count:" << m_points.elementCount(); qDebug() << "After generation - Current position:" << m_points.currentPosition(); if (m_points.elementCount() <= 1) { qWarning() << "Path has only" << m_points.elementCount() << "elements! Adding direct line"; m_points.lineTo(end); } // 确保路径结束于终点 if (m_points.currentPosition() != end) { qWarning() << "Path does not end at destination! Adding final segment"; qDebug() << "Expected end:" << end << "Actual end:" << m_points.currentPosition(); m_points.lineTo(end); } update(); m_boundingRect = m_points.boundingRect(); prepareGeometryChange(); qDebug() << "Final path bounds:" << m_boundingRect; qDebug() << "=== calculatePath end ===\n"; } // 使用形状进行避障 void ElectricConnectLineItem::generateAvoidancePath(const QPointF& start, const QPointF& end, const QList& components) { qDebug() << "=== generateAvoidancePath (rectilinear) ==="; m_points = QPainterPath(); m_points.moveTo(start); // 生成候选路径列表,按长度排序 QMultiMap> candidatePaths; // 1. 收集所有可能的直角路径 collectRectilinearPaths(start, end, components, candidatePaths); // 2. 选择最短的安全路径 for (auto it = candidatePaths.begin(); it != candidatePaths.end(); ++it) { const QList& path = it.value(); if (isPathSafe(path, components)) { qDebug() << " Selected path with length" << it.key() << ":" << path; // 绘制路径 for (int i = 1; i < path.size(); i++) { m_points.lineTo(path[i]); } return; } } // 3. 所有路径都失败,使用强制绕行 qDebug() << " All rectilinear paths failed, using forced bypass"; generateForcedRectilinearBypass(start, end, components); } // 计算路径长度 double ElectricConnectLineItem::calculatePathLength(const QList& path) { double length = 0; for (int i = 0; i < path.size() - 1; i++) { length += QLineF(path[i], path[i+1]).length(); } return length; } // 单一线段与矩形相交检测 bool ElectricConnectLineItem::lineIntersectsRect(const QLineF& line, const QRectF& rect) { // 检查端点是否在矩形内 if (rect.contains(line.p1()) || rect.contains(line.p2())) { return true; } // 检查是否与矩形的边相交 QLineF edges[4] = { QLineF(rect.topLeft(), rect.topRight()), QLineF(rect.topRight(), rect.bottomRight()), QLineF(rect.bottomRight(), rect.bottomLeft()), QLineF(rect.bottomLeft(), rect.topLeft()) }; QPointF intersection; for (int i = 0; i < 4; i++) { if (line.intersects(edges[i], &intersection) == QLineF::BoundedIntersection) { return true; } } return false; } // 辅助方法实现 bool ElectricConnectLineItem::isSegmentSafe(const QPointF& p1, const QPointF& p2, const QList& components) { QLineF segment(p1, p2); for (const QRectF& component : components) { if (segmentPenetratesComponent(segment, component)) { return false; } } return true; } bool ElectricConnectLineItem::isPathSafe(const QList& path, const QList& components) { for (int i = 0; i < path.size() - 1; i++) { if (!isSegmentSafe(path[i], path[i+1], components)) { return false; } } return true; } // 检查线段是否穿透元件 bool ElectricConnectLineItem::segmentPenetratesComponent(const QLineF& segment, const QRectF& component) { // 检查线段端点是否在元件内 bool p1Inside = component.contains(segment.p1()); bool p2Inside = component.contains(segment.p2()); if (p1Inside && p2Inside) { // 线段完全在元件内 return true; } // 获取与元件的交点 int intersectionCount = 0; QLineF edges[4] = { QLineF(component.topLeft(), component.topRight()), QLineF(component.topRight(), component.bottomRight()), QLineF(component.bottomRight(), component.bottomLeft()), QLineF(component.bottomLeft(), component.topLeft()) }; QPointF intersection; for (int i = 0; i < 4; i++) { if (segment.intersects(edges[i], &intersection) == QLineF::BoundedIntersection) { intersectionCount++; } } // 如果线段与元件有2个或更多交点,说明穿透了元件 return intersectionCount >= 2; } // 获取所有元件的总边界 QRectF ElectricConnectLineItem::getTotalComponentsBounds(const QList& components) { if (components.isEmpty()) { return QRectF(); } QRectF total = components.first(); for (int i = 1; i < components.size(); i++) { total = total.united(components[i]); } return total; } // 收集所有可能的直角路径 void ElectricConnectLineItem::collectRectilinearPaths(const QPointF& start, const QPointF& end, const QList& components, QMultiMap>& paths) { // 2段路径 QPointF turn1(start.x(), end.y()); // 水平-垂直 QPointF turn2(end.x(), start.y()); // 垂直-水平 addPathIfRectilinear({start, turn1, end}, paths); addPathIfRectilinear({start, turn2, end}, paths); // 3段路径 double midX = (start.x() + end.x()) / 2; double midY = (start.y() + end.y()) / 2; // 水平-垂直-水平 addPathIfRectilinear({start, QPointF(start.x(), midY), QPointF(end.x(), midY), end}, paths); // 垂直-水平-垂直 addPathIfRectilinear({start, QPointF(midX, start.y()), QPointF(midX, end.y()), end}, paths); // 4段路径(绕行) collectBypassPaths(start, end, components, paths); } // 添加路径(如果是直角) void ElectricConnectLineItem::addPathIfRectilinear(const QList& path, QMultiMap>& paths) { // 检查是否所有线段都是水平或垂直 for (int i = 0; i < path.size() - 1; i++) { if (path[i].x() != path[i+1].x() && path[i].y() != path[i+1].y()) { return; // 不是直角 } } double length = calculatePathLength(path); paths.insert(length, path); } // 收集绕行路径 void ElectricConnectLineItem::collectBypassPaths(const QPointF& start, const QPointF& end, const QList& components, QMultiMap>& paths) { if (components.isEmpty()) return; // 获取所有元件的总边界 QRectF totalBounds = getTotalComponentsBounds(components); if (!totalBounds.isValid()) return; const double clearance = 20.0; QRectF expanded = totalBounds.adjusted(-clearance, -clearance, clearance, clearance); // 从上方绕行 addPathIfRectilinear({start, QPointF(start.x(), expanded.top()), QPointF(end.x(), expanded.top()), end}, paths); // 从下方绕行 addPathIfRectilinear({start, QPointF(start.x(), expanded.bottom()), QPointF(end.x(), expanded.bottom()), end}, paths); // 从左方绕行 addPathIfRectilinear({start, QPointF(expanded.left(), start.y()), QPointF(expanded.left(), end.y()), end}, paths); // 从右方绕行 addPathIfRectilinear({start, QPointF(expanded.right(), start.y()), QPointF(expanded.right(), end.y()), end}, paths); } // 强制直角绕行 void ElectricConnectLineItem::generateForcedRectilinearBypass(const QPointF& start, const QPointF& end, const QList& components) { qDebug() << " In generateForcedRectilinearBypass"; // 找到阻挡的元件 QRectF blocking = findFirstBlockingComponent(start, end, components); if (blocking.isValid()) { qDebug() << " Blocking component:" << blocking; // 从上方或下方绕过 const double clearance = 15.0; double bypassY = (start.y() < blocking.center().y()) ? blocking.top() - clearance : blocking.bottom() + clearance; QList path = {start, QPointF(start.x(), bypassY), QPointF(end.x(), bypassY), end}; qDebug() << " Forced bypass path:" << path; for (int i = 1; i < path.size(); i++) { m_points.lineTo(path[i]); } } else { // 没有阻挡,使用简单的直角路径 qDebug() << " No blocking component, using simple orthogonal path"; QPointF turnPoint = (qAbs(start.x() - end.x()) < qAbs(start.y() - end.y())) ? QPointF(end.x(), start.y()) : QPointF(start.x(), end.y()); m_points.lineTo(turnPoint); m_points.lineTo(end); } } // 找到第一个阻挡的元件 QRectF ElectricConnectLineItem::findFirstBlockingComponent(const QPointF& start, const QPointF& end, const QList& components) { QLineF line(start, end); for (const QRectF& rect : components) { if (lineIntersectsRect(line, rect)) { return rect; } } return QRectF(); }