feat(nmData): 建立 PEBI 原始单元与 VTK Cell 唯一映射

- 写入并校验 OriginalCellId 和 OriginalCellCount
- 建网时严格验证可见单元并预分配 VTK Cell
- 在网格提交、兼容 setter 和 VTU 读写处拦截损坏映射
- 明确旧版无映射网格的兼容与能力降级规则
- 更新阶段 3A 开发清单
feature/nmNum-postprocessing-view-20260910
lh 1 day ago
parent a4f64cfca0
commit 34977e2b67

@ -194,7 +194,7 @@ private:
// 生成vtk数据
void genPebiVTK(const HX_NWTM_GRID_OUTPUT1& P1, QString vtkDir);
// 根据网格输出结构体创建 vtkUnstructuredGrid 对象
// 根据网格输出结构体创建带唯一原始单元映射的 vtkUnstructuredGrid 对象
vtkSmartPointer<vtkUnstructuredGrid> createPebiUnstructuredGrid(
const HX_NWTM_GRID_OUTPUT1& P1,
const QAtomicInt* pCancelRequested = NULL);

@ -599,7 +599,7 @@ public:
/** @brief 整体替换 DLL 井槽位顺序,并由分析方案统一重编号。 */
void setSolverWellOrder(const QVector<nmSolverWellRef>& vecSolverWellOrder);
/**
* @brief VTK
* @brief VTK
* @return true
*/
bool commitPebiGridResult(
@ -785,8 +785,13 @@ public:
/** @brief 显式刷新框架井压力和流量;成果加载流程不得调用。 */
bool loadWellPreAndFlow();
// 设置当前分析下的VTK网格对象
void setUnstructuredGrid(vtkSmartPointer<vtkUnstructuredGrid> grid);
/**
* @brief VTK
*
*
*
*/
void setUnstructuredGrid(vtkSmartPointer<vtkUnstructuredGrid> pGrid);
// 获取当前分析下的VTK网格对象
vtkSmartPointer<vtkUnstructuredGrid> getUnstructuredGrid() const;
// 清理当前分析下的VTK网格对象

@ -126,11 +126,19 @@ public:
nmNumericalWellGaugeData& oGaugeData,
QString* pError = NULL);
/** @brief 以二进制 VTU 写出网格并检查 VTK 返回值和文件存在性。 */
/**
* @brief VTU Missing Invalid
*
* VTK
*/
static bool writeGrid(vtkUnstructuredGrid* pGrid,
const QString& sFilePath,
QString* pError = NULL);
/** @brief 从 VTU 读取网格;调用方接管返回的 VTK 引用。 */
/**
* @brief VTU
*
* VTK
*/
static bool readGrid(const QString& sFilePath,
vtkSmartPointer<vtkUnstructuredGrid>& pGrid,
QString* pError = NULL);

@ -0,0 +1,63 @@
#ifndef NMPEBICELLMAPPING_H
#define NMPEBICELLMAPPING_H
#include "nmData_global.h"
#include <QString>
#include <QVector>
#include <vtkType.h>
class vtkUnstructuredGrid;
/**
* @brief PEBI VTK Cell
*
* vtkUnstructuredGrid CellData FieldData
* DataManager
* 线
*/
class NM_DATA_EXPORT nmPebiCellMapping
{
public:
enum MappingStatus
{
MappingStatus_Missing = 0,
MappingStatus_Valid,
MappingStatus_Invalid
};
/** @brief 返回 CellData 中原始单元 ID 数组的保留名称。 */
static const char* originalCellIdArrayName();
/** @brief 返回 FieldData 中原始单元总数数组的保留名称。 */
static const char* originalCellCountArrayName();
/**
* @brief
*
* ID
* 使 AddArray() OriginalCellId Scalars
*/
static bool attach(
vtkUnstructuredGrid* pGrid,
const QVector<vtkIdType>& vecVtkToOriginal,
vtkIdType nOriginalCellCount,
QString* pError = NULL);
/**
* @brief
*
* Missing
* Invalid Valid
*/
static MappingStatus read(
vtkUnstructuredGrid* pGrid,
QVector<vtkIdType>* pVtkToOriginal = NULL,
QVector<vtkIdType>* pOriginalToVtk = NULL,
QString* pError = NULL);
private:
nmPebiCellMapping();
};
#endif // NMPEBICELLMAPPING_H

