2026-05-08 18:03:54 +08:00
|
|
|
|
#include "diagramEditor/editorDiagramLayoutEngine.h"
|
|
|
|
|
|
#include "diagramEditor/editorDirectionManager.h"
|
2026-05-11 18:38:15 +08:00
|
|
|
|
#include "graphicsDataModel/diagramEditorModel.h"
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 主入口函数
|
|
|
|
|
|
QRectF DiagramLayoutEngine::executeLayout(
|
|
|
|
|
|
QMap<QString, DiagramEditorRouteInfo>& routes,
|
|
|
|
|
|
QMap<QString, DiagramEditorComponentInfo>& components,
|
|
|
|
|
|
const LayoutConfig& config,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
context.initComponentsCache(components);
|
|
|
|
|
|
context.itemCache.clear();
|
|
|
|
|
|
|
|
|
|
|
|
QString mainRouteName = findMainRoute(routes);
|
|
|
|
|
|
if (mainRouteName.isEmpty()) {
|
|
|
|
|
|
qWarning() << "No main route found";
|
|
|
|
|
|
return QRectF();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// 1. 布局主线
|
|
|
|
|
|
layoutMainRoute(routes[mainRouteName], config, context);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// 2. 布局所有支线(✅ 此时方向数据必须是最新的)
|
2026-05-08 18:03:54 +08:00
|
|
|
|
for (auto it = routes.begin(); it != routes.end(); ++it) {
|
|
|
|
|
|
if (it->sRouteName == mainRouteName) continue;
|
|
|
|
|
|
layoutBranchRoute(*it, config, context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 3. 所有布局完成之后,才更新 components
|
2026-05-08 18:03:54 +08:00
|
|
|
|
if (!context.saveToModel) {
|
2026-05-11 18:38:15 +08:00
|
|
|
|
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;
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// 4. 计算边界
|
2026-05-08 18:03:54 +08:00
|
|
|
|
if (!context.saveToModel) {
|
|
|
|
|
|
return calculateBoundingRect(components);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
return QRectF();
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 查找主线
|
|
|
|
|
|
QString DiagramLayoutEngine::findMainRoute(
|
|
|
|
|
|
const QMap<QString, DiagramEditorRouteInfo>& routes) {
|
|
|
|
|
|
|
|
|
|
|
|
QString mainRoute;
|
|
|
|
|
|
bool hasMain = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 查找标记为主线
|
|
|
|
|
|
for (auto it = routes.begin(); it != routes.end(); ++it) {
|
|
|
|
|
|
if (it->bMainRoute) {
|
|
|
|
|
|
mainRoute = it->sRouteName;
|
|
|
|
|
|
hasMain = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 未设置主线,选择设备最多的线路
|
|
|
|
|
|
if (!hasMain) {
|
|
|
|
|
|
int maxCount = 0;
|
|
|
|
|
|
for (auto it = routes.begin(); it != routes.end(); ++it) {
|
|
|
|
|
|
int count = it->lstCompo.size();
|
|
|
|
|
|
if (count > maxCount) {
|
|
|
|
|
|
maxCount = count;
|
|
|
|
|
|
mainRoute = it->sRouteName;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 标记为主线
|
|
|
|
|
|
if (!mainRoute.isEmpty()) {
|
|
|
|
|
|
const_cast<QMap<QString, DiagramEditorRouteInfo>&>(routes)[mainRoute].bMainRoute = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return mainRoute;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 布局主线
|
|
|
|
|
|
void DiagramLayoutEngine::layoutMainRoute(
|
|
|
|
|
|
DiagramEditorRouteInfo& route,
|
|
|
|
|
|
const LayoutConfig& config,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
Direction mainDir = config.mainDirection();
|
|
|
|
|
|
auto& components = route.lstCompo;
|
|
|
|
|
|
|
|
|
|
|
|
if (components.isEmpty()) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算分段
|
|
|
|
|
|
int nSeg = components.size() / 2;
|
|
|
|
|
|
int nSegIndex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 确定起始索引方向
|
|
|
|
|
|
if (mainDir == Direction::Down || mainDir == Direction::Right) {
|
|
|
|
|
|
nSegIndex = -nSeg; // 正向从负半开始
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nSegIndex = nSeg; // 反向从正半开始
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历所有组件
|
|
|
|
|
|
for (int i = 0; i < components.size(); ++i) {
|
|
|
|
|
|
DiagramEditorComponentInfo& compo = components[i];
|
|
|
|
|
|
|
|
|
|
|
|
// 确定方向占用
|
|
|
|
|
|
Direction dir = mainDir;
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
|
// 队首保持主线方向
|
|
|
|
|
|
} else if (i == components.size() - 1) {
|
|
|
|
|
|
// 队尾取反方向
|
|
|
|
|
|
dir = DirectionManager::getOpposite(mainDir);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 中间元件双向占用
|
|
|
|
|
|
compo.nUsedDirection = static_cast<int>(mainDir) |
|
|
|
|
|
|
static_cast<int>(DirectionManager::getOpposite(mainDir));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算位置增量
|
|
|
|
|
|
QPoint delta = QPoint(0, 0);
|
|
|
|
|
|
int spacing = DirectionManager::isHorizontal(mainDir)
|
|
|
|
|
|
? config.horizontalSpacing()
|
|
|
|
|
|
: config.verticalSpacing();
|
|
|
|
|
|
|
|
|
|
|
|
if (DirectionManager::isHorizontal(mainDir)) {
|
|
|
|
|
|
delta.setX(nSegIndex * spacing);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
delta.setY(nSegIndex * spacing);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算旋转角度
|
|
|
|
|
|
int rotate = DirectionManager::getRotationAngle(mainDir);
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
if (!context.saveToModel) {
|
|
|
|
|
|
context.componentsCache[compo.sName] = compo;
|
|
|
|
|
|
}
|
2026-05-08 18:03:54 +08:00
|
|
|
|
// 更新组件
|
|
|
|
|
|
updateComponent(compo, dir, delta, rotate, context);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新索引
|
|
|
|
|
|
if (mainDir == Direction::Up || mainDir == Direction::Left) {
|
|
|
|
|
|
nSegIndex -= 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nSegIndex += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 拆分支线
|
|
|
|
|
|
void DiagramLayoutEngine::splitBranchRoute(
|
|
|
|
|
|
DiagramEditorRouteInfo& route,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
route.lstOrder.clear();
|
|
|
|
|
|
route.lstReverse.clear();
|
|
|
|
|
|
|
|
|
|
|
|
if (route.lstCompo.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查首尾元件
|
|
|
|
|
|
int firstDir = getComponentDirection(route.lstCompo.first().sName, context);
|
|
|
|
|
|
int lastDir = getComponentDirection(route.lstCompo.last().sName, context);
|
|
|
|
|
|
|
|
|
|
|
|
if (firstDir != 0) {
|
|
|
|
|
|
// 情况1: 首元件是节点
|
|
|
|
|
|
route.lstOrder = route.lstCompo;
|
|
|
|
|
|
} else if (lastDir != 0) {
|
|
|
|
|
|
// 情况2: 末元件是节点
|
|
|
|
|
|
for (auto it = route.lstCompo.rbegin(); it != route.lstCompo.rend(); ++it) {
|
|
|
|
|
|
route.lstReverse.append(*it);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 情况3: 查找中间节点
|
|
|
|
|
|
int nodeIndex = -1;
|
|
|
|
|
|
for (int i = 0; i < route.lstCompo.size(); ++i) {
|
|
|
|
|
|
int dir = getComponentDirection(route.lstCompo[i].sName, context);
|
|
|
|
|
|
if (dir != 0) {
|
|
|
|
|
|
nodeIndex = i;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (nodeIndex == -1) {
|
|
|
|
|
|
// 没有节点,默认为正序
|
|
|
|
|
|
route.lstOrder = route.lstCompo;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 反向序列: 从节点到开头
|
|
|
|
|
|
for (int i = nodeIndex; i >= 0; --i) {
|
|
|
|
|
|
route.lstReverse.append(route.lstCompo[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 正序序列: 从节点到结尾
|
|
|
|
|
|
for (int i = nodeIndex; i < route.lstCompo.size(); ++i) {
|
|
|
|
|
|
route.lstOrder.append(route.lstCompo[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 布局支线
|
|
|
|
|
|
void DiagramLayoutEngine::layoutBranchRoute(
|
|
|
|
|
|
DiagramEditorRouteInfo& route,
|
|
|
|
|
|
const LayoutConfig& config,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
splitBranchRoute(route, context);
|
|
|
|
|
|
|
|
|
|
|
|
if (route.lstOrder.size() > 1) {
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 第一个元件的真实方向,由 determineBranchDirection 决定
|
|
|
|
|
|
Direction startDir =
|
|
|
|
|
|
determineBranchDirection(route.lstOrder[0],
|
|
|
|
|
|
config.subDirection(),
|
|
|
|
|
|
context);
|
|
|
|
|
|
|
|
|
|
|
|
int polarity = 1;
|
|
|
|
|
|
layoutBranchSequence(route.lstOrder,
|
|
|
|
|
|
startDir,
|
|
|
|
|
|
config,
|
|
|
|
|
|
context,
|
|
|
|
|
|
true,
|
|
|
|
|
|
polarity);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (route.lstReverse.size() > 1) {
|
2026-05-11 18:38:15 +08:00
|
|
|
|
Direction startDir =
|
|
|
|
|
|
determineBranchDirection(route.lstReverse[0],
|
|
|
|
|
|
config.subDirection(),
|
|
|
|
|
|
context);
|
|
|
|
|
|
int polarity = -1;
|
|
|
|
|
|
layoutBranchSequence(route.lstReverse,
|
|
|
|
|
|
startDir,
|
|
|
|
|
|
config,
|
|
|
|
|
|
context,
|
|
|
|
|
|
false,
|
|
|
|
|
|
polarity);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 布局分支序列
|
|
|
|
|
|
void DiagramLayoutEngine::layoutBranchSequence(
|
|
|
|
|
|
QList<DiagramEditorComponentInfo>& sequence,
|
|
|
|
|
|
Direction branchDir,
|
|
|
|
|
|
const LayoutConfig& config,
|
|
|
|
|
|
Context& context,
|
2026-05-11 18:38:15 +08:00
|
|
|
|
bool isOrder,
|
|
|
|
|
|
int polarity) {
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
|
|
|
|
|
if (sequence.size() < 2) return;
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 1. 根据主线方向决定展开轴
|
|
|
|
|
|
bool mainIsVertical =
|
|
|
|
|
|
DirectionManager::isVertical(config.mainDirection());
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 2. 间距由主线方向决定
|
|
|
|
|
|
int spacing = mainIsVertical
|
2026-05-08 18:03:54 +08:00
|
|
|
|
? config.horizontalSpacing()
|
|
|
|
|
|
: config.verticalSpacing();
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
for (int i = 0; i < sequence.size(); ++i) {
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 当前元件作为“起点”
|
|
|
|
|
|
QPoint basePos = getComponentPosition(sequence[i].sName, context);
|
|
|
|
|
|
Direction dir =
|
|
|
|
|
|
determineBranchDirection(sequence[i], branchDir, context);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 如果后面还有元件,才计算偏移
|
|
|
|
|
|
if (i + 1 < sequence.size()) {
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
DiagramEditorComponentInfo& next = sequence[i + 1];
|
|
|
|
|
|
int offset = (i + 1) * polarity * spacing;
|
|
|
|
|
|
QPoint nextPos = basePos;
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
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()); // ✅ 隐式成立,无需再写
|
|
|
|
|
|
}
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
QPoint deltaPos = nextPos - basePos;
|
|
|
|
|
|
Direction nextConnectionDir =
|
|
|
|
|
|
DirectionManager::getOpposite(dir);
|
|
|
|
|
|
int rotate =
|
|
|
|
|
|
DirectionManager::getRotationAngle(dir);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
updateComponent(next, nextConnectionDir,
|
|
|
|
|
|
nextPos, rotate, context);
|
|
|
|
|
|
}
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确定支线方向
|
|
|
|
|
|
Direction DiagramLayoutEngine::determineBranchDirection(
|
|
|
|
|
|
const DiagramEditorComponentInfo& currentNode,
|
|
|
|
|
|
Direction preferredDir,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
int usedDirections = getComponentDirection(currentNode.sName, context);
|
|
|
|
|
|
bool isHorizontalLayout = DirectionManager::isHorizontal(preferredDir);
|
|
|
|
|
|
|
|
|
|
|
|
if (isHorizontalLayout) {
|
|
|
|
|
|
// 水平布局,检查左右
|
|
|
|
|
|
bool leftOccupied = DirectionManager::isDirectionOccupied(usedDirections, Direction::Left);
|
|
|
|
|
|
bool rightOccupied = DirectionManager::isDirectionOccupied(usedDirections, Direction::Right);
|
|
|
|
|
|
|
|
|
|
|
|
if (leftOccupied && rightOccupied) {
|
|
|
|
|
|
qWarning() << "Component" << currentNode.sName
|
|
|
|
|
|
<< "has both left and right directions occupied";
|
|
|
|
|
|
return preferredDir;
|
|
|
|
|
|
} else if (leftOccupied && !rightOccupied) {
|
|
|
|
|
|
return Direction::Right;
|
|
|
|
|
|
} else if (rightOccupied && !leftOccupied) {
|
|
|
|
|
|
return Direction::Left;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return preferredDir;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 垂直布局,检查上下
|
|
|
|
|
|
bool upOccupied = DirectionManager::isDirectionOccupied(usedDirections, Direction::Up);
|
|
|
|
|
|
bool downOccupied = DirectionManager::isDirectionOccupied(usedDirections, Direction::Down);
|
|
|
|
|
|
|
|
|
|
|
|
if (upOccupied && downOccupied) {
|
|
|
|
|
|
qWarning() << "Component" << currentNode.sName
|
|
|
|
|
|
<< "has both up and down directions occupied";
|
|
|
|
|
|
return preferredDir;
|
|
|
|
|
|
} else if (upOccupied && !downOccupied) {
|
|
|
|
|
|
return Direction::Down;
|
|
|
|
|
|
} else if (downOccupied && !upOccupied) {
|
|
|
|
|
|
return Direction::Up;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return preferredDir;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取组件位置
|
|
|
|
|
|
QPoint DiagramLayoutEngine::getComponentPosition(
|
|
|
|
|
|
const QString& componentName,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
if (context.saveToModel) {
|
|
|
|
|
|
QStandardItem* item = getNameItem(componentName, context);
|
|
|
|
|
|
if (item) {
|
|
|
|
|
|
QVariant posData = item->data(Qt::UserRole + 2);
|
|
|
|
|
|
if (posData.isValid() && posData.canConvert<QPoint>()) {
|
|
|
|
|
|
return posData.toPoint();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-11 18:38:15 +08:00
|
|
|
|
return QPoint(0, 0);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
} else {
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 核心修复:优先使用 componentsCache
|
2026-05-08 18:03:54 +08:00
|
|
|
|
if (context.componentsCache.contains(componentName)) {
|
|
|
|
|
|
return context.componentsCache[componentName].deltaPos;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
// ✅ 终极兜底:如果 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);
|
|
|
|
|
|
}
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取组件方向
|
|
|
|
|
|
int DiagramLayoutEngine::getComponentDirection(
|
|
|
|
|
|
const QString& compoName,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
if (context.saveToModel) {
|
|
|
|
|
|
QStandardItem* item = getNameItem(compoName, context);
|
|
|
|
|
|
return item ? item->data().toInt() : 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (context.componentsCache.contains(compoName)) {
|
|
|
|
|
|
return context.componentsCache[compoName].nUsedDirection;
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取名称项
|
|
|
|
|
|
QStandardItem* DiagramLayoutEngine::getNameItem(
|
|
|
|
|
|
const QString& name,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
if (!m_model)
|
|
|
|
|
|
return nullptr;
|
2026-05-08 18:03:54 +08:00
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
return m_model->getNameItem(name, context.sourceId);
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新组件
|
|
|
|
|
|
void DiagramLayoutEngine::updateComponent(
|
|
|
|
|
|
DiagramEditorComponentInfo& compo,
|
|
|
|
|
|
Direction dir,
|
|
|
|
|
|
const QPoint& position,
|
|
|
|
|
|
int rotate,
|
|
|
|
|
|
Context& context) {
|
|
|
|
|
|
|
|
|
|
|
|
if (context.saveToModel) {
|
|
|
|
|
|
QStandardItem* item = getNameItem(compo.sName, context);
|
|
|
|
|
|
if (item) {
|
|
|
|
|
|
int currentDir = item->data().toInt();
|
|
|
|
|
|
int newDir = DirectionManager::markDirectionOccupied(currentDir, dir);
|
|
|
|
|
|
item->setData(QString::number(newDir));
|
|
|
|
|
|
item->setData(position, Qt::UserRole + 2);
|
|
|
|
|
|
item->setData(rotate, Qt::UserRole + 5);
|
2026-05-11 18:38:15 +08:00
|
|
|
|
|
|
|
|
|
|
//compo.nUsedDirection = DirectionManager::markDirectionOccupied(compo.nUsedDirection, dir);
|
|
|
|
|
|
//compo.deltaPos = position;
|
|
|
|
|
|
//compo.nRotate = rotate;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新缓存
|
|
|
|
|
|
//context.componentsCache[compo.sName] = compo;
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
compo.nUsedDirection = DirectionManager::markDirectionOccupied(compo.nUsedDirection, dir);
|
|
|
|
|
|
compo.deltaPos = position;
|
|
|
|
|
|
compo.nRotate = rotate;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新缓存
|
2026-05-11 18:38:15 +08:00
|
|
|
|
context.componentsCache[compo.sName].nUsedDirection = compo.nUsedDirection;
|
|
|
|
|
|
context.componentsCache[compo.sName].deltaPos = compo.deltaPos;
|
|
|
|
|
|
context.componentsCache[compo.sName].nRotate = compo.nRotate;
|
2026-05-08 18:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算边界矩形
|
|
|
|
|
|
QRectF DiagramLayoutEngine::calculateBoundingRect(
|
|
|
|
|
|
const QMap<QString, DiagramEditorComponentInfo>& components) {
|
|
|
|
|
|
|
|
|
|
|
|
if (components.isEmpty()) {
|
|
|
|
|
|
return QRectF();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
qreal minX = 0, maxX = 0, minY = 0, maxY = 0;
|
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
|
|
|
|
for (auto it = components.begin(); it != components.end(); ++it) {
|
|
|
|
|
|
if (it->nUsedDirection == 0) continue; // 未使用的组件
|
|
|
|
|
|
|
|
|
|
|
|
QPointF pos = it->deltaPos;
|
|
|
|
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
|
|
minX = pos.x();
|
|
|
|
|
|
maxX = pos.x() + m_compoWidth;
|
|
|
|
|
|
minY = pos.y();
|
|
|
|
|
|
maxY = pos.y() + m_compoHeight;
|
|
|
|
|
|
first = false;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
minX = qMin(minX, pos.x());
|
|
|
|
|
|
maxX = qMax(maxX, pos.x() + m_compoWidth);
|
|
|
|
|
|
minY = qMin(minY, pos.y());
|
|
|
|
|
|
maxY = qMax(maxY, pos.y() + m_compoHeight);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
|
|
return QRectF(); // 没有使用的组件
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return QRectF(minX, minY, maxX - minX, maxY - minY);
|
|
|
|
|
|
}
|