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/nmSubWndUtils.cpp

1297 lines
44 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 "iRibbonXmlCmd.h"
#include <QEvent>
#include <QMdiArea>
#include <QMdiSubWindow>
#include "zxSysUtils.h"
#include "ZxUiBase.h"
#include "ZxMainWindow.h"
#include "ZxMdiSubWindow.h"
#include "ZxTabWidget.h"
#include "TreeWxMain.h"
#include "iDockBaseWx.h"
#include "iModuleHelper.h"
#include "ZxDataWell.h"
#include "ZxDataProject.h"
#include "nmFrameworkTest.h"
#include "iSubWndFitting.h"
#ifdef MY_OWN_GRID
#include "iSubWndGrid.h"
#else
#include "nmSubWndDemo.h"
#endif
#include "nmSubWndUtils.h"
#include "nmSubWndMain.h"
#include "nmSubWndGrid.h"
#include "nmSubWndPostprocessing.h"
#include "nmWxGridDlg.h"
#include "nmWxPostprocessingAnimationWidget.h"
#include "nmGuiPlot.h"
#include "ZxObjBase.h"
#include "nmDataAnalyzeManager.h"
#include "iRibbonXmlTab.h"
#include "nmWxParameterProperty.h"
#include "nmWxNumericalDesign.h"
#include "nmDataOutline.h"
#include "ZxRstWnd.h"
#include "nmWxChangeAnal.h"
#include "nmDataAxis.h"
namespace {
// 判断指定相态下是否至少有一个PVT曲线结果
bool hasPvtCurve(iSubWndFitting* pSubWndF, PvtFluidType eType, const QStringList& listParas)
{
if(pSubWndF == nullptr) {
return false;
}
for(int i = 0; i < listParas.size(); ++i) {
VecDouble vecX;
QVector<double> vecY;
pSubWndF->getPvtRstOf(eType, listParas[i], vecX, vecY);
if(!vecX.isEmpty()) {
return true;
}
}
return false;
}
}
nmSubWndUtils* nmSubWndUtils::getInstance()
{
static nmSubWndUtils s_instance; // 在第一次调用时创建唯一实例
return &s_instance;
}
nmSubWndUtils::nmSubWndUtils()
{
m_pMainWnd = nullptr;
m_pTabWx = nullptr;
}
nmSubWndUtils::~nmSubWndUtils() {}
iSubWnd* nmSubWndUtils::createSubWnd(const iRibbonXmlCmd* pCmdInfo, \
const ZxMainWindow* pMainWnd, \
bool& bCreatedNewOne)
{
if (nullptr == pCmdInfo)
{
return nullptr;
}
// TODO 此处是自行控制是否单一模式
bool bOnlyOneForCurTabWx = true;
return makesureSubWnd(pCmdInfo->m_sID, pCmdInfo->m_sExtInfo, \
pMainWnd, bCreatedNewOne, \
bOnlyOneForCurTabWx);
}
iSubWnd* nmSubWndUtils::makesureSubWnd(QString sID, QString sExt, \
const ZxMainWindow* pMainWnd, \
bool& bCreatedNewOne, \
bool bOnlyOneForCurTabWx /*= true*/)
{
Q_ASSERT (nullptr != pMainWnd);
//单一模式,则先查找,如果已经存在,则直接返回
if (bOnlyOneForCurTabWx)
{
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx(); //仅仅在当前TabWx下查找此处可以根据需要调整
if (nullptr != pTabWx)
{
for (int i = 0; i < pTabWx->count(); i++)
{
iSubWnd* pSubWnd = dynamic_cast<iSubWnd*>(pTabWx->widget(i));
if (nullptr != pSubWnd)
{
if (_isSame(sID, pSubWnd->getWndID()))
{
bCreatedNewOne = false;
// TODO 根据需要,是否需要激活当前
if (i != pTabWx->currentIndex())
{
pTabWx->setCurrentIndex(i);
}
return pSubWnd;
}
}
}
}
}
// 创建新的
bCreatedNewOne = true;
iSubWnd* pSubWnd = nullptr;
// Here is your own codes
int nID = sID.toInt();
if(nID == 5118) {
// TODO提示应该先打开一个分析
//QMessageBox::information(pSubWnd, tr("error"), tr("please open an analyze!"));
// 判断油藏参数是否已经初始化
//if(nmDataAnalyzeManager::getCurrentInstance()->getReservoirData() == nullptr) {
// // 初始化油藏参数
// nmDataAnalyzeManager::getCurrentInstance()->createReservoir();
// // 初始化PVT
// nmDataAnalyzeManager::getCurrentInstance()->initPvtParaFromSubFit();
//}
// 1、获取当前窗体下的所有流动段分析
// 选择一个流动段分析里的数据作为当前地图要展示的数据
// TODO2、没有流动段分析
if(nmDataAnalyzeManager::getCurrentFitting() != nullptr) {
nmSubWndMain* pSubWndMain = new nmSubWndMain(NULL, sExt);
pSubWnd = pSubWndMain;
} else {
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
QMessageBox::information(pMainWnd1, tr("No Data"), tr("please open an Fitting and click Numerical button"));
}
} else if(nID == 5114) {
// PEBI GridControl控制参数对应HX_NWTM_GRID_INPUT::GridControl
double dPebiGridControl = 150.0;
bool bGeneratePebiGrid = true;
// 判断是否是加载进来的数据,如果不是加载进来的,则需要添加设置网格信息的对话框
if(!nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData) {
// 当前只保留PEBI网格弹窗只需要设置GridControl
nmWxGridDlg dlg(&dPebiGridControl);
if(dlg.exec() == QDialog::Rejected) {
return NULL;
}
} else {
// 更新标志
nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData = false;
bGeneratePebiGrid = false;
}
// 创建PEBI网格窗口新建数据时生成网格加载数据时直接展示已加载结果。
nmSubWndGrid* pSubWndGrid = new nmSubWndGrid(NULL, sExt, dPebiGridControl, bGeneratePebiGrid);
disconnect(nmDataAnalyzeManager::getCurrentInstance(), SIGNAL(dataChanged()), pSubWndGrid, SLOT(updateGrid()));
connect(nmDataAnalyzeManager::getCurrentInstance(), SIGNAL(dataChanged()), pSubWndGrid, SLOT(updateGrid()), Qt::QueuedConnection);
pSubWnd = pSubWndGrid;
} else if(nID == 5116) {
// 后处理
nmSubWndPostprocessing* pSubWndPostProcessing = new nmSubWndPostprocessing(NULL, sExt);
pSubWnd = pSubWndPostProcessing;
}
if(NULL != pSubWnd) {
// TODO 此处根据需要设置 改变 标识
pSubWnd->setModified(true);
}
return pSubWnd;
}
bool nmSubWndUtils::runCmdBySpecial(const iRibbonXmlCmd* pCmdInfo, \
const ZxMainWindow* pMainWnd)
{
//nmSubWndUtils* pUtilsInstance = nmSubWndUtils::getInstance();
// 第一次创建TODO或者打开另一个窗体时连接槽函数避免多次调用
//if (pUtilsInstance->m_pMainWnd == nullptr || pUtilsInstance->m_pMainWnd != pMainWnd)
//{
// // 第一次操作时连接tab的槽函数
// ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
// if (nullptr != pMainWnd1)
// {
// pUtilsInstance->m_pMainWnd = pMainWnd1;
// ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx();
// if (nullptr != pTabWx){
// disconnect(pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
// connect(pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
// }
// }
//}
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
nmSubWndUtils* pUtilsInstance = nmSubWndUtils::getInstance();
if(nullptr != pMainWnd1) {
ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx();
if(nullptr != pTabWx) {
if(pUtilsInstance->m_pTabWx == nullptr || pUtilsInstance->m_pTabWx != pTabWx) {
pUtilsInstance->m_pTabWx = pTabWx;
disconnect(pUtilsInstance->m_pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
connect(pUtilsInstance->m_pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
}
}
}
if(nullptr == pCmdInfo) {
return false;
}
// 20250310 测试Release崩溃问题暂时放开
//#ifdef QT_DEBUG
// 专门提供给数值模块,进行一些框架代码的调试
if (_isSame(pCmdInfo->m_sID, "5999"))
{
nmFrameworkTest::testFrmCodes(pCmdInfo, pMainWnd);
return true;
}
//#endif
return runCmdBySpecial(pCmdInfo->m_sID, pCmdInfo->m_sExtInfo, pMainWnd);
}
bool nmSubWndUtils::runCmdBySpecial(QString sID, QString sExt, \
const ZxMainWindow* pMainWnd)
{
// Here is your own codes
if(_isSame(sID, "12345")) {
QMessageBox::information(nullptr, zxAppDescEN, QObject::tr("I am abc"));
return true;
} if(_isSame(sID, "5130")) {
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
// 创建并显示对话框
nmWxChangeAnal analChangeDlg(nullptr, pMainWnd1);
// 执行对话框并判断返回值
if(analChangeDlg.exec() == QDialog::Accepted) {
}
return true;
} else {
return false;
}
}
bool nmSubWndUtils::isEnableOfID_Common(QString sID, QString sName, \
const bool bLicensed, \
const ZxMainWindow* pMainWnd)
{
// 20250310 测试Release崩溃问题暂时放开
//#ifdef QT_DEBUG
// 专门提供给数值模块,进行一些框架代码的调试
if (_isSame(sID, "5999"))
{
return (true);
}
//#endif
bool b1 = (nullptr != zxCurProject);
// Here is your own codes
if (_isSame(sID, "5101"))
{
return (true);
}
else if (_isSame(sID, "5002")) //或者 _isSame(sName, "PropertyLoad")
{
// <Cmd ID="5002" Bounds="0,1,2,1" Name="PropertyLoad" Alias="属性导入"
// TODO 只有当前窗体为流动分析或者流动段选择的情况下才能点击
bool bOk = false;
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
if (nullptr != pMainWnd1)
{
iSubWnd* pSubWnd = pMainWnd1->getCurSubWnd(); //当前窗体
if (nullptr != pSubWnd)
{
QString sCurID = pSubWnd->getWndID();
bOk = (_isSame(sCurID, "3003") || _isSame(sCurID, "3004")
// || _isSame(sCurID, "6001") //TODO 这是试井设计页面,待定
);
}
}
return bOk;
} else if(_isSame(sName, "NmMap")) {
return (b1 && bLicensed);
} else if(_isSame(sName, "NmAnalChange")) {
return (b1 && bLicensed);
}
else
{
return false;
}
}
bool nmSubWndUtils::dealwithRibbonTab(iRibbonXmlTab* pTab, \
const ZxMainWindow* pMainWnd)
{
return false; //your own codes
}
bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
{
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
Q_ASSERT(nullptr != pSubWndF);
if(pSubWndF == nullptr) {
return false;
}
// 如果当前分析没有对应相态的PVT相关参数提示并返回
//PvtFluidType eType = pSubWndF->getBasicPft();
//bool bHasPvtData = false;
//if(eType == WFT_Oil) {
// bHasPvtData = hasPvtCurve(pSubWndF, WFT_Oil, QStringList() << "Rs" << "Bo" << "Co" << "Rhoo" << "Miuo");
//} else if(eType == WFT_Gas) {
// bHasPvtData = hasPvtCurve(pSubWndF, WFT_Gas, QStringList() << "Rv" << "Bg" << "Cg" << "Miug" << "Rhog" << "Zg");
//} else if(eType == WFT_Water) {
// bHasPvtData = hasPvtCurve(pSubWndF, WFT_Water, QStringList() << "Rsw" << "Bw" << "Cw" << "Miuw" << "Rhow");
//} else if(eType == WFT_Oil_Water) {
// bHasPvtData = hasPvtCurve(pSubWndF, WFT_Oil, QStringList() << "Rs" << "Bo" << "Co" << "Rhoo" << "Miuo")
// || hasPvtCurve(pSubWndF, WFT_Water, QStringList() << "Rsw" << "Bw" << "Cw" << "Miuw" << "Rhow");
//}
//if(!bHasPvtData) {
// QString appDir = QCoreApplication::applicationDirPath();
// appDir = appDir.section('/', 0, -2); // 获取上一级目录
// QMessageBox msgBox;
// msgBox.setWindowTitle(tr("PVT Data Missing"));
// msgBox.setText(tr("Please check if PVT parameters have been calculated in the analysis."));
// msgBox.setIconPixmap(QPixmap(appDir + "/Res/Icon/NmPVTDataMissMessage.png")); // PVT 参数计算向导
// msgBox.setStandardButtons(QMessageBox::Ok);
// msgBox.exec();
// return false;
//}
iDockBaseWx* pWxDockNm1 = pSubWndF->getNmDockWx(0);
iDockBaseWx* pWxDockNm2 = pSubWndF->getNmDockWx(1);
Q_ASSERT (nullptr != pWxDockNm1);
Q_ASSERT (nullptr != pWxDockNm2);
if (pWxDockNm1->widget() != nullptr && pWxDockNm2->widget() != nullptr)
{
return true; //已经设定的话,则不再处理
}
// 获取当前井并检查类型是否支持
ZxDataWell* pWellData = zxCurWell;
if(pWellData == nullptr) {
return false;
}
QString wellClass = pWellData->getWellClassEn();
// 定义支持的井类型列表
QStringList supportedTypes;
supportedTypes << "VerticalWell" << "VerticalFracturedWell" << "HorizontalMultiFracturedWell";
if (!supportedTypes.contains(wellClass)) {
QMessageBox::warning(nullptr, tr("Unsupported Well Type"),
tr("The current well type '%1' is not supported for numerical modeling.\n"
"Supported types: Vertical, Vertical Fractured, and Horizontal Multi-Fractured Wells.")
.arg(pWellData->getWellClassCn()));
return false;
}
// 进入到这里,说明是新打开的流动段分析,所以需要动态创建数据管理中心
// 根据分析窗口创建唯一的数据管理对象
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getInstanceByFitting(pSubWndF);
Q_ASSERT(nullptr != pDataManager);
if(pDataManager == nullptr) {
return false;
}
// 每个成果窗口只需要绑定一次外层MDI激活信号。
// 后续切换成果窗口时,通过激活事件同步对应的数据中心和左侧面板。
nmSubWndUtils::getInstance()->connectMdiActivation(pSubWndF);
// 设置当前分析窗体
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
// TODO初始化坐标轴相关信息
nmDataAxis* pAxisData = pDataManager->getAxisData();
if(pAxisData == nullptr) {
pAxisData = new nmDataAxis;
// 将 pAxisData 存入数据中心
nmDataAnalyzeManager::getCurrentInstance()->setAxisData(pAxisData);
}
// 读取解析解的参数
// 1.1 初始化油藏参数
pDataManager->createReservoir();
// 1.2 初始化PVT参数
pDataManager->initPvtParaFromSubFit();
// 1.3 初始化当前井数据
pDataManager->initCurWellData();
// 1.4 初始化边界数据
nmDataWellBase* pCurWell = pDataManager->getCurWellData();
Q_ASSERT(nullptr != pCurWell);
if(pCurWell == nullptr) {
return false;
}
double dX = pCurWell->getX().getValue().toDouble();
double dY = pCurWell->getY().getValue().toDouble();
// 解析解相关参数
QMap<QString, QVariant> mapAnaParas;
mapAnaParas.clear();
pSubWndF->getBrotherDockParas(mapAnaParas, false);
Q_ASSERT(mapAnaParas.count() > 0);
// 解析解边界类型
m_Bdy_Type oBdyType = BT_None;
QString sKey = "Bdy";
if(mapAnaParas.contains(sKey)) {
int n = mapAnaParas[sKey].toInt();
if(n <= (int)BT_Rect) {
oBdyType = m_Bdy_Type(n);
}
}
// 边界距离(是井点到四周的直线距离)
if(oBdyType == BT_Rect || oBdyType == BT_Circle) {
// 设置边界数据
if(oBdyType == BT_Rect) {
// 矩形边界
VecDouble vecBdyDiss;
vecBdyDiss.clear();
QStringList list;
list << "ne" << "se" << "we" << "ee";
for(int i = 0; i < list.count(); i++) {
QString s = list[i];
if(mapAnaParas.contains(s)) {
vecBdyDiss << mapAnaParas[s].toDouble();
}
}
double top_dist = vecBdyDiss[0];
double right_dist = vecBdyDiss[1];
double bottom_dist = vecBdyDiss[2];
double left_dist = vecBdyDiss[3];
// 计算四个顶点的坐标
QPointF topLeft(dX - left_dist, dY + top_dist); // 左上角
QPointF topRight(dX + right_dist, dY + top_dist); // 右上角
QPointF bottomRight(dX + right_dist, dY - bottom_dist); // 右下角
QPointF bottomLeft(dX - left_dist, dY - bottom_dist); // 左下角
// 创建边界点集合
QVector<QPointF> vecBoundaryPoints;
vecBoundaryPoints << topLeft << topRight << bottomRight << bottomLeft;
// 创建矩形边界数据对象
nmDataOutline* pOutlineData = pDataManager->createOutline();
Q_ASSERT(pOutlineData);
if(pOutlineData == nullptr) {
return false;
}
// 设置默认边界名称
pOutlineData->setName("");
// 设置边界点
pOutlineData->setOutlinePoints(vecBoundaryPoints);
// 设置边界类型
pOutlineData->setOutlineType(NM_Rect_Outline_Type);
// 设置流型列表假设全部为0
QVector<int> vecFlowTypes(vecBoundaryPoints.size(), 0);
pOutlineData->setFlowTypeList(vecFlowTypes);
} else {
// 圆形边界
QString s = "re";
double dRadius = 0.0;
if(mapAnaParas.contains(s)) {
dRadius = mapAnaParas[s].toDouble();
}
// 创建圆形边界数据对象
nmDataOutline* pOutlineData = pDataManager->createOutline();
Q_ASSERT(pOutlineData);
if(pOutlineData == nullptr) {
return false;
}
// 设置默认边界名称
pOutlineData->setName("");
// 设置半径
pOutlineData->setRadius(dRadius);
// 设置圆心
pOutlineData->setCenter(QPointF(dX, dY));
// 设置边界类型
pOutlineData->setOutlineType(NM_Data_Outline_Type::NM_Round_Outline_Type);
// 设置流型列表假设全部为0
QVector<int> vecFlowTypes(1, 0);
pOutlineData->setFlowTypeList(vecFlowTypes);
// 创建存储点的向量
QVector<QPointF> vecPoints;
// 放入圆心
vecPoints.append(QPointF(dX, dY));
// 放入半径
vecPoints.append(QPointF(dRadius, dRadius));
// 计算圆上的四个关键点并放入向量(上、右、下、左)
vecPoints.append(QPointF(dX, dY - dRadius));
vecPoints.append(QPointF(dX + dRadius, dY));
vecPoints.append(QPointF(dX, dY + dRadius));
vecPoints.append(QPointF(dX - dRadius, dY));
// 添加到数据中
pOutlineData->setOutlinePoints(vecPoints);
}
} else {
// 如果解析解这里没有设置边界,数值解设置默认边界
// 创建默认矩形边界数据对象
nmDataOutline* pDefaultOutlineData = pDataManager->createOutline();
Q_ASSERT(pDefaultOutlineData);
if(pDefaultOutlineData == nullptr) {
return false;
}
// 设置默认边界名称
pDefaultOutlineData->setName("");
// 设置边界点
QVector<QPointF> vecPoints;
vecPoints << QPointF(-1000.00, 1000.00)
<< QPointF(1000.00, 1000.00)
<< QPointF(1000.00, -1000.00)
<< QPointF(-1000.00, -1000.00);
pDefaultOutlineData->setOutlinePoints(vecPoints);
// 设置边界类型
pDefaultOutlineData->setOutlineType(NM_Rect_Outline_Type);
// 设置流型列表假设全部为0
QVector<int> vecFlowTypes(vecPoints.size(), 0);
pDefaultOutlineData->setFlowTypeList(vecFlowTypes);
}
// 1.6 创建时间步设置相关数据
pDataManager->createTimeStep();
// 创建敏感性分析数据
pDataManager->createSensitiveData();
// TODO创建nmSubWndMain的作用主要是因为求解函数在这个类里后续应该拆分掉
nmSubWndMain* pSubWndMain = new nmSubWndMain(NULL, "");
ZxMainWindow* pMainWnd = pSubWndF->getMainWindow();
// 设置当前窗口到Map
pSubWndMain->setMainWindow(pMainWnd);
pWxDockNm1->setWindowTitle(tr("Generate numerical model")); //改变Title
pWxDockNm2->setWindowTitle(tr("Parameters"));
//QTextEdit* pWx1 = new QTextEdit("This is demo for upper");
//QTextEdit* pWx2 = new QTextEdit("This is demo for lower");
nmWxNumericalDesign* pAnalWx = new nmWxNumericalDesign();
nmWxParameterProperty* pParaWx = new nmWxParameterProperty();
// 建立求解调用连接
connect(pAnalWx, SIGNAL(sigGenerateClicked()),
pSubWndMain, SLOT(onGenerateButtonClicked()));
// 切换查看井结果时刷新曲线窗口
connect(pAnalWx, SIGNAL(sigResultWellChanged(QString)),
pSubWndMain, SLOT(onWellSelected(QString)));
// 建立更新参数栏连接
//connect(pAnalWx, SIGNAL(sigIncludeWells()),
// pParaWx, SLOT(onUpdate()));
// 井图元更新连接
// connect(pAnalWx, SIGNAL(sigUpdateWellPlot(nmDataAnalyzeManager*)),
// pSubWndMain, SLOT(slotUpdateWellPlotByDataManager(nmDataAnalyzeManager*)));
// QTextEdit* pWx1 = new CustomParaWx("This is demo for upper");
// pWx1->...
Q_ASSERT(nullptr != pAnalWx);
Q_ASSERT(nullptr != pParaWx);
pWxDockNm1->setWidget(pAnalWx);
pWxDockNm2->setWidget(pParaWx);
return true; //your own codes
}
bool nmSubWndUtils::getAnaDockParas(iSubWnd* pSubWnd)
{
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
Q_ASSERT(nullptr != pSubWndF);
if(pSubWndF == nullptr) {
return false;
}
//////////////////////////////////////////////////////////////////
// 如下代码,请根据需要在合适位置借鉴参照编写
QMap<QString, QVariant> mapAnaParas;//当前解析解的参数
mapAnaParas.clear();
pSubWndF->getBrotherDockParas(mapAnaParas, false);
Q_ASSERT(mapAnaParas.count() > 0);
// 解析解边界类型
m_Bdy_Type oBdyType = BT_None;
QString sKey = "Bdy";
if (mapAnaParas.contains(sKey))
{
int n = mapAnaParas[sKey].toInt();
if (n <= (int)BT_Rect)
{
oBdyType = m_Bdy_Type(n);
}
}
// 边界距离(是井点到四周的直线距离)
if (oBdyType == BT_Rect || oBdyType == BT_Circle)
{
VecDouble vecBdyDiss;
vecBdyDiss.clear();
int nCount = (oBdyType == BT_Rect ? 4 : 1);
for (int i = 1; i <= nCount; i++)
{
QString sRealBdyName = getBdyRealNameOf(i, mapAnaParas); //sRealBdyName为map中边界距离key的真实内容
sKey = sRealBdyName;
if (!sKey.isEmpty() && mapAnaParas.contains(sKey))
{
vecBdyDiss << mapAnaParas[sKey].toDouble();
}
else
{
Q_ASSERT (false);//TODO
}
}
// 说明对于BT_RectvecBdyDiss中存放的四个距离数值依次为ne/下se/左we/右ee
// 对于BT_CirclevecBdyDiss中存放的是圆形半径r
}
//////////////////////////////////////////////////////////////////
return true;
}
QString nmSubWndUtils::getBdyRealNameOf(int xIndex, QMap<QString, QVariant>& map)
{
QStringList list;
list << "ne" << "se" << "we" << "ee" << "re";
int n = -1;
for (int i = 0; i < list.count(); i++)
{
QString s = list[i];
if (map.find(s) != map.end())
{
n++;
if (n == xIndex - 1)//TODO -1,从1开始
{
return s;
}
}
}
//m_sError = QString("Bdy name of 'x%1'' not found.").arg(xIndex);
//zxLogRunF(m_sError);
return "";
}
bool nmSubWndUtils::nmCalAndFresh(iSubWnd* pSubWnd, \
const ZxMainWindow* pMainWnd)
{
return false;
}
bool nmSubWndUtils::saveRsts(iSubWnd* pSubWnd, \
QString sRstName, \
const ZxMainWindow* pMainWnd)
{
Q_ASSERT(nullptr != pSubWnd);
if(pSubWnd == nullptr) {
return false;
}
// 流动段分析窗体
if(pSubWnd->getWndID() == "3004") {
// 转换为Fitting窗口
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
if(pSubWndF == nullptr) {
return false;
}
// 根据窗体指针,找到创建的对应的数据管理对象
nmDataAnalyzeManager*pDataManager = nmDataAnalyzeManager::findManagerByFitting(pSubWndF);
// 如果不存在,则说明当前分析窗体没有做数值解,不需要做保存处理
if(pDataManager == nullptr) {
return false;
}
// 如果存在,则对当前分析数据进行保存
if(!pDataManager->saveNmResult(sRstName, pSubWndF)) {
return false;
}
} else if(pSubWnd->getWndID() == "5118") {
return true;
} else if(pSubWnd->getWndID() == "5114") {
return true;
}
// TODOMap窗口保存、网格窗口保存
return true;
}
bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
QString sRstName, \
const ZxMainWindow* pMainWnd)
{
Q_ASSERT(nullptr != pSubWnd);
if(pSubWnd == nullptr) {
return false;
}
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
nmSubWndUtils* pUtilsInstance = nmSubWndUtils::getInstance();
if(nullptr != pMainWnd1) {
ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx();
if(nullptr != pTabWx) {
if(pUtilsInstance->m_pTabWx == nullptr || pUtilsInstance->m_pTabWx != pTabWx) {
pUtilsInstance->m_pTabWx = pTabWx;
disconnect(pUtilsInstance->m_pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
connect(pUtilsInstance->m_pTabWx, SIGNAL(currentChanged(int)), pUtilsInstance, SLOT(slotHandleTabChange(int)));
}
}
}
// 处理流动段分析窗口数据
if(pSubWnd->getWndID() == "3004") {
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
if(pSubWndF == nullptr) {
return false;
}
// 获取当前分析窗体Code
ZxRstWnd* pRstWnd = pSubWndF->getRstUtilWnd();
if(pRstWnd == nullptr) {
return false;
}
QString sRstUtilWndCode = pRstWnd->getCode();
ZxDataWell* pCurrentWell = pSubWndF->getDataWell();
if(pCurrentWell == nullptr) {
return false;
}
// 获取该分析所在的目录
QString sDir = ZxBaseUtil::getWellDirOf(pCurrentWell->getName(), "Nm");
sDir += sRstName + "/" + sRstUtilWndCode;
// 判断分析目录是否存在
bool bDirExists = nmDataAnalyzeManager::isDirExist(sDir);
// 如果不存在,则说明没有保存数值解的参数
if(!bDirExists) {
return false;
}
// 存在,说明保存了数值解的参数,需要解析文件里的数据到数据中心
// 动态创建数据中心类
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getInstanceByFitting(pSubWndF);
if(pDataManager == nullptr) {
return false;
}
// 监听外层成果窗口切换,保证重新激活已经打开过的成果时可以同步数据中心。
pUtilsInstance->connectMdiActivation(pSubWndF);
// 设置当前操作的是哪一个分析
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
// 加载本地文件的数据到数据中心里的数据体里
pDataManager->loadNmResult(sDir);
// 加载当前分析中的PVT数据
pDataManager->initPvtParaFromSubFit();
// 切换左侧参数视图
pSubWndF->swapAnaNmDocks(true);
iDockBaseWx* pWxDockNm1 = pSubWndF->getNmDockWx(0);
iDockBaseWx* pWxDockNm2 = pSubWndF->getNmDockWx(1);
Q_ASSERT(nullptr != pWxDockNm1);
Q_ASSERT(nullptr != pWxDockNm2);
if(pWxDockNm1 == nullptr || pWxDockNm2 == nullptr) {
return false;
}
if(pWxDockNm1->widget() != nullptr && pWxDockNm2->widget() != nullptr) {
return true; //已经设定的话,则不再处理
}
// 创建Map暂时
nmSubWndMain* pSubWndMain = new nmSubWndMain(NULL, "");
ZxMainWindow* pMainWnd1 = const_cast<ZxMainWindow*>(pMainWnd);
pSubWndMain->setMainWindow(pMainWnd1);
//pWxDockNm1->setWindowTitle(tr("Dock1's Title"));
//pWxDockNm2->setWindowTitle(tr("Dock2's Title"));
pWxDockNm1->setWindowTitle(tr("Generate numerical model")); //改变Title
pWxDockNm2->setWindowTitle(tr("Parameters"));
// 自定义窗体指针
nmWxNumericalDesign* pAnalWx = new nmWxNumericalDesign();
nmWxParameterProperty* pParaWx = new nmWxParameterProperty();
Q_ASSERT(nullptr != pAnalWx);
Q_ASSERT(nullptr != pParaWx);
// 建立求解调用连接
connect(pAnalWx, SIGNAL(sigGenerateClicked()),
pSubWndMain, SLOT(onGenerateButtonClicked()));
// 切换查看井结果时刷新曲线窗口
connect(pAnalWx, SIGNAL(sigResultWellChanged(QString)),
pSubWndMain, SLOT(onWellSelected(QString)));
// 建立更新参数栏连接
connect(pAnalWx, SIGNAL(sigIncludeWells()),
pParaWx, SLOT(onUpdate()));
// 井图元更新连接
// connect(pAnalWx, SIGNAL(sigUpdateWellPlot(nmDataAnalyzeManager*)),
// pSubWndMain, SLOT(slotUpdateWellPlotByDataManager(nmDataAnalyzeManager*)));
//connect(pAnalWx, SIGNAL(sigIncludeWells()),
// pParaWx, SLOT(onUpdate()));
pWxDockNm1->setWidget(pAnalWx);
pWxDockNm2->setWidget(pParaWx);
// 判断是否保存了时间步数据
if(!pDataManager->isTimeStepDataEmpty()) {
QString sErrorMessage;
// 刷新场图
QWidget* p3DWidget = pSubWndF->getFitSubRstWxOf(FSRT_Nm3D, true, &sErrorMessage);
// 创建 vtkWidget
nmWxPostprocessingAnimationWidget* pVtkWidget = nullptr;
pVtkWidget = new nmWxPostprocessingAnimationWidget();
if(p3DWidget == nullptr || pVtkWidget == nullptr) {
delete pVtkWidget;
return false;
}
// 先清理
// 获取当前布局
QLayout* p3DLayout = p3DWidget->layout();
if(p3DLayout) {
// 移除布局中的所有控件
QLayoutItem* item;
while((item = p3DLayout->takeAt(0))) {
if(item->widget()) {
// 删除控件
delete item->widget();
}
delete item; // 删除布局项
}
// 删除布局
delete p3DLayout;
}
// 确保布局被移除
p3DWidget->setLayout(nullptr);
// 创建一个垂直布局管理器
QVBoxLayout* p3DnewLayout = new QVBoxLayout(p3DWidget);
// 将现有的控件添加到布局中
p3DnewLayout->addWidget(pVtkWidget);
// 设置 widget 的布局
p3DWidget->setLayout(p3DnewLayout);
// 刷新结果参数
// 结果参数界面
QWidget* pRstWidget = pSubWndF->getFitSubRstWxOf(FSRT_NmRst, true, &sErrorMessage);
if(pRstWidget == nullptr) {
return false;
}
// 创建结果参数界面
nmWxResultParameters* pResultWidget = new nmWxResultParameters;
// 先清理
// 获取当前布局
QLayout* pRstLayout = pRstWidget->layout();
if(pRstLayout) {
// 移除布局中的所有控件
QLayoutItem* item;
while((item = pRstLayout->takeAt(0))) {
if(item->widget()) {
// 删除控件
delete item->widget();
}
delete item; // 删除布局项
}
// 删除布局
delete pRstLayout;
}
// 确保布局被移除
pRstWidget->setLayout(nullptr);
// 创建一个垂直布局管理器
QVBoxLayout* pRstnewLayout = new QVBoxLayout(pRstWidget);
// 将现有的控件添加到布局中
pRstnewLayout->addWidget(pResultWidget);
// 设置 widget 的布局
pRstWidget->setLayout(pRstnewLayout);
}
}
//// 请根据需要确定,文件存储的路径
//QString sDir = ZxBaseUtil::getCurWellDirOf("Nm");
////iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
////Q_ASSERT(nullptr != pSubWndF);
//QString sRstUtilWndCode = pSubWnd->getRstUtilWnd()->getCode();
//QByteArray ba = QByteArray();//这是你读取出来的内容
//ZxUiBase* pWx = nullptr; //your own widget
//if (nullptr != pWx && !ba.isNull())
//{
// // 根据二进制内容更新窗体内容
// // 注意loadFromByteArr是 iWxBasePVT模块中的接口如果需要请参考下面源码进行自行实现
// //pWx->loadFromByteArr(ba);
//}
// 如果需要把二进制内容更新至其它如double数组、map等存入可以参照 ZxBaHelper 提供的接口
// 其它代码
return true;
}
// 如果需要加载某个窗体继承自ZxUiBase并且实现了序列化接口onSerialize/onDeserialize
// 则可以参照如下进行
#ifdef _SCAN_OLD_CODES_
bool iWxBase::saveAsByteArr(QByteArray& v)
{
QString sRoot = this->objectName() + "abc";
ZxXpfDoc xpf(sRoot);
ZxSerializer ser(&xpf, true);
onSerialize(&ser);
QDataStream out(&v, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_8);
if (xpf.save(out))
{
return true;
}
else
{
return false;
}
return true;
}
bool iWxBase::loadFromByteArr(QByteArray& v)
{
QDataStream in(&v, QIODevice::ReadOnly);
// quint32 nVer = ser->getDocDate();
// if (nVer > (quint32)(20180101))
// {
// in.setVersion(QDataStream::Qt_4_8);
// }
// else
{
in.setVersion(QDataStream::Qt_4_8);
}
QString sRoot = this->objectName() + "abc";
ZxXpfDoc xpf(sRoot);
if (!xpf.load(in))
{
zxLogRunW(tr("Failed to load ByteArray"));
return false;
}
ZxSerializer ser(&xpf, false);
onDeserialize(&ser);
return true;
}
#endif
void nmSubWndUtils::slotHandleTabChange(int index)
{
// 找到索引对应的流动段分析窗体
if(m_pTabWx == nullptr) {
return;
}
if(index >= 0 && index < m_pTabWx->count()) {
iSubWnd* pSubWnd = dynamic_cast<iSubWnd*>(m_pTabWx->widget(index));
if(pSubWnd == nullptr) {
return;
}
// 切换的是流动段分析
if(pSubWnd->getWndID() == "3004") {
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
if(pSubWndF == nullptr) {
return;
}
// 查找有没有对应的数据中心实例
nmDataAnalyzeManager* pDataManger = nmDataAnalyzeManager::findManagerByFitting(pSubWndF);
if(pDataManger != nullptr && nmDataAnalyzeManager::getCurrentFitting() != pSubWndF) {
// 有对应的实例,并且不是当前分析
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
ZxMainWindow* pMainWnd = pSubWndF->getMainWindow();
Q_ASSERT(nullptr != pMainWnd);
if(pMainWnd == nullptr) {
return;
}
// 如果地图和网格窗体存在,则更新
QVector<iSubWnd*> vecSubWnds = pMainWnd->getAllSubWndsOf(m_pTabWx);
foreach(iSubWnd* pSub, vecSubWnds) {
nmSubWndMain* pMap = dynamic_cast<nmSubWndMain*>(pSub);
if(nullptr != pMap) {
// 更新地图相关信息
pMap->updateMapByDataManager(pDataManger);
}
// TODO网格更新
nmSubWndGrid* pSubWndGrid = dynamic_cast<nmSubWndGrid*>(pSub);
if(nullptr != pSubWndGrid) {
// 更新网格
disconnect(pDataManger, SIGNAL(dataChanged()), pSubWndGrid, SLOT(updateGrid()));
connect(pDataManger, SIGNAL(dataChanged()), pSubWndGrid, SLOT(updateGrid()), Qt::QueuedConnection);
// 手动更新
pSubWndGrid->updateGrid();
}
}
}
}
}
}
// 监听外层MDI成果窗口切换
void nmSubWndUtils::connectMdiActivation(iSubWndFitting* pSubWndF)
{
if(pSubWndF == nullptr) {
return;
}
// 关闭成果窗口或流动段分析页签时都会销毁对应的iSubWndFitting。
// 在Close事件中先解除图元引用队列槽再等子对象完成析构后释放数据管理器。
m_mapFittingKeys.insert(pSubWndF, pSubWndF);
pSubWndF->installEventFilter(this);
connect(pSubWndF, SIGNAL(destroyed(QObject*)),
this, SLOT(slotHandleFittingDestroyed(QObject*)),
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
ZxMdiSubWindow* pMdiChild = pSubWndF->getMdiChild();
ZxMainWindow* pMainWnd = pSubWndF->getMainWindow();
if(pMdiChild != nullptr) {
// 外层成果关闭时先记录状态,避免子窗口析构期间主动遍历半析构画布。
pMdiChild->installEventFilter(this);
connect(pMdiChild, SIGNAL(sigConformClosing(bool&)),
this, SLOT(slotHandleMdiClosing(bool&)),
Qt::UniqueConnection);
connect(pMdiChild, SIGNAL(destroyed(QObject*)),
this, SLOT(slotHandleMdiDestroyed(QObject*)),
Qt::UniqueConnection);
}
if(pMdiChild == nullptr || pMainWnd == nullptr || pMdiChild->mdiArea() == nullptr) {
return;
}
m_pMainWnd = pMainWnd;
// 一个QMdiArea中可以同时存在多个成果窗口。
// 使用UniqueConnection避免每次打开成果时重复绑定同一个激活信号。
connect(pMdiChild->mdiArea(), SIGNAL(subWindowActivated(QMdiSubWindow*)),
this, SLOT(slotHandleMdiSubWindowActivated(QMdiSubWindow*)),
Qt::UniqueConnection);
}
// 在窗口仍完整时处理关闭事件
bool nmSubWndUtils::eventFilter(QObject* pObject, QEvent* pEvent)
{
if(pEvent == nullptr || pEvent->type() != QEvent::Close) {
return QObject::eventFilter(pObject, pEvent);
}
ZxMdiSubWindow* pMdiChild = qobject_cast<ZxMdiSubWindow*>(pObject);
if(pMdiChild != nullptr) {
m_closingMdiChildren.insert(pMdiChild);
return QObject::eventFilter(pObject, pEvent);
}
iSubWndFitting* pSubWndF = m_mapFittingKeys.value(pObject, nullptr);
if(pSubWndF != nullptr && !m_closingMdiChildren.contains(pSubWndF->getMdiChild())) {
detachFittingPlot(pSubWndF);
}
return QObject::eventFilter(pObject, pEvent);
}
// 单独关闭流动段分析页签时,先解除画布图元对数据的引用
void nmSubWndUtils::detachFittingPlot(iSubWndFitting* pSubWndF)
{
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::findManagerByFitting(pSubWndF);
if(pDataManager == nullptr) {
return;
}
nmGuiPlot* pPlot = pDataManager->getPlot();
if(pPlot == nullptr) {
return;
}
// 关闭页签时可能会先触发页签切换导致Map短暂刷新到待关闭分析。
// 以DataManager是否仍绑定Plot判断Map是否实际展示该分析避免只看currentFitting误判。
pPlot->deleteAllPlotObjs();
pDataManager->setPlot(nullptr);
if(nmDataAnalyzeManager::getCurrentFitting() != pSubWndF) {
nmDataAnalyzeManager* pCurManager = nmDataAnalyzeManager::getCurrentInstance();
if(pCurManager != nullptr) {
// 关闭的不是当前分析时清掉待关闭分析图元后恢复当前分析的Map显示。
pCurManager->setPlot(pPlot);
pPlot->setPlotsByDataManger(pCurManager);
}
}
}
// 外层成果窗口关闭时先清理仍绑定到Map上的图元
void nmSubWndUtils::detachMdiFittingPlots(ZxMdiSubWindow* pMdiChild)
{
if(pMdiChild == nullptr || m_pMainWnd == nullptr) {
return;
}
ZxTabWidget* pTabWx = m_pMainWnd->getTabWxOf(pMdiChild);
if(pTabWx == nullptr) {
return;
}
QVector<iSubWnd*> vecSubWnds = m_pMainWnd->getAllSubWndsOf(pTabWx, "3004", true);
// 同一个成果内可能有多个分析只清理仍占用Map Plot的DataManager。
foreach(iSubWnd* pSubWnd, vecSubWnds) {
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::findManagerByFitting(pSubWndF);
if(pDataManager == nullptr || pDataManager->getPlot() == nullptr) {
continue;
}
nmGuiPlot* pPlot = pDataManager->getPlot();
pPlot->deleteAllPlotObjs();
pDataManager->setPlot(nullptr);
}
}
// 流动段分析窗口销毁后,释放对应的数据管理器
void nmSubWndUtils::slotHandleFittingDestroyed(QObject* pObject)
{
// 队列槽执行时窗口对象已经销毁只使用析构前保存的地址作为静态映射key。
iSubWndFitting* pSubWndF = m_mapFittingKeys.take(pObject);
nmDataAnalyzeManager::removeInstanceByFitting(pSubWndF);
}
// 外层成果取消关闭时移除Close事件过滤器提前保存的状态
void nmSubWndUtils::slotHandleMdiClosing(bool& bAllowClose)
{
if(!bAllowClose) {
m_closingMdiChildren.remove(sender());
return;
}
// 用户确认关闭成果窗口后再清理Map避免取消关闭时误清当前显示。
ZxMdiSubWindow* pMdiChild = qobject_cast<ZxMdiSubWindow*>(sender());
if(pMdiChild != nullptr) {
detachMdiFittingPlots(pMdiChild);
}
}
// 外层成果窗口析构后,移除仅用于生命周期判断的地址
void nmSubWndUtils::slotHandleMdiDestroyed(QObject* pObject)
{
m_closingMdiChildren.remove(pObject);
}
// 切换外层MDI成果窗口后同步当前流动段分析窗口
void nmSubWndUtils::slotHandleMdiSubWindowActivated(QMdiSubWindow* pSubWindow)
{
ZxMdiSubWindow* pMdiChild = qobject_cast<ZxMdiSubWindow*>(pSubWindow);
if(pMdiChild == nullptr || m_pMainWnd == nullptr) {
return;
}
ZxTabWidget* pTabWx = m_pMainWnd->getTabWxOf(pMdiChild);
if(pTabWx == nullptr) {
return;
}
// 每个成果窗口内部都有自己的页签容器。
// 切换外层成果后,保存当前容器并继续监听该成果内部的页签切换。
m_pTabWx = pTabWx;
connect(m_pTabWx, SIGNAL(currentChanged(int)),
this, SLOT(slotHandleTabChange(int)),
Qt::UniqueConnection);
// 找到当前成果中的流动段分析窗口。
// 窗口ID为3004后续的数据中心和左侧面板都属于这个分析窗口。
QVector<iSubWnd*> vecSubWnds = m_pMainWnd->getAllSubWndsOf(m_pTabWx, "3004", true);
if(vecSubWnds.isEmpty()) {
return;
}
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(vecSubWnds.first());
if(pSubWndF == nullptr || nmDataAnalyzeManager::findManagerByFitting(pSubWndF) == nullptr) {
return;
}
// 先切换数据中心,再刷新左侧面板。
// 下拉框填充函数会读取getCurrentInstance(),顺序不能颠倒。
nmDataAnalyzeManager::setCurrentFitting(pSubWndF);
iDockBaseWx* pWxDockNm1 = pSubWndF->getNmDockWx(0);
if(pWxDockNm1 == nullptr) {
return;
}
nmWxNumericalDesign* pAnalWx = dynamic_cast<nmWxNumericalDesign*>(pWxDockNm1->widget());
if(pAnalWx != nullptr) {
// 已经打开过的成果会复用旧面板,不会再次进入构造函数。
// 主动更新活动面板指针,保证静态通知刷新的是当前成果中的下拉框。
pAnalWx->activateCurrentInstance();
}
}