|
|
|
|
|
#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;
|
|
|
|
|
|
}
|