diff --git a/common/core_model/diagram.h b/common/core_model/diagram.h index 85daab1..6c2fdbc 100644 --- a/common/core_model/diagram.h +++ b/common/core_model/diagram.h @@ -153,7 +153,7 @@ struct DiagramEditorRouteInfo //间隔中单条线路信息 struct DiagramEditorBayInfo //组态编辑间隔信息 { QString name; //间隔名 - int nLayout; //布局 0纵向1横向 + int nLayout = 0; //布局 0纵向1横向 QList lstFrom; //起始 QList lstTo; //结束 QMap mapRoute; //线路信息 diff --git a/diagramCavas/include/diagramEditor/editorDiagramLayoutEngine.h b/diagramCavas/include/diagramEditor/editorDiagramLayoutEngine.h index 239a17c..a29d542 100644 --- a/diagramCavas/include/diagramEditor/editorDiagramLayoutEngine.h +++ b/diagramCavas/include/diagramEditor/editorDiagramLayoutEngine.h @@ -4,6 +4,8 @@ // layout_engine.h /********editor布局生成核心类**********/ +class DiagramEditorModel; + class DiagramLayoutEngine { public: struct Context { @@ -17,6 +19,9 @@ public: } }; + explicit DiagramLayoutEngine(DiagramEditorModel* model) + : m_model(model) {} + QRectF executeLayout( QMap& routes, QMap& components, @@ -41,7 +46,8 @@ private: Direction branchDir, const LayoutConfig& config, Context& context, - bool isOrder); + bool isOrder, + int polarity); // 组件相关 Direction determineBranchDirection(const DiagramEditorComponentInfo& currentNode, @@ -63,4 +69,5 @@ private: private: int m_compoWidth = 50; int m_compoHeight = 30; + DiagramEditorModel* m_model = nullptr; }; diff --git a/diagramCavas/include/diagramEditor/editorLayoutConfig.h b/diagramCavas/include/diagramEditor/editorLayoutConfig.h index 7f9b0f8..693080f 100644 --- a/diagramCavas/include/diagramEditor/editorLayoutConfig.h +++ b/diagramCavas/include/diagramEditor/editorLayoutConfig.h @@ -27,6 +27,6 @@ private: Direction m_mainDir = Direction::Down; Direction m_subDir = Direction::Right; - int m_verticalSpacing = 50; // 默认值 - int m_horizontalSpacing = 50; // 默认值 + int m_verticalSpacing = 30; // 默认值 + int m_horizontalSpacing = 30; // 默认值 }; diff --git a/diagramCavas/include/diagramEditor/layoutCalculator.h b/diagramCavas/include/diagramEditor/layoutCalculator.h index 925125c..bccb3bc 100644 --- a/diagramCavas/include/diagramEditor/layoutCalculator.h +++ b/diagramCavas/include/diagramEditor/layoutCalculator.h @@ -14,6 +14,7 @@ public: double maxUpHeight = 0; // 整行最大上高度 double maxDownHeight = 0; // 整行最大下高度 double startY = 0; // 行起始Y + QList containers; }; diff --git a/diagramCavas/include/graphicsDataModel/baseModel.h b/diagramCavas/include/graphicsDataModel/baseModel.h index 38fd2b5..f3a5d09 100644 --- a/diagramCavas/include/graphicsDataModel/baseModel.h +++ b/diagramCavas/include/graphicsDataModel/baseModel.h @@ -30,6 +30,14 @@ public: return qSqrt(diff.x() * diff.x() + diff.y() * diff.y()); } ItemPort* getClosestUnusedPort(QMap,GraphicsBaseItem* item,ModelFunctionType); //返回距离item最近未使用端点 +protected: + ItemPort* selectBusOrNodePort(GraphicsBaseItem* pBusOrNode,GraphicsBaseItem* pOther,ModelFunctionType nType); //母线 / 节点端口选择 + ItemPort* selectDevicePortByMode(GraphicsBaseItem* pDevice,GraphicsBaseItem* pPeer,int nMode,int nParam,ModelFunctionType nType); //设备端口选择(支持 nMode / nParam) + void selectNormalDevicePort(GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,int nMode,int nParam,ModelFunctionType nType,ItemPort*& pSrcPort,ItemPort*& pDestPort);//普通设备 ↔ 设备(含变压器) + void selectTransformerPort(GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,int nMode,int nParam,ItemPort*& pSrcPort,ItemPort*& pDestPort);//变压器端口选择 + void selectBusToBusPorts(GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,ModelFunctionType nType,ItemPort*& pSrcPort,ItemPort*& pDestPort);//母线 ↔ 母线 / 节点 ↔ 节点 + template + void bindLineAndTopology(ItemPort* pSrcPort,ItemPort* pDestPort,TypeLine* pItem,GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,ModelFunctionType nType);//绑定连线 + 拓扑 }; diff --git a/diagramCavas/include/graphicsDataModel/diagramEditorModel.h b/diagramCavas/include/graphicsDataModel/diagramEditorModel.h index 319ca78..ba252b7 100644 --- a/diagramCavas/include/graphicsDataModel/diagramEditorModel.h +++ b/diagramCavas/include/graphicsDataModel/diagramEditorModel.h @@ -65,7 +65,7 @@ public: QStandardItem* getNameItem(const QString&,int nFrom = 0); //获取返回当前设备模型中的name项 nFrom,0间隔1变压器 void generateItemByModel(QStandardItemModel* pModel,DiagramEditorBaseBlock* pBlock,int nFrom = 0,QPoint delta = QPoint(0,0)); //0间隔1变压器 - QList generateItemByInfo(QMap mapRoute,QMap mapCompo,QPointF delta = QPointF(0,0),DiagramEditorBaseBlock* pParent = nullptr); //根据data生成item parent:生成的对象添加到parent下(非拓扑计算) + QList generateItemByInfo(QMap& mapRoute,QMap& mapCompo,QPointF delta = QPointF(0,0),DiagramEditorBaseBlock* pParent = nullptr); //根据data生成item parent:生成的对象添加到parent下(非拓扑计算) QMultiMap generateOutConnection(QList,QList&,int nTypeTransCon,int nPos = 0,DiagramEditorBaseBlock* pParent = nullptr); //生成外部连接(手动bind的连接)relation:层级关系引用 nTypeTransCon变压器连线类型,1中性点连接2外部连接,nPos中性点连接时的位置 QRectF updateTarget(QMap&,QMap&,int nLayout,int nSource,bool saveToModel = true); //更新位置 nLayout主次朝向:8421,8421 上下左右,上下左右 nSource:0间隔1变压器 regenerate重新生成标志 saveToModel:生成到模型或map void clearCompoDir(QMap&,QMap&,int nSource); //清空component中的dir(updateTarget前调用) diff --git a/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp index b5233bb..c5058c2 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp @@ -224,13 +224,13 @@ void DiagramEditorBayDetailAddDlg::updateBindLst() QStandardItem* item = nullptr; if(con.nPara == 0){ - item = new QStandardItem("高压接线端子"); + item = new QStandardItem("高压线圈接线点"); } else if(con.nPara == 1){ - item = new QStandardItem("中压接线端子"); + item = new QStandardItem("中压线圈接线点"); } else if(con.nPara == 2){ - item = new QStandardItem("低压接线端子"); + item = new QStandardItem("低压线圈接线点"); } if(item){ item->setData(conOp.nType, Qt::UserRole+1); diff --git a/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp index 9c91020..f10bbe3 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp @@ -83,7 +83,7 @@ void DiagramEditorBayDetailSettingDlg::refreshModel() QString sCategory; QString sType; if(info.nCategory == 0){ - sCategory = "设备"; + sCategory = "电气设备"; sType = BaseTypeManager::getInstance()->getNameById(info.nType); } else if(info.nCategory == 1){ @@ -119,11 +119,17 @@ void DiagramEditorBayDetailSettingDlg::refreshModel() _routeModel->setColumnCount(2); _routeModel->setHorizontalHeaderLabels({"线路名", "包含设备"}); auto info = _curOperateObj->getBayInfo(); + if(info.nLayout == 0) //纵向 + ui->cb_layout->setCurrentIndex(0); + else + ui->cb_layout->setCurrentIndex(1); setBayInfo(info); auto mapRoute = info.mapRoute; //更新路径数据到本界面 for(auto& route:mapRoute){ QString sRoute = route.sRouteName; + if(sRoute.isEmpty()) + continue; QStringList lstComp; for(auto& comp:route.lstCompo){ lstComp.append(comp.sName); @@ -168,7 +174,7 @@ void DiagramEditorBayDetailSettingDlg::onOkClicked() //将ui设置的参数更新到对应block if(_curOperateObj){ - QMap mapComponents; + /*QMap mapComponents; int nRowCount = _compoModel->rowCount(); for(int i = 0;i < nRowCount;++i){ QStandardItem *itemCate = _compoModel->item(i, 0); @@ -219,7 +225,74 @@ void DiagramEditorBayDetailSettingDlg::onOkClicked() QRectF recBounding = getModel()->updateTarget(_curBayInfo.mapRoute,_curBayInfo.mapComponent,nDir,0,false); if(_curOperateObj->getRecSize().isEmpty()) _curOperateObj->setRecSize(recBounding); - _curOperateObj->setBayInfo(_curBayInfo); + _curOperateObj->setBayInfo(_curBayInfo);*/ + + QMap tempComponents; + int nRowCount = _compoModel->rowCount(); + for (int i = 0; i < nRowCount; ++i) { + QStandardItem *itemCate = _compoModel->item(i, 0); + QStandardItem *itemName = _compoModel->item(i, 1); + QStandardItem *itemType = _compoModel->item(i, 2); + QStandardItem *itemBind = _compoModel->item(i, 3); + QStandardItem *itemRoute = _compoModel->item(i, 4); + + DiagramEditorComponentInfo info; + // ✅ 必须恢复的字段(原代码中有) + int nDir = itemName->data(Qt::UserRole+1).toInt(); + QPoint deltaPos = itemName->data(Qt::UserRole+2).toPoint(); + int nVal = itemName->data(Qt::UserRole+4).toInt(); + int nRotate = itemName->data(Qt::UserRole+5).toInt(); + + info.sName = itemName->text(); + info.uid = itemName->data(Qt::UserRole+3).toUuid(); + + if(itemCate->text() == "电气设备"){ + info.nCategory = 0; + } + else if(itemCate->text() == "连接关系"){ + info.nCategory = 1; + } + + info.nType = itemType->data().toInt(); + info.sBindObj = itemBind->text(); + info.nBindType = itemBind->data().toInt(); + info.nBindPara = itemBind->data(Qt::UserRole+2).toInt(); + info.sBindParent = itemBind->data(Qt::UserRole+3).toString(); + info.sUsedRoute = itemRoute->text().split(","); + + // ✅ 关键修复:恢复被丢弃的状态 + info.nUsedDirection = nDir; + info.deltaPos = deltaPos; + info.nFlag = nVal; + info.nRotate = nRotate; + tempComponents.insert(info.sName, info); + } + + // ✅ 2. 设置布局参数 + int nLayout = ui->cb_layout->currentData().toInt(); + _curBayInfo.nLayout = nLayout; + _curBayInfo.mapComponent = tempComponents; // ✅ 仅存非布局数据 + + // ✅ 3. 执行布局(唯一正确时机) + int nDir = (nLayout == 0) ? 41 : 14; + getModel()->clearCompoDir( + _curBayInfo.mapRoute, + _curBayInfo.mapComponent, + 0); + + QRectF recBounding = + getModel()->updateTarget( + _curBayInfo.mapRoute, + _curBayInfo.mapComponent, + nDir, + 0, + false); // ✅ 结果写回 mapComponent + + // ✅ 4. 保存“已经算好的正确数据” + if (_curOperateObj->getRecSize().isEmpty()) + _curOperateObj->setRecSize(recBounding); + + _curOperateObj->setBayInfo(_curBayInfo); // ✅ 此时 mapComponent 是正确的 TopologyManager::instance().clearGlobalBlockData(_curOperateObj->getName()); TopologyManager::instance().moveTempBlockData(); diff --git a/diagramCavas/source/diagramEditor/editorDiagramLayoutEngine.cpp b/diagramCavas/source/diagramEditor/editorDiagramLayoutEngine.cpp index b79f6f6..13d37c1 100644 --- a/diagramCavas/source/diagramEditor/editorDiagramLayoutEngine.cpp +++ b/diagramCavas/source/diagramEditor/editorDiagramLayoutEngine.cpp @@ -1,5 +1,6 @@ #include "diagramEditor/editorDiagramLayoutEngine.h" #include "diagramEditor/editorDirectionManager.h" +#include "graphicsDataModel/diagramEditorModel.h" // 主入口函数 QRectF DiagramLayoutEngine::executeLayout( @@ -8,45 +9,41 @@ QRectF DiagramLayoutEngine::executeLayout( const LayoutConfig& config, Context& context) { - // 1. 初始化上下文 context.initComponentsCache(components); context.itemCache.clear(); - // 2. 查找主线 QString mainRouteName = findMainRoute(routes); if (mainRouteName.isEmpty()) { qWarning() << "No main route found"; return QRectF(); } - // 3. 布局主线 - if (routes.contains(mainRouteName)) { - layoutMainRoute(routes[mainRouteName], config, context); - } + // 1. 布局主线 + layoutMainRoute(routes[mainRouteName], config, context); - // 4. 布局所有支线 + // 2. 布局所有支线(✅ 此时方向数据必须是最新的) for (auto it = routes.begin(); it != routes.end(); ++it) { if (it->sRouteName == mainRouteName) continue; layoutBranchRoute(*it, config, context); } - // 5. 更新组件映射 + // ✅ 3. 所有布局完成之后,才更新 components if (!context.saveToModel) { - for (auto& route : routes) { - for (auto& compo : route.lstCompo) { - components[compo.sName] = compo; - } + for(auto& compo:components){ //从compo缓存中读取计算过的数据 + auto mapCatch = context.componentsCache; + compo.nUsedDirection = mapCatch[compo.sName].nUsedDirection; + compo.nRotate = mapCatch[compo.sName].nRotate; + compo.deltaPos = mapCatch[compo.sName].deltaPos; } } - // 6. 计算边界矩形 + // 4. 计算边界 if (!context.saveToModel) { return calculateBoundingRect(components); } - return QRectF(); // saveToModel 时由场景计算边界 + return QRectF(); } - // 查找主线 QString DiagramLayoutEngine::findMainRoute( const QMap& routes) { @@ -137,6 +134,9 @@ void DiagramLayoutEngine::layoutMainRoute( // 计算旋转角度 int rotate = DirectionManager::getRotationAngle(mainDir); + if (!context.saveToModel) { + context.componentsCache[compo.sName] = compo; + } // 更新组件 updateComponent(compo, dir, delta, rotate, context); @@ -208,19 +208,36 @@ void DiagramLayoutEngine::layoutBranchRoute( const LayoutConfig& config, Context& context) { - // 1. 拆分支线 splitBranchRoute(route, context); - // 2. 布局正序序列 if (route.lstOrder.size() > 1) { - layoutBranchSequence(route.lstOrder, config.subDirection(), - config, context, true); + // ✅ 第一个元件的真实方向,由 determineBranchDirection 决定 + Direction startDir = + determineBranchDirection(route.lstOrder[0], + config.subDirection(), + context); + + int polarity = 1; + layoutBranchSequence(route.lstOrder, + startDir, + config, + context, + true, + polarity); } - // 3. 布局反序序列 if (route.lstReverse.size() > 1) { - layoutBranchSequence(route.lstReverse, config.subDirection(), - config, context, false); + Direction startDir = + determineBranchDirection(route.lstReverse[0], + config.subDirection(), + context); + int polarity = -1; + layoutBranchSequence(route.lstReverse, + startDir, + config, + context, + false, + polarity); } } @@ -230,59 +247,56 @@ void DiagramLayoutEngine::layoutBranchSequence( Direction branchDir, const LayoutConfig& config, Context& context, - bool isOrder) { + bool isOrder, + int polarity) { if (sequence.size() < 2) return; - // 获取基准位置 - QPoint basePos = getComponentPosition(sequence[0].sName, context); - int index = 1; // 偏移索引从1开始 - int polarity = 1; // 方向极性 + // ✅ 1. 根据主线方向决定展开轴 + bool mainIsVertical = + DirectionManager::isVertical(config.mainDirection()); - // 确定极性 - if (branchDir == Direction::Left || branchDir == Direction::Up) { - polarity = -1; - } - - // 计算间距 - int spacing = DirectionManager::isHorizontal(branchDir) + // ✅ 2. 间距由主线方向决定 + int spacing = mainIsVertical ? config.horizontalSpacing() : config.verticalSpacing(); - // 布局后续元件 - for (int i = 0; i < sequence.size() - 1; ++i) { - DiagramEditorComponentInfo& current = sequence[i]; - DiagramEditorComponentInfo& next = sequence[i + 1]; - // 确定分支方向 - Direction dir = determineBranchDirection(current, branchDir, context); + for (int i = 0; i < sequence.size(); ++i) { - // 计算下一个元件的位置 - QPoint nextPos = basePos; - int offset = index * polarity * spacing; + // ✅ 当前元件作为“起点” + QPoint basePos = getComponentPosition(sequence[i].sName, context); + Direction dir = + determineBranchDirection(sequence[i], branchDir, context); - if (DirectionManager::isHorizontal(dir)) { - nextPos.setX(basePos.x() + offset); - } else { - nextPos.setY(basePos.y() + offset); + // ✅ 如果后面还有元件,才计算偏移 + if (i + 1 < sequence.size()) { + + DiagramEditorComponentInfo& next = sequence[i + 1]; + int offset = (i + 1) * polarity * spacing; + QPoint nextPos = basePos; + + if (mainIsVertical) { + // ✅ 只在 X 轴应用偏移,Y 轴纹丝不动 + nextPos.setX(basePos.x() + offset); + // nextPos.setY(basePos.y()); // ✅ 隐式成立,无需再写 + } else { + // ✅ 只在 Y 轴应用偏移,X 轴纹丝不动 + nextPos.setY(basePos.y() + offset); + // nextPos.setX(basePos.x()); // ✅ 隐式成立,无需再写 + } + + QPoint deltaPos = nextPos - basePos; + Direction nextConnectionDir = + DirectionManager::getOpposite(dir); + int rotate = + DirectionManager::getRotationAngle(dir); + + updateComponent(next, nextConnectionDir, + nextPos, rotate, context); } - - // 计算相对位置 - QPoint deltaPos = nextPos - basePos; - - // 下一个元件的连接方向与当前方向相反 - Direction nextConnectionDir = DirectionManager::getOpposite(dir); - - // 计算旋转角度 - int rotate = DirectionManager::getRotationAngle(dir); - - // 更新元件 - updateComponent(next, nextConnectionDir, deltaPos, rotate, context); - - index++; } } - // 确定支线方向 Direction DiagramLayoutEngine::determineBranchDirection( const DiagramEditorComponentInfo& currentNode, @@ -340,13 +354,24 @@ QPoint DiagramLayoutEngine::getComponentPosition( return posData.toPoint(); } } + return QPoint(0, 0); } else { + // ✅ 核心修复:优先使用 componentsCache if (context.componentsCache.contains(componentName)) { return context.componentsCache[componentName].deltaPos; } - } - return QPoint(0, 0); + // ✅ 终极兜底:如果 cache 里也没有,从原始 components 取 + QStandardItem* item = getNameItem(componentName, context); + if (item) { + QVariant posData = item->data(Qt::UserRole + 2); + if (posData.isValid() && posData.canConvert()) { + return posData.toPoint(); // ✅ 返回真实的 deltaPos + } + } + + return QPoint(0, 0); + } } // 获取组件方向 @@ -370,16 +395,10 @@ QStandardItem* DiagramLayoutEngine::getNameItem( const QString& name, Context& context) { - QString cacheKey = QString("%1_%2").arg(name).arg(context.sourceId); + if (!m_model) + return nullptr; - if (!context.itemCache.contains(cacheKey)) { - // 这里应该是具体的模型查找实现 - // 为了示例,返回一个临时项 - QStandardItem* item = new QStandardItem(name); - context.itemCache[cacheKey] = item; - } - - return context.itemCache[cacheKey]; + return m_model->getNameItem(name, context.sourceId); } // 更新组件 @@ -398,6 +417,13 @@ void DiagramLayoutEngine::updateComponent( item->setData(QString::number(newDir)); item->setData(position, Qt::UserRole + 2); item->setData(rotate, Qt::UserRole + 5); + + //compo.nUsedDirection = DirectionManager::markDirectionOccupied(compo.nUsedDirection, dir); + //compo.deltaPos = position; + //compo.nRotate = rotate; + + // 更新缓存 + //context.componentsCache[compo.sName] = compo; } } else { compo.nUsedDirection = DirectionManager::markDirectionOccupied(compo.nUsedDirection, dir); @@ -405,7 +431,9 @@ void DiagramLayoutEngine::updateComponent( compo.nRotate = rotate; // 更新缓存 - context.componentsCache[compo.sName] = compo; + context.componentsCache[compo.sName].nUsedDirection = compo.nUsedDirection; + context.componentsCache[compo.sName].deltaPos = compo.deltaPos; + context.componentsCache[compo.sName].nRotate = compo.nRotate; } } diff --git a/diagramCavas/source/diagramEditor/layoutCalculator.cpp b/diagramCavas/source/diagramEditor/layoutCalculator.cpp index 6549bf2..79e31a3 100644 --- a/diagramCavas/source/diagramEditor/layoutCalculator.cpp +++ b/diagramCavas/source/diagramEditor/layoutCalculator.cpp @@ -59,7 +59,7 @@ void FixedLayoutCalculator::calculateContainerSizes(LevelLayout& levelLayout) { levelLayout.maxUpHeight = 0; levelLayout.maxDownHeight = 0; - for (auto container : levelLayout.containers) { + for (auto& container : levelLayout.containers) { if (!container) continue; auto mapBlocks = container->getBlockMap(); @@ -128,7 +128,7 @@ void FixedLayoutCalculator::calculatePositions(LevelLayout& levelLayout, double startX = CONTAINER_START_X; bool isFirstContainer = true; - for (auto container : levelLayout.containers) { + for (auto& container : levelLayout.containers) { if (!container) continue; // 设置容器高度 diff --git a/diagramCavas/source/graphicsDataModel/baseModel.cpp b/diagramCavas/source/graphicsDataModel/baseModel.cpp index 74935bd..48831e2 100644 --- a/diagramCavas/source/graphicsDataModel/baseModel.cpp +++ b/diagramCavas/source/graphicsDataModel/baseModel.cpp @@ -99,7 +99,320 @@ ItemPort* BaseModel::getClosestUnusedPort(QMap mapPorts,Graph return nullptr; } -template void BaseModel::establishConnection(GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,TypeLine* pItem,ModelFunctionType nType,int nMode,int nParam) +ItemPort* BaseModel::selectBusOrNodePort( + GraphicsBaseItem* pBusOrNode, + GraphicsBaseItem* pOther, + ModelFunctionType nType) +{ + ItemPort* pPort = nullptr; + + int nTypeSelf = pBusOrNode->getProperty()->type(); + + if (nTypeSelf == 1) // 母线 + { + int index = pBusOrNode->addPort( + p_movable, + pBusOrNode->mapFromScene( + calculateBusPortPos(pBusOrNode, pOther))); + createTopoTerminalsByItem(pBusOrNode, nType); + pPort = pBusOrNode->getPortPtr(index); + } + else // 节点 + { + int index = pBusOrNode->addPort( + p_movable, QPoint(0,0)); + createTopoTerminalsByItem(pBusOrNode, nType); + pPort = pBusOrNode->getPortPtr(index); + } + + return pPort; +} + +ItemPort* BaseModel::selectDevicePortByMode( + GraphicsBaseItem* pDevice, + GraphicsBaseItem* pPeer, + int nMode, + int nParam, + ModelFunctionType nType) +{ + ItemPort* pPort = nullptr; + QMap mapPorts = pDevice->getPorts(); + + if (nMode == 0) + { + pPort = getClosestUnusedPort(mapPorts, pPeer, nType); + } + else if (nMode == 1) // 中性点 + { + for (auto& port : mapPorts) + { + if (port->getType() == T_newTral) + { + int pos = port->portPos(); + if ((nParam == 0 && pos == P_top) || + (nParam == 1 && (pos == P_left || pos == P_right)) || + (nParam == 2 && pos == P_down)) + { + pPort = port; + break; + } + } + } + } + else if (nMode == 2) // 非中性点 + { + for (auto& port : mapPorts) + { + if (port->getType() != T_newTral) + { + int pos = port->portPos(); + if ((nParam == 0 && pos == P_top) || + (nParam == 1 && (pos == P_left || pos == P_right)) || + (nParam == 2 && pos == P_down)) + { + pPort = port; + break; + } + } + } + } + + return pPort; +} + +void BaseModel::selectNormalDevicePort( + GraphicsBaseItem* pSrc, + GraphicsBaseItem* pDest, + int nMode, + int nParam, + ModelFunctionType nType, + ItemPort*& pSrcPort, + ItemPort*& pDestPort) +{ + if (nMode == 1 || nMode == 2) + { + selectTransformerPort(pSrc, pDest, + nMode, nParam, + pSrcPort, pDestPort); + } + else + { + QMap mapSrc = pSrc->getPorts(); + QMap mapDest = pDest->getPorts(); + + for (auto& port : mapSrc) + if (port->getType() == T_lineOut) + pSrcPort = port; + + for (auto& port : mapDest) + if (port->getType() == T_lineIn) + pDestPort = port; + } +} + +void BaseModel::selectTransformerPort( + GraphicsBaseItem* pSrc, + GraphicsBaseItem* pDest, + int nMode, + int nParam, + ItemPort*& pSrcPort, + ItemPort*& pDestPort) +{ + int nTypeSrc = pSrc->getProperty()->type(); + int nTypeDest = pDest->getProperty()->type(); + + QMap mapSrc = pSrc->getPorts(); + QMap mapDest = pDest->getPorts(); + + // src 是变压器 + if (nTypeSrc == 15 || nTypeSrc == 16) + { + for (auto& port : mapSrc) + { + int tpe = port->getType(); + int pos = port->portPos(); + if (tpe != T_newTral) + { + if ((nParam == 0 && pos == P_top) || + (nParam == 1 && (pos == P_left || pos == P_right)) || + (nParam == 2 && pos == P_down)) + { + pSrcPort = port; + break; + } + } + } + + int transType = pSrcPort ? pSrcPort->getType() : 0; + for (auto& port : mapDest) + { + if (transType == T_lineOut && port->getType() == T_lineIn) + { + pDestPort = port; + break; + } + else if (transType == T_lineIn && port->getType() == T_lineOut) + { + pDestPort = port; + break; + } + } + } + // dest 是变压器 + else if (nTypeDest == 15 || nTypeDest == 16) + { + for (auto& port : mapDest) + { + int tpe = port->getType(); + int pos = port->portPos(); + if (tpe != T_newTral) + { + if ((nParam == 0 && pos == P_top) || + (nParam == 1 && (pos == P_left || pos == P_right)) || + (nParam == 2 && pos == P_down)) + { + pDestPort = port; + break; + } + } + } + + int transType = pDestPort ? pDestPort->getType() : 0; + for (auto& port : mapSrc) + { + if (transType == T_lineOut && port->getType() == T_lineIn) + { + pSrcPort = port; + break; + } + else if (transType == T_lineIn && port->getType() == T_lineOut) + { + pSrcPort = port; + break; + } + } + } +} + +void BaseModel::selectBusToBusPorts( + GraphicsBaseItem* pSrc, + GraphicsBaseItem* pDest, + ModelFunctionType nType, + ItemPort*& pSrcPort, + ItemPort*& pDestPort) +{ + int idx = pSrc->addPort( + p_movable, + pSrc->mapFromScene( + calculateBusPortPos(pSrc, pDest))); + createTopoTerminalsByItem(pSrc, nType); + pSrcPort = pSrc->getPortPtr(idx); + + idx = pDest->addPort( + p_movable, + pDest->mapFromScene( + calculateBusPortPos(pDest, pSrc))); + createTopoTerminalsByItem(pDest, nType); + pDestPort = pDest->getPortPtr(idx); +} + +template +void BaseModel::bindLineAndTopology( + ItemPort* pSrcPort, + ItemPort* pDestPort, + TypeLine* pItem, + GraphicsBaseItem* pSrc, + GraphicsBaseItem* pDest, + ModelFunctionType nType) +{ + if (!pSrcPort || !pDestPort) + return; + + pItem->setStartPoint(pSrcPort->scenePos()); + pItem->setEndPoint(pDestPort->scenePos()); + pItem->calculatePath(); + + PowerConnection* pCon = + TopologyManager::instance().createConnection( + pItem->itemId().toString(), + pSrcPort->getId(), + pDestPort->getId(), + pSrc->itemId().toString(), + pDest->itemId().toString(), + nType); + + if (pCon) + pCon->setState(DataState::Changed); + + pItem->getProperty()->setConnection( + Connection( + pSrc->itemId(), + QUuid(pSrcPort->getId()), + pSrcPort->getType(), + pSrcPort->portPos(), + pDest->itemId(), + QUuid(pDestPort->getId()), + pDestPort->getType(), + pDestPort->portPos())); +} + +template +void BaseModel::establishConnection( + GraphicsBaseItem* pSrc, + GraphicsBaseItem* pDest, + TypeLine* pItem, + ModelFunctionType nType, + int nMode, + int nParam) +{ + ItemPort* pSrcPort = nullptr; + ItemPort* pDestPort = nullptr; + + auto pSrcData = pSrc->getProperty(); + auto pDestData = pDest->getProperty(); + int nTypeSrc = 0; + int nTypeDest = 0; + + if(pSrcData) + nTypeSrc = pSrcData->type(); + if(pDestData) + nTypeDest = pDestData->type(); + + // ===== 场景 1:源是母线或节点 ===== + if ((nTypeSrc == 1 || nTypeSrc == 0) && + (nTypeDest != 1 && nTypeDest != 0)) + { + pSrcPort = selectBusOrNodePort(pSrc, pDest, nType); + pDestPort = selectDevicePortByMode(pDest, pSrc, nMode, nParam, nType); + } + // ===== 场景 2:目标是母线或节点 ===== + else if ((nTypeDest == 1 || nTypeDest == 0) && + (nTypeSrc != 1 && nTypeSrc != 0)) + { + pDestPort = selectBusOrNodePort(pDest, pSrc, nType); + pSrcPort = selectDevicePortByMode(pSrc, pDest, nMode, nParam, nType); + } + // ===== 场景 3:两端都是母线或节点 ===== + else if ((nTypeSrc == 1 || nTypeSrc == 0) && + (nTypeDest == 1 || nTypeDest == 0)) + { + selectBusToBusPorts(pSrc, pDest, nType, + pSrcPort, pDestPort); + } + // ===== 场景 4:普通设备 ↔ 设备 ===== + else + { + selectNormalDevicePort(pSrc, pDest, + nMode, nParam, nType, + pSrcPort, pDestPort); + } + + // ===== 绑定 ===== + bindLineAndTopology(pSrcPort, pDestPort, + pItem, pSrc, pDest, nType); +} + +/*template void BaseModel::establishConnection(GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,TypeLine* pItem,ModelFunctionType nType,int nMode,int nParam) { ItemPort* pSrcPort = nullptr; ItemPort* pDestPort = nullptr; @@ -457,6 +770,6 @@ template void BaseModel::establishConnection(GraphicsBaseItem pCon->setState(DataState::Changed); pItem->getProperty()->setConnection(Connection(pSrc->itemId(),QUuid(pSrcPort->getId()),pSrcPort->getType(),pSrcPort->portPos(),pDest->itemId(),QUuid(pDestPort->getId()),pDestPort->getType(),pDestPort->portPos())); } -} +}*/ template void BaseModel::establishConnection(GraphicsBaseItem*,GraphicsBaseItem*,ElectricBaseModelLineItem*,ModelFunctionType,int,int); diff --git a/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp b/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp index fb097ce..6578159 100644 --- a/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp +++ b/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp @@ -22,6 +22,7 @@ #include "common/core_model/constants.h" #include "include/instance/baseTypeManager.h" #include "diagramEditor/layoutCalculator.h" +#include "diagramEditor/editorDiagramLayoutEngine.h" int g_nCompoWidth = 50; //元件默认宽度(计算布局使用) int g_nCompoHeight = 50; @@ -797,174 +798,6 @@ void DiagramEditorModel::generatePreview(bool bVisible) void DiagramEditorModel::calculateBlockPos() { - /*if(_pWizard){ - double deltaY = 0; //竖直方向每行增量 - double lastMaxDownH = 0; //上一行的下部最大高度 - auto mapTotal = _pWizard->getContainerStruct(); - for(auto iter = mapTotal.begin();iter != mapTotal.end();++iter){ - if(iter.key() == Constants::TRANSFORMER_LEVEL) - continue; - double dMaxUp = 0; //计算最大上方空间 - double dMaxDown = 0; //计算最大下方空间 - - for(auto &pCon:iter.value()){ //首次循环遍历每行container,计算最大上空间高度,最大下空间高度,容器宽度 - auto mapBlocks = pCon->getBlockMap(); - auto lstBlockUp = mapBlocks.value(0); - auto lstBus1 = mapBlocks.value(1); //1母 - auto lstBus2 = mapBlocks.value(2); //2母 - auto lstBlockDown = mapBlocks.value(3); - double dConWidth = 0; - - double dWidthUp = 0; - for(auto pBlock:lstBlockUp){ - QRectF rec = pBlock->getRecSize(); - double dHeight = rec.height(); - double dWidth = rec.width(); - if(dMaxUp < dHeight) - dMaxUp = dHeight; - dWidthUp += g_nHorizontalBlockSpacing+dWidth; - } - dMaxUp += Constants::EDITOR_ITEM_HEIGHT; - - double dWidthDown = 0; - for(auto pBlock:lstBlockDown){ - QRectF rec = pBlock->getRecSize(); - double dHeight = rec.height(); - double dWidth = rec.width(); - if(dMaxDown < dHeight) - dMaxDown = dHeight; - dWidthDown = g_nHorizontalBlockSpacing+dWidth; - } - dMaxDown += Constants::EDITOR_ITEM_HEIGHT; - - int nBusLen = 0; - if(!lstBus1.empty()){ - nBusLen = lstBus1.first()->getRecSize().width(); - } - - if(!lstBus2.empty()){ - int nLen = lstBus2.first()->getRecSize().width(); - if(nBusLen < nLen) - nBusLen = nLen; - } - - dConWidth = dWidthUp > dWidthDown ? dWidthUp : dWidthDown; - if(dConWidth < nBusLen) - dConWidth = nBusLen; - pCon->setWidth(dConWidth); - } - - if(dMaxUp == 0){ - dMaxUp = Constants::EDITOR_ITEM_HEIGHT; - } - if(dMaxDown == 0){ - dMaxDown = Constants::EDITOR_ITEM_HEIGHT; - } - double dDeltaX = 50; //每行横向偏移 - for(auto &pCon:iter.value()){ //第二次循环赋值,计算位置(首先确定母线位置) - pCon->setMaxUpH(dMaxUp); - pCon->setMaxDownH(dMaxDown); - if(iter.value().first() == pCon){ //每行只进行一次y位移 - if(iter == mapTotal.begin()){ //首行 deltaY = 首行dMaxUpH - deltaY = pCon->getMaxUpH(); - } - else if(iter == std::next(mapTotal.begin())){ //第二行 - if(!mapTotal.value(Constants::TRANSFORMER_LEVEL).empty()){ //有变压器 - deltaY = deltaY + pCon->getMaxUpH(); - } - else - deltaY = deltaY + 50 + lastMaxDownH + pCon->getMaxUpH(); - } - else //其他行 deltaY = deltaY+母线高度+上行dMaxDownH+本行dMaxUpH - { - deltaY = deltaY + 50 + lastMaxDownH + pCon->getMaxUpH(); - } - - lastMaxDownH = pCon->getMaxDownH(); - } - pCon->setMidUpY(deltaY); - pCon->setMidDownY(deltaY+50); - pCon->setStartX(dDeltaX); - dDeltaX += pCon->getWidth()+100; - - //计算container中block中心点的位置 - auto mapBlocks = pCon->getBlockMap(); - - for(auto it = mapBlocks.begin();it != mapBlocks.end();++it){ - double pStartX = pCon->getStartX(); //容器起始x - double dMiddleUpY = pCon->getMidUpY(); //获取1母上边y - double dMiddleDownY = pCon->getMidDownY(); //获取2母下边y - double deltaX = pStartX; - for(auto pBlock:it.value()){ - QRectF recBlock = pBlock->getRecSize(); - QPointF center; - if(pBlock->getType() == 1){ //母线 - if(it.key() == 1){ //1母 - center = QPointF(pStartX,dMiddleUpY+recBlock.height()*0.5); - } - else if(it.key() == 2){ //2母 - center = QPointF(pStartX,dMiddleDownY-recBlock.height()*0.5); - } - } - else if(pBlock->getType() == 2){ //间隔 - if(it.key() == 0){ //容器最上层 - center = QPointF(deltaX+recBlock.width()*0.5,dMiddleUpY-recBlock.height()*0.5-Constants::EDITOR_ITEM_HEIGHT*0.5); - } - else if(it.key() == 3){ //容器最下层 - center = QPointF(deltaX+recBlock.width()*0.5,dMiddleDownY+recBlock.height()*0.5+Constants::EDITOR_ITEM_HEIGHT*0.5); - } - deltaX += recBlock.width(); - } - else if(pBlock->getType() == 3){ //变压器 - } - - if(!center.isNull()) - pBlock->setSeceneDelta(center); - //qDebug()<getName()<<":"<getBlockMap(); - auto lstBlock = mapBlocks.value(1); - for(auto &pb:lstBlock){ - QRectF rec = pb->getRecSize(); - pCon->setWidth(rec.width()); - pCon->setHeight(rec.height()); - } - } - - for(auto &pCon:lstCon){ //计算位置 - if(pCon == lstCon.first()){ - //只在每行第一次改变deltaY - deltaY = deltaY + 50 + lastMaxDownH + pCon->getHeight(); - } - double dHeight = pCon->getHeight(); - double dWidth = pCon->getWidth(); - pCon->setStartY(deltaY-dHeight*0.5); - pCon->setStartX(dDeltaX); - dDeltaX += dWidth+200; - - auto mapBlocks = pCon->getBlockMap(); - - for(auto it = mapBlocks.begin();it != mapBlocks.end();++it){ - for(auto pBlock:it.value()){ - QRectF recBlock = pBlock->getRecSize(); - QPointF center = QPointF(pCon->getStartX()+recBlock.width()*0.5,pCon->getStartY()+recBlock.height()*0.5); - pBlock->setSeceneDelta(center); - qDebug()<getName()<<":"< DiagramEditorModel::generateItemByInfo(QMap mapRoute,QMap mapCompo,QPointF delta,DiagramEditorBaseBlock* pParent) +QList DiagramEditorModel::generateItemByInfo(QMap& mapRoute,QMap& mapCompo,QPointF delta,DiagramEditorBaseBlock* pParent) { QList lstBind; //连接外部对象的component QString sMain; @@ -1503,21 +1336,33 @@ void DiagramEditorModel::clearCompoDir(QMap& dat compoInfo.nRotate = 0; } } - /*for(auto &routeInfo:data){ - routeInfo.lstOrder.clear(); - routeInfo.lstReverse.clear(); - for(auto &compo:routeInfo.lstCompo){ - compo.nUsedDirection = 0; - } - } - - for(auto &compoInfo:compos){ - compoInfo.nUsedDirection = 0; - compoInfo.nRotate = 0; - }*/ } -QRectF DiagramEditorModel::updateTarget(QMap& data,QMap& compos,int nLayout,int nSource,bool saveToModel) +QRectF DiagramEditorModel::updateTarget( + QMap& data, + QMap& compos, + int nLayout, + int nSource, + bool saveToModel) { + + // 1. 创建配置 + LayoutConfig config(nLayout); + config.setSpacing(Constants::V_DIAGRAM_SPACING, + Constants::H_DIAGRAM_SPACING); + + // 2. 创建引擎和上下文 + DiagramLayoutEngine engine(this); + DiagramLayoutEngine::Context context; + context.sourceId = nSource; + context.saveToModel = saveToModel; + + // 3. 执行布局 + QRectF boundingRect = engine.executeLayout(data, compos, config, context); + + return boundingRect; +} + +/*QRectF DiagramEditorModel::updateTarget(QMap& data,QMap& compos,int nLayout,int nSource,bool saveToModel) { QRectF recBounding; //包含所有元件的矩形 auto& mapRoute = data; @@ -2082,39 +1927,6 @@ QRectF DiagramEditorModel::updateTarget(QMap& da } if(!route.lstCompo.isEmpty()){ //拆分线路为以节点为首 - /*auto pItemFirst = getNameItem(route.lstCompo.first().sName,nSource); - int nFirstVal = pItemFirst->data().toInt(); - auto pItemLast = getNameItem(route.lstCompo.last().sName,nSource); - int nLastVal = pItemLast->data().toInt(); - if(nFirstVal != 0){ //首位为节点 - route.lstOrder = route.lstCompo; - } - else if(nLastVal != 0){ //末位为节点 - for (auto it = route.lstCompo.rbegin(); it != route.lstCompo.rend(); ++it) { - route.lstReverse.append(*it); - } - } - else{ //节点在中间 - int nIndex = 0; - for(int i = 0;i < route.lstCompo.size();++i){ - auto pItem = getNameItem(route.lstCompo[i].sName,nSource); - if(pItem){ - int nVal = pItem->data().toInt(); - if(nVal != 0){ - nIndex = i; - break; - } - } - } - - for(int i = nIndex;i >= 0;--i){ - route.lstReverse.append(route.lstCompo[i]); - } - - for(int i = nIndex;i < route.lstCompo.size();++i){ - route.lstOrder.append(route.lstCompo[i]); - } - }*/ if(saveToModel){ auto pItemFirst = getNameItem(route.lstCompo.first().sName,nSource); int nFirstVal = pItemFirst->data().toInt(); @@ -2561,7 +2373,7 @@ QRectF DiagramEditorModel::updateTarget(QMap& da } } return recBounding; -} +}*/ void DiagramEditorModel::bulidAndLinkComponent(QList lst,QMap components,DiagramEditorBaseBlock* pParent) { diff --git a/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui b/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui index 326ae34..6086e9b 100644 --- a/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui +++ b/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui @@ -313,7 +313,7 @@ QPushButton:disabled { - 设备库 + 间隔设备 diff --git a/diagramCavas/ui/diagramEditorTransDetailAddDlg.ui b/diagramCavas/ui/diagramEditorTransDetailAddDlg.ui index 2613b7c..a2232e0 100644 --- a/diagramCavas/ui/diagramEditorTransDetailAddDlg.ui +++ b/diagramCavas/ui/diagramEditorTransDetailAddDlg.ui @@ -313,7 +313,7 @@ QPushButton:disabled { - 设备库 + 间隔设备