#include "nmPebiCellMapping.h" #include #include #include #include #include #include #include #include #include #include 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 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, QVector* pOriginalToVtk, QString* pError) { if(nOriginalCellCount <= 0 || nOriginalCellCount > INT_MAX || nOriginalCellCount < static_cast( vecVtkToOriginal.size())) { return failAttach(pError, "PEBI original cell count is invalid for the mapping."); } QVector vecOriginalToVtk( static_cast(nOriginalCellCount), static_cast(-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(nOriginalCellId)] >= 0) { return failAttach(pError, "PEBI mapping contains a duplicate original cell ID."); } vecOriginalToVtk[static_cast(nOriginalCellId)] = static_cast(nVtkCellId); } // 双向核对可避免以后调整构造过程时只维护其中一个方向。 for(int nVtkCellId = 0; nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) { const vtkIdType nOriginalCellId = vecVtkToOriginal[nVtkCellId]; if(vecOriginalToVtk[static_cast(nOriginalCellId)] != static_cast(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& vecVtkToOriginal, vtkIdType nOriginalCellCount, QString* pError) { if(pError != NULL) { pError->clear(); } if(pGrid == NULL || pGrid->GetNumberOfCells() <= 0 || pGrid->GetNumberOfCells() > INT_MAX || static_cast(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 pOriginalCellIds = vtkSmartPointer::New(); pOriginalCellIds->SetName(originalCellIdArrayName()); pOriginalCellIds->SetNumberOfComponents(1); pOriginalCellIds->SetNumberOfTuples( static_cast(vecVtkToOriginal.size())); for(int nVtkCellId = 0; nVtkCellId < vecVtkToOriginal.size(); ++nVtkCellId) { pOriginalCellIds->SetValue( static_cast(nVtkCellId), static_cast(vecVtkToOriginal[nVtkCellId])); } vtkSmartPointer pOriginalCellCount = vtkSmartPointer::New(); pOriginalCellCount->SetName(originalCellCountArrayName()); pOriginalCellCount->SetNumberOfComponents(1); pOriginalCellCount->SetNumberOfTuples(1); pOriginalCellCount->SetValue(0, static_cast(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* pVtkToOriginal, QVector* 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."); } vtkDataArray* pOriginalCellIds = vtkDataArray::SafeDownCast(pOriginalCellIdsAbstract); vtkDataArray* pOriginalCellCount = vtkDataArray::SafeDownCast(pOriginalCellCountAbstract); if(!isSupportedMappingArray(pOriginalCellIds) || !isSupportedMappingArray(pOriginalCellCount)) { return failRead(pError, "PEBI cell mapping arrays must use Int32 or vtkIdType integers."); } 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."); } 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) { 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; 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; }