#include "nmPebiCellMapping.h" #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 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), vecVtkToOriginal[nVtkCellId]); } vtkSmartPointer pOriginalCellCount = vtkSmartPointer::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* 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."); } 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 vecVtkToOriginal( static_cast(nVtkCellCount)); for(vtkIdType nVtkCellId = 0; nVtkCellId < nVtkCellCount; ++nVtkCellId) { vecVtkToOriginal[static_cast(nVtkCellId)] = pOriginalCellIds->GetValue(nVtkCellId); } 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; }