2026-05-06 19:48:33 +08:00
|
|
|
|
// LayoutCalculator.cpp
|
|
|
|
|
|
#include "diagramEditor/layoutCalculator.h"
|
|
|
|
|
|
#include "diagramEditor/diagramEditorWizard.h"
|
2026-05-18 19:12:28 +08:00
|
|
|
|
#include "graphicsDataModel/diagramEditorModel.h"
|
2026-05-06 19:48:33 +08:00
|
|
|
|
#include "diagramEditor/diagramEditorStructContainer.h"
|
|
|
|
|
|
#include "diagramEditor/diagramEditorBaseBlock.h"
|
2026-05-18 19:12:28 +08:00
|
|
|
|
#include "diagramEditor/editPanel.h"
|
|
|
|
|
|
#include "diagramEditor/editScene.h"
|
2026-05-06 19:48:33 +08:00
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
FixedLayoutCalculator::FixedLayoutCalculator(DiagramEditorModel* model)
|
|
|
|
|
|
: m_model(model) {}
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
|
|
|
|
|
QMap<DiagramEditorBaseBlock*, QPointF> FixedLayoutCalculator::calculateLayout() {
|
|
|
|
|
|
m_blockPositions.clear();
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
if (!m_model) {
|
2026-05-06 19:48:33 +08:00
|
|
|
|
qWarning() << "FixedLayoutCalculator: Wizard为空";
|
|
|
|
|
|
return m_blockPositions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
auto mapTotal = m_model->getWizard()->getContainerStruct();
|
2026-05-06 19:48:33 +08:00
|
|
|
|
double deltaY = 0;
|
|
|
|
|
|
double lastMaxDownH = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 按层级顺序处理
|
|
|
|
|
|
for (auto iter = mapTotal.begin(); iter != mapTotal.end(); ++iter) {
|
|
|
|
|
|
int level = iter.key();
|
|
|
|
|
|
|
|
|
|
|
|
if (level == Constants::TRANSFORMER_LEVEL) {
|
|
|
|
|
|
continue; // 变压器特殊处理
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建层级布局
|
|
|
|
|
|
LevelLayout levelLayout;
|
|
|
|
|
|
levelLayout.level = level;
|
|
|
|
|
|
levelLayout.containers = iter.value();
|
|
|
|
|
|
|
|
|
|
|
|
if (levelLayout.containers.isEmpty()) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一阶段:计算尺寸
|
|
|
|
|
|
calculateContainerSizes(levelLayout);
|
|
|
|
|
|
|
|
|
|
|
|
// 第二阶段:计算位置
|
|
|
|
|
|
calculatePositions(levelLayout, deltaY, lastMaxDownH);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理变压器(在层级0之后)
|
|
|
|
|
|
if (level == 0 && mapTotal.contains(Constants::TRANSFORMER_LEVEL)) {
|
|
|
|
|
|
auto transformers = mapTotal.value(Constants::TRANSFORMER_LEVEL);
|
|
|
|
|
|
if (!transformers.isEmpty()) {
|
|
|
|
|
|
calculateTransformerPositions(transformers, deltaY, lastMaxDownH);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return m_blockPositions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FixedLayoutCalculator::calculateContainerSizes(LevelLayout& levelLayout) {
|
|
|
|
|
|
levelLayout.maxUpHeight = 0;
|
|
|
|
|
|
levelLayout.maxDownHeight = 0;
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
for (auto& container : levelLayout.containers) {
|
2026-05-06 19:48:33 +08:00
|
|
|
|
if (!container) continue;
|
|
|
|
|
|
|
|
|
|
|
|
auto mapBlocks = container->getBlockMap();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算上间隔尺寸
|
|
|
|
|
|
auto topBays = mapBlocks.value(0);
|
|
|
|
|
|
double maxUp = 0;
|
|
|
|
|
|
double widthUp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (auto block : topBays) {
|
|
|
|
|
|
if (!block) continue;
|
|
|
|
|
|
QRectF rec = block->getRecSize();
|
|
|
|
|
|
maxUp = qMax(maxUp, rec.height());
|
|
|
|
|
|
widthUp += 100 + rec.width();
|
|
|
|
|
|
}
|
|
|
|
|
|
maxUp += Constants::EDITOR_ITEM_HEIGHT;
|
|
|
|
|
|
levelLayout.maxUpHeight = qMax(levelLayout.maxUpHeight, maxUp);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算下间隔尺寸
|
|
|
|
|
|
auto bottomBays = mapBlocks.value(3);
|
|
|
|
|
|
double maxDown = 0;
|
|
|
|
|
|
double widthDown = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (auto block : bottomBays) {
|
|
|
|
|
|
if (!block) continue;
|
|
|
|
|
|
QRectF rec = block->getRecSize();
|
|
|
|
|
|
maxDown = qMax(maxDown, rec.height());
|
|
|
|
|
|
widthDown += 100 + rec.width();
|
|
|
|
|
|
}
|
|
|
|
|
|
maxDown += Constants::EDITOR_ITEM_HEIGHT;
|
|
|
|
|
|
levelLayout.maxDownHeight = qMax(levelLayout.maxDownHeight, maxDown);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算母线宽度
|
|
|
|
|
|
double busWidth = 0;
|
|
|
|
|
|
auto bus1 = mapBlocks.value(1);
|
|
|
|
|
|
auto bus2 = mapBlocks.value(2);
|
|
|
|
|
|
|
|
|
|
|
|
if (!bus1.isEmpty()) {
|
|
|
|
|
|
busWidth = qMax(busWidth, bus1.first()->getRecSize().width());
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!bus2.isEmpty()) {
|
|
|
|
|
|
busWidth = qMax(busWidth, bus2.first()->getRecSize().width());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算容器宽度
|
|
|
|
|
|
double containerWidth = qMax(widthUp, widthDown);
|
|
|
|
|
|
if (containerWidth < busWidth) {
|
|
|
|
|
|
containerWidth = busWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置容器尺寸
|
|
|
|
|
|
container->setWidth(containerWidth);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理空的情况
|
|
|
|
|
|
if (levelLayout.maxUpHeight == 0) {
|
|
|
|
|
|
levelLayout.maxUpHeight = Constants::EDITOR_ITEM_HEIGHT;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (levelLayout.maxDownHeight == 0) {
|
|
|
|
|
|
levelLayout.maxDownHeight = Constants::EDITOR_ITEM_HEIGHT;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FixedLayoutCalculator::calculatePositions(LevelLayout& levelLayout,
|
|
|
|
|
|
double& deltaY, double& lastMaxDownH) {
|
|
|
|
|
|
double startX = CONTAINER_START_X;
|
|
|
|
|
|
bool isFirstContainer = true;
|
|
|
|
|
|
|
2026-05-11 18:38:15 +08:00
|
|
|
|
for (auto& container : levelLayout.containers) {
|
2026-05-06 19:48:33 +08:00
|
|
|
|
if (!container) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置容器高度
|
|
|
|
|
|
container->setMaxUpH(levelLayout.maxUpHeight);
|
|
|
|
|
|
container->setMaxDownH(levelLayout.maxDownHeight);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算垂直位置(每行第一个容器计算一次)
|
|
|
|
|
|
if (isFirstContainer) {
|
|
|
|
|
|
if (levelLayout.level == 0) { // 首行
|
|
|
|
|
|
deltaY = container->getMaxUpH();
|
|
|
|
|
|
} else { // 其他行
|
|
|
|
|
|
deltaY = deltaY + BUS_V_SPACING + lastMaxDownH + container->getMaxUpH();
|
|
|
|
|
|
}
|
|
|
|
|
|
lastMaxDownH = container->getMaxDownH();
|
|
|
|
|
|
isFirstContainer = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置容器的关键Y坐标
|
|
|
|
|
|
container->setMidUpY(deltaY);
|
|
|
|
|
|
container->setMidDownY(deltaY + BUS_V_SPACING);
|
|
|
|
|
|
container->setStartX(startX);
|
|
|
|
|
|
|
2026-05-14 20:11:48 +08:00
|
|
|
|
// 计算容器内间隔位置
|
2026-05-06 19:48:33 +08:00
|
|
|
|
calculateBlockPositionsInContainer(container, startX, deltaY, deltaY + BUS_V_SPACING);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新水平位置
|
|
|
|
|
|
startX += container->getWidth() + CONTAINER_H_SPACING;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FixedLayoutCalculator::calculateBlockPositionsInContainer(DiagramEditorStructContainer* container,
|
|
|
|
|
|
double startX,
|
|
|
|
|
|
double midUpY,
|
|
|
|
|
|
double midDownY) {
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
|
|
|
|
auto mapBlocks = container->getBlockMap();
|
|
|
|
|
|
double currentX = startX;
|
|
|
|
|
|
|
|
|
|
|
|
for (auto it = mapBlocks.begin(); it != mapBlocks.end(); ++it) {
|
|
|
|
|
|
int layer = it.key();
|
|
|
|
|
|
auto blocks = it.value();
|
|
|
|
|
|
|
|
|
|
|
|
for (auto block : blocks) {
|
|
|
|
|
|
if (!block) continue;
|
|
|
|
|
|
|
|
|
|
|
|
QRectF rec = block->getRecSize();
|
2026-05-14 20:11:48 +08:00
|
|
|
|
QPointF centerOffset = block->getCenterOffset(); //参考中心与boundingrect中心的偏移量
|
2026-05-06 19:48:33 +08:00
|
|
|
|
QPointF center;
|
|
|
|
|
|
|
|
|
|
|
|
int blockType = block->getType();
|
|
|
|
|
|
|
|
|
|
|
|
if (blockType == 1) { // 母线
|
|
|
|
|
|
if (layer == 1) { // 母线1
|
2026-05-14 20:11:48 +08:00
|
|
|
|
center = QPointF(startX-20, midUpY + rec.height() * 0.5);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
} else if (layer == 2) { // 母线2
|
2026-05-14 20:11:48 +08:00
|
|
|
|
center = QPointF(startX-20, midDownY - rec.height() * 0.5);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else if (blockType == 2) { // 间隔
|
2026-05-14 20:11:48 +08:00
|
|
|
|
/*int nLayout = 0; //默认垂直
|
|
|
|
|
|
auto pBay = dynamic_cast<DiagramEditorBayBlock*>(block);
|
|
|
|
|
|
if(pBay){
|
|
|
|
|
|
nLayout = pBay->getBayInfo().nLayout;
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
2026-05-06 19:48:33 +08:00
|
|
|
|
if (layer == 0) { // 上间隔
|
|
|
|
|
|
center = QPointF(currentX + rec.width() * 0.5,
|
2026-05-14 20:11:48 +08:00
|
|
|
|
midUpY - rec.height() * 0.5 + centerOffset.y() - Constants::EDITOR_ITEM_HEIGHT * 0.5);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
} else if (layer == 3) { // 下间隔
|
|
|
|
|
|
center = QPointF(currentX + rec.width() * 0.5,
|
2026-05-14 20:11:48 +08:00
|
|
|
|
midDownY + rec.height() * 0.5 + centerOffset.y() + Constants::EDITOR_ITEM_HEIGHT * 0.5);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
currentX += rec.width();
|
|
|
|
|
|
}
|
|
|
|
|
|
// 变压器不在这里处理
|
|
|
|
|
|
|
|
|
|
|
|
if (!center.isNull()) {
|
|
|
|
|
|
m_blockPositions[block] = center;
|
|
|
|
|
|
block->setSeceneDelta(center);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
void FixedLayoutCalculator::calculateTransformerPositions(
|
|
|
|
|
|
const QList<DiagramEditorStructContainer*>& transformers,
|
|
|
|
|
|
double& deltaY, double& lastMaxDownH)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (transformers.isEmpty())
|
|
|
|
|
|
return;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
// ---------- ① 计算变压器尺寸 ----------
|
2026-05-06 19:48:33 +08:00
|
|
|
|
for (auto container : transformers) {
|
2026-05-18 19:12:28 +08:00
|
|
|
|
if (!container)
|
|
|
|
|
|
continue;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
|
|
|
|
|
auto mapBlocks = container->getBlockMap();
|
2026-05-18 19:12:28 +08:00
|
|
|
|
auto transBlocks = mapBlocks.value(1); // layer 1
|
|
|
|
|
|
|
|
|
|
|
|
if (transBlocks.isEmpty())
|
|
|
|
|
|
continue;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
|
|
|
|
|
for (auto block : transBlocks) {
|
2026-05-18 19:12:28 +08:00
|
|
|
|
if (!block)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2026-05-06 19:48:33 +08:00
|
|
|
|
QRectF rec = block->getRecSize();
|
|
|
|
|
|
container->setWidth(rec.width());
|
|
|
|
|
|
container->setHeight(rec.height());
|
2026-05-18 19:12:28 +08:00
|
|
|
|
break; // 仍然只取第一个
|
2026-05-06 19:48:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
// ---------- ② 纵向位置(保持不变) ----------
|
|
|
|
|
|
double centerY = 0;
|
|
|
|
|
|
if (!transformers.isEmpty()) {
|
|
|
|
|
|
deltaY += CONTAINER_H_SPACING + lastMaxDownH + transformers.first()->getHeight();
|
|
|
|
|
|
centerY = deltaY - transformers.first()->getHeight() * 0.5;
|
|
|
|
|
|
}
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
// ---------- ③ 固定宽度水平布局 ----------
|
|
|
|
|
|
double sceneWidth = m_model->getPanel()->getScene()->width();
|
|
|
|
|
|
const int count = transformers.size();
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
// 没有变压器,直接返回
|
|
|
|
|
|
if (count == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 等间距分布(含左右边距)
|
|
|
|
|
|
const double spacing = sceneWidth / (count + 1);
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- ④ 逐个放置 ----------
|
|
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
|
|
auto container = transformers.at(i);
|
|
|
|
|
|
if (!container)
|
|
|
|
|
|
continue;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
|
|
|
|
|
container->setStartY(centerY);
|
2026-05-18 19:12:28 +08:00
|
|
|
|
|
|
|
|
|
|
// 计算水平中心
|
|
|
|
|
|
const double centerX = spacing * (i + 1);
|
|
|
|
|
|
const double startX = centerX - container->getWidth() * 0.5;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
container->setStartX(startX);
|
|
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
// ---------- ⑤ 内部 block 居中 ----------
|
2026-05-06 19:48:33 +08:00
|
|
|
|
auto mapBlocks = container->getBlockMap();
|
|
|
|
|
|
for (auto it = mapBlocks.begin(); it != mapBlocks.end(); ++it) {
|
|
|
|
|
|
for (auto block : it.value()) {
|
2026-05-18 19:12:28 +08:00
|
|
|
|
if (!block)
|
|
|
|
|
|
continue;
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
|
|
|
|
|
QRectF rec = block->getRecSize();
|
2026-05-18 19:12:28 +08:00
|
|
|
|
QPointF pos(
|
|
|
|
|
|
startX + rec.width() * 0.5,
|
|
|
|
|
|
centerY + rec.height() * 0.5
|
|
|
|
|
|
);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
|
2026-05-18 19:12:28 +08:00
|
|
|
|
m_blockPositions[block] = pos;
|
|
|
|
|
|
block->setSeceneDelta(pos);
|
2026-05-06 19:48:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|