/*========================================================================= Program: Visualization Toolkit Module: vtkExtractGeometry.cxx 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. =========================================================================*/ #include "FITKExtractGeometry.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkCellIterator.h" #include "vtkFloatArray.h" #include "vtkIdList.h" #include "vtkImplicitFunction.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkSmartPointer.h" #include "vtkUnstructuredGrid.h" vtkStandardNewMacro(FITKExtractGeometry); vtkCxxSetObjectMacro(FITKExtractGeometry, ImplicitFunction, vtkImplicitFunction); //---------------------------------------------------------------------------- // Construct object with ExtractInside turned on. FITKExtractGeometry::FITKExtractGeometry(vtkImplicitFunction* f) { this->ImplicitFunction = f; if (this->ImplicitFunction) { this->ImplicitFunction->Register(this); } this->ExtractInside = 1; this->ExtractBoundaryCells = 0; this->ExtractOnlyBoundaryCells = 0; } //---------------------------------------------------------------------------- FITKExtractGeometry::~FITKExtractGeometry() { this->SetImplicitFunction(nullptr); } // Overload standard modified time function. If implicit function is modified, // then this object is modified as well. vtkMTimeType FITKExtractGeometry::GetMTime() { vtkMTimeType mTime = this->MTime.GetMTime(); vtkMTimeType impFuncMTime; if (this->ImplicitFunction != nullptr) { impFuncMTime = this->ImplicitFunction->GetMTime(); mTime = (impFuncMTime > mTime ? impFuncMTime : mTime); } return mTime; } QList< int > FITKExtractGeometry::getSelectOriginalPoints() const { return _originalCurrentPointMap.keys(); } QList< int > FITKExtractGeometry::getSelectOriginalCells() const { return _originalCurrentCellMap.keys(); } const QHash< int, int >& FITKExtractGeometry::getPointMap() const { return _originalCurrentPointMap; } const QHash< int, int >& FITKExtractGeometry::getCellMap() const { return _originalCurrentCellMap; } //---------------------------------------------------------------------------- int FITKExtractGeometry::RequestData( vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // get the info objects vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); // get the input and output vtkDataSet* input = vtkDataSet::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkUnstructuredGrid* output = vtkUnstructuredGrid::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); // May be nullptr, check before dereferencing. vtkUnstructuredGrid* gridInput = vtkUnstructuredGrid::SafeDownCast(input); vtkIdType ptId, numPts, numCells, i, newCellId, newId, *pointMap; vtkSmartPointer< vtkCellIterator > cellIter = vtkSmartPointer< vtkCellIterator >::Take(input->NewCellIterator()); vtkIdList* pointIdList; int cellType; vtkIdType numCellPts; double x[3]; double multiplier; vtkPoints* newPts; vtkIdList* newCellPts; vtkPointData* pd = input->GetPointData(); vtkCellData* cd = input->GetCellData(); vtkPointData* outputPD = output->GetPointData(); vtkCellData* outputCD = output->GetCellData(); int npts; vtkDebugMacro(<< "Extracting geometry"); if (!this->ImplicitFunction) { vtkErrorMacro(<< "No implicit function specified"); return 1; } // As this filter is doing a subsetting operation, set the Copy Tuple flag // for GlobalIds array so that, if present, it will be copied to the output. outputPD->CopyGlobalIdsOn(); outputCD->CopyGlobalIdsOn(); newCellPts = vtkIdList::New(); newCellPts->Allocate(VTK_CELL_SIZE); if (this->ExtractInside) { multiplier = 1.0; } else { multiplier = -1.0; } // Loop over all points determining whether they are inside the // implicit function. Copy the points and point data if they are. // numPts = input->GetNumberOfPoints(); numCells = input->GetNumberOfCells(); pointMap = new vtkIdType[numPts]; // maps old point ids into new for (i = 0; i < numPts; i++) { pointMap[i] = -1; } output->Allocate(numCells / 4); //allocate storage for geometry/topology newPts = vtkPoints::New(); newPts->Allocate(numPts / 4, numPts); outputPD->CopyAllocate(pd); outputCD->CopyAllocate(cd); vtkFloatArray* newScalars = nullptr; if (!this->ExtractBoundaryCells) { for (ptId = 0; ptId < numPts; ptId++) { input->GetPoint(ptId, x); if ((this->ImplicitFunction->FunctionValue(x) * multiplier) < 0.0) { newId = newPts->InsertNextPoint(x); pointMap[ptId] = newId; _originalCurrentPointMap.insert(ptId, newId); outputPD->CopyData(pd, ptId, newId); } } } else { // To extract boundary cells, we have to create supplemental information double val; newScalars = vtkFloatArray::New(); newScalars->SetNumberOfValues(numPts); for (ptId = 0; ptId < numPts; ptId++) { input->GetPoint(ptId, x); val = this->ImplicitFunction->FunctionValue(x) * multiplier; newScalars->SetValue(ptId, val); } } // Now loop over all cells to see whether they are inside implicit // function (or on boundary if ExtractBoundaryCells is on). // for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { cellType = cellIter->GetCellType(); numCellPts = cellIter->GetNumberOfPoints(); pointIdList = cellIter->GetPointIds(); newCellPts->Reset(); if (!this->ExtractBoundaryCells) //requires less work { for (npts = 0, i = 0; i < numCellPts; i++, npts++) { ptId = pointIdList->GetId(i); if (pointMap[ptId] < 0) { break; //this cell won't be inserted } else { newCellPts->InsertId(i, pointMap[ptId]); } } } //if don't want to extract boundary cells else //want boundary cells { for (npts = 0, i = 0; i < numCellPts; i++) { ptId = pointIdList->GetId(i); if (newScalars->GetValue(ptId) <= 0.0) { npts++; } } int extraction_condition = 0; if (this->ExtractOnlyBoundaryCells) { if ((npts > 0) && (npts != numCellPts)) { extraction_condition = 1; } } else { if (npts > 0) { extraction_condition = 1; } } if (extraction_condition) { for (i = 0; i < numCellPts; i++) { ptId = pointIdList->GetId(i); if (pointMap[ptId] < 0) { input->GetPoint(ptId, x); newId = newPts->InsertNextPoint(x); pointMap[ptId] = newId; _originalCurrentPointMap.insert(ptId, newId); outputPD->CopyData(pd, ptId, newId); } newCellPts->InsertId(i, pointMap[ptId]); } } //a boundary or interior cell } //if mapping boundary cells int extraction_condition = 0; if (this->ExtractOnlyBoundaryCells) { if (npts != numCellPts && (this->ExtractBoundaryCells && npts > 0)) { extraction_condition = 1; } } else { if (npts >= numCellPts || (this->ExtractBoundaryCells && npts > 0)) { extraction_condition = 1; } } if (extraction_condition) { // special handling for polyhedron cells if (gridInput && cellType == VTK_POLYHEDRON) { newCellPts->Reset(); gridInput->GetFaceStream(cellIter->GetCellId(), newCellPts); vtkUnstructuredGrid::ConvertFaceStreamPointIds(newCellPts, pointMap); } newCellId = output->InsertNextCell(cellType, newCellPts); int orignalCellID = cellIter->GetCellId(); outputCD->CopyData(cd, orignalCellID, newCellId); _originalCurrentCellMap.insert(orignalCellID, newCellId); } } //for all cells // Update ourselves and release memory // delete[] pointMap; newCellPts->Delete(); output->SetPoints(newPts); newPts->Delete(); if (this->ExtractBoundaryCells) { newScalars->Delete(); } output->Squeeze(); return 1; } //---------------------------------------------------------------------------- int FITKExtractGeometry::FillInputPortInformation(int, vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); return 1; } //---------------------------------------------------------------------------- void FITKExtractGeometry::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Implicit Function: " << static_cast(this->ImplicitFunction) << "\n"; os << indent << "Extract Inside: " << (this->ExtractInside ? "On\n" : "Off\n"); os << indent << "Extract Boundary Cells: " << (this->ExtractBoundaryCells ? "On\n" : "Off\n"); os << indent << "Extract Only Boundary Cells: " << (this->ExtractOnlyBoundaryCells ? "On\n" : "Off\n"); }