/*========================================================================= Program: Visualization Toolkit Module: TestMappedGridDeepCopy Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*---------------------------------------------------------------------------- This test was written by Menno Deij - van Rijswijk (MARIN). ----------------------------------------------------------------------------*/ #include "vtkDataArray.h" #include "vtkDebugLeaks.h" #include "vtkCell.h" // for cell types #include "vtkCellIterator.h" #include "vtkIdList.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkMappedUnstructuredGrid.h" #include "vtkNew.h" #include "vtkPoints.h" #include "vtkTestUtilities.h" #include "vtkUnstructuredGrid.h" #include "vtkXMLUnstructuredGridReader.h" #include "vtkXMLUnstructuredGridWriter.h" #include #include #include #include namespace { // this namespace contains the supporting mapped grid definition used in the test template class MappedCellIterator : public vtkCellIterator { public: vtkTemplateTypeMacro(MappedCellIterator, vtkCellIterator); typedef MappedCellIterator ThisType; static MappedCellIterator* New(); void SetMappedUnstructuredGrid(vtkMappedUnstructuredGrid *grid); virtual void PrintSelf(std::ostream& os, vtkIndent id) override; virtual bool IsDoneWithTraversal() override; virtual vtkIdType GetCellId() override; protected: MappedCellIterator(); ~MappedCellIterator() override; virtual void ResetToFirstCell() override { this->CellId = 0; } virtual void IncrementToNextCell() override { this->CellId++; } virtual void FetchCellType() override; virtual void FetchPointIds() override; virtual void FetchPoints() override; virtual void FetchFaces() override; private: MappedCellIterator(const MappedCellIterator&) VTK_DELETE_FUNCTION; void operator=(const MappedCellIterator&) VTK_DELETE_FUNCTION; vtkIdType CellId; vtkIdType NumberOfCells; vtkSmartPointer Impl; vtkSmartPointer GridPoints; }; template MappedCellIterator* MappedCellIterator::New() { VTK_STANDARD_NEW_BODY(ThisType); } template MappedCellIterator::MappedCellIterator() : CellId(0) , NumberOfCells(0) , Impl(nullptr) , GridPoints(nullptr) { } template void MappedCellIterator ::PrintSelf(ostream& os, vtkIndent indent) { os << indent << "Mapped Internal Block" << endl; } template MappedCellIterator::~MappedCellIterator() { } template void MappedCellIterator::SetMappedUnstructuredGrid(vtkMappedUnstructuredGrid *grid) { this->Impl = grid->GetImplementation(); this->CellId = 0; this->GridPoints = grid->GetPoints(); this->NumberOfCells = grid->GetNumberOfCells(); } template bool MappedCellIterator::IsDoneWithTraversal() { if (!this->Impl) return true; return CellId >= this->NumberOfCells; } template vtkIdType MappedCellIterator::GetCellId() { return this->CellId; } template void MappedCellIterator::FetchCellType() { this->CellType = Impl->GetCellType(this->CellId); } template void MappedCellIterator::FetchPointIds() { this->Impl->GetCellPoints(this->CellId, this->PointIds); } template void MappedCellIterator::FetchPoints() { this->GridPoints->GetPoints(this->GetPointIds(), this->Points); } template void MappedCellIterator::FetchFaces() { this->Impl->GetFaceStream(this->CellId, this->Faces); } class MappedGrid; class MappedGridImpl : public vtkObject { public: static MappedGridImpl* New(); vtkTypeMacro(MappedGridImpl, vtkObject); void Initialize(vtkUnstructuredGrid* ug) { ug->Register(this); _grid = ug; } void PrintSelf(std::ostream& os, vtkIndent id) override; //API for vtkMappedUnstructuredGrid implementation virtual int GetCellType(vtkIdType cellId); virtual void GetCellPoints(vtkIdType cellId, vtkIdList *ptIds); virtual void GetFaceStream(vtkIdType cellId, vtkIdList *ptIds); virtual void GetPointCells(vtkIdType ptId, vtkIdList *cellIds); virtual int GetMaxCellSize(); virtual void GetIdsOfCellsOfType(int type, vtkIdTypeArray *array); virtual int IsHomogeneous(); // This container is read only -- these methods do nothing but print a warning. void Allocate(vtkIdType numCells, int extSize = 1000); vtkIdType InsertNextCell(int type, vtkIdList *ptIds); vtkIdType InsertNextCell(int type, vtkIdType npts, vtkIdType *ptIds); vtkIdType InsertNextCell(int type, vtkIdType npts, vtkIdType *ptIds, vtkIdType nfaces, vtkIdType *faces); void ReplaceCell(vtkIdType cellId, int npts, vtkIdType *pts); vtkIdType GetNumberOfCells(); void SetOwner(MappedGrid* owner) { this->Owner = owner; } vtkPoints* GetPoints() { return _grid->GetPoints(); } protected: MappedGridImpl(){} virtual ~MappedGridImpl() override { _grid->UnRegister(this); } private: vtkUnstructuredGrid* _grid; MappedGrid* Owner; }; vtkStandardNewMacro(MappedGridImpl) void MappedGridImpl::PrintSelf(ostream& os, vtkIndent indent) { os << indent << "Mapped Grid Implementation" << endl; } int MappedGridImpl::GetCellType(vtkIdType cellId) { return _grid->GetCellType(cellId); } int MappedGridImpl::GetMaxCellSize() { return _grid->GetMaxCellSize(); } void MappedGridImpl::GetCellPoints(vtkIdType cellId, vtkIdList *ptIds) { _grid->GetCellPoints(cellId, ptIds); } void MappedGridImpl::GetFaceStream(vtkIdType cellId, vtkIdList *ptIds) { _grid->GetFaceStream(cellId, ptIds); } void MappedGridImpl::GetPointCells(vtkIdType ptId, vtkIdList* cellIds) { _grid->GetPointCells(ptId, cellIds); } int MappedGridImpl::IsHomogeneous() { return _grid->IsHomogeneous(); } vtkIdType MappedGridImpl::GetNumberOfCells() { return _grid->GetNumberOfCells(); } void MappedGridImpl::GetIdsOfCellsOfType(int type, vtkIdTypeArray *array) { _grid->GetIdsOfCellsOfType(type, array); } void MappedGridImpl::Allocate(vtkIdType vtkNotUsed(numCells), int vtkNotUsed(extSize)) { vtkWarningMacro(<<"Read only block\n"); return; } vtkIdType MappedGridImpl::InsertNextCell(int vtkNotUsed(type), vtkIdList* vtkNotUsed(ptIds)) { vtkWarningMacro(<<"Read only block\n"); return -1; } vtkIdType MappedGridImpl::InsertNextCell(int vtkNotUsed(type), vtkIdType vtkNotUsed(npts), vtkIdType *vtkNotUsed(ptIds)) { vtkWarningMacro(<<"Read only block\n"); return -1; } vtkIdType MappedGridImpl::InsertNextCell(int vtkNotUsed(type), vtkIdType vtkNotUsed(npts), vtkIdType *vtkNotUsed(ptIds), vtkIdType vtkNotUsed(nfaces), vtkIdType *vtkNotUsed(faces)) { vtkWarningMacro(<<"Read only block\n"); return -1; } void MappedGridImpl::ReplaceCell(vtkIdType vtkNotUsed(cellId), int vtkNotUsed(npts), vtkIdType *vtkNotUsed(pts)) { vtkWarningMacro(<<"Read only block\n"); return; } class MappedGrid : public vtkMappedUnstructuredGrid > { public: typedef vtkMappedUnstructuredGrid > _myBase; vtkTypeMacro(MappedGrid, _myBase); int GetDataObjectType() VTK_OVERRIDE { return VTK_UNSTRUCTURED_GRID_BASE; } static MappedGrid* New(); vtkPoints* GetPoints() override { return this->GetImplementation()->GetPoints(); } vtkIdType GetNumberOfPoints() override { return this->GetImplementation()->GetPoints()->GetNumberOfPoints(); } protected: MappedGrid() { MappedGridImpl* ig = MappedGridImpl::New(); ig->SetOwner(this); this->SetImplementation(ig); ig->Delete(); } ~MappedGrid() override {} private: MappedGrid(const MappedGrid&) = delete; void operator=(const MappedGrid&) = delete; }; vtkStandardNewMacro(MappedGrid) } // end anonymous namespace using namespace std; int TestMappedGridDeepCopy(int vtkNotUsed(argc), char*[] vtkNotUsed(argv)) { vtkNew points; points->InsertNextPoint(0, 0, 0); points->InsertNextPoint(1, 0, 0); points->InsertNextPoint(1, 1, 0); points->InsertNextPoint(0, 1, 0); points->InsertNextPoint(0, 0, 1); points->InsertNextPoint(1, 0, 1); points->InsertNextPoint(1, 1, 1); points->InsertNextPoint(0, 1, 1); points->InsertNextPoint(.5, .5, 2); points->InsertNextPoint(.5, .5, -1); vtkNew original; original->SetPoints(points); original->Allocate(3); // allocate for 3 cells vtkNew ids; // add a hexahedron of the first 8 points (i.e. a cube) ids->InsertNextId(0); ids->InsertNextId(1); ids->InsertNextId(2); ids->InsertNextId(3); ids->InsertNextId(4); ids->InsertNextId(5); ids->InsertNextId(6); ids->InsertNextId(7); original->InsertNextCell(VTK_HEXAHEDRON, ids.GetPointer()); ids->Reset(); // add a polyhedron comprise of the top hexahedron face // and four triangles to the 9th point ids->InsertNextId(4); ids->InsertNextId(5); ids->InsertNextId(6); ids->InsertNextId(7); ids->InsertNextId(8); // this list of faces does NOT include nfaces as the first entry vtkNew faces; // top face of four points faces->InsertNextId(4); faces->InsertNextId(4); faces->InsertNextId(5); faces->InsertNextId(6); faces->InsertNextId(7); // four triangle side faces, each of three points faces->InsertNextId(3); faces->InsertNextId(4); faces->InsertNextId(5); faces->InsertNextId(8); faces->InsertNextId(3); faces->InsertNextId(5); faces->InsertNextId(6); faces->InsertNextId(8); faces->InsertNextId(3); faces->InsertNextId(6); faces->InsertNextId(7); faces->InsertNextId(8); faces->InsertNextId(3); faces->InsertNextId(7); faces->InsertNextId(4); faces->InsertNextId(8); // insert the polyhedron cell original->InsertNextCell(VTK_POLYHEDRON, 5, ids.GetPointer()->GetPointer(0), 5, faces.GetPointer()->GetPointer(0)); vtkNew aCell; original->GetCell(1, aCell.GetPointer()); // this is the full faces list, *including* the leading nfaces vtkIdType* cellFaces = aCell->GetFaces(); if (cellFaces[0] != 5) { cerr << " expected 5 faces, got " << cellFaces[0] << endl; return EXIT_FAILURE; } for(int i = 0; i < faces->GetNumberOfIds(); ++i) { if (faces->GetId(i) != cellFaces[i+1]) { cerr << "faces array not identical at position " << i << endl; return EXIT_FAILURE; } } // put another pyramid on the bottom towards the 10th point faces->Reset(); ids->Reset(); // the list of points that the pyramid references ids->InsertNextId(0); ids->InsertNextId(1); ids->InsertNextId(2); ids->InsertNextId(3); ids->InsertNextId(9); // bottom face of four points faces->InsertNextId(4); faces->InsertNextId(0); faces->InsertNextId(1); faces->InsertNextId(2); faces->InsertNextId(3); // four side faces, each of three points faces->InsertNextId(3); faces->InsertNextId(0); faces->InsertNextId(1); faces->InsertNextId(9); faces->InsertNextId(3); faces->InsertNextId(1); faces->InsertNextId(2); faces->InsertNextId(9); faces->InsertNextId(3); faces->InsertNextId(2); faces->InsertNextId(3); faces->InsertNextId(9); faces->InsertNextId(3); faces->InsertNextId(3); faces->InsertNextId(0); faces->InsertNextId(9); // insert the cell. We now have two pyramids with a cube in between original->InsertNextCell(VTK_POLYHEDRON, 5, ids.GetPointer()->GetPointer(0), 5, faces.GetPointer()->GetPointer(0)); // create a mapped grid which basically takes the original grid // and uses it to map to. vtkNew mg; mg->GetImplementation()->Initialize(original); // copy the mapped grid into a normal unstructured grid. // copying will proceed via the super class // vtkUnstructuredGridBase::DeepCopy function // implementation that uses a cell iterator. This will // invoke to InsertNextCell function with face list // for *all* cells (even if they are not VTK_POLYHEDRON). // In the old implementation this gave copy errors. The fix // proposed together with this test addresses that issue. vtkNew copy; copy->Allocate(mg->GetNumberOfCells()); copy->DeepCopy(mg.GetPointer()); vtkCellIterator* oIt = original->NewCellIterator(); vtkCellIterator* cIt = copy->NewCellIterator(); vtkNew orig, copied; for(cIt->InitTraversal(), oIt->InitTraversal(); !cIt->IsDoneWithTraversal() && !oIt->IsDoneWithTraversal(); cIt->GoToNextCell(), oIt->GoToNextCell()) { oIt->GetCell(orig.GetPointer()); cIt->GetCell(copied.GetPointer()); if (cIt->GetCellType() != oIt->GetCellType()) { cerr << "Cell types do not match" << endl; return EXIT_FAILURE; } if (cIt->GetCellType() == VTK_POLYHEDRON) { vtkIdList *oFaces = oIt->GetFaces(); vtkIdList *cFaces = cIt->GetFaces(); if (cFaces->GetNumberOfIds() != oFaces->GetNumberOfIds()) { cerr << "Face id list length does not match" << endl; cerr << "Original: "; for(vtkIdType i = 0; i < oFaces->GetNumberOfIds(); ++i) { cerr << oFaces->GetId(i) << " "; } cerr << endl; cerr << "Copied: "; for(vtkIdType i = 0; i < cFaces->GetNumberOfIds(); ++i) cerr << cFaces->GetId(i) << " "; cerr << endl; return EXIT_FAILURE; } for (vtkIdType i = 0; i < cFaces->GetNumberOfIds(); ++i) { vtkIdType c = cFaces->GetId(i); vtkIdType o = oFaces->GetId(i); if (c != o) { cerr << "Face id list content does not match at" << i << endl; return EXIT_FAILURE; } } } } oIt->Delete(); cIt->Delete(); return EXIT_SUCCESS; }