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/nmSubWnd/nmSubWndGrid.cpp

336 lines
10 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 "zxLogInstance.h"
#include "ZxBaHelper.h"
#include "ZxResolutionHelper.h"
#include "zxSysUtils.h"
#include "ZxPtyDock.h"
#include "iDockBaseWx.h"
#include "ZxMainWindow.h"
#include "ZxSubAxisX.h"
#include "ZxSubAxisY.h"
#include "ZxPlot.h"
#include "ZxObjCurve.h"
#include "ZxSubTitle.h"
#include "tCurvePlotScene.h"
#include "tCurvePlotView.h"
#include "ZxTableView.h"
#include "ZxTableModel.h"
#include "mModuleDefines.h"
#include "ZxDataWell.h"
#include "ZxDataProject.h"
#ifdef QT_DEBUG
#include "ZxDataGaugeP.h"
#endif
#ifdef QT_DEBUG
#include "nmXmlHelper.h"
#endif
#include "nmSubWndGrid.h"
#include "nmDataDemo.h"
#include "nmDataLogFile.h"
#include "nmGuiPlot.h"
#include "nmWxGridVTKContainerWidget.h"
#include "nmCalculationUtils.h"
#include "nmCalculationPebiGrid.h"
#include "nmCalculationPebiGridTask.h"
#include "nmDataAnalyzeManager.h"
#include "QListWidget.h"
#include <QVector>
#include <QProcess>
#include <QTimer>
#include <QLabel>
#include <QStackedLayout>
#include "ZxRstWnd.h"
nmSubWndGrid::nmSubWndGrid(QWidget *parent,
QString sExt,
double pebiGridControl,
bool bGeneratePebiGrid,
nmDataAnalyzeManager* pDataManager) :
iSubWndBaseFit(parent, sExt),
m_mainLayout(nullptr),
m_vtkWidget(nullptr),
m_pGridLoadingLabel(nullptr),
m_pDebounceTimer(nullptr),
m_pDataManager(pDataManager),
m_pGridTask(nullptr),
m_bGridUpdatePending(false),
m_dPebiGridControl(pebiGridControl),
m_bGeneratePebiGrid(bGeneratePebiGrid)
{
m_sMdiWndType = s_MdiType_DataAnal;
setWindowTitle(tr("nmSubWndGrid"));
}
nmSubWndGrid::~nmSubWndGrid()
{
// 外部 DLL 不支持安全中止;窗口析构前等待自己的任务退出,避免销毁运行中的 QThread。
if(!m_pGridTask.isNull() && m_pGridTask->isRunning()) {
disconnect(m_pGridTask, nullptr, this, nullptr);
m_pGridTask->wait();
}
}
void nmSubWndGrid::configWnd(QString sPrevInfo)
{
iSubWndBaseFit::configWnd(sPrevInfo);
if(NULL != m_pMainWindow) {
disconnect(this, SIGNAL(sigAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)), \
m_pMainWindow, SLOT(slotAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)));
connect(this, SIGNAL(sigAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)), \
m_pMainWindow, SLOT(slotAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)));
}
initUI();
}
bool nmSubWndGrid::loadRsts()
{
return true;
}
bool nmSubWndGrid::saveRsts()
{
ZxRstWnd* pRstWnd = this->getRstUtilWnd();
if (nullptr == pRstWnd)
{
return false;
}
return pRstWnd->save();
}
bool nmSubWndGrid::onConfirmClosing()
{
// 先走基类关闭确认;用户取消关闭时不清理网格数据。
if(!iSubWndBaseFit::onConfirmClosing()) {
return false;
}
nmCalculationPebiGrid::getInstance()->clearGridData(m_pDataManager.data());
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(pDataManager != nullptr) {
// 当前窗口选择清除网格缓存后,分析方案也必须同步失效。
pDataManager->invalidatePebiGrid();
pDataManager->clearUnstructuredGrid();
}
return true;
}
void nmSubWndGrid::initUI()
{
QWidget* mainWidget = new QWidget(this);
// 设置 mainWidget 的布局和尺寸策略
mainWidget->setLayout(new QStackedLayout(mainWidget)); // 加载背景和网格共用稳定显示区域。
mainWidget->layout()->setContentsMargins(0, 0, 0, 0); // 移除边距
mainWidget->layout()->setSpacing(0); // 移除间距
mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 扩展策略
setCentralWidget(mainWidget);
// m_mainLayout 应该直接是 mainWidget 的布局
m_mainLayout = qobject_cast<QStackedLayout*>(mainWidget->layout());
// 第一步:先建立轻量加载页。颜色与网格 Renderer 保持一致,后台任务尚未
// 返回时也能立即绘制正常背景,不会显示空 QVTKWidget 的黑色原生窗口。
m_pGridLoadingLabel = new QLabel(tr("Generating grid..."), mainWidget);
m_pGridLoadingLabel->setAlignment(Qt::AlignCenter);
m_pGridLoadingLabel->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
m_pGridLoadingLabel->setStyleSheet(
"QLabel { color: white; font-size: 14px; "
"background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
"stop:0 rgb(0, 128, 255), stop:1 rgb(171, 209, 240)); }");
m_mainLayout->addWidget(m_pGridLoadingLabel);
// 第二步:新建成果在渲染窗口就绪后立即启动后台划分;加载成果则直接显示
// DataManager 中已有的网格,不进入生成状态。VTK 页只在网格有效后创建。
if(m_bGeneratePebiGrid) {
generatePebiGrid();
} else {
showGridResult();
}
}
QWidget* nmSubWndGrid::initUiMainWx()
{
return nullptr;
}
bool nmSubWndGrid::runCmdBy(QString sName, QString sID)
{
if(sID.toInt() == 5401) {
return true;
}
return false;
}
bool nmSubWndGrid::generatePebiGrid()
{
// PEBI网格
nmCalculationPebiGrid* pPebiGridGeneratorInstance = nmCalculationPebiGrid::getInstance();
// 当前流程只保留PEBI网格;这里仍写入数据中心,供求解和后处理的旧判断继续使用。
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(pDataManager == nullptr) {
return false;
}
pDataManager->setGridType(NM_Grid_PEBI);
// 将对话框中的GridControl传给PEBI输入参数GridControl
pPebiGridGeneratorInstance->setGridControl(m_dPebiGridControl,
pDataManager);
// 首次手工生成无需等待防抖窗口。此时 VTK 背景已经完成初始化,任务启动
// 后界面可以立即绘制;连续 dataChanged 仍由 updateGrid() 合并处理。
showGridLoading();
onDebounceTimeout();
return true;
}
void nmSubWndGrid::updateGrid()
{
// 角色、产量等只影响求解的变化也会发送 dataChanged;网格仍有效时无需重划。
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(pDataManager != nullptr && pDataManager->isPebiGridValid()) {
return;
}
showGridLoading();
// dataChanged可能连续触发,使用当前窗口自己的定时器合并为一次网格重建
if(!m_pDebounceTimer) {
m_pDebounceTimer = new QTimer(this);
m_pDebounceTimer->setSingleShot(true); // 单次触发
connect(m_pDebounceTimer, SIGNAL(timeout()), this, SLOT(onDebounceTimeout()));
}
m_pDebounceTimer->start(500); // 500ms 防抖
}
void nmSubWndGrid::onDebounceTimeout()
{
// 第一步:同一窗口只允许一个网格线程运行,连续编辑合并为下一次重建。
if(!m_pGridTask.isNull() && m_pGridTask->isRunning()) {
m_bGridUpdatePending = true;
return;
}
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(pDataManager == nullptr) {
return;
}
// 第二步:把窗口参数写回所属分析方案,再启动绑定同一管理器的后台任务。
nmCalculationPebiGrid::getInstance()->setGridControl(
m_dPebiGridControl, pDataManager);
m_pGridTask = new nmCalculationPebiGridTask(pDataManager, this);
connect(m_pGridTask, SIGNAL(pebiGridGenerated(bool)),
this, SLOT(onPebiGridGenerated(bool)), Qt::QueuedConnection);
connect(m_pGridTask, SIGNAL(finished()),
this, SLOT(onPebiGridTaskFinished()));
connect(m_pGridTask, SIGNAL(finished()),
m_pGridTask, SLOT(deleteLater()));
m_pGridTask->start();
}
void nmSubWndGrid::onPebiGridGenerated(bool success)
{
// 第一步:信号通过队列回到主线程后才允许写 DataManager。后台任务只保存
// 局部结果;如果用户在划分期间修改了输入,commitResult() 会按版本拒绝。
nmCalculationPebiGridTask* pCompletedTask =
qobject_cast<nmCalculationPebiGridTask*>(sender());
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(success && pCompletedTask != nullptr && pDataManager != nullptr) {
success = pCompletedTask->commitResult(pDataManager);
} else {
success = false;
}
// 第二步:提交成功后创建绑定最新网格的 VTK 页。失败或版本过期时,如果
// 没有排队中的更新,则恢复旧网格或显示失败状态,不能永久停留在加载文字。
if(success) {
showGridResult();
} else if(!m_bGridUpdatePending) {
showGridFailure();
}
}
void nmSubWndGrid::onPebiGridTaskFinished()
{
// 第一步:只清理由当前窗口持有的任务,避免旧 finished 信号覆盖新任务指针。
if(sender() == m_pGridTask.data()) {
m_pGridTask = nullptr;
}
// 第二步:运行期间若又有数据变化,重新启动防抖计时,只补做最后一次网格。
if(m_bGridUpdatePending) {
m_bGridUpdatePending = false;
updateGrid();
}
}
void nmSubWndGrid::showGridLoading()
{
if(m_pGridLoadingLabel == nullptr || m_mainLayout == nullptr) {
return;
}
m_pGridLoadingLabel->setText(tr("Generating grid..."));
m_mainLayout->setCurrentWidget(m_pGridLoadingLabel);
}
void nmSubWndGrid::showGridResult()
{
if(m_mainLayout == nullptr || m_pDataManager.isNull()) {
return;
}
// 网格已经在主线程完整提交,此处一次创建新的 VTK 页,不会向用户暴露
// 没有 RenderWindow 的中间状态。
if(m_vtkWidget != nullptr) {
m_mainLayout->removeWidget(m_vtkWidget);
delete m_vtkWidget;
m_vtkWidget = nullptr;
}
m_vtkWidget = new nmWxGridVTKContainerWidget(
m_pDataManager.data(), centralWidget());
m_vtkWidget->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
m_mainLayout->addWidget(m_vtkWidget);
m_mainLayout->setCurrentWidget(m_vtkWidget);
}
void nmSubWndGrid::showGridFailure()
{
if(m_mainLayout == nullptr) {
return;
}
// 更新失败但旧网格仍可显示时保留旧成果;首次生成失败时在正常背景上给出
// 明确状态,避免用户把空白或黑屏误认为程序仍在计算。
if(m_vtkWidget != nullptr) {
m_mainLayout->setCurrentWidget(m_vtkWidget);
} else if(m_pGridLoadingLabel != nullptr) {
m_pGridLoadingLabel->setText(tr("Grid generation failed"));
m_mainLayout->setCurrentWidget(m_pGridLoadingLabel);
}
}