diff --git a/diagramCavas/include/baseDrawingPanel.h b/diagramCavas/include/baseDrawingPanel.h index 66efcdf..90d8094 100644 --- a/diagramCavas/include/baseDrawingPanel.h +++ b/diagramCavas/include/baseDrawingPanel.h @@ -62,7 +62,7 @@ protected: DesignerScene* m_pGraphicsScene; SelectorManager* m_pSelectorManager; StatusBar* m_pStatusBar; - QPointer _pModel; + FixedPortsModel* _pModel; DiagramMode _mode; QString _name; PowerEntity* _pEntity; //组态图拓扑对象 diff --git a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h index 984c6d0..b4b24b3 100644 --- a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h +++ b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h @@ -63,6 +63,7 @@ public: QWidget* getTopWidget(); QPointF getTerminalPos(const QString& sTerminalId); //获取拓扑接线点在当前diagram中的位置 ElectricConnectLineItem* getLineItemById(const QString& terminalId); + void updateItemLinePort(QUuid,ModelFunctionType); //刷新连接item的线端点位置 void showModelDlg(const QString&,QUuid,GraphicsProjectModelItem*); //点击时显示指定模型的dlg、指定item的数据(模型名,对象Uuid,触发事件的item) void initialPropertyDlg(); //初始化属性设置dlg,每个模型拥各自的dlg @@ -153,6 +154,7 @@ public Q_SLOTS: void onSignal_generateDiagram(const QString&); //生成工程组态信号 void onSignal_openBayManager(); void onDataTimerOut(); + void onSelectionChanged(); private: void addPortsToItem_json(PortState,QJsonArray,GraphicsProjectModelItem*); //将json格式的port添加到item void autoSetModelName(GraphicsBaseModelItem*); //如果此页的工程模已被设置,将projectName更新到item diff --git a/diagramCavas/include/graphicsItem/electricConnectLineItem.h b/diagramCavas/include/graphicsItem/electricConnectLineItem.h index 3b4c637..9642b52 100644 --- a/diagramCavas/include/graphicsItem/electricConnectLineItem.h +++ b/diagramCavas/include/graphicsItem/electricConnectLineItem.h @@ -18,14 +18,26 @@ public: QPainterPath getPoints(void) const { return m_points; } void moveLine(QPointF); //鼠标点击拖动 - void calculatePath(); void resetCurLine(){_curLine = QPoint();} + void calculatePath(); + void generateAvoidancePath(const QPointF& start, const QPointF& end,const QList& obstacleShapes); // 使用形状进行避障 + double calculatePathLength(const QList& path); + bool lineIntersectsRect(const QLineF& line, const QRectF& rect); + bool isSegmentSafe(const QPointF& p1, const QPointF& p2,const QList& components); + bool isPathSafe(const QList& path,const QList& components); + bool segmentPenetratesComponent(const QLineF& segment,const QRectF& component); + QRectF getTotalComponentsBounds(const QList& components); + void collectRectilinearPaths(const QPointF& start, const QPointF& end,const QList& components,QMultiMap>& paths); + void addPathIfRectilinear(const QList& path,QMultiMap>& paths); + void collectBypassPaths(const QPointF& start, const QPointF& end,const QList& components,QMultiMap>& paths); + void generateForcedRectilinearBypass(const QPointF& start, const QPointF& end,const QList& components); + QRectF findFirstBlockingComponent(const QPointF& start, const QPointF& end,const QList& components); -protected: virtual QPainterPath shape() const override; virtual QRectF boundingRect() const override; virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; -private: + +protected: void initial(); private: QPainterPath m_points; diff --git a/diagramCavas/include/graphicsItem/graphicsBaseItem.h b/diagramCavas/include/graphicsItem/graphicsBaseItem.h index bd09dbf..79491c1 100644 --- a/diagramCavas/include/graphicsItem/graphicsBaseItem.h +++ b/diagramCavas/include/graphicsItem/graphicsBaseItem.h @@ -14,6 +14,8 @@ #include "propertyType/dataSourceType.h" //#include "graphicsItem/itemPort.h" +class FixedPortsModel; + enum ShapeType { T_undefined, @@ -171,12 +173,35 @@ protected: class GraphicsBaseItem :public QObject, public AbstractShapeType { Q_OBJECT - public: +public: + enum RotateAngle { + Angle_0 = 0, + Angle_90 = 90, + Angle_180 = 180, + Angle_270 = 270 + }; + Q_ENUM(RotateAngle); + + Q_PROPERTY(QString Name READ getName WRITE setName) + Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition) + Q_PROPERTY(QRectF Size READ getSize WRITE setSize) + Q_PROPERTY(RotateAngle Rotation READ getRotateAngle WRITE setRotateAngle) +public: GraphicsBaseItem(QGraphicsItem *parent); GraphicsBaseItem(const GraphicsBaseItem&); virtual ~GraphicsBaseItem(); virtual GraphicsBaseItem* clone() const = 0; - +signals: + void itemRotated(GraphicsBaseItem*); +public: + virtual QString getName() const; + virtual void setName(QString); + virtual QPointF getPosition() const; + virtual void setPosition(QPointF); + virtual QRectF getSize() const; + virtual void setSize(QRectF); + virtual RotateAngle getRotateAngle() const; + virtual void setRotateAngle(RotateAngle); public: int addPort(PortState typ,QPointF vec,QString id = "",HandleType hType = T_lineInOut,PortPos pos = P_top,double dXPercent = 0,double dYPercent = 0); //新建,返回-1失败 virtual void movePort(QString id,QPointF vec); //移动可动点 @@ -206,6 +231,7 @@ public: virtual bool hasDynamicText(const QString& tag); virtual void setDynamicLayoutRadius(qreal radius); virtual QMap getDynamicText() {return m_mapDynamicText;} + void setHandle(FixedPortsModel* p){_pHandle = p;} int collidesWithHandle(const QPointF& point) { @@ -489,7 +515,10 @@ public slots: void onUpdateData(); //data发送的更新通知 protected: void rearrangeDynamicText(); //重新设置动态数据的布局 + QList getComponentCollisionRects() const; //获取图所有碰撞矩形 + QList getObstacleShapes() const; //获取所有碰撞shape protected: + FixedPortsModel* _pHandle; ModelProperty* _property; PowerEntity* _pEntity; //图元拓扑 bool _itemChanged; //图元变化标志,判断是否需要保存 @@ -543,10 +572,8 @@ class GraphicsProjectModelItem : public GraphicsBaseItem //工程模item { Q_OBJECT public: - Q_PROPERTY(QString Name READ getName WRITE setName) - Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition) - Q_PROPERTY(QRectF Size READ getSize WRITE setSize) Q_PROPERTY(DataSourceType DataSourceType READ getDataSourceType WRITE setDataSourceType) + public: GraphicsProjectModelItem(QGraphicsItem *parent); GraphicsProjectModelItem(const GraphicsProjectModelItem&); @@ -595,12 +622,6 @@ public: } } public: - QString getName() const; - void setName(QString); - QPointF getPosition() const; - void setPosition(QPointF); - QRectF getSize() const; - void setSize(QRectF); DataSourceType getDataSourceType() const; void setDataSourceType(DataSourceType); protected: diff --git a/diagramCavas/include/powerConnection.h b/diagramCavas/include/powerConnection.h index 60431ca..496f18e 100644 --- a/diagramCavas/include/powerConnection.h +++ b/diagramCavas/include/powerConnection.h @@ -22,6 +22,7 @@ public: QVariantMap properties() const { return m_properties; } DataState state() {return m_state;} void setState(DataState s) {m_state = s;} + void setId(QString sId){m_uuid = sId;} void setProperty(const QString& key, const QVariant& value); diff --git a/diagramCavas/source/baseDrawingPanel.cpp b/diagramCavas/source/baseDrawingPanel.cpp index d41a0e8..f029383 100644 --- a/diagramCavas/source/baseDrawingPanel.cpp +++ b/diagramCavas/source/baseDrawingPanel.cpp @@ -23,7 +23,7 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM ,_pPropertyProxy(nullptr) { _pEntity = pEntity; - _pModel = QPointer(new FixedPortsModel(pEntity)); + _pModel = new FixedPortsModel(pEntity); _pModel->setTopWidget(this); m_pSelectorManager = new SelectorManager(_pModel,this); m_pGraphicsScene = new DesignerScene(_pModel,this); @@ -36,20 +36,7 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM m_pGraphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); m_pGraphicsScene->setView(m_pGraphicsView); _pModel->setScene(m_pGraphicsScene); - connect(m_pGraphicsScene, &DesignerScene::selectionChanged, this, [&](){ - QList selectedItems = m_pGraphicsScene->selectedItems(); - if(_pModel){ - auto pCavas = _pModel->getCavas(); - if(pCavas){ - if(selectedItems.count() != 1) { - _pModel->getCavas()->onTargetSelected(_pPropertyProxy); - return; - } - GraphicsBaseItem *item = static_cast(selectedItems.first()); - _pModel->getCavas()->onTargetSelected(item); - } - } - }); + connect(m_pGraphicsScene, &DesignerScene::selectionChanged, _pModel, &FixedPortsModel::onSelectionChanged); m_pStatusBar = new StatusBar(this); m_pStatusBar->setMaximumHeight(25); @@ -77,8 +64,8 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM BaseDrawingPanel::~BaseDrawingPanel() { - if(_pModel) - delete _pModel; + //if(_pModel) + // delete _pModel; if(_pPropertyProxy) delete _pPropertyProxy; } diff --git a/diagramCavas/source/drawingPanel.cpp b/diagramCavas/source/drawingPanel.cpp index 3f1023a..7775096 100644 --- a/diagramCavas/source/drawingPanel.cpp +++ b/diagramCavas/source/drawingPanel.cpp @@ -192,6 +192,7 @@ void DrawingPanel::loadNodes(QJsonObject obj) PowerConnection* pCon = TopologyManager::instance().connection(srcPortId.toString(),destPortId.toString()); if(pCon) { + pCon->setId(id.toString()); QString srcItemId = pCon->fromComponent(); QString destItemId = pCon->toComponent(); //todo:从拓扑结构中查找port的id diff --git a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp index f1f52d0..544ef64 100644 --- a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp +++ b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp @@ -51,6 +51,7 @@ #include "instance/dataAccessor.h" #include "graphicsItem/handleText.h" #include "bayMeasureDlg.h" +#include "basePannelPropertyProxy.h" #include "global.h" bool FixedPortsModel::_dataInitialised = false; @@ -84,7 +85,7 @@ FixedPortsModel::FixedPortsModel(PowerEntity* pEntity) FixedPortsModel::~FixedPortsModel() { - + _cavas.clear(); } QMap FixedPortsModel::allNodePos() const @@ -143,8 +144,18 @@ bool FixedPortsModel::addNodeItem(QUuid uuid,GraphicsProjectModelItem* pItem) return false; else { + pItem->setHandle(this); _nodeItem.insert(uuid,pItem); connect(pItem,&GraphicsProjectModelItem::ifExist,this,&FixedPortsModel::onSignal_ifExits); + connect(pItem,&GraphicsBaseItem::itemRotated,this,[this](GraphicsBaseItem* pBase){ + if(pBase){ + auto pPro = pBase->getProperty(); + QUuid uid = pPro->uuid(); + if(pPro->type() != 8){ //排除线 + updateItemLinePort(uid,ModelFunctionType::ProjectModel); + } + } + }); return true; } } @@ -645,10 +656,18 @@ QString FixedPortsModel::addNodeItem(QUuid id,QPointF pos,double width,double he item->addPoint(pos); item->setProperty(pro); //绑定模型 item->updateByProperty(); //使用模型更新自身 - //QString sModel = _projectModelName.value(id.toString()); - //item->setModelName(sModel); + item->setHandle(this); _nodeItem.insert(id,item); connect(item,&GraphicsProjectModelItem::ifExist,this,&FixedPortsModel::onSignal_ifExits); + connect(item,&GraphicsBaseItem::itemRotated,this,[this](GraphicsBaseItem* pBase){ + if(pBase){ + auto pPro = pBase->getProperty(); + QUuid uid = pPro->uuid(); + if(pPro->type() != 8){ //排除线 + updateItemLinePort(uid,ModelFunctionType::ProjectModel); + } + } + }); } return pro->name(); } @@ -1610,6 +1629,19 @@ void FixedPortsModel::onDataTimerOut() } } +void FixedPortsModel::onSelectionChanged() +{ + QList selectedItems = _scene->selectedItems(); + if(_cavas){ + if(selectedItems.count() != 1) { + _cavas->onTargetSelected(_widget->getPropertyProxy()); + return; + } + GraphicsBaseItem *item = static_cast(selectedItems.first()); + _cavas->onTargetSelected(item); + } +} + void FixedPortsModel::startHttpRequest() { if(_timer) @@ -1794,6 +1826,31 @@ ElectricConnectLineItem* FixedPortsModel::getLineItemById(const QString& termina return nullptr; } +void FixedPortsModel::updateItemLinePort(QUuid uid,ModelFunctionType type) +{ + QList lstCon = TopologyManager::instance().getConnectionsFor(uid.toString(),type); //获取item的所有连接 + for(auto &pCon:lstCon){ + QString baseFromComponentId = pCon->fromComponent(); + QString baseToComponentId = pCon->toComponent(); + QString baseFromTerId = pCon->fromTerminalId(); + QString baseToTerId = pCon->toTerminalId(); + + auto pLine = static_cast(nodeItem(QUuid(pCon->id()))); + if(pLine){ + if(uid.toString() == baseFromComponentId){ + QPointF posFrom = getTerminalPos(baseFromTerId); + pLine->setStartPoint(posFrom); + pLine->calculatePath(); + } + else if(uid.toString() == baseToComponentId){ + QPointF posTo = getTerminalPos(baseToTerId); + pLine->setEndPoint(posTo); + pLine->calculatePath(); + } + } + } +} + void FixedPortsModel::showModelDlg(const QString& sName,QUuid uuid,GraphicsProjectModelItem* pItem) { modelStateInfo stateInfo = _modelStateInfo[sName]; diff --git a/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp b/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp index 0f23c35..7439144 100644 --- a/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp +++ b/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp @@ -352,47 +352,341 @@ void ElectricConnectLineItem::moveLine(QPointF pos) void ElectricConnectLineItem::calculatePath() { - int n = m_lstPoints.size(); - /*for(int i = 0;i < n-1;++i) - { - if(m_lstPoints[i] == m_lstPoints[i+1]) - { - if(i == 0) //头重复去除一个 - { - m_lstPoints.removeAt(i+1); - } - else if((i+1 == n-1)) //尾重复去除一个 - { - m_lstPoints.removeAt(i+1); - } - else - { - m_lstPoints.removeAt(i+1); - m_lstPoints.removeAt(i); - } - qDebug()<<"reset"; - resetCurLine(); - break; - } - }*/ - prepareGeometryChange(); - m_points.clear(); - m_pointsBoundingRect.clear(); + if (m_lstPoints.size() < 2) return; - if(m_lstPoints.size() == 2 && (m_lstPoints.first().x() != m_lstPoints.last().x()) && (m_lstPoints.first().y() != m_lstPoints.last().y())) - { - if(m_lstPoints.first().y() < m_lstPoints.last().y()) - m_lstPoints.insert(1,QPointF(m_lstPoints.first().x(),m_lstPoints.last().y())); - else - m_lstPoints.insert(1,QPointF(m_lstPoints.last().x(),m_lstPoints.first().y())); + 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); } - m_points.moveTo(m_lstPoints.first()); - QPointF pLast = m_lstPoints.first(); - for(int i = 1;i & 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(); +} + diff --git a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp index 8129a5a..6c121ad 100644 --- a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp +++ b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp @@ -3,6 +3,7 @@ #include "graphicsItem/handleText.h" #include "graphicsItem/itemPort.h" #include "baseProperty.h" +#include "graphicsDataModel/fixedPortsModel.h" #include "dataBase.h" #include #include @@ -13,6 +14,7 @@ GraphicsBaseItem::GraphicsBaseItem(QGraphicsItem *parent) : AbstractShapeType(parent) ,_property(nullptr) ,_pEntity(nullptr) + ,_pHandle(nullptr) { m_type = T_item; _itemChanged = false; @@ -69,6 +71,69 @@ GraphicsBaseItem::~GraphicsBaseItem() } } +QString GraphicsBaseItem::getName() const +{ + if(_property) + return _property->name(); + return QString(); +} + +void GraphicsBaseItem::setName(QString str) +{ + if(_property) + _property->setName(str); +} + +QPointF GraphicsBaseItem::getPosition() const +{ + return pos(); +} + +void GraphicsBaseItem::setPosition(QPointF pos) +{ + setPos(pos); +} + +QRectF GraphicsBaseItem::getSize() const +{ + return m_boundingRect; +} + +void GraphicsBaseItem::setSize(QRectF rec) +{ + prepareGeometryChange(); + m_boundingRect = rec; + update(); +} + +GraphicsBaseItem::RotateAngle GraphicsBaseItem::getRotateAngle() const +{ + int nRotate = rotation(); + + // 标准化角度到 0-360 范围 + nRotate = nRotate % 360; + if (nRotate < 0) nRotate += 360; + + // 映射到最近的 90 度倍数 + int normalized = ((nRotate + 45) / 90) * 90 % 360; + + QMetaEnum metaEnum = QMetaEnum::fromType(); + + // 检查标准化后的角度是否是有效的枚举值 + if (metaEnum.valueToKey(normalized) != nullptr) { + return static_cast(normalized); + } + + return RotateAngle::Angle_0; +} + +void GraphicsBaseItem::setRotateAngle(RotateAngle angle) +{ + int nAngle = static_cast(angle); + setRotation(nAngle); + emit itemRotated(this); +} + int GraphicsBaseItem::addPort(PortState typ,QPointF vec,QString id,HandleType hType,PortPos pos,double dXPercent,double dYPercent) { int ntagId = -1; @@ -321,6 +386,56 @@ void GraphicsBaseItem::rearrangeDynamicText() ++i; } } + +QList GraphicsBaseItem::getComponentCollisionRects() const +{ + QList lst; + if(_pHandle){ + auto mapItems = _pHandle->allItems(); + for(auto &pItem:mapItems){ + if (pItem == this) continue; + ModelProperty* pPro = pItem->getProperty(); + if(pPro){ + if(pPro->type() == 8) continue; //排除线 + } + QRectF bounds = pItem->boundingRect(); + bounds = pItem->mapRectToScene(bounds); + lst.append(bounds); + } + } + return lst; +} + +QList GraphicsBaseItem::getObstacleShapes() const +{ + QList obstacles; + + if (!scene()) { + return obstacles; + } + if(_pHandle){ + auto mapItems = _pHandle->allItems(); + for(auto &pItem:mapItems){ + if (pItem == this) continue; + ModelProperty* pPro = pItem->getProperty(); + if(pPro){ + if(pPro->type() == 8) continue; //排除线 + } + + // 获取元件的形状(考虑旋转) + QPainterPath shape = pItem->mapToScene(pItem->shape()); + + // 如果需要,可以稍微扩大形状 + QPainterPathStroker stroker; + stroker.setWidth(10); // 扩大10像素作为安全距离 + QPainterPath expandedShape = stroker.createStroke(shape); + + obstacles.append(expandedShape); + } + } + + return obstacles; +} /********************************基模****************************************/ GraphicsBaseModelItem::GraphicsBaseModelItem(QGraphicsItem *parent) :GraphicsBaseItem(parent) @@ -580,41 +695,6 @@ void GraphicsProjectModelItem::syncRotationDataFromParent(const double& data) m_dSyncRotationByParent += 360; } -QString GraphicsProjectModelItem::getName() const -{ - if(_property) - return _property->name(); - return QString(); -} - -void GraphicsProjectModelItem::setName(QString str) -{ - if(_property) - _property->setName(str); -} - -QPointF GraphicsProjectModelItem::getPosition() const -{ - return pos(); -} - -void GraphicsProjectModelItem::setPosition(QPointF pos) -{ - setPos(pos); -} - -QRectF GraphicsProjectModelItem::getSize() const -{ - return m_boundingRect; -} - -void GraphicsProjectModelItem::setSize(QRectF rec) -{ - prepareGeometryChange(); - m_boundingRect = rec; - update(); -} - DataSourceType GraphicsProjectModelItem::getDataSourceType() const { return _sourceType; diff --git a/diagramCavas/source/monitorPanel.cpp b/diagramCavas/source/monitorPanel.cpp index cd9e8b0..ae138af 100644 --- a/diagramCavas/source/monitorPanel.cpp +++ b/diagramCavas/source/monitorPanel.cpp @@ -229,6 +229,7 @@ void MonitorPanel::loadNodes(QJsonObject obj) PowerConnection* pCon = TopologyManager::instance().connection(srcPortId.toString(),destPortId.toString()); if(pCon) { + pCon->setId(id.toString()); QString srcItemId = pCon->fromComponent(); QString destItemId = pCon->toComponent(); //todo:从拓扑结构中查找port的id diff --git a/diagramCavas/source/util/linkMovingSelector.cpp b/diagramCavas/source/util/linkMovingSelector.cpp index da1b249..30a0850 100644 --- a/diagramCavas/source/util/linkMovingSelector.cpp +++ b/diagramCavas/source/util/linkMovingSelector.cpp @@ -40,8 +40,8 @@ void LinkMovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, Designe } else { - if(m_pMovingLine) - m_pMovingLine->moveLine(ms_ptMouseLast); + //if(m_pMovingLine) + //m_pMovingLine->moveLine(ms_ptMouseLast); //暂时屏蔽移动线 260204 } } diff --git a/include/mainwindow.h b/include/mainwindow.h index e5e9e04..74cd90c 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -57,6 +57,7 @@ private slots: void onAction_createEditor(); void onAction_unloadEditor(const QString&); + void onCavasItemSelected(QObject*); public: GraphicElementsPanel* graphicsElementsPanel() const; diff --git a/source/mainwindow.cpp b/source/mainwindow.cpp index 3870f87..fc10028 100644 --- a/source/mainwindow.cpp +++ b/source/mainwindow.cpp @@ -143,9 +143,7 @@ void CMainWindow::initializeDockUi() m_pPropertiesEditorView->setObject(m_pDiagramCavas); PropertyEditorDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); this->addDockWidget(Qt::RightDockWidgetArea,PropertyEditorDock); - connect(m_pDiagramCavas,&DiagramCavas::selectTarget,this,[&](QObject* obj){ - m_pPropertiesEditorView->setObject(obj); - }); + connect(m_pDiagramCavas,&DiagramCavas::selectTarget,this,&CMainWindow::onCavasItemSelected); } void CMainWindow::initializeAction() @@ -356,6 +354,12 @@ void CMainWindow::onAction_unloadEditor(const QString& str) m_pDiagramCavas->onSignal_unloadProject(str); } +void CMainWindow::onCavasItemSelected(QObject* obj) +{ + if(m_pPropertiesEditorView) + m_pPropertiesEditorView->setObject(obj); +} + GraphicElementsPanel* CMainWindow::graphicsElementsPanel() const { if(m_pGraphicElementsPanel)