@ -1,10 +1,13 @@
#include "nmCalculationPebiGrid.h"
#include <Windows.h>
#include <QDebug>
#include <QMap>
#include <QMutex>
#include <QMutexLocker>
#include <QThread>
#include <QVector>
#include <cmath>
#include <limits.h>
#include <QSet>
#include <QHash>
@ -26,9 +29,11 @@
#include "nmDataBinaryTools.h"
#include "nmDataPvtParaForPebi.h"
#include "nmDataTimeStepSetting.h"
#include "nmPebiCellMapping.h"
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkMath.h>
#include <vtkType.h>
#include <vtkUnsignedCharArray.h>
@ -902,88 +907,126 @@ vtkSmartPointer<vtkUnstructuredGrid> nmCalculationPebiGrid::createPebiUnstructur
const HX_NWTM_GRID_OUTPUT1& P1,
const QAtomicInt* pCancelRequested)
{
vtkSmartPointer<vtkUnstructuredGrid> pUnstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
vtkSmartPointer<vtkPoints> pPoints = vtkSmartPointer<vtkPoints>::New();
// 用于存储所有有效单元引用的唯一点索引
const size_t nPointCount = P1.PEBI_cell.p.size();
const size_t nCellDefinitionCount = P1.PEBI_cell.pindex.size();
const size_t nOriginalCellCount = P1.PEBI_cell.isplot.size();
if(nPointCount == 0 || nPointCount > static_cast<size_t>(INT_MAX) ||
nOriginalCellCount == 0 ||
nOriginalCellCount > static_cast<size_t>(INT_MAX) ||
nCellDefinitionCount > static_cast<size_t>(INT_MAX) ||
nCellDefinitionCount != nOriginalCellCount) {
qWarning() << "PEBI grid output dimensions are invalid.";
return nullptr;
}
// 第一遍只验证 DLL 输出并收集点,不向 VTK 对象提交半成品几何。
QSet<int> setUniquePointIndices;
// 1. 预处理单元数据,确定哪些单元是有效的,并收集这些单元引用的所有唯一点索引
// 这一步先不向 vtkPoints 添加点,而是收集需要添加的点的索引。
int nVisibleCellCount = 0;
for(size_t i = 0; i < P1.PEBI_cell.pindex.size(); ++i) {
if((i % 256) == 0 && isCancellationRequested(pCancelRequested)) {
return nullptr;
}
// 只处理 isplot 为 1 的单元
if(i >= P1.PEBI_cell.isplot.size() || P1.PEBI_cell.isplot[i] != 1) {
const std::vector<int>& vecIndices = P1.PEBI_cell.pindex[i];
if(vecIndices.size() > static_cast<size_t>(INT_MAX)) {
qWarning() << "PEBI cell point count exceeds VTK capacity:" << i;
return nullptr;
}
if(P1.PEBI_cell.isplot[i] != 1) {
continue;
}
const std::vector<int>& vecIndices = P1.PEBI_cell.pindex[i];
if(vecIndices.empty()) continue;
// 确定实际点数(检查首尾是否相同)
int nPointsInCell = vecIndices.size();
if(vecIndices.empty()) {
qWarning() << "PEBI cell has an invalid point count:" << i;
return nullptr;
}
int nPointsInCell = static_cast<int>(vecIndices.size());
if(nPointsInCell > 1 && vecIndices[0] == vecIndices[nPointsInCell - 1]) {
nPointsInCell--;
}
// 保留既有 VTK_LINE 规则,因此去除闭合尾点后至少需要两个不同点。
if(nPointsInCell < 2) {
qWarning() << "PEBI cell has fewer than two usable points:" << i;
return nullptr;
}
if(nPointsInCell < 2) continue; // 过滤掉无效单元点数小于2
// 将此有效单元引用的所有点索引添加到 setUniquePointIndices 集合中
QSet<int> setCellPointIndices;
for(int j = 0; j < nPointsInCell; ++j) {
setUniquePointIndices.insert(vecIndices[j]);
const int nOriginalPointId = vecIndices[j];
if(nOriginalPointId < 0 ||
static_cast<size_t>(nOriginalPointId) >= nPointCount) {
qWarning() << "PEBI cell references an invalid point:"
<< i << nOriginalPointId;
return nullptr;
}
if(setCellPointIndices.contains(nOriginalPointId)) {
qWarning() << "PEBI cell contains a repeated interior point:"
<< i << nOriginalPointId;
return nullptr;
}
const double dX = P1.PEBI_cell.p[nOriginalPointId].x;
const double dY = P1.PEBI_cell.p[nOriginalPointId].y;
if(!vtkMath::IsFinite(dX) || !vtkMath::IsFinite(dY)) {
qWarning() << "PEBI cell references a non-finite point:" << i;
return nullptr;
}
setCellPointIndices.insert(nOriginalPointId);
setUniquePointIndices.insert(nOriginalPointId);
}
++nVisibleCellCount;
}
if(nVisibleCellCount <= 0 || setUniquePointIndices.isEmpty()) {
qWarning() << "PEBI grid output contains no visible cells.";
return nullptr;
}
if(isCancellationRequested(pCancelRequested)) {
return nullptr;
}
// 创建一个映射表,将原始点索引映射到 VTK 中的新点索引
vtkSmartPointer<vtkUnstructuredGrid> pUnstructuredGrid =
vtkSmartPointer<vtkUnstructuredGrid>::New();
vtkSmartPointer<vtkPoints> pPoints =
vtkSmartPointer<vtkPoints>::New();
QMap<int, vtkIdType> mapOriginalToVtkPointId;
vtkIdType currentVtkPointId = 0;
pPoints->SetNumberOfPoints(
static_cast<vtkIdType>(setUniquePointIndices.size()));
// 2. 根据收集到的唯一点索引,将这些点添加到 vtkPoints
pPoints->SetNumberOfPoints(setUniquePointIndices.size());
// 遍历 setUniquePointIndices
int nProcessedPointCount = 0;
foreach(int nOriginalIdx, setUniquePointIndices) {
if(nOriginalIdx >= 0 && nOriginalIdx < P1.PEBI_cell.p.size()) {
pPoints->SetPoint(currentVtkPointId, P1.PEBI_cell.p[nOriginalIdx].x, P1.PEBI_cell.p[nOriginalIdx].y, 0.0);
mapOriginalToVtkPointId[nOriginalIdx] = currentVtkPointId;
currentVtkPointId++;
} else {
// 处理异常情况:如果 setUniquePointIndices 中包含了无效的原始点索引
qDebug() << "Warning: Invalid original point index" << nOriginalIdx << "found in setUniquePointIndices.";
if((nProcessedPointCount % 256) == 0 &&
isCancellationRequested(pCancelRequested)) {
return nullptr;
}
pPoints->SetPoint(currentVtkPointId,
P1.PEBI_cell.p[nOriginalIdx].x,
P1.PEBI_cell.p[nOriginalIdx].y,
0.0);
mapOriginalToVtkPointId.insert(
nOriginalIdx, currentVtkPointId);
++currentVtkPointId;
++nProcessedPointCount;
}
pUnstructuredGrid->SetPoints(pPoints);
pUnstructuredGrid->Allocate(
static_cast<vtkIdType>(nVisibleCellCount));
// 3. 再次遍历单元数据,这次是根据新的 VTK 点索引来插入单元
// 第二遍只提交已经验证过的可见单元,并同步构造 VTK -> 原始单元映射。
QVector<vtkIdType> vecVtkToOriginal;
vecVtkToOriginal.reserve(nVisibleCellCount);
for(size_t i = 0; i < P1.PEBI_cell.pindex.size(); ++i) {
if((i % 256) == 0 && isCancellationRequested(pCancelRequested)) {
return nullptr;
}
// 再次检查 isplot 标志,确保只处理有效单元
if(i >= P1.PEBI_cell.isplot.size() || P1.PEBI_cell.isplot[i] != 1) {
if(P1.PEBI_cell.isplot[i] != 1) {
continue;
}
const std::vector<int>& vecIndices = P1.PEBI_cell.pindex[i];
if(vecIndices.empty()) continue;
// 检查首尾是否重复
int nPointsInCell = vecIndices.size();
int nPointsInCell = static_cast<int>(vecIndices.size());
if(nPointsInCell > 1 && vecIndices[0] == vecIndices[nPointsInCell - 1]) {
nPointsInCell--;
}
if(nPointsInCell < 2) continue; // 过滤掉无效单元
int vtkCellType = 0;
if(nPointsInCell == 2) {
vtkCellType = VTK_LINE;
} else if(nPointsInCell == 3) {
@ -994,24 +1037,52 @@ vtkSmartPointer<vtkUnstructuredGrid> nmCalculationPebiGrid::createPebiUnstructur
vtkCellType = VTK_POLYGON;
}
// 使用映射表将原始索引转换为新的 VTK 索引
vtkIdType* pts = new vtkIdType[nPointsInCell];
QVector<vtkIdType> vecVtkPointIds(nPointsInCell);
for(int j = 0; j < nPointsInCell; ++j) {
if(mapOriginalToVtkPointId.contains(vecIndices[j])) { // 确保点在映射表中
pts[j] = mapOriginalToVtkPointId[vecIndices[j]];
} else {
qDebug() << "Error: Point" << vecIndices[j] << "for cell" << i << "not found in map. This should not happen!";
// 可以选择跳过此单元或进行其他错误处理
delete[] pts;
QMap<int, vtkIdType>::const_iterator oPointIt =
mapOriginalToVtkPointId.constFind(vecIndices[j]);
if(oPointIt == mapOriginalToVtkPointId.constEnd()) {
qWarning() << "Validated PEBI point is missing from the map:"
<< i << vecIndices[j];
return nullptr;
}
vecVtkPointIds[j] = oPointIt.value();
}
pUnstructuredGrid->InsertNextCell(vtkCellType, nPointsInCell, pts);
delete[] pts;
const vtkIdType nExpectedVtkCellId =
static_cast<vtkIdType>(vecVtkToOriginal.size());
const vtkIdType nInsertedVtkCellId =
pUnstructuredGrid->InsertNextCell(
vtkCellType,
static_cast<vtkIdType>(nPointsInCell),
vecVtkPointIds.data());
if(nInsertedVtkCellId != nExpectedVtkCellId) {
qWarning() << "PEBI VTK cell insertion order is invalid.";
return nullptr;
}
vecVtkToOriginal.append(static_cast<vtkIdType>(i));
}
if(isCancellationRequested(pCancelRequested)) {
return nullptr;
}
if(vecVtkToOriginal.size() != nVisibleCellCount ||
pUnstructuredGrid->GetNumberOfCells() !=
static_cast<vtkIdType>(vecVtkToOriginal.size())) {
qWarning() << "PEBI visible cell mapping is incomplete.";
return nullptr;
}
QString sMappingError;
if(!nmPebiCellMapping::attach(
pUnstructuredGrid,
vecVtkToOriginal,
static_cast<vtkIdType>(nOriginalCellCount),
&sMappingError)) {
qWarning() << "Unable to attach PEBI cell mapping:"
<< sMappingError;
return nullptr;
}
return pUnstructuredGrid;
}

@ -1,6 +1,7 @@
#include "nmDataAnalyzeManager.h"
#include "nmAttrRegistry.h"
#include "nmPebiCellMapping.h"
#include "nmPebiResultSnapshot.h"
#include "nmPebiResultSnapshotSerializer.h"
#include "nmNumericalSaveSession.h"
@ -4540,7 +4541,21 @@ bool nmDataAnalyzeManager::commitPebiGridResult(
return false;
}
// 第三步:整体替换 DLL 槽位顺序,再登记同一输入版本并替换 VTK 网格。
// 第三步:新生成网格必须携带完整映射;验证失败不得修改井顺序和版本。
QString sMappingError;
const nmPebiCellMapping::MappingStatus eMappingStatus =
nmPebiCellMapping::read(
pGrid, NULL, NULL, &sMappingError);
if(eMappingStatus != nmPebiCellMapping::MappingStatus_Valid) {
qWarning() << "Cannot commit PEBI grid with invalid cell mapping:"
<< (eMappingStatus ==
nmPebiCellMapping::MappingStatus_Missing
? QString("mapping arrays are missing")
: sMappingError);
return false;
}
// 第四步:整体替换 DLL 槽位顺序,再登记同一输入版本并替换 VTK 网格。
// setSolverWellOrder() 会统一重编号,避免逐井追加期间暴露半成品顺序。
m_oNumericalAnalysisCase.setSolverWellOrder(vecSolverWellOrder);
if(!m_oNumericalAnalysisCase.markGridBuiltIfCurrent(
@ -7163,9 +7178,21 @@ vtkSmartPointer<vtkUnstructuredGrid> nmDataAnalyzeManager::getUnstructuredGrid()
return m_pVtkUnstructuredGrid;
}
void nmDataAnalyzeManager::setUnstructuredGrid(vtkSmartPointer<vtkUnstructuredGrid> grid)
void nmDataAnalyzeManager::setUnstructuredGrid(
vtkSmartPointer<vtkUnstructuredGrid> pGrid)
{
m_pVtkUnstructuredGrid = grid;
if(pGrid != NULL) {
QString sMappingError;
const nmPebiCellMapping::MappingStatus eMappingStatus =
nmPebiCellMapping::read(
pGrid, NULL, NULL, &sMappingError);
if(eMappingStatus == nmPebiCellMapping::MappingStatus_Invalid) {
qWarning() << "Cannot install PEBI grid with invalid cell mapping:"
<< sMappingError;
return;
}
}
m_pVtkUnstructuredGrid = pGrid;
}
void nmDataAnalyzeManager::clearUnstructuredGrid()

@ -1,6 +1,7 @@
#include "nmNumericalResultPersistence.h"
#include "nmDataWellBase.h"
#include "nmPebiCellMapping.h"
#include <QByteArray>
#include <QCryptographicHash>
@ -1026,6 +1027,17 @@ bool nmNumericalResultPersistence::writeGrid(
return setError(pError, "Numerical grid is empty.");
}
QString sMappingError;
const nmPebiCellMapping::MappingStatus eMappingStatus =
nmPebiCellMapping::read(
pGrid, NULL, NULL, &sMappingError);
if(eMappingStatus == nmPebiCellMapping::MappingStatus_Invalid)
{
return setError(pError, sMappingError.isEmpty()
? QString("Numerical grid cell mapping is invalid.")
: sMappingError);
}
vtkNew<vtkXMLUnstructuredGridWriter> pWriter;
pWriter->SetInputData(pGrid);
pWriter->SetFileName(sFilePath.toLocal8Bit().constData());
@ -1065,6 +1077,18 @@ bool nmNumericalResultPersistence::readGrid(
{
return setError(pError, "Numerical VTU grid is invalid.");
}
QString sMappingError;
const nmPebiCellMapping::MappingStatus eMappingStatus =
nmPebiCellMapping::read(
pOutput, NULL, NULL, &sMappingError);
if(eMappingStatus == nmPebiCellMapping::MappingStatus_Invalid)
{
return setError(pError, sMappingError.isEmpty()
? QString("Numerical VTU grid cell mapping is invalid.")
: sMappingError);
}
// Missing 表示旧版几何,仍可加载;映射相关能力必须另行要求 Valid。
pGrid = pOutput;
return pGrid != NULL;
}

@ -0,0 +1,290 @@
#include "nmPebiCellMapping.h"
#include <limits.h>
#include <vtkAbstractArray.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkFieldData.h>
#include <vtkIdTypeArray.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
namespace {
const char g_sOriginalCellIdArrayName[] = "OriginalCellId";
const char g_sOriginalCellCountArrayName[] = "OriginalCellCount";
bool failAttach(QString* pError, const char* pMessage)
{
if(pError != NULL) {
*pError = QString::fromLatin1(pMessage);
}
return false;
}
nmPebiCellMapping::MappingStatus failRead(
QString* pError,
const char* pMessage)
{
if(pError != NULL) {
*pError = QString::fromLatin1(pMessage);
}
return nmPebiCellMapping::MappingStatus_Invalid;
}
bool validateMappingValues(
const QVector<vtkIdType>& vecVtkToOriginal,
vtkIdType nOriginalCellCount,
QVector<vtkIdType>* pOriginalToVtk,
QString* pError)
{
if(nOriginalCellCount <= 0 || nOriginalCellCount > INT_MAX ||
nOriginalCellCount < static_cast<vtkIdType>(
vecVtkToOriginal.size())) {
return failAttach(pError,
"PEBI original cell count is invalid for the mapping.");
}
QVector<vtkIdType> vecOriginalToVtk(
static_cast<int>(nOriginalCellCount),
static_cast<vtkIdType>(-1));
for(int nVtkCellId = 0;
nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) {
const vtkIdType nOriginalCellId =
vecVtkToOriginal[nVtkCellId];
if(nOriginalCellId < 0 ||
nOriginalCellId >= nOriginalCellCount) {
return failAttach(pError,
"PEBI mapping contains an out-of-range original cell ID.");
}
if(vecOriginalToVtk[static_cast<int>(nOriginalCellId)] >= 0) {
return failAttach(pError,
"PEBI mapping contains a duplicate original cell ID.");
}
vecOriginalToVtk[static_cast<int>(nOriginalCellId)] =
static_cast<vtkIdType>(nVtkCellId);
}
// 双向核对可避免以后调整构造过程时只维护其中一个方向。
for(int nVtkCellId = 0;
nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) {
const vtkIdType nOriginalCellId =
vecVtkToOriginal[nVtkCellId];
if(vecOriginalToVtk[static_cast<int>(nOriginalCellId)] !=
static_cast<vtkIdType>(nVtkCellId)) {
return failAttach(pError,
"PEBI cell mapping is not reversible.");
}
}
if(pOriginalToVtk != NULL) {
*pOriginalToVtk = vecOriginalToVtk;
}
return true;
}
}
const char* nmPebiCellMapping::originalCellIdArrayName()
{
return g_sOriginalCellIdArrayName;
}
const char* nmPebiCellMapping::originalCellCountArrayName()
{
return g_sOriginalCellCountArrayName;
}
bool nmPebiCellMapping::attach(
vtkUnstructuredGrid* pGrid,
const QVector<vtkIdType>& vecVtkToOriginal,
vtkIdType nOriginalCellCount,
QString* pError)
{
if(pError != NULL) {
pError->clear();
}
if(pGrid == NULL || pGrid->GetNumberOfCells() <= 0 ||
pGrid->GetNumberOfCells() > INT_MAX ||
static_cast<vtkIdType>(vecVtkToOriginal.size()) !=
pGrid->GetNumberOfCells()) {
return failAttach(pError,
"PEBI grid cell count does not match the mapping.");
}
vtkCellData* pCellData = pGrid->GetCellData();
vtkPointData* pPointData = pGrid->GetPointData();
vtkFieldData* pFieldData = pGrid->GetFieldData();
if(pCellData == NULL || pPointData == NULL || pFieldData == NULL) {
return failAttach(pError,
"PEBI grid data containers are unavailable.");
}
if(pCellData->GetAbstractArray(originalCellIdArrayName()) != NULL ||
pCellData->GetAbstractArray(originalCellCountArrayName()) != NULL ||
pPointData->GetAbstractArray(originalCellIdArrayName()) != NULL ||
pPointData->GetAbstractArray(originalCellCountArrayName()) != NULL ||
pFieldData->GetAbstractArray(originalCellIdArrayName()) != NULL ||
pFieldData->GetAbstractArray(originalCellCountArrayName()) != NULL) {
return failAttach(pError,
"PEBI grid already contains reserved mapping arrays.");
}
if(!validateMappingValues(vecVtkToOriginal,
nOriginalCellCount, NULL, pError)) {
return false;
}
vtkSmartPointer<vtkIdTypeArray> pOriginalCellIds =
vtkSmartPointer<vtkIdTypeArray>::New();
pOriginalCellIds->SetName(originalCellIdArrayName());
pOriginalCellIds->SetNumberOfComponents(1);
pOriginalCellIds->SetNumberOfTuples(
static_cast<vtkIdType>(vecVtkToOriginal.size()));
for(int nVtkCellId = 0;
nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) {
pOriginalCellIds->SetValue(
static_cast<vtkIdType>(nVtkCellId),
vecVtkToOriginal[nVtkCellId]);
}
vtkSmartPointer<vtkIdTypeArray> pOriginalCellCount =
vtkSmartPointer<vtkIdTypeArray>::New();
pOriginalCellCount->SetName(originalCellCountArrayName());
pOriginalCellCount->SetNumberOfComponents(1);
pOriginalCellCount->SetNumberOfTuples(1);
pOriginalCellCount->SetValue(0, nOriginalCellCount);
vtkDataArray* pPreviousScalars = pCellData->GetScalars();
if(pCellData->AddArray(pOriginalCellIds) < 0) {
return failAttach(pError,
"Unable to add the PEBI original cell ID array.");
}
if(pFieldData->AddArray(pOriginalCellCount) < 0) {
pCellData->RemoveArray(originalCellIdArrayName());
return failAttach(pError,
"Unable to add the PEBI original cell count array.");
}
const bool bAttached =
pCellData->GetAbstractArray(originalCellIdArrayName()) ==
pOriginalCellIds.GetPointer() &&
pFieldData->GetAbstractArray(originalCellCountArrayName()) ==
pOriginalCellCount.GetPointer() &&
pCellData->GetScalars() == pPreviousScalars &&
pCellData->GetScalars() != pOriginalCellIds.GetPointer();
if(!bAttached) {
// VTK 不提供成组 AddArray第二步或事后校验失败时显式撤销整组。
pFieldData->RemoveArray(originalCellCountArrayName());
pCellData->RemoveArray(originalCellIdArrayName());
return failAttach(pError,
"Unable to attach the complete PEBI cell mapping.");
}
return true;
}
nmPebiCellMapping::MappingStatus nmPebiCellMapping::read(
vtkUnstructuredGrid* pGrid,
QVector<vtkIdType>* pVtkToOriginal,
QVector<vtkIdType>* pOriginalToVtk,
QString* pError)
{
if(pVtkToOriginal != NULL) {
pVtkToOriginal->clear();
}
if(pOriginalToVtk != NULL) {
pOriginalToVtk->clear();
}
if(pError != NULL) {
pError->clear();
}
if(pVtkToOriginal != NULL &&
pVtkToOriginal == pOriginalToVtk) {
return failRead(pError,
"PEBI mapping outputs must use different containers.");
}
if(pGrid == NULL) {
return failRead(pError, "PEBI grid is unavailable.");
}
vtkCellData* pCellData = pGrid->GetCellData();
vtkPointData* pPointData = pGrid->GetPointData();
vtkFieldData* pFieldData = pGrid->GetFieldData();
if(pCellData == NULL || pPointData == NULL || pFieldData == NULL) {
return failRead(pError,
"PEBI grid data containers are unavailable.");
}
vtkAbstractArray* pOriginalCellIdsAbstract =
pCellData->GetAbstractArray(originalCellIdArrayName());
vtkAbstractArray* pOriginalCellCountAbstract =
pFieldData->GetAbstractArray(originalCellCountArrayName());
if(pCellData->GetAbstractArray(originalCellCountArrayName()) != NULL ||
pPointData->GetAbstractArray(originalCellIdArrayName()) != NULL ||
pPointData->GetAbstractArray(originalCellCountArrayName()) != NULL ||
pFieldData->GetAbstractArray(originalCellIdArrayName()) != NULL) {
return failRead(pError,
"PEBI grid contains mapping arrays in invalid locations.");
}
if(pOriginalCellIdsAbstract == NULL &&
pOriginalCellCountAbstract == NULL) {
return MappingStatus_Missing;
}
if(pOriginalCellIdsAbstract == NULL ||
pOriginalCellCountAbstract == NULL) {
return failRead(pError,
"PEBI grid contains an incomplete cell mapping.");
}
vtkIdTypeArray* pOriginalCellIds =
vtkIdTypeArray::SafeDownCast(pOriginalCellIdsAbstract);
vtkIdTypeArray* pOriginalCellCount =
vtkIdTypeArray::SafeDownCast(pOriginalCellCountAbstract);
if(pOriginalCellIds == NULL || pOriginalCellCount == NULL) {
return failRead(pError,
"PEBI cell mapping arrays have invalid types.");
}
const vtkIdType nVtkCellCount = pGrid->GetNumberOfCells();
if(nVtkCellCount <= 0 || nVtkCellCount > INT_MAX ||
pOriginalCellIds->GetNumberOfComponents() != 1 ||
pOriginalCellIds->GetNumberOfTuples() != nVtkCellCount ||
pOriginalCellCount->GetNumberOfComponents() != 1 ||
pOriginalCellCount->GetNumberOfTuples() != 1) {
return failRead(pError,
"PEBI cell mapping array dimensions are invalid.");
}
if(pCellData->GetScalars() == pOriginalCellIds) {
return failRead(pError,
"PEBI original cell IDs must not be active scalars.");
}
const vtkIdType nOriginalCellCount = pOriginalCellCount->GetValue(0);
QVector<vtkIdType> vecVtkToOriginal(
static_cast<int>(nVtkCellCount));
for(vtkIdType nVtkCellId = 0;
nVtkCellId < nVtkCellCount; ++nVtkCellId) {
vecVtkToOriginal[static_cast<int>(nVtkCellId)] =
pOriginalCellIds->GetValue(nVtkCellId);
}
QVector<vtkIdType> vecOriginalToVtk;
QString sValidationError;
if(!validateMappingValues(vecVtkToOriginal,
nOriginalCellCount,
&vecOriginalToVtk,
&sValidationError)) {
if(pError != NULL) {
*pError = sValidationError;
}
return MappingStatus_Invalid;
}
if(pVtkToOriginal != NULL) {
*pVtkToOriginal = vecVtkToOriginal;
}
if(pOriginalToVtk != NULL) {
*pOriginalToVtk = vecOriginalToVtk;
}
return MappingStatus_Valid;
}
Loading…
Cancel
Save