optimize editor topology algorithm

This commit is contained in:
baiYue 2026-05-11 18:38:15 +08:00
parent 3afdc864d9
commit 9ef08a005e
14 changed files with 549 additions and 307 deletions

View File

@ -153,7 +153,7 @@ struct DiagramEditorRouteInfo //间隔中单条线路信息
struct DiagramEditorBayInfo //组态编辑间隔信息
{
QString name; //间隔名
int nLayout; //布局 0纵向1横向
int nLayout = 0; //布局 0纵向1横向
QList<QUuid> lstFrom; //起始
QList<QUuid> lstTo; //结束
QMap<QString,DiagramEditorRouteInfo> mapRoute; //线路信息

View File

@ -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<QString, DiagramEditorRouteInfo>& routes,
QMap<QString, DiagramEditorComponentInfo>& 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;
};

View File

@ -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; // 默认值
};

View File

@ -14,6 +14,7 @@ public:
double maxUpHeight = 0; // 整行最大上高度
double maxDownHeight = 0; // 整行最大下高度
double startY = 0; // 行起始Y
QList<DiagramEditorStructContainer*> containers;
};

View File

@ -30,6 +30,14 @@ public:
return qSqrt(diff.x() * diff.x() + diff.y() * diff.y());
}
ItemPort* getClosestUnusedPort(QMap<QString,ItemPort*>,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<typename TypeLine>
void bindLineAndTopology(ItemPort* pSrcPort,ItemPort* pDestPort,TypeLine* pItem,GraphicsBaseItem* pSrc,GraphicsBaseItem* pDest,ModelFunctionType nType);//绑定连线 + 拓扑
};

View File

@ -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<DiagramEditorComponentInfo> generateItemByInfo(QMap<QString,DiagramEditorRouteInfo> mapRoute,QMap<QString,DiagramEditorComponentInfo> mapCompo,QPointF delta = QPointF(0,0),DiagramEditorBaseBlock* pParent = nullptr); //根据data生成item parent:生成的对象添加到parent下(非拓扑计算)
QList<DiagramEditorComponentInfo> generateItemByInfo(QMap<QString,DiagramEditorRouteInfo>& mapRoute,QMap<QString,DiagramEditorComponentInfo>& mapCompo,QPointF delta = QPointF(0,0),DiagramEditorBaseBlock* pParent = nullptr); //根据data生成item parent:生成的对象添加到parent下(非拓扑计算)
QMultiMap<int,QUuid> generateOutConnection(QList<DiagramEditorComponentInfo>,QList<HierarchyItem>&,int nTypeTransCon,int nPos = 0,DiagramEditorBaseBlock* pParent = nullptr); //生成外部连接手动bind的连接relation:层级关系引用 nTypeTransCon变压器连线类型,1中性点连接2外部连接,nPos中性点连接时的位置
QRectF updateTarget(QMap<QString,DiagramEditorRouteInfo>&,QMap<QString,DiagramEditorComponentInfo>&,int nLayout,int nSource,bool saveToModel = true); //更新位置 nLayout主次朝向:8421,8421 上下左右,上下左右 nSource:0间隔1变压器 regenerate重新生成标志 saveToModel:生成到模型或map
void clearCompoDir(QMap<QString,DiagramEditorRouteInfo>&,QMap<QString,DiagramEditorComponentInfo>&,int nSource); //清空component中的dir(updateTarget前调用)

View File

@ -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);

View File

@ -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<QString,DiagramEditorComponentInfo> mapComponents;
/*QMap<QString,DiagramEditorComponentInfo> 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<QString, DiagramEditorComponentInfo> 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();

View File

@ -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<QString, DiagramEditorRouteInfo>& 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<QPoint>()) {
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;
}
}

View File

@ -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;
// 设置容器高度

View File

@ -99,7 +99,320 @@ ItemPort* BaseModel::getClosestUnusedPort(QMap<QString,ItemPort*> mapPorts,Graph
return nullptr;
}
template<typename TypeLine> 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<QString, ItemPort*> 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<QString, ItemPort*> mapSrc = pSrc->getPorts();
QMap<QString, ItemPort*> 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<QString, ItemPort*> mapSrc = pSrc->getPorts();
QMap<QString, ItemPort*> 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<typename TypeLine>
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<typename TypeLine>
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<typename TypeLine> 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<typename TypeLine> 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<ElectricBaseModelLineItem>(GraphicsBaseItem*,GraphicsBaseItem*,ElectricBaseModelLineItem*,ModelFunctionType,int,int);

View File

@ -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()<<pBlock->getName()<<":"<<center<<"-"<<recBlock;
}
}
}
dDeltaX = 150; //首个变压器位置
if(iter.key() == 0){ //若设置了变压器,直接插入到第一行下方
if(!mapTotal.value(Constants::TRANSFORMER_LEVEL).empty()){
auto lstCon = mapTotal.value(Constants::TRANSFORMER_LEVEL);
for(auto &pCon:lstCon){ //首次计算变压器大小
auto mapBlocks = pCon->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()<<pBlock->getName()<<":"<<center<<"-"<<recBlock;
}
}
}
}
}
}
}*/
if (!_pWizard) {
qWarning() << "calculateBlockPos: Wizard为空";
return;
@ -1213,7 +1046,7 @@ void DiagramEditorModel::generateItemByModel(QStandardItemModel* pModel,DiagramE
}
}
QList<DiagramEditorComponentInfo> DiagramEditorModel::generateItemByInfo(QMap<QString,DiagramEditorRouteInfo> mapRoute,QMap<QString,DiagramEditorComponentInfo> mapCompo,QPointF delta,DiagramEditorBaseBlock* pParent)
QList<DiagramEditorComponentInfo> DiagramEditorModel::generateItemByInfo(QMap<QString,DiagramEditorRouteInfo>& mapRoute,QMap<QString,DiagramEditorComponentInfo>& mapCompo,QPointF delta,DiagramEditorBaseBlock* pParent)
{
QList<DiagramEditorComponentInfo> lstBind; //连接外部对象的component
QString sMain;
@ -1503,21 +1336,33 @@ void DiagramEditorModel::clearCompoDir(QMap<QString,DiagramEditorRouteInfo>& 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<QString,DiagramEditorRouteInfo>& data,QMap<QString,DiagramEditorComponentInfo>& compos,int nLayout,int nSource,bool saveToModel)
QRectF DiagramEditorModel::updateTarget(
QMap<QString, DiagramEditorRouteInfo>& data,
QMap<QString, DiagramEditorComponentInfo>& 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<QString,DiagramEditorRouteInfo>& data,QMap<QString,DiagramEditorComponentInfo>& compos,int nLayout,int nSource,bool saveToModel)
{
QRectF recBounding; //包含所有元件的矩形
auto& mapRoute = data;
@ -2082,39 +1927,6 @@ QRectF DiagramEditorModel::updateTarget(QMap<QString,DiagramEditorRouteInfo>& 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<QString,DiagramEditorRouteInfo>& da
}
}
return recBounding;
}
}*/
void DiagramEditorModel::bulidAndLinkComponent(QList<DiagramEditorComponentInfo> lst,QMap<QString,DiagramEditorComponentInfo> components,DiagramEditorBaseBlock* pParent)
{

View File

@ -313,7 +313,7 @@ QPushButton:disabled {
<item row="2" column="1">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>设备</string>
<string>间隔设备</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">

View File

@ -313,7 +313,7 @@ QPushButton:disabled {
<item row="2" column="1">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>设备</string>
<string>间隔设备</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">