diff --git a/Include/nmNum/nmData/nmPebiCellMapping.h b/Include/nmNum/nmData/nmPebiCellMapping.h index 455438a..5f4a669 100644 --- a/Include/nmNum/nmData/nmPebiCellMapping.h +++ b/Include/nmNum/nmData/nmPebiCellMapping.h @@ -35,8 +35,9 @@ public: /** * @brief 将一份已验证的正向映射附加到尚未发布的网格。 * - * 保留名称已被占用、映射不完整或 ID 不可逆时不修改网格。该函数只 - * 使用 AddArray() 登记映射,不会把 OriginalCellId 设为活动 Scalars。 + * 保留名称已被占用、映射不完整或 ID 不可逆时不修改网格。持久化 + * 数组使用固定 Int32,公开输入仍使用 vtkIdType;该函数只使用 + * AddArray() 登记映射,不会把 OriginalCellId 设为活动 Scalars。 */ static bool attach( vtkUnstructuredGrid* pGrid, @@ -48,7 +49,8 @@ public: * @brief 读取并完整验证网格携带的正向与反向映射。 * * 两个数组均不存在时返回 Missing;只存在一个或任一字段损坏时返回 - * Invalid。输出在进入函数时清空,且只在返回 Valid 时接收完整结果。 + * Invalid。读取接受 Int32 和旧内存对象的 vtkIdType 整数表示,拒绝 + * 浮点数组。输出在进入函数时清空,且只在返回 Valid 时接收完整结果。 */ static MappingStatus read( vtkUnstructuredGrid* pGrid, diff --git a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp index ed41275..8f72dd0 100644 --- a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp +++ b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp @@ -3162,7 +3162,8 @@ void nmDataAnalyzeManager::updateAutomaticFittingData(const nmDataAutomaticFitti void nmDataAnalyzeManager::initPvtParaFromSubFit() { // 1. 获取上下文 - iSubWndFitting* pSubWndFitting = nmDataAnalyzeManager::getCurrentFitting(); + // PVT 必须来自本 Manager 绑定的成果窗口,不能随全局当前页签切换数据源。 + iSubWndFitting* pSubWndFitting = m_pOwnerFitting; nmDataAnalyzeContextProvider* pCtx = nmDataAnalyzeContext::provider(); Q_ASSERT(nullptr != pSubWndFitting); Q_ASSERT(nullptr != pCtx); @@ -6562,11 +6563,16 @@ bool nmDataAnalyzeManager::validateNmResultV3Window( return false; } - if(oReferences.m_bHasCurrentGrid && - !nmNumericalResultPersistence::validateFileReference( - sWindowDirectory, oReferences.m_oCurrentGrid, - NULL, pError)) { - return false; + if(oReferences.m_bHasCurrentGrid) { + QString sCurrentGridPath; + vtkSmartPointer pValidatedCurrentGrid; + if(!nmNumericalResultPersistence::validateFileReference( + sWindowDirectory, oReferences.m_oCurrentGrid, + &sCurrentGridPath, pError) || + !nmNumericalResultPersistence::readGrid( + sCurrentGridPath, pValidatedCurrentGrid, pError)) { + return false; + } } QMap::const_iterator oIt = diff --git a/Src/nmNum/nmData/nmPebiCellMapping.cpp b/Src/nmNum/nmData/nmPebiCellMapping.cpp index 0211da7..247c402 100644 --- a/Src/nmNum/nmData/nmPebiCellMapping.cpp +++ b/Src/nmNum/nmData/nmPebiCellMapping.cpp @@ -6,7 +6,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -34,6 +35,36 @@ nmPebiCellMapping::MappingStatus failRead( return nmPebiCellMapping::MappingStatus_Invalid; } +bool isSupportedMappingArray(vtkDataArray* pArray) +{ + if(pArray == NULL) { + return false; + } + const int nDataType = pArray->GetDataType(); + return nDataType == VTK_INT || nDataType == VTK_ID_TYPE; +} + +bool readMappingValue( + vtkDataArray* pArray, + vtkIdType nTupleId, + vtkIdType* pValue) +{ + if(pArray == NULL || pValue == NULL) { + return false; + } + const double dValue = pArray->GetComponent(nTupleId, 0); + if(!vtkMath::IsFinite(dValue) || dValue < 0.0 || + dValue > static_cast(INT_MAX)) { + return false; + } + const vtkIdType nValue = static_cast(dValue); + if(static_cast(nValue) != dValue) { + return false; + } + *pValue = nValue; + return true; +} + bool validateMappingValues( const QVector& vecVtkToOriginal, vtkIdType nOriginalCellCount, @@ -135,8 +166,8 @@ bool nmPebiCellMapping::attach( return false; } - vtkSmartPointer pOriginalCellIds = - vtkSmartPointer::New(); + vtkSmartPointer pOriginalCellIds = + vtkSmartPointer::New(); pOriginalCellIds->SetName(originalCellIdArrayName()); pOriginalCellIds->SetNumberOfComponents(1); pOriginalCellIds->SetNumberOfTuples( @@ -145,15 +176,15 @@ bool nmPebiCellMapping::attach( nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) { pOriginalCellIds->SetValue( static_cast(nVtkCellId), - vecVtkToOriginal[nVtkCellId]); + static_cast(vecVtkToOriginal[nVtkCellId])); } - vtkSmartPointer pOriginalCellCount = - vtkSmartPointer::New(); + vtkSmartPointer pOriginalCellCount = + vtkSmartPointer::New(); pOriginalCellCount->SetName(originalCellCountArrayName()); pOriginalCellCount->SetNumberOfComponents(1); pOriginalCellCount->SetNumberOfTuples(1); - pOriginalCellCount->SetValue(0, nOriginalCellCount); + pOriginalCellCount->SetValue(0, static_cast(nOriginalCellCount)); vtkDataArray* pPreviousScalars = pCellData->GetScalars(); if(pCellData->AddArray(pOriginalCellIds) < 0) { @@ -236,13 +267,14 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read( "PEBI grid contains an incomplete cell mapping."); } - vtkIdTypeArray* pOriginalCellIds = - vtkIdTypeArray::SafeDownCast(pOriginalCellIdsAbstract); - vtkIdTypeArray* pOriginalCellCount = - vtkIdTypeArray::SafeDownCast(pOriginalCellCountAbstract); - if(pOriginalCellIds == NULL || pOriginalCellCount == NULL) { + vtkDataArray* pOriginalCellIds = + vtkDataArray::SafeDownCast(pOriginalCellIdsAbstract); + vtkDataArray* pOriginalCellCount = + vtkDataArray::SafeDownCast(pOriginalCellCountAbstract); + if(!isSupportedMappingArray(pOriginalCellIds) || + !isSupportedMappingArray(pOriginalCellCount)) { return failRead(pError, - "PEBI cell mapping arrays have invalid types."); + "PEBI cell mapping arrays must use Int32 or vtkIdType integers."); } const vtkIdType nVtkCellCount = pGrid->GetNumberOfCells(); @@ -259,13 +291,23 @@ nmPebiCellMapping::MappingStatus nmPebiCellMapping::read( "PEBI original cell IDs must not be active scalars."); } - const vtkIdType nOriginalCellCount = pOriginalCellCount->GetValue(0); + vtkIdType nOriginalCellCount = 0; + if(!readMappingValue(pOriginalCellCount, 0, &nOriginalCellCount) || + nOriginalCellCount <= 0) { + return failRead(pError, + "PEBI original cell count is not a valid positive integer."); + } QVector vecVtkToOriginal( static_cast(nVtkCellCount)); for(vtkIdType nVtkCellId = 0; nVtkCellId < nVtkCellCount; ++nVtkCellId) { - vecVtkToOriginal[static_cast(nVtkCellId)] = - pOriginalCellIds->GetValue(nVtkCellId); + vtkIdType nOriginalCellId = 0; + if(!readMappingValue( + pOriginalCellIds, nVtkCellId, &nOriginalCellId)) { + return failRead(pError, + "PEBI mapping contains a non-integer or out-of-range ID."); + } + vecVtkToOriginal[static_cast(nVtkCellId)] = nOriginalCellId; } QVector vecOriginalToVtk; diff --git a/Src/nmNum/nmSubWnd/nmSubWndUtils.cpp b/Src/nmNum/nmSubWnd/nmSubWndUtils.cpp index a04ce78..3cd810d 100644 --- a/Src/nmNum/nmSubWnd/nmSubWndUtils.cpp +++ b/Src/nmNum/nmSubWnd/nmSubWndUtils.cpp @@ -210,32 +210,26 @@ iSubWnd* nmSubWndUtils::makesureSubWnd(QString sID, QString sExt, \ } else if(nID == 5114) { // PEBI GridControl控制参数,对应HX_NWTM_GRID_INPUT::GridControl double dPebiGridControl = 150.0; - bool bGeneratePebiGrid = true; + nmDataAnalyzeManager* pDataManager = + nmDataAnalyzeManager::getCurrentInstance(); + if(pDataManager == nullptr) { + return NULL; + } - // 判断是否是加载进来的数据,如果不是加载进来的,则需要添加设置网格信息的对话框 - if(!nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData) { - // 当前只保留PEBI网格,弹窗只需要设置GridControl + // 是否需要建网只由当前输入版本的真实网格状态决定,不能依赖一次性加载标志。 + const bool bGeneratePebiGrid = !pDataManager->isPebiGridValid(); + if(bGeneratePebiGrid) { + // 当前只保留 PEBI 网格,缺少有效网格时设置 GridControl 后正常建网。 nmWxGridDlg dlg(&dPebiGridControl); if(dlg.exec() == QDialog::Rejected) { - return NULL; + return nullptr; } } else { - // 更新标志 - nmDataAnalyzeManager::getCurrentInstance()->m_bIsLoadData = false; - bGeneratePebiGrid = false; - } - - // 创建PEBI网格窗口;新建数据时生成网格,加载数据时直接展示已加载结果。 - nmDataAnalyzeManager* pDataManager = - nmDataAnalyzeManager::getCurrentInstance(); - if(pDataManager == nullptr) { - return NULL; - } - if(!bGeneratePebiGrid) { dPebiGridControl = pDataManager->getPebiGridControl(); } + // 创建 PEBI 网格窗口;已有有效网格时直接展示,否则按正常流程生成。 nmSubWndGrid* pSubWndGrid = new nmSubWndGrid( NULL, sExt, dPebiGridControl, bGeneratePebiGrid, pDataManager); pSubWnd = pSubWndGrid; @@ -1024,26 +1018,36 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \ return true; } - // 存在,说明保存了数值解的参数,需要解析文件里的数据到数据中心 - // 动态创建数据中心类 - nmDataAnalyzeManager* pDataManager = nmDataAnalyzeManager::getInstanceByFitting(pSubWndF); + // 先查询再按需创建,失败时只释放本次加载产生的空 Manager。 + iSubWndFitting* pPreviousCurrentFitting = + nmDataAnalyzeManager::getCurrentFitting(); + nmDataAnalyzeManager* pDataManager = + nmDataAnalyzeManager::findManagerByFitting(pSubWndF); + const bool bCreatedDataManager = pDataManager == nullptr; + if(bCreatedDataManager) { + pDataManager = + nmDataAnalyzeManager::getInstanceByFitting(pSubWndF); + } if(pDataManager == nullptr) { return false; } - // 监听外层成果窗口切换,保证重新激活已经打开过的成果时可以同步数据中心。 - pUtilsInstance->connectMdiActivation(pSubWndF); - - // 设置当前操作的是哪一个分析 - nmDataAnalyzeManager::setCurrentFitting(pSubWndF); - - // v3 在候选 Manager 中读取 PVT 和全部成果,成功后才替换当前状态。 + // Manager 内部继续使用候选对象事务加载;这里在成功前不切换全局当前分析。 if(!pDataManager->loadNmResult(sDir)) { + if(bCreatedDataManager) { + nmDataAnalyzeManager::removeInstanceByFitting(pSubWndF); + } + nmDataAnalyzeManager::setCurrentFitting( + pPreviousCurrentFitting); QMessageBox::warning(nullptr, tr("Numerical Result Load Failed"), tr("The numerical result is incomplete or inconsistent and could not be loaded.")); return false; } + + // 只有成果完整加载后,才允许该窗口接管激活通知和全局当前数据源。 + pUtilsInstance->connectMdiActivation(pSubWndF); + nmDataAnalyzeManager::setCurrentFitting(pSubWndF); // 注册井参数到 nmAttrRegistry(必须在 loadNmResult 之后,面板构建之前) pDataManager->syncWellAttrs();