|
|
#include "zxLogInstance.h"
|
|
|
#include "ZxBaHelper.h"
|
|
|
#include <QDebug>
|
|
|
#include "ZxResolutionHelper.h"
|
|
|
#include "zxSysUtils.h"
|
|
|
#include "ZxPtyDock.h"
|
|
|
#include "iDockBaseWx.h"
|
|
|
#include "ZxMainWindow.h"
|
|
|
#include "ZxTabWidget.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 "nmGuiPlot.h"
|
|
|
#include "nmPlotGraphicBinder.h"
|
|
|
#include "nmSubWndMain.h"
|
|
|
#include "nmPlotDialogContext.h"
|
|
|
#include "nmPlotDialogContextProvider.h"
|
|
|
|
|
|
#include "nmWxGridVTKContainerWidget.h"
|
|
|
#include "nmWxSelectWellsDlg.h"
|
|
|
#include "nmWxSelectWellsWidget.h"
|
|
|
#include "nmWxParameterProperty.h"
|
|
|
#include "nmCalculationDllPebiSolverTask.h"
|
|
|
#include "nmCalculationUtils.h"
|
|
|
|
|
|
#include "nmObjPointWell.h"
|
|
|
|
|
|
#include "nmDataAnalyzeManager.h"
|
|
|
#include "nmPebiResultSnapshot.h"
|
|
|
#include "nmDataDemo.h"
|
|
|
#include "nmDataLogFile.h"
|
|
|
#include "nmDataMeasure.h"
|
|
|
|
|
|
#include "nmWxParaProperty.h"
|
|
|
#include "nmWxRCDialog.h"
|
|
|
#include "nmWxWellLayerDlg.h"
|
|
|
#include "nmWxGeometryLayerDlg.h"
|
|
|
#include "nmReservoirPropertiesDataSource.h"
|
|
|
#include "nmWxReservoirPropertiesEditor.h"
|
|
|
#include "nmWxPropertyInterpolationDlg.h"
|
|
|
#include "nmWxPostprocessingAnimationWidget.h"
|
|
|
#include "nmWxGeoRefDlg.h"
|
|
|
|
|
|
#include "iSubWndFitting.h"
|
|
|
#include "iAnalRun.h"
|
|
|
|
|
|
#include <QVector>
|
|
|
#include <QSet>
|
|
|
#include <QHash>
|
|
|
#include <QPushButton>
|
|
|
|
|
|
#include "nmSingalCenter.h"
|
|
|
|
|
|
#include "nmWxParaPropertyPebi.h"
|
|
|
#include "nmWxNumericalDesign.h"
|
|
|
|
|
|
#include "nmWxReservoirProperties.h"
|
|
|
|
|
|
|
|
|
#include "nmCalculationPebiGrid.h"
|
|
|
#include "nmDataOutline.h"
|
|
|
#include "nmDataVerticalFracturedWell.h"
|
|
|
#include "nmDataHorizontalFracturedWell.h"
|
|
|
#include "nmDataVerticalWell.h"
|
|
|
#include "ZxDataGaugeP.h"
|
|
|
#include "ZxDataGaugeF.h"
|
|
|
|
|
|
#include "nmWxDFN.h"
|
|
|
#include "nmWxDisplaySettings.h"
|
|
|
#include "ZxRstWnd.h"
|
|
|
|
|
|
#include <QPointer>
|
|
|
|
|
|
namespace
|
|
|
{
|
|
|
// 保留原来求解器单例的防重入语义:全局同一时间只允许一个DLL求解任务运行。
|
|
|
// QPointer会在QObject销毁后自动变空,避免保留已经释放的线程指针。
|
|
|
QPointer<nmCalculationDllPebiSolverTask> s_pRunningSolverTask;
|
|
|
QPointer<nmSubWndMain> s_pPendingSolverWindow;
|
|
|
}
|
|
|
|
|
|
nmSubWndMain::nmSubWndMain(QWidget *parent, QString sExt) :
|
|
|
iSubWndBaseFit(parent, sExt)
|
|
|
{
|
|
|
m_pWxPlot = NULL;
|
|
|
m_pWxDockParas = NULL;
|
|
|
m_pWxParas = NULL;
|
|
|
m_pWxDockData1 = NULL;
|
|
|
m_pTableView1 = NULL;
|
|
|
m_pWxDockData2 = NULL;
|
|
|
m_pTableView2 = NULL;
|
|
|
#ifdef QT_DEBUG
|
|
|
m_pWxDockTemp = NULL;
|
|
|
m_pListWxTemp = NULL;
|
|
|
#endif
|
|
|
|
|
|
// 为了后续支持多井提供方便
|
|
|
if(m_pDataWell == NULL) {
|
|
|
m_pDataWell = zxCurWell;
|
|
|
}
|
|
|
|
|
|
//m_sMdiWndType = s_MdiType_DataNum;
|
|
|
m_sMdiWndType = s_MdiType_DataAnal;
|
|
|
setWindowTitle(tr("nmSubWndMain"));
|
|
|
|
|
|
m_lockState = false; // 默认为false
|
|
|
m_openDialogCmdIds.clear();
|
|
|
m_pProgressDlg = nullptr;
|
|
|
m_pSolverTask = nullptr;
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
m_pPendingResultDataManager = nullptr;
|
|
|
m_pPendingResultFitting = nullptr;
|
|
|
m_bPendingResultWidgetRefresh = false;
|
|
|
m_bPendingResultCompletionMessage = false;
|
|
|
m_bPendingResultWindowReady = false;
|
|
|
m_nPendingResultPebiCount = -1;
|
|
|
m_nPendingResultSolveTimeMs = -1;
|
|
|
m_bSolverResultCompletionPending = false;
|
|
|
m_bPendingSolverSucceeded = false;
|
|
|
m_bPendingSolverInputChanged = false;
|
|
|
m_nPendingSolverPebiCount = -1;
|
|
|
m_nPendingSolverTimeMs = -1;
|
|
|
m_bSolverStartPending = false;
|
|
|
m_bSolverCancelRequested = false;
|
|
|
m_pPlotToolBar = nullptr;
|
|
|
}
|
|
|
|
|
|
nmSubWndMain::~nmSubWndMain()
|
|
|
{
|
|
|
if(m_pWxPlot != nullptr) {
|
|
|
// Map窗口析构时,解除DataManager中保存的Plot引用,避免后续访问已释放画布。
|
|
|
foreach(nmDataAnalyzeManager* pManager, nmDataAnalyzeManager::s_mapDataAnalManager.values()) {
|
|
|
if(pManager != nullptr && pManager->getPlot() == m_pWxPlot) {
|
|
|
pManager->setPlot(nullptr);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
|
|
// 坚持谁创建谁析构原则,删除(首先需要去除绑定)
|
|
|
if(NULL != m_pWxDockTemp) {
|
|
|
//QObject* pParent = m_pWxDockTemp->parent();
|
|
|
//ZxMainWindow* p = dynamic_cast<ZxMainWindow*>(pParent);
|
|
|
ZxMainWindow* p = m_pMainWindow;
|
|
|
|
|
|
if(NULL != p) {
|
|
|
p->detachOuterDockWx(m_pWxDockTemp);
|
|
|
}
|
|
|
|
|
|
delete m_pWxDockTemp;
|
|
|
m_pWxDockTemp = NULL;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
this->setTopDocksVisible(true);
|
|
|
|
|
|
// TODO:删除已有在图元的数据对象
|
|
|
//if (m_pWxPlot != nullptr) {
|
|
|
// QVector<nmObjBase*> vecObjs = m_pWxPlot->getAllPlots();
|
|
|
// foreach(nmObjBase* obj, vecObjs) {
|
|
|
// obj->removeData();
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
|
|
|
m_bSolverStartPending = false;
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
|
|
|
if (m_pProgressDlg) {
|
|
|
delete m_pProgressDlg;
|
|
|
m_pProgressDlg = NULL;
|
|
|
}
|
|
|
|
|
|
if (m_pSolverTask) {
|
|
|
// 第一步:停止向正在析构的窗口投递完成回调。
|
|
|
disconnect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)), this, SLOT(on_solverTaskFinished(bool)));
|
|
|
m_pSolverTask->requestCancel();
|
|
|
// 第二步:DataManager 会在成果窗口销毁后释放,而任务仍读取该对象。
|
|
|
// Qt 4.8 下 DLL 执行中只能等待其正常返回,绝不能强杀持锁线程。
|
|
|
if(m_pSolverTask->isRunning()) {
|
|
|
m_pSolverTask->wait();
|
|
|
}
|
|
|
if (m_pSolverTask == s_pRunningSolverTask) {
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
}
|
|
|
// 第三步:线程已经停止,当前窗口仍是任务的明确所有者,可直接释放。
|
|
|
delete m_pSolverTask;
|
|
|
m_pSolverTask = nullptr;
|
|
|
}
|
|
|
|
|
|
/*if (m_parameterPropertyWindow != nullptr) {
|
|
|
delete m_parameterPropertyWindow;
|
|
|
m_parameterPropertyWindow = nullptr;
|
|
|
}*/
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::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();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::initUI()
|
|
|
{
|
|
|
// iSubWndBaseAF::initUI();
|
|
|
#ifdef QT_DEBUG
|
|
|
// 示例:演示增加Dock并且追加至程序主窗口
|
|
|
initUiTop();
|
|
|
#endif
|
|
|
// 主布局:定义
|
|
|
initUiMain();
|
|
|
// 外围布局,DockWx
|
|
|
{
|
|
|
initUiDockWxs();
|
|
|
initUiDockPtys();
|
|
|
}
|
|
|
|
|
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
|
|
// 示例:如何加载xml文件
|
|
|
if(_nmXmlHelper->loadXmlDefines()) {
|
|
|
foreach(nmXmlData* pData, *(_nmXmlHelper->getVecNmXmlDataPtrs())) {
|
|
|
Q_ASSERT(NULL != pData);
|
|
|
qDebug() << QString("%1: %2").arg(pData->m_sName).arg(pData->m_sAlias);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
QWidget* nmSubWndMain::initUiMainWx()
|
|
|
{
|
|
|
QSplitter* pSplitter = new QSplitter(Qt::Vertical);
|
|
|
Q_ASSERT(NULL != pSplitter);
|
|
|
nmGuiPlot* pWxPlot = new nmGuiPlot();
|
|
|
m_pWxPlot = pWxPlot;
|
|
|
|
|
|
// 将绘图对象添加到数据中心
|
|
|
nmDataAnalyzeManager::getCurrentInstance()->setPlot(m_pWxPlot);
|
|
|
|
|
|
{
|
|
|
// 建立信号,以便在此处增加新的工具
|
|
|
connect(pWxPlot, SIGNAL(sigToolbarBuilt(QToolBar*)),
|
|
|
this, SLOT(slotToolbarBuilt(QToolBar*)));
|
|
|
QSize sz = QSize(265, 203);
|
|
|
pWxPlot->initUI("TestGui", sz);
|
|
|
bindChartSignals(pWxPlot);
|
|
|
pSplitter->addWidget(pWxPlot);
|
|
|
}
|
|
|
|
|
|
return pSplitter;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::initUiDockWxs()
|
|
|
{
|
|
|
// TODO,本Dock的操作
|
|
|
// 基础参数Dock
|
|
|
// {
|
|
|
// m_pWxDockParas = new iDockBaseWx(tr("Parameters"));
|
|
|
// Q_ASSERT (NULL != m_pWxDockParas);
|
|
|
// addDockWidget(Qt::LeftDockWidgetArea, m_pWxDockParas);
|
|
|
// m_pWxParas = new nmWxParaProperty();
|
|
|
// Q_ASSERT (NULL != m_pWxParas);
|
|
|
// m_pWxParas->initUI();
|
|
|
// m_pWxDockParas->setWidget(m_pWxParas);
|
|
|
// m_pWxDockParas->setMinimumWidth(_resoSizeW(200));
|
|
|
// }
|
|
|
// 表格数据Dock
|
|
|
// {
|
|
|
// QStringList listTitles;
|
|
|
// listTitles << tr("Name1");
|
|
|
// iDockBaseWx* pDockWx1 = new iDockBaseWx(tr("Data1"));
|
|
|
// Q_ASSERT (NULL != pDockWx1);
|
|
|
// {
|
|
|
// addDockWidget(Qt::RightDockWidgetArea, pDockWx1);
|
|
|
// m_pWxDockData1 = pDockWx1;
|
|
|
// ZxTableView* pTableView = new ZxTableView();
|
|
|
// Q_ASSERT (NULL != pTableView);
|
|
|
// {
|
|
|
// ZxTableModel* pTableModel = new ZxTableModel(1, 1, listTitles);
|
|
|
// Q_ASSERT (NULL != pTableModel);
|
|
|
// pTableView->setModel(pTableModel);
|
|
|
// pTableView->setMenuMode(ZxTableView::MTM_Edit_Without_Col);
|
|
|
// pTableView->setSelectionBehavior(ZxTableView::SelectRows);
|
|
|
// pTableView->fuzzyUiOfQt5();
|
|
|
// }
|
|
|
// pDockWx1->setWidget(pTableView);
|
|
|
// m_pTableView1 = pTableView;
|
|
|
// }
|
|
|
// iDockBaseWx* pDockWx2 = new iDockBaseWx(tr("Data2"));
|
|
|
// Q_ASSERT (NULL != pDockWx2);
|
|
|
// {
|
|
|
// addDockWidget(Qt::RightDockWidgetArea, pDockWx2);
|
|
|
// tabifyDockWidget(pDockWx1, pDockWx2);
|
|
|
// m_pWxDockData2 = pDockWx2;
|
|
|
// ZxTableView* pTableView = new ZxTableView();
|
|
|
// Q_ASSERT (NULL != pTableView);
|
|
|
// {
|
|
|
// ZxTableModel* pTableModel = new ZxTableModel(1, 1, listTitles);
|
|
|
// Q_ASSERT (NULL != pTableModel);
|
|
|
// pTableView->setModel(pTableModel);
|
|
|
// pTableView->setMenuMode(ZxTableView::MTM_Readonly);
|
|
|
// pTableView->fuzzyUiOfQt5();
|
|
|
// }
|
|
|
// pDockWx2->setWidget(pTableView);
|
|
|
// m_pTableView2 = pTableView;
|
|
|
// }
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::initUiDockPtys()
|
|
|
{
|
|
|
iSubWndBaseAF::initUiDockPtys();
|
|
|
// 属性Dock
|
|
|
{
|
|
|
Q_ASSERT(NULL != m_pDockPty);
|
|
|
m_pDockPty->setMinimumWidth(_resoSizeW(200));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#ifdef QT_DEBUG
|
|
|
// 示例:演示增加Dock并且追加至程序主窗口
|
|
|
void nmSubWndMain::initUiTop()
|
|
|
{
|
|
|
#if 0
|
|
|
return;
|
|
|
// 隐藏所有Dock
|
|
|
this->setTopDocksVisible(false);
|
|
|
// 创建新的Dock
|
|
|
iDockBaseWx* pDockWx = new iDockBaseWx(tr("TODO:Demo"));
|
|
|
Q_ASSERT(NULL != pDockWx);
|
|
|
// QListWidget* pListWx = new QListWidget();
|
|
|
nmWxTreeWidget* treeWidget = new nmWxTreeWidget(pDockWx, m_pAnalyzeData);
|
|
|
Q_ASSERT(NULL != treeWidget);
|
|
|
pDockWx->setWidget(treeWidget);
|
|
|
// m_pListWxTemp = pListWx;
|
|
|
pDockWx->setMinimumWidth(_resoSizeW(200));
|
|
|
emit sigAppendDock2Main(pDockWx, Qt::LeftDockWidgetArea);
|
|
|
m_pWxDockTemp = pDockWx;
|
|
|
return;
|
|
|
// 基础参数Dock
|
|
|
// {
|
|
|
// iDockBaseWx* pDockWx = new iDockBaseWx(tr("TODO:Demo"));
|
|
|
// Q_ASSERT (NULL != pDockWx);
|
|
|
// QListWidget* pListWx = new QListWidget();
|
|
|
// Q_ASSERT (NULL != pListWx);
|
|
|
// pDockWx->setWidget(pListWx);
|
|
|
// m_pListWxTemp = pListWx;
|
|
|
// pDockWx->setMinimumWidth(_resoSizeW(200));
|
|
|
// emit sigAppendDock2Main(pDockWx, Qt::LeftDockWidgetArea);
|
|
|
// m_pWxDockTemp = pDockWx;
|
|
|
// }
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
void nmSubWndMain::bindChartSignals(iGuiPlot* pWxPlot)
|
|
|
{
|
|
|
nmGuiPlot* p = dynamic_cast<nmGuiPlot*>(pWxPlot);
|
|
|
|
|
|
if(NULL != p) {
|
|
|
connect(p, SIGNAL(sigObjSelChanged(ZxObjBase*, bool)), \
|
|
|
this, SLOT(slotObjSelChanged(ZxObjBase*, bool)));
|
|
|
connect(p, SIGNAL(sigObjPtsChanged(ZxObjBase*)),
|
|
|
this, SLOT(slotObjPtsChanged(ZxObjBase*)));
|
|
|
}
|
|
|
|
|
|
iSubWndBaseAF::bindChartSignals(pWxPlot);
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::runActionOf(QString sAction)
|
|
|
{
|
|
|
if(iSubWnd::runActionOf(sAction)) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// 数据加载
|
|
|
QString s = sAction;
|
|
|
|
|
|
if(_isSame(s, "LoadP")) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::runCmdBy(QString sName, QString sID)
|
|
|
{
|
|
|
QString s = sName;
|
|
|
int nId = sID.toInt();
|
|
|
|
|
|
// 运行菜单之前,先将所有处于选中状态的图元状态恢复
|
|
|
if(m_pWxPlot != nullptr) {
|
|
|
m_pWxPlot->clearPlotsSelectStates();
|
|
|
}
|
|
|
|
|
|
switch(nId) {
|
|
|
case 5102:
|
|
|
this->geologicalMapImport();
|
|
|
return true;
|
|
|
|
|
|
/*case 5103:
|
|
|
this->geologicalMapHide();
|
|
|
return true;*/
|
|
|
|
|
|
case 5120:
|
|
|
this->drawMeasuringScale();
|
|
|
return true;
|
|
|
|
|
|
case 5103:
|
|
|
this->drawPolygonOutline();
|
|
|
return true;
|
|
|
|
|
|
case 5104:
|
|
|
this->drawSquareOutline();
|
|
|
return true;
|
|
|
|
|
|
case 5105:
|
|
|
this->drawRoundOutline();
|
|
|
return true;
|
|
|
|
|
|
case 5106:
|
|
|
this->drawFault();
|
|
|
return true;
|
|
|
|
|
|
case 5107:
|
|
|
this->selectWell();
|
|
|
return true;
|
|
|
|
|
|
// 新建井菜单暂时停用。
|
|
|
// case 5108:
|
|
|
// this->drawWell();
|
|
|
// return true;
|
|
|
|
|
|
case 5109:
|
|
|
this->drawCrack();
|
|
|
return true;
|
|
|
|
|
|
case 5110:
|
|
|
this->drawRegion();
|
|
|
return true;
|
|
|
|
|
|
case 5111:
|
|
|
this->drawRegionMark();
|
|
|
return true;
|
|
|
|
|
|
case 5112:
|
|
|
this->geoLayering();
|
|
|
return true;
|
|
|
|
|
|
case 5113:
|
|
|
this->reservoirCharacteristics();
|
|
|
return true;
|
|
|
|
|
|
/*case 5114:
|
|
|
this->generationMesh();
|
|
|
return true;
|
|
|
*/
|
|
|
case 5115:
|
|
|
this->solveAndAnalyze();
|
|
|
return true;
|
|
|
|
|
|
case 5117:
|
|
|
this->mergeAnaResultToFitting();
|
|
|
this->schedulePendingResultWidgets();
|
|
|
return true;
|
|
|
|
|
|
case 5121:
|
|
|
this->deleteOneObj();
|
|
|
return true;
|
|
|
|
|
|
case 5119:
|
|
|
this->setLocked();
|
|
|
return true;
|
|
|
|
|
|
case 5122:
|
|
|
this->generateDFN();
|
|
|
return true;
|
|
|
|
|
|
case 5123:
|
|
|
this->displaySetting();
|
|
|
return true;
|
|
|
|
|
|
case 5124:
|
|
|
return m_pWxPlot != nullptr &&
|
|
|
m_pWxPlot->runAction("print_Preview");
|
|
|
|
|
|
case 5125:
|
|
|
return m_pWxPlot != nullptr &&
|
|
|
m_pWxPlot->runAction("Print");
|
|
|
|
|
|
/*
|
|
|
case 5117:
|
|
|
this->initData();
|
|
|
return true;
|
|
|
*/
|
|
|
case 5129:
|
|
|
if(isDialogCmdOpened(5129)) {
|
|
|
return true;
|
|
|
}
|
|
|
this->drawMeasure();
|
|
|
return true;
|
|
|
|
|
|
case 5127:
|
|
|
this->drawGeoRef();
|
|
|
return true;
|
|
|
|
|
|
case 5128:
|
|
|
if(isDialogCmdOpened(5128)) {
|
|
|
return true;
|
|
|
}
|
|
|
this->drawPointerPos();
|
|
|
return true;
|
|
|
|
|
|
case 5126:
|
|
|
if(isDialogCmdOpened(5126)) {
|
|
|
return true;
|
|
|
}
|
|
|
this->showPropertyInterpolationDialog();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if(_isSame(s, "RunGrid")) {
|
|
|
if(NULL != m_pWxPlot) {
|
|
|
//m_pWxPlot->refreshGrid(true);
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::checkCmdEnable(bool &b, \
|
|
|
QString sName, int nID, \
|
|
|
bool bLicensed)
|
|
|
{
|
|
|
bool b1 = (NULL != zxCurProject);
|
|
|
bool b2 = (NULL != m_pDataWell);
|
|
|
|
|
|
// 判断当前锁定状态
|
|
|
if(m_lockState) {
|
|
|
/*
|
|
|
if(nID >= 5102 && nID <= 5125) {
|
|
|
b = (b1 && b2 && bLicensed && !isReadonly() && NULL != m_pWxPlot);
|
|
|
return true;
|
|
|
}
|
|
|
*/
|
|
|
/*
|
|
|
if ((nID >= 5122 && nID <= 5125) || (nID >= 5112 && nID <= 5119 ))
|
|
|
{
|
|
|
b = true;
|
|
|
return true;
|
|
|
}
|
|
|
*/
|
|
|
/*
|
|
|
if(nID >= 5102 && nID <= 5124) {
|
|
|
b = true;
|
|
|
return true;
|
|
|
}
|
|
|
*/
|
|
|
// 可使用菜单栏
|
|
|
if(sName == "NmMap" || sName == "NmUnlocked" || sName == "NmGeometry" ||
|
|
|
sName == "NmProperties" || sName == "NmDFN" || sName == "NmCaculation" ||
|
|
|
sName == "NmBack" || sName == "NmResult" || sName == "NmGrid" ||
|
|
|
sName == "NmInterpolation" ||
|
|
|
sName == "NmShow" || sName == "NmPrintPreview" || sName == "NmPrint" ||
|
|
|
sName == "VisibleAnalBasic" || sName == "VisibleAnalPVT" || sName == "VisibleAnalDiff" ||
|
|
|
sName == "VisibleAnalPseu" || sName == "nmFitModel" || sName == "NmAnalChange") {
|
|
|
b = true;
|
|
|
return true;
|
|
|
} else {
|
|
|
b = false;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
if((nID >= 5102 && nID <= 5130) /*|| (nID >= 9002 && nID <= 9003) */ || (nID >= 9101 && nID <= 9104) || nID == 3104) {
|
|
|
b = (b1 && b2 && bLicensed && !isReadonly() && NULL != m_pWxPlot);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return iSubWndBaseFit::checkCmdEnable(b, sName, nID, bLicensed);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::reAdjustToolbar(QToolBar* pToolBar)
|
|
|
{
|
|
|
iSubWndBaseAF::reAdjustToolbar(pToolBar);
|
|
|
m_pPlotToolBar = pToolBar;
|
|
|
// 获取所有动作的列表
|
|
|
// QList<QAction *> actions = m_pPlotToolBar->actions();
|
|
|
// // 隐藏第1个和第2个动作
|
|
|
// if (actions.size() > 0) {
|
|
|
// actions[0]->setVisible(false); // 隐藏第1个动作
|
|
|
// }
|
|
|
// if (actions.size() > 1) {
|
|
|
// actions[1]->setVisible(false); // 隐藏第2个动作
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::firstLoadAndUpdate()
|
|
|
{
|
|
|
iSubWndBaseAF::firstLoadAndUpdate();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::finalDeals()
|
|
|
{
|
|
|
iSubWndBaseAF::finalDeals();
|
|
|
#ifdef QT_DEBUG
|
|
|
updatePlots();
|
|
|
updateDockWxs();
|
|
|
|
|
|
if(m_pWxDockData1 != NULL) {
|
|
|
Q_ASSERT(NULL != m_pWxDockData1);
|
|
|
m_pWxDockData1->raise();
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onActivated()
|
|
|
{
|
|
|
#ifdef QT_DEBUG
|
|
|
|
|
|
// 当前窗体激活时,可以做些事情,比如把隐藏的Dock显示出来
|
|
|
if(NULL != m_pWxDockTemp) {
|
|
|
if(!m_pWxDockTemp->isVisible()) {
|
|
|
m_pWxDockTemp->setVisible(true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
|
|
void nmSubWndMain::updatePlots()
|
|
|
{
|
|
|
#if 0
|
|
|
// 里面根据曲线,重新刷了一下坐标轴范围。你屏蔽该函数,即可
|
|
|
// 坐标轴范围会变成背景图的大小
|
|
|
return ;
|
|
|
// 说明:以从当前井获取一条压力数据进行绘图为例
|
|
|
QString sType = iDataModelType::sTypeDataGaugeP;
|
|
|
QString sCodeP = ""; //如果已知压力数据Code,可以直接引用
|
|
|
ZxDataGaugeP* pDataObjP = dynamic_cast<ZxDataGaugeP*>(getDataObjOf(sType, sCodeP));
|
|
|
|
|
|
if(NULL == pDataObjP) {
|
|
|
qDebug() << tr("Failed to get data of type '%1'").arg(sType);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
VecDouble vecX, vecY;
|
|
|
QByteArray ba = pDataObjP->getGaugeDataOf(0);
|
|
|
|
|
|
if(!ZxBaHelper::convertBa2VecXY(vecX, vecY, ba)) {
|
|
|
qDebug() << tr("Failed to get x-y data of dataobj '%1'").arg(pDataObjP->getCode());
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
nmGuiPlot* pWxPlot = m_pWxPlot;
|
|
|
Q_ASSERT(NULL != pWxPlot);
|
|
|
QString sName = tr("CurveName");
|
|
|
ZxObjBase* pObj = pWxPlot->updatePlotObjBy(sName, vecX, vecY, true);
|
|
|
|
|
|
if(NULL != pObj) {
|
|
|
pObj->setLockPos(true); //可以调整属性
|
|
|
// pObj->setReadOnly(true);
|
|
|
pWxPlot->freshAxisScales(true);//刷新坐标轴刻度
|
|
|
// 设置标题+坐标轴等
|
|
|
pWxPlot->setAxisX(tr("Time"), "hr");
|
|
|
pWxPlot->setAxisY(tr("Pressure"), "MPa");
|
|
|
pWxPlot->setAxisXYLog(false, 0);
|
|
|
pWxPlot->setAxisXYLog(false, 1);
|
|
|
pWxPlot->m_pPlot->setLegendVisible(false);
|
|
|
pWxPlot->m_pPlot->getTitle()->setName(tr("Demo"));
|
|
|
}
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
ZxDataObject* nmSubWndMain::getDataObjOf(QString sType, QString sCode /*= ""*/)
|
|
|
{
|
|
|
ZxDataWell* pDataWell = zxCurWell;
|
|
|
Q_ASSERT(NULL != pDataWell);
|
|
|
ZxDataObject* pDataObj = NULL;
|
|
|
|
|
|
if(!sCode.isEmpty()) {
|
|
|
pDataObj = pDataWell->getChild(sType, sCode);
|
|
|
} else {
|
|
|
ZxDataObjectList vecObjs = pDataWell->getChildren(sType);
|
|
|
|
|
|
if(!vecObjs.isEmpty()) {
|
|
|
pDataObj = vecObjs[0];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return pDataObj;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::updateDockWxs()
|
|
|
{
|
|
|
#if 0
|
|
|
// TODO,刷新Dock内容
|
|
|
return;
|
|
|
// 左侧参数窗体
|
|
|
Q_ASSERT(NULL != m_pWxParas);
|
|
|
QStringList listParas;
|
|
|
listParas << "K" << "S" << "rw" << "Miuo" << "Bo" << "phi";
|
|
|
m_pWxParas->refreshUIs(listParas);
|
|
|
// 表格数据1
|
|
|
Q_ASSERT(NULL != m_pTableView1);
|
|
|
ZxTableModel* pTableModel = m_pTableView1->getModel();
|
|
|
Q_ASSERT(NULL != pTableModel);
|
|
|
QStringList listTitles;
|
|
|
listTitles << tr("Col1") << tr("Col2\n(MPa)");
|
|
|
VVecDouble vvec;
|
|
|
{
|
|
|
VecDouble vec;
|
|
|
vec << 0.2 << 3.4;
|
|
|
vvec << vec;
|
|
|
}
|
|
|
|
|
|
{
|
|
|
VecDouble vec;
|
|
|
vec << 5.6 << 0.456;
|
|
|
vvec << vec;
|
|
|
}
|
|
|
|
|
|
pTableModel->setTitles(listTitles);
|
|
|
pTableModel->setData(vvec);
|
|
|
|
|
|
if(NULL != m_pListWxTemp) {
|
|
|
m_pListWxTemp->clear();
|
|
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
|
QString sItem = tr("Demo Item %1").arg(i + 1);
|
|
|
QListWidgetItem* pItem = new QListWidgetItem(sItem);
|
|
|
Q_ASSERT(NULL != pItem);
|
|
|
pItem->setIcon(zxLoadIcon("Open"));
|
|
|
m_pListWxTemp->addItem(pItem);
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::updateTableByCurve(ZxObjCurve* pObjCurve, ZxTableView* pTableView)
|
|
|
{
|
|
|
Q_ASSERT(NULL != pObjCurve);
|
|
|
Q_ASSERT(NULL != pTableView);
|
|
|
// 刷新表格标题
|
|
|
{
|
|
|
QString sNameX = pObjCurve->getAxisX()->getName();
|
|
|
QString sUnit = pObjCurve->getAxisX()->getUnit();
|
|
|
|
|
|
if(!sUnit.isEmpty()) {
|
|
|
sNameX += QString("\n(%1)").arg(sUnit);
|
|
|
}
|
|
|
|
|
|
QString sNameY = pObjCurve->getAxisY()->getName();
|
|
|
sUnit = pObjCurve->getAxisY()->getUnit();
|
|
|
|
|
|
if(!sUnit.isEmpty()) {
|
|
|
sNameY += QString("\n(%1)").arg(sUnit);
|
|
|
}
|
|
|
|
|
|
QStringList listTitles;
|
|
|
listTitles << sNameX << sNameY;
|
|
|
pTableView->getModel()->setTitles(listTitles);
|
|
|
}
|
|
|
|
|
|
// 刷新表格数据
|
|
|
{
|
|
|
VVecDouble vvec;
|
|
|
QVector<QPointF> vecValues = pObjCurve->getAllValues();
|
|
|
|
|
|
for(int i = 0; i < vecValues.count(); i++) {
|
|
|
VecDouble vec;
|
|
|
vec << vecValues.at(i).x() * 1.0;
|
|
|
vec << vecValues.at(i).y() * 1.0;
|
|
|
vvec << vec;
|
|
|
}
|
|
|
|
|
|
pTableView->getModel()->setData(vvec);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
void nmSubWndMain::slotObjSelChanged(ZxObjBase* p, bool b)
|
|
|
{
|
|
|
#ifdef QT_DEBUG
|
|
|
// 如果选中了一条曲线,则把其数据显示在数据表格2中
|
|
|
ZxObjCurve* pObjCurve = dynamic_cast<ZxObjCurve*>(p);
|
|
|
|
|
|
if(NULL != pObjCurve && b) {
|
|
|
Q_ASSERT(NULL != m_pWxDockData2);
|
|
|
m_pWxDockData2->raise();
|
|
|
updateTableByCurve(pObjCurve, m_pTableView2);
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::slotObjPtsChanged(ZxObjBase* p)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onSerialize(ZxSerializer* ser)
|
|
|
{
|
|
|
iSubWndBaseAF::onSerialize(ser);
|
|
|
|
|
|
if(NULL != m_pWxPlot) {
|
|
|
m_pWxPlot->setModified(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onDeserialize(ZxSerializer* ser)
|
|
|
{
|
|
|
iSubWndBaseAF::onDeserialize(ser);
|
|
|
|
|
|
if(NULL != m_pWxPlot) {
|
|
|
m_pWxPlot->setModified(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onDeserialized()
|
|
|
{
|
|
|
if(NULL != m_pWxPlot) {
|
|
|
m_pWxPlot->resetAfterDeserialized();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//bool nmSubWndMain::loadRss() {
|
|
|
// ZxRstJobWnd* pRstWnd = getRstJobWnd();
|
|
|
// Q_ASSERT(NULL != pRstWnd);
|
|
|
// // 基础信息
|
|
|
// {
|
|
|
// QByteArray v = pRstWnd->getDataInfo();
|
|
|
// IxSerDes* pSerObj = this;
|
|
|
|
|
|
// if(!loadRstInfoFromArr(v, pSerObj)) {
|
|
|
// return false;
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
// // 图形
|
|
|
// if(NULL != m_pWxPlot) {
|
|
|
// QByteArray v = pRstWnd->getDataInfo1();
|
|
|
// ZxPlot* pPlot = NULL;
|
|
|
// loadOnePlot(pPlot, v);
|
|
|
|
|
|
// if(NULL != pPlot) {
|
|
|
// m_pWxPlot->m_pPlotScene->freshToPlot(pPlot,
|
|
|
// m_pWxPlot->m_pPlotView);
|
|
|
// m_pWxPlot->m_pPlot = m_pWxPlot->m_pPlotScene->m_pPlot;
|
|
|
// pPlot->resetTools(m_pWxPlot->m_pPlotView);
|
|
|
// m_pWxPlot->resetAfterDeserialized();
|
|
|
// }
|
|
|
|
|
|
// m_pWxPlot->runUpdate();
|
|
|
// }
|
|
|
|
|
|
// return true;
|
|
|
//}
|
|
|
|
|
|
//bool nmSubWndMain::saveRss() {
|
|
|
// ZxRstJobWnd* pRstWnd = getRstJobWnd();
|
|
|
|
|
|
// if(NULL == pRstWnd) {
|
|
|
// return false;
|
|
|
// }
|
|
|
|
|
|
// // 基础信息
|
|
|
// {
|
|
|
// QByteArray v;
|
|
|
// IxSerDes* pSerObj = this;
|
|
|
|
|
|
// if(!saveRstInfoToArr(v, pSerObj)) {
|
|
|
// return false;
|
|
|
// }
|
|
|
|
|
|
// pRstWnd->setDataInfo(v);
|
|
|
// }
|
|
|
|
|
|
// // 图形
|
|
|
// if(NULL != m_pWxPlot) {
|
|
|
// ZxPlot* pPlot = m_pWxPlot->m_pPlot;
|
|
|
// {
|
|
|
// QByteArray v1;
|
|
|
|
|
|
// if(saveOnePlot(pPlot, v1)) {
|
|
|
// pRstWnd->setDataInfo1(v1);
|
|
|
// }
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
// return pRstWnd->save();
|
|
|
//}
|
|
|
|
|
|
bool nmSubWndMain::loadRsts()
|
|
|
{
|
|
|
return true;//
|
|
|
|
|
|
/*
|
|
|
ZxRstWnd* pRstWnd = getRstUtilWnd();
|
|
|
Q_ASSERT (nullptr != pRstWnd);
|
|
|
|
|
|
// 基础信息
|
|
|
if (!loadRstBase(pRstWnd))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 图形
|
|
|
if (nullptr != m_pWxPlot)
|
|
|
{
|
|
|
QByteArray v = QByteArray();
|
|
|
pRstWnd->loadSubPlotContent(v);
|
|
|
ZxPlot* pPlot = nullptr;
|
|
|
loadOnePlotFromBa(pPlot, v);
|
|
|
if (nullptr != pPlot)
|
|
|
{
|
|
|
m_pWxPlot->m_pPlotScene->freshToPlot(pPlot,
|
|
|
m_pWxPlot->m_pPlotView);
|
|
|
m_pWxPlot->m_pPlot = m_pWxPlot->m_pPlotScene->m_pPlot;
|
|
|
pPlot->resetTools(m_pWxPlot->m_pPlotView);
|
|
|
m_pWxPlot->resetAfterDeserialized();
|
|
|
}
|
|
|
m_pWxPlot->runUpdate();
|
|
|
}//*/
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::saveRsts()
|
|
|
{
|
|
|
ZxRstWnd* pRstWnd = this->getRstUtilWnd();
|
|
|
|
|
|
if(nullptr == pRstWnd) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return pRstWnd->save();
|
|
|
|
|
|
// // 基础信息
|
|
|
// if (!saveRstBase(pRstWnd))
|
|
|
// {
|
|
|
// return false;
|
|
|
// }
|
|
|
|
|
|
// // 图形
|
|
|
// if (nullptr != m_pWxPlot)
|
|
|
// {
|
|
|
// ZxPlot* pPlot = m_pWxPlot->m_pPlot;
|
|
|
// {
|
|
|
// QByteArray v1;
|
|
|
// if (saveOnePlotToBa(pPlot, v1))
|
|
|
// {
|
|
|
// pRstWnd->saveSubPlotContent(v1);
|
|
|
// }
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
//return pRstWnd->save();
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::slotSaveAll()
|
|
|
{
|
|
|
ZxRstWnd* pRstWnd = getRstUtilWnd();
|
|
|
Q_ASSERT(NULL != pRstWnd);
|
|
|
if(pRstWnd == NULL) {
|
|
|
return false;
|
|
|
}
|
|
|
return saveRsts();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::updateSelectedWells(QList<ZxDataWell *> wellObjList)
|
|
|
{
|
|
|
// if(wellObjList.count() == 0) {
|
|
|
// return;
|
|
|
// }
|
|
|
|
|
|
// setp 1,获取现在画布上所有井的 ZxDataWell* 数据指针
|
|
|
QVector<nmObjPointWell*> pWellPlotList = m_pWxPlot->getWellPlots();
|
|
|
|
|
|
// QMap<ZxDataWell*, nmObjPointWell*> 用于快速查找和构建当前画布上的井数据列表
|
|
|
QMap<ZxDataWell*, nmObjPointWell*> pWellDataToPlotMap;
|
|
|
|
|
|
for(int i = 0; i < pWellPlotList.count(); ++i) {
|
|
|
nmObjPointWell* wellPlot = pWellPlotList[i];
|
|
|
ZxDataWell *pWellData = wellPlot->getWellData();
|
|
|
if (pWellData) { // 确保数据不为空
|
|
|
pWellDataToPlotMap.insert(pWellData, wellPlot);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 用集合保存当前井和选中井,避免井数增加后反复调用 QList::contains 造成平方级查找。
|
|
|
QList<ZxDataWell*> pWellPlotDataList = pWellDataToPlotMap.keys();
|
|
|
QSet<ZxDataWell*> pWellPlotDataSet;
|
|
|
for(int i = 0; i < pWellPlotDataList.count(); ++i) {
|
|
|
pWellPlotDataSet.insert(pWellPlotDataList[i]);
|
|
|
}
|
|
|
QSet<ZxDataWell*> selectedWellDataSet;
|
|
|
for(int i = 0; i < wellObjList.count(); ++i) {
|
|
|
if(wellObjList[i] != nullptr) {
|
|
|
selectedWellDataSet.insert(wellObjList[i]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// setp 2,找出需要 REMOVE (删除) 的图元
|
|
|
QVector<nmObjPointWell*> vDeleteWellPlotList;
|
|
|
|
|
|
// 遍历所有当前在画布上的井数据
|
|
|
for(int i = 0; i < pWellPlotDataList.count(); ++i) {
|
|
|
ZxDataWell *pWellDataOnPlot = pWellPlotDataList[i];
|
|
|
// 如果该井数据不在用户选中的列表 wellObjList 中,则需要删除
|
|
|
if (!selectedWellDataSet.contains(pWellDataOnPlot)) {
|
|
|
// 从 Map 中获取对应的图元对象
|
|
|
vDeleteWellPlotList.append(pWellDataToPlotMap.value(pWellDataOnPlot));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// setp 3,找出需要 ADD (添加) 的井数据
|
|
|
QVector<ZxDataWell*> vAddWellPlotList;
|
|
|
|
|
|
// 遍历所有用户选中的井数据 wellObjList
|
|
|
for(int i = 0; i < wellObjList.count(); ++i) {
|
|
|
ZxDataWell *pWellDataSelected = wellObjList[i];
|
|
|
// 确保井数据有效
|
|
|
if (pWellDataSelected && !pWellPlotDataSet.contains(pWellDataSelected)) {
|
|
|
// 如果该井数据不在当前画布上的数据列表中,则需要添加
|
|
|
vAddWellPlotList.append(pWellDataSelected);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 单井增删过程中会多次请求重绘;批量阶段先暂停,全部处理完成后再统一刷新。
|
|
|
const bool updatesEnabled = m_pWxPlot->updatesEnabled();
|
|
|
m_pWxPlot->setUpdatesEnabled(false);
|
|
|
|
|
|
// setp 4,执行删除操作
|
|
|
for(int i = 0; i < vDeleteWellPlotList.count(); ++i) {
|
|
|
nmObjPointWell* pWellPlot = vDeleteWellPlotList[i];
|
|
|
// 选择井列表只能移除普通数值井;固定主井始终保留在本次分析中。
|
|
|
if(m_pWxPlot->graphicBinder() &&
|
|
|
m_pWxPlot->graphicBinder()->isPrimaryWellGraphic(pWellPlot))
|
|
|
continue;
|
|
|
|
|
|
// 删除对应的参数类
|
|
|
pWellPlot->removeData();
|
|
|
|
|
|
// 实际从画布上删除图元
|
|
|
m_pWxPlot->m_pPlot->removeObjByName(pWellPlot->getName());
|
|
|
}
|
|
|
|
|
|
// setp 5,将vAddWellPlotList中的井数据,构建图元,添加到画布上
|
|
|
for(int i = 0; i < vAddWellPlotList.count(); i++) {
|
|
|
ZxDataWell* wellObj = vAddWellPlotList[i];
|
|
|
QString sName = wellObj->getName();
|
|
|
QVector<QPointF> points;
|
|
|
points.append(QPointF(wellObj->getLocationX(), wellObj->getLocationY()));
|
|
|
// 构建了图元
|
|
|
|
|
|
nmObjPointWell* pWellPlot = NULL;
|
|
|
pWellPlot = (nmObjPointWell*)m_pWxPlot->appendOneObj(NMOT_Point_Well, sName, points);
|
|
|
if(pWellPlot == NULL) {
|
|
|
continue;
|
|
|
}
|
|
|
// 选择已有井重新生成图元时,先恢复Binder,后续afterCreated才能建立井数据绑定
|
|
|
if(m_pWxPlot->graphicBinder()) {
|
|
|
pWellPlot->setGraphicBinder(m_pWxPlot->graphicBinder());
|
|
|
}
|
|
|
// 设置图元的井数据
|
|
|
pWellPlot->setWellData(wellObj);
|
|
|
// 移动到正确的位置
|
|
|
pWellPlot->moveToPos(pWellPlot->getPosOf(pWellPlot->getAllPos()));
|
|
|
|
|
|
pWellPlot->afterCreated(); //选择完后初始化参数
|
|
|
}
|
|
|
|
|
|
|
|
|
// 添加完毕后,重新渲染
|
|
|
m_pWxPlot->setUpdatesEnabled(updatesEnabled);
|
|
|
if(updatesEnabled) {
|
|
|
m_pWxPlot->update();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 地质图导入
|
|
|
void nmSubWndMain::geologicalMapImport()
|
|
|
{
|
|
|
//打开图片选择弹框
|
|
|
//打开文件对话框选择图片文件
|
|
|
//QString filePath = QFileDialog::getOpenFileName(nullptr, "选择图片文件", "", "Images (*.png *.xpm *.jpg)");
|
|
|
|
|
|
//if(!filePath.isEmpty()) {
|
|
|
// // 画布 设置背景,并自适应宽高
|
|
|
// ZxPlot* pPlot = m_pWxPlot->m_pPlot;
|
|
|
// pPlot->setBkImgFile(filePath);
|
|
|
// // QImage* pBkImg = pPlot->getBkImg();
|
|
|
// // Q_ASSERT (NULL != pBkImg);
|
|
|
// // int w = pBkImg->width();
|
|
|
// // int h = pBkImg->height();
|
|
|
// // pPlot->getMainAxisX()->setRangeMinMax(0, w, true);
|
|
|
// // pPlot->getMainAxisY()->setRangeMinMax(0, h, true);
|
|
|
// nmDataLogFile::getInstance()->writeLog(filePath);
|
|
|
//}
|
|
|
|
|
|
QString sFilter =
|
|
|
"PNG Images (*.png);;"
|
|
|
"JPEG Images (*.jpg *.jpeg);;"
|
|
|
"Bitmap Images (*.bmp);;"
|
|
|
"All Files (*)";
|
|
|
|
|
|
QString sFile = QFileDialog::getOpenFileName(
|
|
|
nullptr,
|
|
|
tr("Open File"),
|
|
|
ZxBaseUtil::getLastDir(),
|
|
|
sFilter
|
|
|
);
|
|
|
|
|
|
if(sFile.isEmpty() || !QFile::exists(sFile)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 更新最后访问目录
|
|
|
QFileInfo fi(sFile);
|
|
|
ZxBaseUtil::setLastDir(fi.absolutePath());
|
|
|
|
|
|
// 输出文件失败原因
|
|
|
QImageReader reader(sFile);
|
|
|
|
|
|
if(!reader.canRead()) {
|
|
|
// 输出具体错误
|
|
|
qDebug() << "Error Message: " << reader.errorString();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(m_pWxPlot == nullptr || m_pWxPlot->m_pPlot == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 设置背景图片
|
|
|
ZxPlot* pPlot = m_pWxPlot->m_pPlot;
|
|
|
pPlot->setBkImgFile(sFile);
|
|
|
|
|
|
// 检查 ZxPlot 是否成功加载图片
|
|
|
QImage* pBkImg = pPlot->getBkImg();
|
|
|
Q_ASSERT(nullptr != pBkImg);
|
|
|
if(pBkImg == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 将图片信息存储到数据中心
|
|
|
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
|
|
|
if(pManager) {
|
|
|
QImage loadedImage = reader.read(); // 假设已经读取成功
|
|
|
BackgroundImageInfo bgInfo;
|
|
|
bgInfo.bIsVisible = true; // 默认设置为可见
|
|
|
bgInfo.sFilePath = sFile; // 当前背景文件路径
|
|
|
bgInfo.objImage = loadedImage; // 存储QImage对象
|
|
|
pManager->setBackgroundImageInfo(bgInfo); // 设置背景图片信息
|
|
|
}
|
|
|
|
|
|
// 手动调整坐标轴(如果 ZxPlot 未自动调整)
|
|
|
//int w = pBkImg->width();
|
|
|
//int h = pBkImg->height();
|
|
|
//if (w > 0 && h > 0) {
|
|
|
// pPlot->getMainAxisX()->setRangeMinMax(0, w, true);
|
|
|
// pPlot->getMainAxisY()->setRangeMinMax(0, h, true);
|
|
|
//}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawMeasuringScale()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_Line_MeasuringScale);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::geologicalMapHide()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::setTopDocksVisible(bool visible)
|
|
|
{
|
|
|
// 获取主程序所有 Dock 视图
|
|
|
QList<QDockWidget*> dockWidgets = m_pMainWindow->findChildren<QDockWidget*>();
|
|
|
|
|
|
// 遍历所有 Dock 视图并移除位于左侧的
|
|
|
foreach(QDockWidget* dock, dockWidgets) {
|
|
|
if(visible) {
|
|
|
dock->show();
|
|
|
} else {
|
|
|
dock->hide();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawPolygonOutline()
|
|
|
{
|
|
|
// 获取多边形边界的绘制,并模拟触发点击操作
|
|
|
// 目前多边形边界绘制是工具栏的第4个,所以用 3
|
|
|
// QList<QAction *> actions = m_pPlotToolBar->actions();
|
|
|
// if (!actions.isEmpty()) {
|
|
|
// QAction *action = actions[3];
|
|
|
// action->trigger();
|
|
|
// }
|
|
|
this->triggerToolBarAction(NMOT_PolygonOutline);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawSquareOutline()
|
|
|
{
|
|
|
// 获取矩形边界的绘制,并模拟触发点击操作
|
|
|
this->triggerToolBarAction(NMOT_RectOutline);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawRoundOutline()
|
|
|
{
|
|
|
// 获取矩形边界的绘制,并模拟触发点击操作
|
|
|
this->triggerToolBarAction(NMOT_RoundOutline);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawFault()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_Line_Fault);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::selectWell()
|
|
|
{
|
|
|
if(m_pWxPlot == nullptr || zxCurProject == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 第一步:Map 当前选择状态使用 WellCode 保存,井名只用于界面显示。
|
|
|
QList<QVariant> selectedWellCodes;
|
|
|
QVector<ZxDataWell*> vecMapWells = m_pWxPlot->getWellDatas();
|
|
|
for(int nIndex = 0; nIndex < vecMapWells.size(); ++nIndex) {
|
|
|
ZxDataWell* pMapWell = vecMapWells[nIndex];
|
|
|
if(pMapWell != nullptr && !pMapWell->getCode().isEmpty()) {
|
|
|
selectedWellCodes.append(pMapWell->getCode());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 第二步:读取项目井库,并建立 WellCode 到项目井对象的稳定映射。
|
|
|
int wellCount = zxCurProject->getChildrenCount(iDataModelType::sTypeWell);
|
|
|
ZxDataObjectList wellList = zxCurProject->getChildren(iDataModelType::sTypeWell);
|
|
|
nmDataLogFile::getInstance()->writeLog(QString(" %1 %2").arg(wellCount).arg(wellList.size()));
|
|
|
QStringList listWellNames;
|
|
|
QList<QVariant> wellCodes;
|
|
|
QMap<QString, ZxDataWell*> wellCodeToObjMap;
|
|
|
for(int i = 0; i < wellList.size(); i++) {
|
|
|
ZxDataWell* wellObj = dynamic_cast<ZxDataWell*>(wellList[i]);
|
|
|
if(wellObj == nullptr || wellObj->getCode().isEmpty()) {
|
|
|
continue;
|
|
|
}
|
|
|
nmDataLogFile::getInstance()->writeLog(wellObj->getName() + " " + wellObj->getCode());
|
|
|
listWellNames.append(wellObj->getName());
|
|
|
wellCodes.append(wellObj->getCode());
|
|
|
wellCodeToObjMap.insert(wellObj->getCode(), wellObj);
|
|
|
}
|
|
|
|
|
|
// 第三步:恢复 Map 中已有井的勾选状态,允许用户增删其他项目井。
|
|
|
nmWxSelectWellsDlg dlg;
|
|
|
nmWxSelectWellsWidget wellListWidget;
|
|
|
wellListWidget.setSelectedValues(selectedWellCodes);
|
|
|
wellListWidget.addItems(listWellNames, wellCodes);
|
|
|
dlg.setWidget(&wellListWidget);
|
|
|
if(dlg.exec() == QDialog::Accepted) {
|
|
|
nmDataLogFile::getInstance()->writeLog(" OK ");
|
|
|
QList<QVariant> selectedValues = wellListWidget.getSelectedValues();
|
|
|
QList<ZxDataWell*> selectWellList;
|
|
|
|
|
|
// 第四步:按 WellCode 解析选择结果,避免同名井或井名修改导致关联错误。
|
|
|
QStringList selectedCodeTexts;
|
|
|
for(int i = 0; i < selectedValues.count(); i++) {
|
|
|
const QString sWellCode = selectedValues[i].toString();
|
|
|
ZxDataWell* pSelectedWell = wellCodeToObjMap.value(sWellCode, nullptr);
|
|
|
if(pSelectedWell != nullptr) {
|
|
|
selectWellList.append(pSelectedWell);
|
|
|
selectedCodeTexts.append(sWellCode);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this->updateSelectedWells(selectWellList);
|
|
|
nmDataLogFile::getInstance()->writeLog(
|
|
|
"===" + selectedCodeTexts.join(";") + "===");
|
|
|
} else {
|
|
|
nmDataLogFile::getInstance()->writeLog(" Cancel ");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 新建井菜单暂时停用。
|
|
|
// void nmSubWndMain::drawWell()
|
|
|
// {
|
|
|
// this->triggerToolBarAction(NMOT_Point_Well);
|
|
|
// nmDataLogFile::getInstance()->writeLog(" in drawWell ");
|
|
|
// }
|
|
|
|
|
|
void nmSubWndMain::drawCrack()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_Line_Fracture);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawRegion()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_Region);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawRegionMark()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_RegionMark);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawMeasure()
|
|
|
{
|
|
|
nmGuiPlot* plot = dynamic_cast<nmGuiPlot*>(m_pWxPlot);
|
|
|
QWidget* measureDlg = showMeasureDialog();
|
|
|
|
|
|
if(plot == nullptr || measureDlg == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
bindMeasureDialog(measureDlg);
|
|
|
plot->setAllPlotObjectsEditable(false);
|
|
|
this->triggerToolBarAction(NMOT_Line_Measure);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawGeoRef()
|
|
|
{
|
|
|
nmWxGeoRefDlg dlg(nullptr);
|
|
|
dlg.exec();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::drawPointerPos()
|
|
|
{
|
|
|
nmGuiPlot* plot = dynamic_cast<nmGuiPlot*>(m_pWxPlot);
|
|
|
|
|
|
if(plot) {
|
|
|
showPointerPosDialog();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::isDialogCmdOpened(int nId) const
|
|
|
{
|
|
|
return m_openDialogCmdIds.contains(nId);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::markDialogCmdOpened(int nId)
|
|
|
{
|
|
|
if(!m_openDialogCmdIds.contains(nId)) {
|
|
|
m_openDialogCmdIds.append(nId);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::markDialogCmdClosed(int nId)
|
|
|
{
|
|
|
// 从后向前遍历,避免索引错乱
|
|
|
for (int i = m_openDialogCmdIds.size() - 1; i >= 0; --i) {
|
|
|
if (m_openDialogCmdIds[i] == nId) {
|
|
|
m_openDialogCmdIds.remove(i);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onDialogCmdDestroyed(QObject* obj)
|
|
|
{
|
|
|
if(obj == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
bool bOk = false;
|
|
|
int nId = obj->property("dialogCmdId").toInt(&bOk);
|
|
|
|
|
|
if(bOk) {
|
|
|
markDialogCmdClosed(nId);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::bindDialogCmdDestroyed(QWidget* dialog, int nId)
|
|
|
{
|
|
|
if(dialog == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
dialog->setProperty("dialogCmdId", nId);
|
|
|
connect(dialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDialogCmdDestroyed(QObject*)));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::bindMeasureDialog(QWidget* measureDlg)
|
|
|
{
|
|
|
nmGuiPlot* plot = dynamic_cast<nmGuiPlot*>(m_pWxPlot);
|
|
|
|
|
|
if(plot == nullptr || measureDlg == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
disconnect(plot, SIGNAL(sigMeasureStarted()), measureDlg, SLOT(resetButtons()));
|
|
|
connect(plot, SIGNAL(sigMeasureStarted()), measureDlg, SLOT(resetButtons()));
|
|
|
|
|
|
disconnect(measureDlg, SIGNAL(needDeleteMeasureObj()), plot, SLOT(finishMeasure()));
|
|
|
connect(measureDlg, SIGNAL(needDeleteMeasureObj()), plot, SLOT(finishMeasure()));
|
|
|
}
|
|
|
|
|
|
QWidget* nmSubWndMain::showMeasureDialog()
|
|
|
{
|
|
|
nmGuiPlot* plot = dynamic_cast<nmGuiPlot*>(m_pWxPlot);
|
|
|
|
|
|
if(plot == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider();
|
|
|
|
|
|
if(pDialogProvider == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
QWidget* measureDlg = pDialogProvider->createMeasureDialog(plot);
|
|
|
|
|
|
if(measureDlg == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
markDialogCmdOpened(5129);
|
|
|
measureDlg->setObjectName("nmMeasureDialog");
|
|
|
measureDlg->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
bindDialogCmdDestroyed(measureDlg, 5129);
|
|
|
nmDataMeasure* measureData = nmDataAnalyzeManager::getCurrentInstance()->getMeasureData();
|
|
|
if(measureData != nullptr) {
|
|
|
connect(measureData, SIGNAL(sigMeasureDataChanged()), measureDlg, SLOT(updateDisplay()));
|
|
|
}
|
|
|
measureDlg->show();
|
|
|
return measureDlg;
|
|
|
}
|
|
|
|
|
|
QWidget* nmSubWndMain::showPointerPosDialog()
|
|
|
{
|
|
|
nmGuiPlot* plot = dynamic_cast<nmGuiPlot*>(m_pWxPlot);
|
|
|
|
|
|
if(plot == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider();
|
|
|
|
|
|
if(pDialogProvider == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
QWidget* pointerPosDlg = pDialogProvider->createPointerPosDialog(plot);
|
|
|
|
|
|
if(pointerPosDlg == nullptr) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
markDialogCmdOpened(5128);
|
|
|
pointerPosDlg->setObjectName("nmPointerPosDialog");
|
|
|
pointerPosDlg->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
bindDialogCmdDestroyed(pointerPosDlg, 5128);
|
|
|
plot->bindPointerPosDialog(pointerPosDlg);
|
|
|
pointerPosDlg->show();
|
|
|
return pointerPosDlg;
|
|
|
}
|
|
|
|
|
|
QWidget* nmSubWndMain::showPropertyInterpolationDialog()
|
|
|
{
|
|
|
nmWxPropertyInterpolationDlg* interpolationDlg = new nmWxPropertyInterpolationDlg(
|
|
|
m_pWxPlot, nmDataAnalyzeManager::getCurrentInstance(), this);
|
|
|
markDialogCmdOpened(5126);
|
|
|
interpolationDlg->setObjectName("nmPropertyInterpolationDialog");
|
|
|
// 关闭窗口时自动释放,并恢复菜单命令的可用状态
|
|
|
interpolationDlg->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
bindDialogCmdDestroyed(interpolationDlg, 5126);
|
|
|
interpolationDlg->show();
|
|
|
interpolationDlg->raise();
|
|
|
interpolationDlg->activateWindow();
|
|
|
return interpolationDlg;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::generationMesh()
|
|
|
{
|
|
|
// // TODO,还不支持原型边界
|
|
|
// // 拿到多边形和点的位置信息
|
|
|
// QVector<ZxObjBase*> pObjVec = m_pWxPlot->getObjsByTag("nObjPolygonOutline");
|
|
|
// nmDataLogFile::getInstance()->writeLog(" ---------- " + QString::number(pObjVec.count()));
|
|
|
// QVector<ZxObjBase*> pWellObjVec = m_pWxPlot->getObjsByTag("nObjPointWell");
|
|
|
// nmDataLogFile::getInstance()->writeLog(" ---------- " + QString::number(pWellObjVec.count()));
|
|
|
|
|
|
// // 生成geo文件
|
|
|
// // 调用gmsh生成vtk文件
|
|
|
// // 弹出网格的dialog,渲染文件
|
|
|
// if(true) {
|
|
|
// QDialog* dlg = new QDialog;
|
|
|
// QVBoxLayout* layout = new QVBoxLayout;
|
|
|
// dlg->setLayout(layout);
|
|
|
// nmWxGridVTKContainerWidget* gridVTKContainerWidget = new nmWxGridVTKContainerWidget(dlg);
|
|
|
// layout->addWidget(gridVTKContainerWidget);
|
|
|
// dlg->resize(800, 600);
|
|
|
// dlg->show();
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::solveAndAnalyze()
|
|
|
{
|
|
|
if(!s_pPendingSolverWindow.isNull() ||
|
|
|
!s_pRunningSolverTask.isNull() ||
|
|
|
m_bSolverResultCompletionPending) {
|
|
|
QMessageBox::information(this, tr("solver error"), tr("task is running!"));
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// Qt 4.8 下复用已经隐藏的进度框,避免窗口析构触发主界面重绘重入。
|
|
|
if (m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->reset();
|
|
|
QPushButton* pCancelButton =
|
|
|
m_pProgressDlg->findChild<QPushButton*>();
|
|
|
if(pCancelButton != nullptr) {
|
|
|
pCancelButton->setEnabled(true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 新一次启动前清空旧上下文;后续所有检查通过后再成对写入。
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
|
|
|
// 根据当前数据中心的分析切换到对应的流动段分析窗口
|
|
|
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(m_pMainWindow);
|
|
|
|
|
|
if(nullptr == pMainWnd1) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx();
|
|
|
iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting();
|
|
|
Q_ASSERT(pSubWndFit != nullptr);
|
|
|
if(pSubWndFit == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
if(pTabWx == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
pTabWx->setCurrentWidget(pSubWndFit);
|
|
|
|
|
|
nmDataAnalyzeManager* pDataManager =
|
|
|
nmDataAnalyzeManager::findManagerByFitting(pSubWndFit);
|
|
|
if(pDataManager == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 第一步:求解时间轴必须由至少一口主动井的产注制度驱动。
|
|
|
// 观察井可以完全不传产量,但不能在所有井都是观察井时启动无源汇计算。
|
|
|
QVector<nmCalculationWellRef> vecEffectiveWells =
|
|
|
pDataManager->getEffectiveCalculationWells();
|
|
|
QHash<QString, nmDataWellBase*> mapWellsByCode;
|
|
|
const QVector<nmDataWellBase*> vecAllWells =
|
|
|
pDataManager->getWellDataList();
|
|
|
for(int nIndex = 0; nIndex < vecAllWells.size(); ++nIndex) {
|
|
|
nmDataWellBase* pWellData = vecAllWells[nIndex];
|
|
|
if(pWellData != nullptr) {
|
|
|
mapWellsByCode.insert(pWellData->getWellCode(), pWellData);
|
|
|
}
|
|
|
}
|
|
|
bool bHasRateControlledWell = false;
|
|
|
for(int nIndex = 0; nIndex < vecEffectiveWells.size(); ++nIndex) {
|
|
|
const nmCalculationWellRef& oWellRef = vecEffectiveWells[nIndex];
|
|
|
nmDataWellBase* pWellData =
|
|
|
mapWellsByCode.value(oWellRef.m_sWellCode, nullptr);
|
|
|
if(pWellData == nullptr) {
|
|
|
QMessageBox::warning(this, tr("solver error"),
|
|
|
tr("A selected well is missing from the map."));
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(oWellRef.m_eMode != NM_CaseWell_RateControlled) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
bHasRateControlledWell = true;
|
|
|
if(pWellData->getFlowPoints().size() < 2) {
|
|
|
QMessageBox::warning(
|
|
|
this,
|
|
|
tr("solver error"),
|
|
|
tr("Rate-controlled well '%1' has no valid rate schedule.")
|
|
|
.arg(pWellData->getWellName()));
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
if(!bHasRateControlledWell) {
|
|
|
QMessageBox::warning(
|
|
|
this,
|
|
|
tr("solver error"),
|
|
|
tr("At least one active production or injection well is required."));
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 手动求解可能直接启动, 因此必须在创建求解线程前初始化拟压力转换器.
|
|
|
// pSubWndFit 保存的是当前拟合窗口克隆后的 PVT、拟压力及模型选项数据.
|
|
|
// configPsAbouts() 会据此初始化常规、三区或组分转换器并设置当前模式.
|
|
|
if(pDataManager->getSolverModelType() == SMT_Gas_VariablePvt) {
|
|
|
iAnalRun* pAnalRun = pSubWndFit->getAnalRun();
|
|
|
if(pAnalRun == nullptr
|
|
|
|| !pAnalRun->configPsAbouts(true,
|
|
|
pSubWndFit->getModelOption(),
|
|
|
false,
|
|
|
pSubWndFit->getAllWxPtr())) {
|
|
|
QMessageBox::warning(this, tr("solver error"),
|
|
|
tr("Gas pseudo-pressure data is unavailable or invalid."));
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(m_pSolverTask != nullptr) {
|
|
|
// 上一次线程已结束但指针还未清空时,先交给Qt事件循环安全释放。
|
|
|
m_pSolverTask->deleteLater();
|
|
|
m_pSolverTask = nullptr;
|
|
|
}
|
|
|
|
|
|
// 第一步:捕获本次求解的完整窗口上下文,完成回调不得再读取全局当前窗口。
|
|
|
m_pSolverDataManager = pDataManager;
|
|
|
m_pSolverFitting = pSubWndFit;
|
|
|
m_bSolverCancelRequested = false;
|
|
|
|
|
|
// 第二步:先显示真实进度框,再在下一轮事件中捕获输入并启动线程。
|
|
|
if (m_pProgressDlg == nullptr)
|
|
|
{
|
|
|
m_pProgressDlg = new QProgressDialog(
|
|
|
tr("Preparing input snapshot..."),
|
|
|
tr("Stop"),
|
|
|
0,
|
|
|
0,
|
|
|
getMainWindow());
|
|
|
m_pProgressDlg->setWindowTitle(tr("Solver Progress"));
|
|
|
// 保持 8 月 25 日前的稳定行为。任务和输入快照负责数据安全,进度框不参与
|
|
|
// 全局窗口阻塞,避免首次创建结果窗口时进入 Qt 4.8 模态布局重入。
|
|
|
m_pProgressDlg->setWindowModality(Qt::NonModal);
|
|
|
|
|
|
// 某些系统下,对话框右上角的关闭按钮可能仍存
|
|
|
// 使用 WindowFlags 彻底禁用关闭按钮
|
|
|
m_pProgressDlg->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
|
|
|
m_pProgressDlg->setMinimumDuration(0);
|
|
|
m_pProgressDlg->setAutoClose(false);
|
|
|
m_pProgressDlg->setAutoReset(false);
|
|
|
connect(m_pProgressDlg, SIGNAL(canceled()),
|
|
|
this, SLOT(onSolverCancelRequested()));
|
|
|
}
|
|
|
|
|
|
m_pProgressDlg->setLabelText(tr("Preparing input snapshot..."));
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
m_pProgressDlg->show();
|
|
|
|
|
|
m_pProgressDlg->raise(); // 提升层级到最前
|
|
|
m_pProgressDlg->activateWindow(); // 激活窗口焦点
|
|
|
|
|
|
m_bSolverStartPending = true;
|
|
|
s_pPendingSolverWindow = this;
|
|
|
QTimer::singleShot(0, this, SLOT(startSolverTask()));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::startSolverTask()
|
|
|
{
|
|
|
if(!m_bSolverStartPending) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(m_pProgressDlg == nullptr || m_pSolverDataManager.isNull() ||
|
|
|
m_pSolverFitting.isNull()) {
|
|
|
m_bSolverStartPending = false;
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->hide();
|
|
|
}
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(waitForPebiGridGeneration()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 先创建不自动捕获的任务,使停止按钮在第一批井输入开始前就有明确接收者。
|
|
|
m_pSolverTask = new nmCalculationDllPebiSolverTask(
|
|
|
QString(),
|
|
|
m_pSolverDataManager.data(),
|
|
|
QString(),
|
|
|
nullptr,
|
|
|
true);
|
|
|
s_pRunningSolverTask = m_pSolverTask;
|
|
|
connect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)),
|
|
|
this, SLOT(on_solverTaskFinished(bool)),
|
|
|
Qt::QueuedConnection);
|
|
|
connect(m_pSolverTask, SIGNAL(sigStageChanged(QString,int,int)),
|
|
|
this, SLOT(onSolverStageChanged(QString,int,int)),
|
|
|
Qt::QueuedConnection);
|
|
|
// 给 Windows 一次完成首帧绘制的机会;后续每个事件循环只捕获一口井。
|
|
|
QTimer::singleShot(20, this, SLOT(continueSolverInputCapture()));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::continueSolverInputCapture()
|
|
|
{
|
|
|
if(!m_bSolverStartPending || m_pSolverTask == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(waitForPebiGridGeneration()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
bool bFinished = false;
|
|
|
const bool bSucceeded =
|
|
|
m_pSolverTask->captureManualInputStep(1, bFinished);
|
|
|
if(!bSucceeded) {
|
|
|
nmCalculationDllPebiSolverTask* pTask = m_pSolverTask;
|
|
|
const bool bCancelled = pTask->wasCancelled();
|
|
|
const bool bInputChanged =
|
|
|
pTask->hasInputChanged(m_pSolverDataManager.data());
|
|
|
m_pSolverTask = nullptr;
|
|
|
if(pTask == s_pRunningSolverTask) {
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
}
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
m_bSolverStartPending = false;
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
disconnect(pTask, nullptr, this, nullptr);
|
|
|
pTask->deleteLater();
|
|
|
|
|
|
if(bCancelled) {
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->hide();
|
|
|
}
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
} else {
|
|
|
scheduleSolverResultCompletion(false, -1, -1, bInputChanged);
|
|
|
}
|
|
|
m_bSolverCancelRequested = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(bFinished) {
|
|
|
// 临时井对象指针已全部释放,只有完整值快照可以进入后台线程。
|
|
|
m_bSolverStartPending = false;
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
m_pSolverTask->start();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
QTimer::singleShot(0, this, SLOT(continueSolverInputCapture()));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onSolverStageChanged(
|
|
|
QString sStage,
|
|
|
int nCurrent,
|
|
|
int nTotal)
|
|
|
{
|
|
|
if(sender() != m_pSolverTask || m_pProgressDlg == nullptr ||
|
|
|
m_bSolverCancelRequested) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
m_pProgressDlg->setLabelText(sStage);
|
|
|
if(nTotal <= 0) {
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
} else {
|
|
|
m_pProgressDlg->setRange(0, nTotal);
|
|
|
m_pProgressDlg->setValue(qBound(0, nCurrent, nTotal));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onSolverCancelRequested()
|
|
|
{
|
|
|
if(m_bSolverStartPending &&
|
|
|
(m_pSolverTask == nullptr || !m_pSolverTask->isRunning())) {
|
|
|
// 等待建网或分批捕获期间尚未进入工作线程,可以立即撤销并释放值快照。
|
|
|
nmCalculationDllPebiSolverTask* pTask = m_pSolverTask;
|
|
|
m_pSolverTask = nullptr;
|
|
|
m_bSolverStartPending = false;
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
if(pTask != nullptr) {
|
|
|
pTask->requestCancel();
|
|
|
if(pTask == s_pRunningSolverTask) {
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
}
|
|
|
disconnect(pTask, nullptr, this, nullptr);
|
|
|
pTask->deleteLater();
|
|
|
}
|
|
|
// QProgressDialog::cancel() 已隐藏窗口;保留对象供下一次求解复用。
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
m_bSolverCancelRequested = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(m_pSolverTask != nullptr) {
|
|
|
m_bSolverCancelRequested = true;
|
|
|
m_pSolverTask->requestCancel();
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
// DLL 没有取消导出;若已进入 DLL,只能等待其返回后丢弃结果。
|
|
|
m_pProgressDlg->setLabelText(
|
|
|
tr("Stopping; waiting for the current solver call to return..."));
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
QPushButton* pCancelButton =
|
|
|
m_pProgressDlg->findChild<QPushButton*>();
|
|
|
if(pCancelButton != nullptr) {
|
|
|
pCancelButton->setEnabled(false);
|
|
|
}
|
|
|
m_pProgressDlg->show();
|
|
|
m_pProgressDlg->raise();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::waitForPebiGridGeneration()
|
|
|
{
|
|
|
nmDataAnalyzeManager* pDataManager = m_pSolverDataManager.data();
|
|
|
if(!m_bSolverStartPending || pDataManager == nullptr ||
|
|
|
!pDataManager->isPebiGridGenerationActive()) {
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 这里只等待主线程提交信号,不获取网格锁;进度框和停止按钮保持可响应。
|
|
|
connect(pDataManager,
|
|
|
SIGNAL(sigPebiGridGenerationFinished(quint64,bool)),
|
|
|
this,
|
|
|
SLOT(onPebiGridGenerationFinished(quint64,bool)),
|
|
|
Qt::UniqueConnection);
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->setLabelText(
|
|
|
tr("Waiting for current grid generation..."));
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::disconnectPebiGridGenerationWait()
|
|
|
{
|
|
|
nmDataAnalyzeManager* pDataManager = m_pSolverDataManager.data();
|
|
|
if(pDataManager == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
disconnect(pDataManager,
|
|
|
SIGNAL(sigPebiGridGenerationFinished(quint64,bool)),
|
|
|
this,
|
|
|
SLOT(onPebiGridGenerationFinished(quint64,bool)));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onPebiGridGenerationFinished(
|
|
|
quint64 nGridInputRevision,
|
|
|
bool bSucceeded)
|
|
|
{
|
|
|
Q_UNUSED(nGridInputRevision);
|
|
|
Q_UNUSED(bSucceeded);
|
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pSolverDataManager.data();
|
|
|
if(sender() != pDataManager || !m_bSolverStartPending ||
|
|
|
pDataManager == nullptr ||
|
|
|
pDataManager->isPebiGridGenerationActive()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
disconnectPebiGridGenerationWait();
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->setLabelText(tr("Preparing input snapshot..."));
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
}
|
|
|
|
|
|
// 失败或版本过期也恢复原流程,由快照缓存检查决定是否重新生成一次网格。
|
|
|
if(m_pSolverTask == nullptr) {
|
|
|
QTimer::singleShot(0, this, SLOT(startSolverTask()));
|
|
|
} else {
|
|
|
QTimer::singleShot(0, this, SLOT(continueSolverInputCapture()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::triggerToolBarAction(int index)
|
|
|
{
|
|
|
// 获取多边形边界的绘制,并模拟触发点击操作
|
|
|
// 目前多边形边界绘制是工具栏的第4个,所以用 3
|
|
|
if (m_pPlotToolBar == nullptr) return;
|
|
|
QList<QAction *> actions = m_pPlotToolBar->actions();
|
|
|
|
|
|
if(!actions.isEmpty() && index >= 0 && index < actions.count()) {
|
|
|
QAction *action = actions[index];
|
|
|
action->trigger();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::mergeAnaResultToFitting()
|
|
|
{
|
|
|
//QMessageBox::information(this, tr("solver success"), tr("solver succeed!"));
|
|
|
|
|
|
/*if (m_parameterPropertyWindow != nullptr) {
|
|
|
delete m_parameterPropertyWindow;
|
|
|
m_parameterPropertyWindow = nullptr;
|
|
|
}
|
|
|
|
|
|
m_parameterPropertyWindow = new nmWxParameterProperty(this);
|
|
|
m_parameterPropertyWindow->show();*/
|
|
|
|
|
|
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(m_pMainWindow);
|
|
|
|
|
|
if(nullptr == pMainWnd1) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
iSubWndFitting* pSubWndFit = !m_pSolverFitting.isNull()
|
|
|
? m_pSolverFitting.data() : nmDataAnalyzeManager::getCurrentFitting();
|
|
|
Q_ASSERT(pSubWndFit != nullptr);
|
|
|
if(pSubWndFit == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nmDataAnalyzeManager* pInstance = !m_pSolverDataManager.isNull()
|
|
|
? m_pSolverDataManager.data()
|
|
|
: nmDataAnalyzeManager::getCurrentInstance();
|
|
|
if(pInstance == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 捕获的拟合窗口和数据管理器必须仍保持原来的映射关系。
|
|
|
if(nmDataAnalyzeManager::findManagerByFitting(pSubWndFit) != pInstance) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 新一轮主动刷新替代尚未执行的旧请求;已经投递的旧槽会检测标记并直接返回。
|
|
|
m_bPendingResultWidgetRefresh = false;
|
|
|
m_pPendingResultDataManager = nullptr;
|
|
|
m_pPendingResultFitting = nullptr;
|
|
|
m_bPendingResultCompletionMessage = false;
|
|
|
m_bPendingResultWindowReady = false;
|
|
|
m_nPendingResultPebiCount = -1;
|
|
|
m_nPendingResultSolveTimeMs = -1;
|
|
|
|
|
|
if(pInstance->getGridType() == NM_Grid_PEBI) {
|
|
|
QSharedPointer<const nmPebiResultSnapshot> pSnapshot =
|
|
|
pInstance->getPebiResultSnapshot();
|
|
|
if(pSnapshot.isNull()) {
|
|
|
return false;
|
|
|
}
|
|
|
QString sWellInstanceId =
|
|
|
pInstance->getCurrentResultWellInstanceId();
|
|
|
if(!pSnapshot->isDisplayWell(sWellInstanceId)) {
|
|
|
pInstance->setCurrentResultWellInstanceId(QString());
|
|
|
sWellInstanceId =
|
|
|
pInstance->getCurrentResultWellInstanceId();
|
|
|
}
|
|
|
|
|
|
// 曲线及下拉框都使用同一 UUID;显示列表为空时曲线入口收到空值并被清空。
|
|
|
if(!refreshPebiResultCurves(pSubWndFit,
|
|
|
pInstance,
|
|
|
sWellInstanceId)) {
|
|
|
return false;
|
|
|
}
|
|
|
nmWxNumericalDesign::notifyResultWellSelectorChanged(
|
|
|
pInstance, sWellInstanceId);
|
|
|
}
|
|
|
|
|
|
if(pInstance->getGridType() != NM_Grid_PEBI) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
QString errorMessage;
|
|
|
// getFitSubRstWxOf(..., true) 会同步创建 iWxResult、挂入 MDI 并切换当前页。
|
|
|
// 首次创建时只建立外层载体,待本轮 show/resize/layout 事件结束后再填充内容。
|
|
|
QWidget* p3DWidget = pSubWndFit->getFitSubRstWxOf(
|
|
|
FSRT_Nm3D, false, &errorMessage);
|
|
|
if(p3DWidget == nullptr) {
|
|
|
p3DWidget = pSubWndFit->getFitSubRstWxOf(
|
|
|
FSRT_Nm3D, true, &errorMessage);
|
|
|
if(p3DWidget == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
m_pPendingResultDataManager = pInstance;
|
|
|
m_pPendingResultFitting = pSubWndFit;
|
|
|
m_bPendingResultWidgetRefresh = true;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return populateResultWidgets(pSubWndFit, pInstance);
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::populateResultWidgets(
|
|
|
iSubWndFitting* pSubWndFit,
|
|
|
nmDataAnalyzeManager* pDataManager)
|
|
|
{
|
|
|
if(pSubWndFit == nullptr || pDataManager == nullptr ||
|
|
|
pDataManager->getGridType() != NM_Grid_PEBI ||
|
|
|
nmDataAnalyzeManager::findManagerByFitting(pSubWndFit) != pDataManager) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
QString sErrorMessage;
|
|
|
QWidget* p3DWidget = pSubWndFit->getFitSubRstWxOf(
|
|
|
FSRT_Nm3D, true, &sErrorMessage);
|
|
|
if(p3DWidget == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nmWxPostprocessingAnimationWidget* pVtkWidget =
|
|
|
p3DWidget->findChild<nmWxPostprocessingAnimationWidget*>();
|
|
|
if(pVtkWidget != nullptr) {
|
|
|
// 复用既有渲染窗口和 VTK 管道,只切换本轮已整体提交的数据。
|
|
|
pVtkWidget->refreshResult();
|
|
|
} else {
|
|
|
pVtkWidget = new nmWxPostprocessingAnimationWidget(NULL, pDataManager);
|
|
|
QLayout* p3DLayout = p3DWidget->layout();
|
|
|
if(p3DLayout == nullptr) {
|
|
|
p3DLayout = new QVBoxLayout(p3DWidget);
|
|
|
} else {
|
|
|
QLayoutItem* pItem = nullptr;
|
|
|
while((pItem = p3DLayout->takeAt(0)) != nullptr) {
|
|
|
if(pItem->widget() != nullptr) {
|
|
|
delete pItem->widget();
|
|
|
}
|
|
|
delete pItem;
|
|
|
}
|
|
|
}
|
|
|
p3DLayout->addWidget(pVtkWidget);
|
|
|
}
|
|
|
|
|
|
// 结果参数界面
|
|
|
QWidget* pResultPage = pSubWndFit->getFitSubRstWxOf(
|
|
|
FSRT_NmRst, true, &sErrorMessage);
|
|
|
if(pResultPage == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nmWxParaPropertyPebi* pResultWidget =
|
|
|
pResultPage->findChild<nmWxParaPropertyPebi*>();
|
|
|
if(pResultWidget == nullptr) {
|
|
|
// 与左侧共用属性面板类,结果区使用独立实例和只读参数列表。
|
|
|
pResultWidget = new nmWxParaPropertyPebi;
|
|
|
pResultWidget->initUI();
|
|
|
pResultWidget->setDataManager(pDataManager);
|
|
|
// 保持 8 月 24 日版本的稳定顺序:离屏完成参数构建后再加入可见布局。
|
|
|
pResultWidget->rebuildResultParas();
|
|
|
|
|
|
QLayout* pResultLayout = pResultPage->layout();
|
|
|
if(pResultLayout == nullptr) {
|
|
|
pResultLayout = new QVBoxLayout(pResultPage);
|
|
|
} else {
|
|
|
QLayoutItem* pItem = nullptr;
|
|
|
while((pItem = pResultLayout->takeAt(0)) != nullptr) {
|
|
|
if(pItem->widget() != nullptr) {
|
|
|
delete pItem->widget();
|
|
|
}
|
|
|
delete pItem;
|
|
|
}
|
|
|
}
|
|
|
pResultLayout->addWidget(pResultWidget);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
pResultWidget->setDataManager(pDataManager);
|
|
|
pResultWidget->rebuildResultParas();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::schedulePendingResultWidgets()
|
|
|
{
|
|
|
if(m_bPendingResultWidgetRefresh) {
|
|
|
QTimer::singleShot(0, this, SLOT(populatePendingResultWidgets()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::populatePendingResultWidgets()
|
|
|
{
|
|
|
if(!m_bPendingResultWidgetRefresh) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
iSubWndFitting* pSubWndFit = m_pPendingResultFitting.data();
|
|
|
nmDataAnalyzeManager* pDataManager = m_pPendingResultDataManager.data();
|
|
|
m_bPendingResultWidgetRefresh = false;
|
|
|
m_pPendingResultDataManager = nullptr;
|
|
|
m_pPendingResultFitting = nullptr;
|
|
|
|
|
|
const bool bResultWindowReady =
|
|
|
populateResultWidgets(pSubWndFit, pDataManager);
|
|
|
if(m_bPendingResultCompletionMessage) {
|
|
|
m_bPendingResultWindowReady = bResultWindowReady;
|
|
|
QTimer::singleShot(
|
|
|
0,
|
|
|
this,
|
|
|
SLOT(showPendingSolverResultCompletion()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::showPendingSolverResultCompletion()
|
|
|
{
|
|
|
if(!m_bPendingResultCompletionMessage) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const bool bResultWindowReady = m_bPendingResultWindowReady;
|
|
|
const int nPebiCount = m_nPendingResultPebiCount;
|
|
|
const int nSolveTimeMs = m_nPendingResultSolveTimeMs;
|
|
|
m_bPendingResultCompletionMessage = false;
|
|
|
m_bPendingResultWindowReady = false;
|
|
|
m_nPendingResultPebiCount = -1;
|
|
|
m_nPendingResultSolveTimeMs = -1;
|
|
|
showSolverResultCompletion(bResultWindowReady,
|
|
|
nPebiCount,
|
|
|
nSolveTimeMs);
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::inithalfLog(QVector<QVector<double >> & vvecLogPreData, QVector<iCurveDesc>& vecDescs, bool isHistoryData)
|
|
|
{
|
|
|
// 半对数压力曲线
|
|
|
iCurveDesc curveDesc;
|
|
|
|
|
|
if(vvecLogPreData.size() != 2) {
|
|
|
vecDescs.append(curveDesc);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// X轴数据
|
|
|
curveDesc.m_vecX = vvecLogPreData[0];
|
|
|
// Y轴数据
|
|
|
curveDesc.m_vecY = vvecLogPreData[1];
|
|
|
|
|
|
curveDesc.m_oCurveType = POT_CurvePressure;
|
|
|
|
|
|
// 判断是历史数据还是计算数据
|
|
|
if(isHistoryData) {
|
|
|
curveDesc.m_sCurveName = s_SemiSouce_Curve;
|
|
|
curveDesc.m_bLineVisible = false; // 关闭线模式可见性
|
|
|
curveDesc.m_bPointVisible = true; // 开启点模式可见性
|
|
|
curveDesc.m_oDot.setColor(Qt::red); // 设置点的颜色
|
|
|
curveDesc.m_oDot.setStyle(ZxDotType::DTS_Cross); // x形状
|
|
|
} else {
|
|
|
curveDesc.m_sCurveName = s_SemiTheorySouce_Curve; // 理论曲线
|
|
|
curveDesc.m_bLineVisible = true; // 开启线模式可见性
|
|
|
curveDesc.m_bPointVisible = false; // 关闭点模式可见性
|
|
|
curveDesc.m_oPen.setColor(Qt::green); // 设置线的颜色
|
|
|
}
|
|
|
|
|
|
// 将 curveDesc 添加到 QVector
|
|
|
vecDescs.append(curveDesc);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::initloglog(QVector<QVector<double> > &vvecLogPreData, QVector<iCurveDesc>& vecDescs, bool isHistoryData)
|
|
|
{
|
|
|
// 双对数压力曲线
|
|
|
iCurveDesc curveDesc1, curveDesc2;
|
|
|
|
|
|
if(vvecLogPreData.size() != 3) {
|
|
|
vecDescs.append(curveDesc1);
|
|
|
vecDescs.append(curveDesc2);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 确保每个内部 QVector 都不为空,然后移除其最后一个元素
|
|
|
// 移除 vvecLogPreData[0] (vX) 中的最后一个元素
|
|
|
if(!vvecLogPreData[0].isEmpty()) {
|
|
|
vvecLogPreData[0].remove(vvecLogPreData[0].size() - 1);
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 移除 vvecLogPreData[1] (vY) 中的最后一个元素
|
|
|
if(!vvecLogPreData[1].isEmpty()) {
|
|
|
vvecLogPreData[1].remove(vvecLogPreData[1].size() - 1);
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 移除 vvecLogPreData[2] (vZ) 中的最后一个元素
|
|
|
if(!vvecLogPreData[2].isEmpty()) {
|
|
|
vvecLogPreData[2].remove(vvecLogPreData[2].size() - 1);
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 曲线1
|
|
|
curveDesc1.m_vecX = vvecLogPreData[0];
|
|
|
curveDesc1.m_vecY = vvecLogPreData[1];
|
|
|
// 曲线2
|
|
|
curveDesc2.m_vecX = vvecLogPreData[0];
|
|
|
curveDesc2.m_vecY = vvecLogPreData[2];
|
|
|
|
|
|
curveDesc1.m_oCurveType = POT_CurveDiscrete;
|
|
|
curveDesc2.m_oCurveType = POT_CurveDiscrete;
|
|
|
|
|
|
// 判断是历史数据还是计算数据
|
|
|
if(isHistoryData) {
|
|
|
curveDesc1.m_sCurveName = s_Souce_Curve;
|
|
|
curveDesc2.m_sCurveName = s_Deriv_Curve;
|
|
|
|
|
|
curveDesc1.m_bLineVisible = false; // 关闭线模式可见性
|
|
|
curveDesc1.m_bPointVisible = true; // 开启点模式可见性
|
|
|
curveDesc1.m_oDot.setColor(Qt::green); // 设置点的颜色
|
|
|
curveDesc1.m_oDot.setStyle(ZxDotType::DTS_Cross); // X形状
|
|
|
|
|
|
curveDesc2.m_bLineVisible = false; // 关闭线模式可见性
|
|
|
curveDesc2.m_bPointVisible = true; // 开启点模式可见性
|
|
|
curveDesc2.m_oDot.setColor(Qt::red); // 设置点的颜色
|
|
|
curveDesc2.m_oDot.setStyle(ZxDotType::DTS_Circle); // O形状
|
|
|
curveDesc2.m_oDot.setFilling(false); // 不填充
|
|
|
} else {
|
|
|
curveDesc1.m_sCurveName = s_TheorySouce_Curve;
|
|
|
curveDesc2.m_sCurveName = s_TheoryDeriv_Curve;
|
|
|
|
|
|
curveDesc1.m_bLineVisible = true; // 关闭线模式可见性
|
|
|
curveDesc1.m_bPointVisible = false; // 开启点模式可见性
|
|
|
curveDesc1.m_oPen.setColor(Qt::red); // 设置线的颜色
|
|
|
|
|
|
curveDesc2.m_bLineVisible = true; // 关闭线模式可见性
|
|
|
curveDesc2.m_bPointVisible = false; // 开启点模式可见性
|
|
|
curveDesc2.m_oPen.setColor(Qt::green); // 设置线的颜色
|
|
|
}
|
|
|
|
|
|
// 将 curveDesc 添加到 QVector
|
|
|
vecDescs.append(curveDesc1);
|
|
|
// 将 curveDesc 添加到 QVector
|
|
|
vecDescs.append(curveDesc2);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::initPreHistory(QVector<QVector<double> > &vvecHistoryData, QVector<iCurveDesc>& vecDescs, bool isHistoryData)
|
|
|
{
|
|
|
// 压力曲线
|
|
|
iCurveDesc curveDesc;
|
|
|
|
|
|
if(vvecHistoryData.size() != 2) {
|
|
|
vecDescs.append(curveDesc);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// X轴数据
|
|
|
curveDesc.m_vecX = vvecHistoryData[0];
|
|
|
// Y轴数据
|
|
|
curveDesc.m_vecY = vvecHistoryData[1];
|
|
|
|
|
|
curveDesc.m_oCurveType = POT_CurvePressure;
|
|
|
|
|
|
// 判断是历史数据还是计算数据
|
|
|
if(isHistoryData) {
|
|
|
curveDesc.m_sCurveName = s_HistorySouce_CurveP;
|
|
|
curveDesc.m_bLineVisible = false; // 关闭线模式可见性
|
|
|
curveDesc.m_bPointVisible = true; // 开启点模式可见性
|
|
|
curveDesc.m_oDot.setColor(Qt::red); // 设置点的颜色
|
|
|
curveDesc.m_oDot.setStyle(ZxDotType::DTS_Plus); // +形状
|
|
|
} else {
|
|
|
curveDesc.m_sCurveName = s_HistoryFit_CurveP;
|
|
|
curveDesc.m_bLineVisible = true; // 关闭线模式可见性
|
|
|
curveDesc.m_bPointVisible = false; // 开启点模式可见性
|
|
|
curveDesc.m_oPen.setColor(Qt::green); // 设置线的颜色
|
|
|
}
|
|
|
|
|
|
// 将 curveDesc 添加到 QVector
|
|
|
vecDescs.append(curveDesc);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::onConfirmClosing()
|
|
|
{
|
|
|
// 正常关闭入口在求解结束前保持当前成果和 DataManager 存活;应用退出等绕过
|
|
|
// 该确认流程的路径仍由析构函数 wait() 兜底。
|
|
|
if(m_bSolverStartPending ||
|
|
|
(m_pSolverTask != nullptr && m_pSolverTask->isRunning())) {
|
|
|
QMessageBox::information(this, tr("solver error"), tr("task is running!"));
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return iSubWndBaseAF::onConfirmClosing();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::reservoirCharacteristics()
|
|
|
{
|
|
|
// 第一步:取得当前分析窗口对应的数据管理器,避免新对话框访问全局单例。
|
|
|
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getCurrentInstance();
|
|
|
if (pDataManager == nullptr)
|
|
|
{
|
|
|
QMessageBox::warning(this, tr("Reservoir properties"),
|
|
|
tr("The current numerical well-test data is unavailable."));
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 第二步:在入口处组装数据源和编辑器,两个对象的生命周期覆盖整个模态会话。
|
|
|
nmAnalyzeManagerReservoirDataSource oDataSource(pDataManager);
|
|
|
nmWxReservoirPropertiesEditor oEditor(&oDataSource, this);
|
|
|
|
|
|
// 第三步:先建立工作副本;初始化失败时不打开不完整的参数界面。
|
|
|
QString sError;
|
|
|
if (!oEditor.initialize(sError))
|
|
|
{
|
|
|
QMessageBox::warning(this, tr("Reservoir properties"), sError);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 第四步:确定时由编辑会话一次性提交,取消时真实数据保持不变。
|
|
|
oEditor.exec();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::geoLayering()
|
|
|
{
|
|
|
nmWxGeometryLayerDlg dlg;
|
|
|
|
|
|
if(dlg.exec() == QDialog::Rejected) {
|
|
|
return;
|
|
|
} else {
|
|
|
QVector<nmDataLayer*> layers = dlg.getLayerData();
|
|
|
// 添加到数据中心
|
|
|
nmDataAnalyzeManager::getCurrentInstance()->setLayers(layers);
|
|
|
|
|
|
//for (int i = 0; i < layers.size(); ++i) {
|
|
|
// nmDataLayer* layer = layers[i];
|
|
|
// qDebug() << "Layer" << i + 1 << "Top:" << layer->getTop()
|
|
|
// << "Bottom:" << layer->getBottom()
|
|
|
// << "Thickness:" << layer->getThickness()
|
|
|
// << "IsChecked:" << layer->getIsChecked();
|
|
|
//}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::on_calculationFinished(NM_Calculation_Result result)
|
|
|
{
|
|
|
if(result == NM_Calculation_Result_Success) {
|
|
|
return this->mergeAnaResultToFitting();
|
|
|
} else {
|
|
|
// 如果失败,进度条其实没必要拉满了,直接提示错误
|
|
|
QMessageBox::warning(this, tr("solver error"), tr("solver failed!"));
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::scheduleSolverResultCompletion(
|
|
|
bool bSucceeded,
|
|
|
int nPebiCount,
|
|
|
int nSolveTimeMs,
|
|
|
bool bInputChanged)
|
|
|
{
|
|
|
s_pPendingSolverWindow = this;
|
|
|
m_bSolverResultCompletionPending = true;
|
|
|
m_bPendingSolverSucceeded = bSucceeded;
|
|
|
m_bPendingSolverInputChanged = bInputChanged;
|
|
|
m_nPendingSolverPebiCount = nPebiCount;
|
|
|
m_nPendingSolverTimeMs = nSolveTimeMs;
|
|
|
|
|
|
// 当前完成信号栈只登记后续工作;隐藏和结果刷新各占一轮独立事件。
|
|
|
QTimer::singleShot(0, this, SLOT(dismissPendingSolverProgress()));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::dismissPendingSolverProgress()
|
|
|
{
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->hide();
|
|
|
}
|
|
|
QTimer::singleShot(0, this, SLOT(completePendingSolverResult()));
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::completePendingSolverResult()
|
|
|
{
|
|
|
if(!m_bSolverResultCompletionPending) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const bool bSucceeded = m_bPendingSolverSucceeded;
|
|
|
const bool bInputChanged = m_bPendingSolverInputChanged;
|
|
|
const int nPebiCount = m_nPendingSolverPebiCount;
|
|
|
const int nSolveTimeMs = m_nPendingSolverTimeMs;
|
|
|
m_bSolverResultCompletionPending = false;
|
|
|
m_bPendingSolverSucceeded = false;
|
|
|
m_bPendingSolverInputChanged = false;
|
|
|
m_nPendingSolverPebiCount = -1;
|
|
|
m_nPendingSolverTimeMs = -1;
|
|
|
|
|
|
bool bResultWindowReady = false;
|
|
|
if(bInputChanged) {
|
|
|
QMessageBox::warning(
|
|
|
this,
|
|
|
tr("Solver result discarded"),
|
|
|
tr("The input changed while the solver was preparing or running. "
|
|
|
"The outdated result was discarded."));
|
|
|
} else {
|
|
|
bResultWindowReady = on_calculationFinished(bSucceeded
|
|
|
? NM_Calculation_Result_Success
|
|
|
: NM_Calculation_Result_Fail);
|
|
|
}
|
|
|
|
|
|
// mergeAnaResultToFitting() 已使用完启动时捕获的上下文。
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
m_bSolverCancelRequested = false;
|
|
|
|
|
|
if(bSucceeded && bResultWindowReady &&
|
|
|
m_bPendingResultWidgetRefresh) {
|
|
|
// 首次结果页尚未填充,最终提示必须等页面真实创建结果返回后再显示。
|
|
|
m_bPendingResultCompletionMessage = true;
|
|
|
m_nPendingResultPebiCount = nPebiCount;
|
|
|
m_nPendingResultSolveTimeMs = nSolveTimeMs;
|
|
|
} else if(bSucceeded) {
|
|
|
showSolverResultCompletion(bResultWindowReady,
|
|
|
nPebiCount,
|
|
|
nSolveTimeMs);
|
|
|
}
|
|
|
|
|
|
// 首次结果载体创建后再跨一个事件循环填充,避免 Qt 4.8 布局重入。
|
|
|
schedulePendingResultWidgets();
|
|
|
if(s_pPendingSolverWindow == this) {
|
|
|
s_pPendingSolverWindow = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::showSolverResultCompletion(
|
|
|
bool bResultWindowReady,
|
|
|
int nPebiCount,
|
|
|
int nSolveTimeMs)
|
|
|
{
|
|
|
if(bResultWindowReady && nPebiCount >= 0 && nSolveTimeMs >= 0) {
|
|
|
QMessageBox::information(this, tr("Solver completed"),
|
|
|
tr("Grid count: %1\nSolve time: %2 ms")
|
|
|
.arg(nPebiCount)
|
|
|
.arg(nSolveTimeMs));
|
|
|
} else if(!bResultWindowReady) {
|
|
|
QMessageBox::warning(
|
|
|
this,
|
|
|
tr("Result display error"),
|
|
|
tr("Solver completed and the results were committed, but the "
|
|
|
"result window could not be opened."));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::on_solverTaskFinished(bool isSuccessed)
|
|
|
{
|
|
|
// 第一步:只接受当前窗口实际启动的任务,忽略已经失效的旧回调。
|
|
|
nmCalculationDllPebiSolverTask* pTask = qobject_cast<nmCalculationDllPebiSolverTask*>(sender());
|
|
|
if(pTask == nullptr || pTask != m_pSolverTask) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
int nPebiCount = pTask != nullptr ? pTask->getPebiCount() : -1;
|
|
|
int nSolveTimeMs = pTask != nullptr ? pTask->getSolveTimeMs() : -1;
|
|
|
const bool bCancelled = pTask->wasCancelled();
|
|
|
bool bInputChanged = false;
|
|
|
// 后台线程只生成局部结果快照。回到主线程后先验证所属 DataManager 和
|
|
|
// 输入版本,再整体替换旧成果;输入变化与真正的求解失败分别提示。
|
|
|
if(isSuccessed && !bCancelled) {
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->setLabelText(tr("Committing results..."));
|
|
|
m_pProgressDlg->setRange(0, 0);
|
|
|
}
|
|
|
bInputChanged =
|
|
|
pTask->hasInputChanged(m_pSolverDataManager.data());
|
|
|
isSuccessed = pTask->commitResult(m_pSolverDataManager.data());
|
|
|
bInputChanged = !isSuccessed && bInputChanged;
|
|
|
} else if(bCancelled) {
|
|
|
isSuccessed = false;
|
|
|
}
|
|
|
m_pSolverTask = nullptr;
|
|
|
if(pTask == s_pRunningSolverTask) {
|
|
|
s_pRunningSolverTask = nullptr;
|
|
|
}
|
|
|
// 正常完成路径由主线程延迟释放任务;析构路径则会等待并直接释放。
|
|
|
pTask->deleteLater();
|
|
|
|
|
|
// 第二步:停止不属于失败,也不允许触发结果提交或覆盖旧成果。
|
|
|
if(bCancelled) {
|
|
|
if(m_pProgressDlg != nullptr) {
|
|
|
m_pProgressDlg->hide();
|
|
|
}
|
|
|
m_pSolverDataManager = nullptr;
|
|
|
m_pSolverFitting = nullptr;
|
|
|
m_bSolverCancelRequested = false;
|
|
|
} else {
|
|
|
scheduleSolverResultCompletion(isSuccessed,
|
|
|
nPebiCount,
|
|
|
nSolveTimeMs,
|
|
|
bInputChanged);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::deleteOneObj()
|
|
|
{
|
|
|
this->triggerToolBarAction(NMOT_Delete);
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::setLocked()
|
|
|
{
|
|
|
if(m_lockState) { // 锁定
|
|
|
m_lockState = false;
|
|
|
|
|
|
int objCount = this->m_pWxPlot->m_pPlot->getObjCount();
|
|
|
|
|
|
for(int i = 0; i < objCount; i++) {
|
|
|
ZxObjBase* obj = this->m_pWxPlot->m_pPlot->getObjByIndex(i);
|
|
|
|
|
|
if(!_isSame("nObjPointWell", obj->getTagName())) {
|
|
|
obj->setReadOnly(false);
|
|
|
obj->setLockPos(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QStringList nIDs;
|
|
|
nIDs.append("5125");
|
|
|
nIDs.append("5124");
|
|
|
nIDs.append("5123");
|
|
|
nIDs.append("5114");
|
|
|
nIDs.append("5115");
|
|
|
nIDs.append("5116");
|
|
|
nIDs.append("5117");
|
|
|
nIDs.append("5118");
|
|
|
nIDs.append("5119");
|
|
|
nIDs.append("5102");
|
|
|
nIDs.append("5120");
|
|
|
nIDs.append("5103");
|
|
|
nIDs.append("5104");
|
|
|
nIDs.append("5105");
|
|
|
nIDs.append("5106");
|
|
|
nIDs.append("5107");
|
|
|
// nIDs.append("5108"); // 新建井菜单暂时停用
|
|
|
nIDs.append("5109");
|
|
|
nIDs.append("5110");
|
|
|
nIDs.append("5111");
|
|
|
nIDs.append("5121");
|
|
|
nIDs.append("5112");
|
|
|
nIDs.append("5113");
|
|
|
nIDs.append("5122");
|
|
|
|
|
|
nIDs.append("9002");
|
|
|
nIDs.append("9003");
|
|
|
nIDs.append("9101");
|
|
|
nIDs.append("9102");
|
|
|
nIDs.append("9103");
|
|
|
nIDs.append("9104");
|
|
|
|
|
|
nIDs.append("3104");
|
|
|
emit sigFreshRnStates(nIDs);
|
|
|
/*
|
|
|
if (m_pMainWindow != NULL) {
|
|
|
//m_pMainWindow->slotFreshRnStates(nIDs);
|
|
|
}
|
|
|
*/
|
|
|
//m_pMainWindow->getMainRibbon
|
|
|
} else {
|
|
|
m_lockState = true;
|
|
|
|
|
|
int objCount = this->m_pWxPlot->m_pPlot->getObjCount();
|
|
|
|
|
|
for(int i = 0; i < objCount; i++) {
|
|
|
ZxObjBase* obj = this->m_pWxPlot->m_pPlot->getObjByIndex(i);
|
|
|
|
|
|
if(!_isSame("nObjPointWell", obj->getTagName())) {
|
|
|
obj->setReadOnly(true);
|
|
|
obj->setLockPos(true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QStringList nIDs;
|
|
|
nIDs.append("5125");
|
|
|
nIDs.append("5124");
|
|
|
nIDs.append("5123");
|
|
|
nIDs.append("5114");
|
|
|
nIDs.append("5115");
|
|
|
nIDs.append("5116");
|
|
|
nIDs.append("5117");
|
|
|
nIDs.append("5118");
|
|
|
nIDs.append("5119");
|
|
|
nIDs.append("5102");
|
|
|
nIDs.append("5120");
|
|
|
nIDs.append("5103");
|
|
|
nIDs.append("5104");
|
|
|
nIDs.append("5105");
|
|
|
nIDs.append("5106");
|
|
|
nIDs.append("5107");
|
|
|
// nIDs.append("5108"); // 新建井菜单暂时停用
|
|
|
nIDs.append("5109");
|
|
|
nIDs.append("5110");
|
|
|
nIDs.append("5111");
|
|
|
nIDs.append("5121");
|
|
|
nIDs.append("5112");
|
|
|
nIDs.append("5113");
|
|
|
nIDs.append("5122");
|
|
|
|
|
|
//nIDs.append("9002");
|
|
|
//nIDs.append("9003");
|
|
|
nIDs.append("9101");
|
|
|
nIDs.append("9102");
|
|
|
nIDs.append("9103");
|
|
|
nIDs.append("9104");
|
|
|
|
|
|
nIDs.append("3104");
|
|
|
emit sigFreshRnStates(nIDs);
|
|
|
/*
|
|
|
if (m_pMainWindow != NULL) {
|
|
|
m_pMainWindow->slotFreshRnStates(nIDs);
|
|
|
}
|
|
|
*/
|
|
|
/*
|
|
|
emit sigFreshRnStates(nIDs);
|
|
|
if (m_pMainWindow != NULL) {
|
|
|
m_pMainWindow->slotFreshRnStates(nIDs);
|
|
|
}
|
|
|
|
|
|
bool b;
|
|
|
QString sName = "NmUnlocked";
|
|
|
int nID = 5119;
|
|
|
bool bLicensed;
|
|
|
nmSubWndMain::checkCmdEnable(b, sName, nID, bLicensed);
|
|
|
nID = 5125;
|
|
|
sName = "NmPrint";
|
|
|
nmSubWndMain::checkCmdEnable(b, sName, nID, bLicensed);
|
|
|
*/
|
|
|
}
|
|
|
}
|
|
|
|
|
|
nmGuiPlot * nmSubWndMain::getWxPlot() const
|
|
|
{
|
|
|
return m_pWxPlot;
|
|
|
}
|
|
|
|
|
|
bool nmSubWndMain::refreshPebiResultCurves(
|
|
|
iSubWndFitting* pSubWndFit,
|
|
|
nmDataAnalyzeManager* pDataManager,
|
|
|
const QString& sWellInstanceId)
|
|
|
{
|
|
|
if(pSubWndFit == nullptr || pDataManager == nullptr ||
|
|
|
pDataManager->getGridType() != NM_Grid_PEBI) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
QSharedPointer<const nmPebiResultSnapshot> pSnapshot =
|
|
|
pDataManager->getPebiResultSnapshot();
|
|
|
if(pSnapshot.isNull() ||
|
|
|
(!sWellInstanceId.isEmpty() &&
|
|
|
!pSnapshot->isDisplayWell(sWellInstanceId))) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const nmPebiResultWellSnapshot* pWell = sWellInstanceId.isEmpty()
|
|
|
? NULL : pSnapshot->findWell(sWellInstanceId);
|
|
|
if(!sWellInstanceId.isEmpty() && pWell == NULL) {
|
|
|
return false;
|
|
|
}
|
|
|
if(!pDataManager->setCurrentResultWellInstanceId(sWellInstanceId)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nmPebiResultWellCurves oEmptyCurves;
|
|
|
const nmPebiResultWellCurves& oCurves = pWell != NULL
|
|
|
? pWell->m_oCurves : oEmptyCurves;
|
|
|
QString sErrorMessage;
|
|
|
|
|
|
// 旧绘图辅助函数会裁掉双对数末点,必须使用隐式共享局部副本,
|
|
|
// 触发写时复制后也不能改动发布后的快照容器。
|
|
|
QVector<QVector<double> > vecHistorySemiLog =
|
|
|
oCurves.m_vecHistorySemiLog;
|
|
|
QVector<QVector<double> > vecResultSemiLog =
|
|
|
oCurves.m_vecResultSemiLog;
|
|
|
QVector<QVector<double> > vecHistoryLogLog =
|
|
|
oCurves.m_vecHistoryLogLog;
|
|
|
QVector<QVector<double> > vecResultLogLog =
|
|
|
oCurves.m_vecResultLogLog;
|
|
|
QVector<QVector<double> > vecHistoryPressure =
|
|
|
oCurves.m_vecHistoryPressure;
|
|
|
QVector<QVector<double> > vecResultPressureData =
|
|
|
oCurves.m_vecResultPressure;
|
|
|
|
|
|
// 每个窗口先发布求解时冻结的历史曲线,再叠加同一快照中的计算曲线。
|
|
|
QVector<iCurveDesc> vecHistoryHalfLog;
|
|
|
this->inithalfLog(vecHistorySemiLog,
|
|
|
vecHistoryHalfLog, true);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_SemiLog, vecHistoryHalfLog, true, &sErrorMessage);
|
|
|
QVector<iCurveDesc> vecHalfLog;
|
|
|
this->inithalfLog(vecResultSemiLog, vecHalfLog, false);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_SemiLog, vecHalfLog, true, &sErrorMessage);
|
|
|
|
|
|
QVector<iCurveDesc> vecHistoryLog;
|
|
|
this->initloglog(vecHistoryLogLog,
|
|
|
vecHistoryLog, true);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_DoubleLog, vecHistoryLog, true, &sErrorMessage);
|
|
|
QVector<iCurveDesc> vecLogLog;
|
|
|
this->initloglog(vecResultLogLog, vecLogLog, false);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_DoubleLog, vecLogLog, true, &sErrorMessage);
|
|
|
|
|
|
QVector<iCurveDesc> vecHistoryPre;
|
|
|
this->initPreHistory(vecHistoryPressure,
|
|
|
vecHistoryPre, true);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_Hist, vecHistoryPre, true, &sErrorMessage);
|
|
|
QVector<iCurveDesc> vecResultPressure;
|
|
|
this->initPreHistory(vecResultPressureData,
|
|
|
vecResultPressure, false);
|
|
|
pSubWndFit->adjustFitSubPlotBy(
|
|
|
FSRT_Hist, vecResultPressure, true, &sErrorMessage);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::onWellSelected(const QString& sWellInstanceId)
|
|
|
{
|
|
|
nmDataAnalyzeManager* pInstance =
|
|
|
nmDataAnalyzeManager::getCurrentInstance();
|
|
|
iSubWndFitting* pSubWndFit =
|
|
|
nmDataAnalyzeManager::getCurrentFitting();
|
|
|
if(pInstance == nullptr || pSubWndFit == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 删除的实时井仍可按快照 UUID 切换;本路径不得查询或重算实时井数据。
|
|
|
refreshPebiResultCurves(
|
|
|
pSubWndFit, pInstance, sWellInstanceId);
|
|
|
}
|
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
|
//void nmSubWndMain::calculationLogData(
|
|
|
// nmDataWellBase* pWellData,
|
|
|
// QVector<QVector<double>>& vvecHistoryData,
|
|
|
// QVector<QVector<double>>& vvecLogPreData,
|
|
|
// QVector<QVector<double>>& vvecSemiLogPreData)
|
|
|
//{
|
|
|
// // 清空输出参数
|
|
|
// vvecHistoryData.clear();
|
|
|
// vvecLogPreData.clear();
|
|
|
// vvecSemiLogPreData.clear();
|
|
|
//
|
|
|
// if(pWellData == nullptr) {
|
|
|
// return;
|
|
|
// }
|
|
|
//
|
|
|
// // 初始化二维数组结构
|
|
|
// vvecHistoryData.resize(2); // [0]=x, [1]=y
|
|
|
// vvecLogPreData.resize(3); // [0]=x, [1]=y, [2]=z
|
|
|
// vvecSemiLogPreData.resize(2); // [0]=x, [1]=pointData[0]
|
|
|
//
|
|
|
// // 准备压力数据
|
|
|
// QVector<QPointF> vecPressure = pWellData->getPressurePoints();
|
|
|
// std::vector<Point> wellPressureData;
|
|
|
//
|
|
|
// // 填充 wellPressureData 和 vvecHistoryData
|
|
|
// foreach(const QPointF& qpoint, vecPressure) {
|
|
|
// // wellPressureData
|
|
|
// Point pt;
|
|
|
// pt.x = qpoint.x();
|
|
|
// pt.y = qpoint.y();
|
|
|
// pt.z = 0.0;
|
|
|
// wellPressureData.push_back(pt);
|
|
|
//
|
|
|
// // vvecHistoryData
|
|
|
// vvecHistoryData[0].append(qpoint.x()); // x
|
|
|
// vvecHistoryData[1].append(qpoint.y()); // y
|
|
|
// }
|
|
|
//
|
|
|
// // 准备流量段数据
|
|
|
// QVector<QPointF> vecTimeQ = pWellData->getFlowPoints();
|
|
|
// int nTimeNumQ = vecTimeQ.size() - 1;
|
|
|
// std::vector<double> timeQ(nTimeNumQ);
|
|
|
// std::vector<double> q(nTimeNumQ);
|
|
|
//
|
|
|
// for(int i = 0; i < nTimeNumQ; ++i) {
|
|
|
// timeQ[i] = vecTimeQ[i + 1].x();
|
|
|
// q[i] = vecTimeQ[i + 1].y();
|
|
|
// }
|
|
|
//
|
|
|
// // 调用 DLL 计算双对数曲线
|
|
|
// std::vector<Point> logPre;
|
|
|
// int iSectionFlowIndex = pWellData->getIndexF();
|
|
|
//
|
|
|
// HMODULE hMod_solver = LoadLibrary(L"singlePhaseSolverDll.dll");
|
|
|
//
|
|
|
// if(hMod_solver) {
|
|
|
// typedef bool (*PreLog)(const std::vector<Point>&, const int&, double*, double*, int, std::vector<Point>&);
|
|
|
// PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre");
|
|
|
//
|
|
|
// if(nullptr == preLogFun) {
|
|
|
// FreeLibrary(hMod_solver);
|
|
|
// std::cout << "preLogFun failed!\n";
|
|
|
// return;
|
|
|
// }
|
|
|
//
|
|
|
// preLogFun(wellPressureData, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPre);
|
|
|
//
|
|
|
// // 不添加最后一个元素
|
|
|
// for(uint i = 0; i < logPre.size() - 1; i++) {
|
|
|
// //logFile << logPre[i].x << "\t" << logPre[i].y << "\t" << logPre[i].z << "\t" << std::endl;
|
|
|
// vvecLogPreData[0].append(logPre[i].x); // x
|
|
|
// vvecLogPreData[1].append(logPre[i].y); // y
|
|
|
// vvecLogPreData[2].append(logPre[i].z); // z
|
|
|
// }
|
|
|
//
|
|
|
// // 填充半对数曲线数据 (x, pointData[0])
|
|
|
// foreach(const auto& point, logPre) {
|
|
|
// vvecSemiLogPreData[0].append(point.x); // x
|
|
|
// double y_value = point.pointData.empty() ? 0.0 : point.pointData[0];
|
|
|
// vvecSemiLogPreData[1].append(y_value); // pointData[0] 或默认值
|
|
|
// }
|
|
|
// FreeLibrary(hMod_solver);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
void nmSubWndMain::onGenerateButtonClicked()
|
|
|
{
|
|
|
if(nmDataAnalyzeManager::getCurrentInstance()->getGridType() == NM_Grid_PEBI) {
|
|
|
// 求解任务创建时会捕获完整输入。网格无效时,工作线程只基于值快照生成
|
|
|
// 一次局部网格,求解成功后再和全部结果一起回主线程提交。
|
|
|
this->solveAndAnalyze();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::generateDFN()
|
|
|
{
|
|
|
nmWxDFN dfnDialog(nullptr);
|
|
|
dfnDialog.exec();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::displaySetting()
|
|
|
{
|
|
|
nmWxDisplaySettings disPlayDlg;
|
|
|
disPlayDlg.exec();
|
|
|
}
|
|
|
|
|
|
void nmSubWndMain::updateMapByDataManager(nmDataAnalyzeManager* pDataManager)
|
|
|
{
|
|
|
// 删除原来的图元信息
|
|
|
if(m_pWxPlot == nullptr || pDataManager == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 一个Map同一时间只展示一个分析的数据,切换前先解除其他DataManager对当前Plot的绑定。
|
|
|
foreach(nmDataAnalyzeManager* pManager, nmDataAnalyzeManager::s_mapDataAnalManager.values()) {
|
|
|
if(pManager != nullptr && pManager != pDataManager && pManager->getPlot() == m_pWxPlot) {
|
|
|
pManager->setPlot(nullptr);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 更新对应的Plot成员变量
|
|
|
pDataManager->setPlot(m_pWxPlot);
|
|
|
|
|
|
m_pWxPlot->deleteAllPlotObjs();
|
|
|
|
|
|
// 切换分析时更新 Binder 绑定的 DataManager,
|
|
|
// 确保用户新画断层时添加到正确的 DataManager
|
|
|
if(m_pWxPlot->graphicBinder()) {
|
|
|
m_pWxPlot->graphicBinder()->updateDataMgr(pDataManager);
|
|
|
}
|
|
|
|
|
|
// 根据数据中心内容绘制新图元
|
|
|
m_pWxPlot->setPlotsByDataManger(pDataManager);
|
|
|
}
|