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++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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);
}
}