You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxDFN.cpp

522 lines
18 KiB
C++

#include "nmWxDFN.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTreeWidgetItem>
#include <QHeaderView>
#include <QDebug>
#include <QCoreApplication>
#include "nmWxDFNGenerateDlg.h"
#include "nmWxDFNLoadFromFile.h"
#include "nmWxDFNExportDlg.h"
#include "nmDataAnalyzeManager.h"
#include "nmGuiPlot.h"
// 构造函数
nmWxDFN::nmWxDFN(QWidget *parent)
: iDlgBase(parent)
{
setWindowTitle(tr("DFN"));
setMinimumSize(516, 519);
// 从数据中心获取DFN数据
m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList();
qsrand(QTime::currentTime().msec());
this->initUI();
this->initConnections();
updateButtonsState();
m_originType = None;
}
nmWxDFN::~nmWxDFN()
{
}
void nmWxDFN::initUI()
{
QVBoxLayout *pMainLayout = new QVBoxLayout(this);
pMainLayout->setSpacing(15); // 增加组件间距
// 操作按钮组
QHBoxLayout *pButtonLayout = new QHBoxLayout();
// 创建包含按钮和标签的Widget
m_pLoadButtonWidget = new QWidget(this);
m_pGenerateButtonWidget = new QWidget(this);
m_pDeleteButtonWidget = new QWidget(this);
m_pExportButtonWidget = new QWidget(this);
m_pLoadButton = new QPushButton(m_pLoadButtonWidget);
m_pGenerateButton = new QPushButton(m_pGenerateButtonWidget);
m_pDeleteButton = new QPushButton(m_pDeleteButtonWidget);
m_pExportButton = new QPushButton(m_pExportButtonWidget);
m_pLoadButtonLabel = new QLabel(tr("Load"), m_pLoadButtonWidget);
m_pGenerateButtonLabel = new QLabel(tr("Generate"), m_pGenerateButtonWidget);
m_pDeleteButtonLabel = new QLabel(tr("Delete"), m_pDeleteButtonWidget);
m_pExportButtonLabel = new QLabel(tr("Export"), m_pExportButtonWidget);
QString appDir = QCoreApplication::applicationDirPath();
appDir = appDir.section('/', 0, -2); // 获取上一级目录
// 设置按钮图标
QIcon loadIcon(appDir + "/Res/Icon/NmDFNLoad.png");
QIcon generateIcon(appDir + "/Res/Icon/NmDFNGenerate.png");
QIcon deleteIcon(appDir + "/Res/Icon/NmDFNDelete.png");
QIcon exportIcon(appDir + "/Res/Icon/NmDFNExport.png");
m_pLoadButton->setIcon(loadIcon);
m_pGenerateButton->setIcon(generateIcon);
m_pDeleteButton->setIcon(deleteIcon);
m_pExportButton->setIcon(exportIcon);
// 设置图标大小
int iconSize = 28;
m_pLoadButton->setIconSize(QSize(iconSize, iconSize));
m_pGenerateButton->setIconSize(QSize(iconSize, iconSize));
m_pDeleteButton->setIconSize(QSize(iconSize, iconSize));
m_pExportButton->setIconSize(QSize(iconSize, iconSize));
int iButtonSize = 32;
m_pLoadButton->setFixedSize(iButtonSize, iButtonSize);
m_pGenerateButton->setFixedSize(iButtonSize, iButtonSize);
m_pDeleteButton->setFixedSize(iButtonSize, iButtonSize);
m_pExportButton->setFixedSize(iButtonSize, iButtonSize);
// 设置标签文本对齐方式为居中
m_pLoadButtonLabel->setAlignment(Qt::AlignHCenter);
m_pGenerateButtonLabel->setAlignment(Qt::AlignHCenter);
m_pDeleteButtonLabel->setAlignment(Qt::AlignHCenter);
m_pExportButtonLabel->setAlignment(Qt::AlignHCenter);
// 使用垂直布局排列按钮和标签
QVBoxLayout *pLoadButtonLayout = new QVBoxLayout(m_pLoadButtonWidget);
// 设置尺寸策略,防止布局收缩或拉伸异常
pLoadButtonLayout->setSizeConstraint(QLayout::SetFixedSize);
pLoadButtonLayout->addWidget(m_pLoadButton);
pLoadButtonLayout->addWidget(m_pLoadButtonLabel);
pLoadButtonLayout->setSpacing(0);
pLoadButtonLayout->setContentsMargins(0, 0, 0, 0);
pLoadButtonLayout->setAlignment(Qt::AlignHCenter);
QVBoxLayout *pGenerateButtonLayout = new QVBoxLayout(m_pGenerateButtonWidget);
pGenerateButtonLayout->setSizeConstraint(QLayout::SetFixedSize);
pGenerateButtonLayout->addWidget(m_pGenerateButton);
pGenerateButtonLayout->addWidget(m_pGenerateButtonLabel);
pGenerateButtonLayout->setSpacing(0);
pGenerateButtonLayout->setContentsMargins(0, 0, 0, 0);
pGenerateButtonLayout->setAlignment(Qt::AlignHCenter);
QVBoxLayout *pDeleteButtonLayout = new QVBoxLayout(m_pDeleteButtonWidget);
pDeleteButtonLayout->setSizeConstraint(QLayout::SetFixedSize);
pDeleteButtonLayout->addWidget(m_pDeleteButton);
pDeleteButtonLayout->addWidget(m_pDeleteButtonLabel);
pDeleteButtonLayout->setSpacing(0);
pDeleteButtonLayout->setContentsMargins(0, 0, 0, 0);
pDeleteButtonLayout->setAlignment(Qt::AlignHCenter);
QVBoxLayout *pExportButtonLayout = new QVBoxLayout(m_pExportButtonWidget);
pExportButtonLayout->setSizeConstraint(QLayout::SetFixedSize);
pExportButtonLayout->addWidget(m_pExportButton);
pExportButtonLayout->addWidget(m_pExportButtonLabel);
pExportButtonLayout->setSpacing(0);
pExportButtonLayout->setContentsMargins(0, 0, 0, 0);
pExportButtonLayout->setAlignment(Qt::AlignHCenter);
pButtonLayout->addWidget(m_pLoadButtonWidget);
pButtonLayout->addWidget(m_pGenerateButtonWidget);
pButtonLayout->addWidget(m_pDeleteButtonWidget);
pButtonLayout->addWidget(m_pExportButtonWidget);
pButtonLayout->addStretch();
pMainLayout->addLayout(pButtonLayout);
// 选项框组
QVBoxLayout *pCheckBoxLayout = new QVBoxLayout();
m_pRedefineKrPcCheckBox = new QCheckBox(tr("Redefine KrPc in natural fissures"), this);
m_pUnconsolidationCheckBox = new QCheckBox(tr("Apply unconsolidation in natural fissures"), this);
pCheckBoxLayout->addWidget(m_pRedefineKrPcCheckBox);
pCheckBoxLayout->addWidget(m_pUnconsolidationCheckBox);
pMainLayout->addLayout(pCheckBoxLayout);
// 参数树
QHBoxLayout *pTreeWidgetLayout = new QHBoxLayout();
m_pParameterTree = new QTreeWidget(this);
m_pParameterTree->setHeaderLabels(QStringList() << tr("Parameters") << "");
m_pParameterTree->setColumnCount(2); // 明确设置列数为2
// 隐藏表头垂直分隔线
QHeaderView* parameterHeader = m_pParameterTree->header();
parameterHeader->setStyleSheet(
"QHeaderView {"
" background-color: #e5e6e9;" // 表头背景色
"}"
"QHeaderView::section {"
" border-right: none;"
" border-left: none;"
"}"
);
// 禁止调整列宽
parameterHeader->setResizeMode(QHeaderView::Fixed);
// 设置表头不可以拖动
parameterHeader->setMovable(false);
parameterHeader->setResizeMode(QHeaderView::Stretch); // 所有列平分
// 设置根节点样式
m_pParameterTree->setStyleSheet(
"QTreeWidget::item:has-children {" // 有子节点的项
" background-color: #b2cbeb;" // 浅蓝色背景
"}"
);
// 设置整行选中
m_pParameterTree->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pParameterTree->setSelectionMode(QAbstractItemView::SingleSelection);
setupParameterTree();
pTreeWidgetLayout->addWidget(m_pParameterTree);
pMainLayout->addLayout(pTreeWidgetLayout);
// 确定/取消按钮
QHBoxLayout *pBottomLayout = new QHBoxLayout();
pBottomLayout->addStretch(); // 添加伸缩项,将按钮推到右侧
m_pOkButton = new QPushButton(tr("OK"), this);
m_pCancelButton = new QPushButton(tr("Cancel"), this);
pBottomLayout->addWidget(m_pOkButton);
pBottomLayout->addWidget(m_pCancelButton);
pMainLayout->addLayout(pBottomLayout);
}
void nmWxDFN::initConnections()
{
connect(m_pLoadButton, SIGNAL(clicked()), this, SLOT(onLoadButtonClicked()));
connect(m_pGenerateButton, SIGNAL(clicked()), this, SLOT(onGenerateButtonClicked()));
connect(m_pDeleteButton, SIGNAL(clicked()), this, SLOT(onDeleteButtonClicked()));
connect(m_pExportButton, SIGNAL(clicked()), this, SLOT(onExportButtonClicked()));
connect(m_pOkButton, SIGNAL(clicked()), this, SLOT(onOkButtonClicked()));
connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(onCancelButtonClicked()));
connect(m_pParameterTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
this, SLOT(onItemClicked(QTreeWidgetItem*, int)));
}
void nmWxDFN::setupParameterTree()
{
//if (m_vecDFNData.empty()) {
// QTreeWidgetItem* pGeneralItem = addRootItem(tr("General"));
// addChildItem(pGeneralItem, tr("Number of fissures"), "0", true);
//} else {
// QTreeWidgetItem* pGeneralItem = addRootItem(tr("General"));
// // 添加新的节点
// addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false);
// addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false);
// // 计算总和和平均值
// double totalXf = 0.0;
// for (int i = 0; i < m_vecDFNData.size(); i++) {
// QVector<QPointF> vecPts = m_vecDFNData[i]->getFracturePoints();
// if (vecPts.size() == 2) {
// QPointF ptStartPoint = vecPts[0];
// QPointF ptEndPoint = vecPts[1];
// totalXf += QLineF(ptStartPoint, ptEndPoint).length();
// }
// }
// double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size();
// addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf));
// addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf));
// QTreeWidgetItem* pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters"));
// // 裂缝流动类型
// addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(),false);
// // TODO:孔隙度
// addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false);
// // TODO:裂缝宽度
// addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false);
// // TODO:裂缝导流能力
// addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false);
//}
this->refreshParameterTree();
}
void nmWxDFN::refreshParameterTree()
{
// 禁用UI更新以提高性能
m_pParameterTree->setUpdatesEnabled(false);
// 清空现有树结构
m_pParameterTree->clear();
// 根据数据状态选择构建方式
if(!m_vecDFNData.empty()) {
setupDFNDataTree();
} else {
setupDefaultTree();
}
// 重新启用更新
m_pParameterTree->setUpdatesEnabled(true);
// 刷新按钮状态
updateButtonsState();
}
void nmWxDFN::setupDFNDataTree()
{
// 1. 添加General分组
QTreeWidgetItem* pGeneralItem = addRootItem(tr("General"));
// 填充General分组
//addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false);
QString originText;
switch (m_originType) {
case Loaded:
originText = tr("Loaded from file");
break;
case Generated:
originText = tr("Generated");
break;
default:
originText = tr("N/A");
break;
}
addChildItem(pGeneralItem, tr("Origin"), originText, false);
addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false);
// 计算总和和平均值
double totalXf = 0.0;
for(int i = 0; i < m_vecDFNData.size(); i++) {
QVector<QPointF> vecPts = m_vecDFNData[i]->getFracturePoints();
if(vecPts.size() == 2) {
QPointF ptStartPoint = vecPts[0];
QPointF ptEndPoint = vecPts[1];
totalXf += QLineF(ptStartPoint, ptEndPoint).length();
}
}
double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size();
addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf));
addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf));
// 2. 添加Global参数分组
QTreeWidgetItem* pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters"));
// 填充Global参数添加安全检查
if(!m_vecDFNData.empty()) {
// 裂缝流动类型
addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(), false);
// TODO:孔隙度
addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false);
// TODO:裂缝宽度
addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false);
// TODO:裂缝导流能力
addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false);
}
}
// 构建默认空树结构
void nmWxDFN::setupDefaultTree()
{
QTreeWidgetItem* pGeneralItem = addRootItem(tr("General"));
addChildItem(pGeneralItem, tr("Number of fissures"), "0", false);
}
// 槽函数实现
void nmWxDFN::onLoadButtonClicked()
{
qDebug() << "Load clicked";
nmWxDFNLoadFromFile loadDialog;
if(loadDialog.exec() == QDialog::Accepted) {
m_originType = Loaded;
// 更新数据并刷新界面
m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList();
this->refreshParameterTree();
//// 将导入文件的裂缝信息数据渲染到当前页面
//m_vecDFNData.clear();
//m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList();
//// 查找已存在的节点
//QTreeWidgetItem* pGeneralItem = findItem(tr("General"));
//if (pGeneralItem) {
// // 删除原来的子节点
// this->deleteAllChildren(pGeneralItem);
// // 添加新的节点
// addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false);
// addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false);
// // 计算总和和平均值
// double totalXf = 0.0;
// for (int i = 0; i < m_vecDFNData.size(); i++) {
// QVector<QPointF> vecPts = m_vecDFNData[i]->getFracturePoints();
// if (vecPts.size() == 2) {
// QPointF ptStartPoint = vecPts[0];
// QPointF ptEndPoint = vecPts[1];
// totalXf += QLineF(ptStartPoint, ptEndPoint).length();
// }
// }
// double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size();
// addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf));
// addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf));
// }
//QTreeWidgetItem* pGlobalParamsItem = findItem(tr("Global fissures physical parameters"));
//if (pGlobalParamsItem == nullptr) {
// // 创建根节点
// pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters"));
//} else {
// // 删除之前的子节点
// this->deleteAllChildren(pGlobalParamsItem);
//}
//// 裂缝流动类型
//addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(),false);
//// TODO:孔隙度
//addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false);
//// TODO:裂缝宽度
//addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false);
//// TODO:裂缝导流能力
//addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false);
}
}
void nmWxDFN::updateButtonsState()
{
bool hasData = !m_vecDFNData.empty();
// Load 和Generate 按钮始终可用
m_pLoadButton->setEnabled(true);
m_pGenerateButton->setEnabled(true);
// 其余按钮只有在有数据时才可用
m_pDeleteButton->setEnabled(hasData);
m_pExportButton->setEnabled(hasData);
}
void nmWxDFN::onGenerateButtonClicked()
{
nmDataAnalyzeManager* mgr = nmDataAnalyzeManager::getCurrentInstance();
nmGuiPlot* plot = mgr->getPlot();
nmDataOutline* outline = mgr->getOutlineData();
nmWxDFNGenerateDlg dlg(this, plot, outline);
if(dlg.exec() == QDialog::Accepted) {
m_originType = Generated;
m_vecDFNData = mgr->getDFNFractureDataList();
refreshParameterTree();
}
}
void nmWxDFN::onDeleteButtonClicked()
{
qDebug() << "Delete clicked";
// 清空原来的DFN图元数据
if(!nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList().isEmpty()) {
nmGuiPlot* pCurPlot = nmDataAnalyzeManager::getCurrentInstance()->getPlot();
pCurPlot->deleteAllDFNPlots();
// m_pParameterTree->clear();
m_originType = None;
// 更新数据并刷新界面
m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList();
this->refreshParameterTree();
}
}
void nmWxDFN::onExportButtonClicked()
{
nmWxDFNExportDlg dlg(this);
dlg.exec();
}
void nmWxDFN::onOkButtonClicked()
{
//qDebug() << "Ok clicked";
this->accept();
}
void nmWxDFN::onCancelButtonClicked()
{
//qDebug() << "Cancel clicked";
this->reject();
}
void nmWxDFN::onItemClicked(QTreeWidgetItem* item, int column)
{
if(item->text(0) == "Number of fissures") {
// 设置第二列获得焦点
m_pParameterTree->editItem(item, 1);
}
}
QTreeWidgetItem* nmWxDFN::addRootItem(const QString& name, bool expand)
{
QTreeWidgetItem* item = new QTreeWidgetItem(m_pParameterTree);
item->setText(0, name);
item->setFlags(item->flags() & ~Qt::ItemIsSelectable); // 分组标题不可选
item->setExpanded(expand);
return item;
}
QTreeWidgetItem* nmWxDFN::addChildItem(QTreeWidgetItem* parent, const QString& name,
const QString& value, bool editable)
{
if(!parent) return nullptr;
QTreeWidgetItem* item = new QTreeWidgetItem(parent);
item->setText(0, name);
item->setText(1, value);
Qt::ItemFlags flags = item->flags();
if(editable) {
flags |= Qt::ItemIsEditable | Qt::ItemIsSelectable;
} else {
flags |= Qt::ItemIsSelectable;
}
item->setFlags(flags);
return item;
}
QTreeWidgetItem* nmWxDFN::findItem(const QString& name, QTreeWidgetItem* parent) const
{
QTreeWidgetItemIterator it(parent ? parent : m_pParameterTree->invisibleRootItem());
while(*it) {
if((*it)->text(0) == name) {
return *it;
}
++it;
}
return nullptr;
}
void nmWxDFN::deleteAllChildren(QTreeWidgetItem* parent)
{
if(!parent) return;
// 逆向删除避免索引问题
for(int i = parent->childCount() - 1; i >= 0; --i) {
delete parent->takeChild(i);
}
}