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/nmData/nmPebiCellMapping.cpp

291 lines
10 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 "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;
}