GridFrame/diagramCavas/source/diagramEditor/editorDiagramLayoutEngine.cpp

448 lines
13 KiB
C++

#include "diagramEditor/editorDiagramLayoutEngine.h"
#include "diagramEditor/editorDirectionManager.h"
// 主入口函数
QRectF DiagramLayoutEngine::executeLayout(
QMap<QString, DiagramEditorRouteInfo>& routes,
QMap<QString, DiagramEditorComponentInfo>& components,
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);
}
// 4. 布局所有支线
for (auto it = routes.begin(); it != routes.end(); ++it) {
if (it->sRouteName == mainRouteName) continue;
layoutBranchRoute(*it, config, context);
}
// 5. 更新组件映射
if (!context.saveToModel) {
for (auto& route : routes) {
for (auto& compo : route.lstCompo) {
components[compo.sName] = compo;
}
}
}
// 6. 计算边界矩形
if (!context.saveToModel) {
return calculateBoundingRect(components);
}
return QRectF(); // saveToModel 时由场景计算边界
}
// 查找主线
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);
// 更新组件
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) {
// 1. 拆分支线
splitBranchRoute(route, context);
// 2. 布局正序序列
if (route.lstOrder.size() > 1) {
layoutBranchSequence(route.lstOrder, config.subDirection(),
config, context, true);
}
// 3. 布局反序序列
if (route.lstReverse.size() > 1) {
layoutBranchSequence(route.lstReverse, config.subDirection(),
config, context, false);
}
}
// 布局分支序列
void DiagramLayoutEngine::layoutBranchSequence(
QList<DiagramEditorComponentInfo>& sequence,
Direction branchDir,
const LayoutConfig& config,
Context& context,
bool isOrder) {
if (sequence.size() < 2) return;
// 获取基准位置
QPoint basePos = getComponentPosition(sequence[0].sName, context);
int index = 1; // 偏移索引从1开始
int polarity = 1; // 方向极性
// 确定极性
if (branchDir == Direction::Left || branchDir == Direction::Up) {
polarity = -1;
}
// 计算间距
int spacing = DirectionManager::isHorizontal(branchDir)
? 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);
// 计算下一个元件的位置
QPoint nextPos = basePos;
int offset = index * polarity * spacing;
if (DirectionManager::isHorizontal(dir)) {
nextPos.setX(basePos.x() + offset);
} else {
nextPos.setY(basePos.y() + offset);
}
// 计算相对位置
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,
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();
}
}
} else {
if (context.componentsCache.contains(componentName)) {
return context.componentsCache[componentName].deltaPos;
}
}
return QPoint(0, 0);
}
// 获取组件方向
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) {
QString cacheKey = QString("%1_%2").arg(name).arg(context.sourceId);
if (!context.itemCache.contains(cacheKey)) {
// 这里应该是具体的模型查找实现
// 为了示例,返回一个临时项
QStandardItem* item = new QStandardItem(name);
context.itemCache[cacheKey] = item;
}
return context.itemCache[cacheKey];
}
// 更新组件
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);
}
} else {
compo.nUsedDirection = DirectionManager::markDirectionOccupied(compo.nUsedDirection, dir);
compo.deltaPos = position;
compo.nRotate = rotate;
// 更新缓存
context.componentsCache[compo.sName] = compo;
}
}
// 计算边界矩形
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);
}