#include "diagramEditor/editorDiagramLayoutEngine.h" #include "diagramEditor/editorDirectionManager.h" #include "graphicsDataModel/diagramEditorModel.h" // 主入口函数 QRectF DiagramLayoutEngine::executeLayout( QMap& routes, QMap& 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(); } // 1. 布局主线 layoutMainRoute(routes[mainRouteName], config, context); // 2. 布局所有支线(✅ 此时方向数据必须是最新的) for (auto it = routes.begin(); it != routes.end(); ++it) { if (it->sRouteName == mainRouteName) continue; layoutBranchRoute(*it, config, context); } // ✅ 3. 所有布局完成之后,才更新 components if (!context.saveToModel) { 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; } } // 4. 计算边界 if (!context.saveToModel) { return calculateBoundingRect(components); } return QRectF(); } // 查找主线 QString DiagramLayoutEngine::findMainRoute( const QMap& 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&>(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(mainDir) | static_cast(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); if (!context.saveToModel) { context.componentsCache[compo.sName] = compo; } // 更新组件 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) { // ✅ 第一个元件的真实方向,由 determineBranchDirection 决定 Direction startDir = determineBranchDirection(route.lstOrder[0], config.subDirection(), context); int polarity = 1; layoutBranchSequence(route.lstOrder, startDir, config, context, true, polarity); } if (route.lstReverse.size() > 1) { Direction startDir = determineBranchDirection(route.lstReverse[0], config.subDirection(), context); int polarity = -1; layoutBranchSequence(route.lstReverse, startDir, config, context, false, polarity); } } // 布局分支序列 void DiagramLayoutEngine::layoutBranchSequence( QList& sequence, Direction branchDir, const LayoutConfig& config, Context& context, bool isOrder, int polarity) { if (sequence.size() < 2) return; // ✅ 1. 根据主线方向决定展开轴 bool mainIsVertical = DirectionManager::isVertical(config.mainDirection()); // ✅ 2. 间距由主线方向决定 int spacing = mainIsVertical ? config.horizontalSpacing() : config.verticalSpacing(); for (int i = 0; i < sequence.size(); ++i) { // ✅ 当前元件作为“起点” QPoint basePos = getComponentPosition(sequence[i].sName, context); Direction dir = determineBranchDirection(sequence[i], branchDir, context); // ✅ 如果后面还有元件,才计算偏移 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); } } } // 确定支线方向 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()) { return posData.toPoint(); } } return QPoint(0, 0); } else { // ✅ 核心修复:优先使用 componentsCache if (context.componentsCache.contains(componentName)) { return context.componentsCache[componentName].deltaPos; } // ✅ 终极兜底:如果 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); } } // 获取组件方向 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) { if (!m_model) return nullptr; return m_model->getNameItem(name, context.sourceId); } // 更新组件 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); //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); compo.deltaPos = position; compo.nRotate = rotate; // 更新缓存 context.componentsCache[compo.sName].nUsedDirection = compo.nUsedDirection; context.componentsCache[compo.sName].deltaPos = compo.deltaPos; context.componentsCache[compo.sName].nRotate = compo.nRotate; } } // 计算边界矩形 QRectF DiagramLayoutEngine::calculateBoundingRect( const QMap& 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); }