// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkHyperTreeGridAxisCut.h" #include "vtkBitArray.h" #include "vtkCellData.h" #include "vtkDataSetAttributes.h" #include "vtkDoubleArray.h" #include "vtkHyperTree.h" #include "vtkHyperTreeGrid.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMathUtilities.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkUniformHyperTreeGrid.h" #include "vtkHyperTreeGridNonOrientedCursor.h" #include "vtkHyperTreeGridNonOrientedGeometryCursor.h" VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkHyperTreeGridAxisCut); //------------------------------------------------------------------------------ vtkHyperTreeGridAxisCut::vtkHyperTreeGridAxisCut() { // Default normal axis is Z this->PlaneNormalAxis = 0; // Default place intercept is 0 this->PlanePosition = 0.; this->PlanePositionRealUse = 0.; // Default mask is empty this->OutMask = nullptr; // Output indices begin at 0 this->CurrentId = 0; // Output should be the same type as the input this->AppropriateOutput = true; } //------------------------------------------------------------------------------ vtkHyperTreeGridAxisCut::~vtkHyperTreeGridAxisCut() { if (this->OutMask) { this->OutMask->Delete(); this->OutMask = nullptr; } } //------------------------------------------------------------------------------ void vtkHyperTreeGridAxisCut::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "PlaneNormalAxis : " << this->PlaneNormalAxis << endl; os << indent << "PlanePosition : " << this->PlanePosition << endl; os << indent << "OutMask: " << this->OutMask << endl; os << indent << "CurrentId: " << this->CurrentId << endl; } //------------------------------------------------------------------------------ int vtkHyperTreeGridAxisCut::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkHyperTreeGrid"); return 1; } //------------------------------------------------------------------------------ int vtkHyperTreeGridAxisCut::ProcessTrees(vtkHyperTreeGrid* input, vtkDataObject* outputDO) { // Downcast output data object to hyper tree grid vtkHyperTreeGrid* output = vtkHyperTreeGrid::SafeDownCast(outputDO); if (!output) { vtkErrorMacro("Incorrect type of output: " << outputDO->GetClassName()); return 0; } // This filter works only with 3D grids if (input->GetDimension() != 3) { vtkErrorMacro(<< "Bad input dimension:" << input->GetDimension()); return 0; } output->Initialize(); // Retrieve normal axis and intercept of cut plane int axis = this->PlaneNormalAxis; this->PlanePositionRealUse = this->PlanePosition; double inter = this->PlanePositionRealUse; // Set output grid sizes; must be 1 in the direction of cut plane normal unsigned int size[3]; input->GetDimensions(size); size[axis] = 1; output->SetDimensions(size); vtkUniformHyperTreeGrid* inputUHTG = vtkUniformHyperTreeGrid::SafeDownCast(input); vtkUniformHyperTreeGrid* outputUHTG = vtkUniformHyperTreeGrid::SafeDownCast(outputDO); if (inputUHTG) { outputUHTG->CopyCoordinates(inputUHTG); outputUHTG->SetFixedCoordinates(axis, inter); } else { output->CopyCoordinates(input); output->SetFixedCoordinates(axis, inter); } // Other grid parameters are identical output->SetTransposedRootIndexing(input->GetTransposedRootIndexing()); output->SetBranchFactor(input->GetBranchFactor()); output->SetHasInterface(input->GetHasInterface()); output->SetInterfaceNormalsName(input->GetInterfaceNormalsName()); output->SetInterfaceInterceptsName(input->GetInterfaceInterceptsName()); // Initialize output point data this->InData = input->GetCellData(); this->OutData = output->GetCellData(); this->OutData->CopyAllocate(this->InData); // Output indices begin at 0 this->CurrentId = 0; // Create material mask bit array if one is present on input if (input->HasMask()) { this->OutMask = vtkBitArray::New(); } // Retrieve material mask this->InMask = this->OutMask ? input->GetMask() : nullptr; // Storage for root cell Cartesian coordinates unsigned int i, j, k; // Storage for material mask indices computed together with output grid vtkNew position; // Iterate over all input hyper trees vtkIdType inIndex; vtkIdType outIndex = 0; vtkHyperTreeGrid::vtkHyperTreeGridIterator it; input->InitializeTreeIterator(it); vtkNew inCursor; vtkNew outCursor; while (it.GetNextTree(inIndex)) { if (this->CheckAbort()) { break; } // Initialize new geometric cursor at root of current input tree input->InitializeNonOrientedGeometryCursor(inCursor, inIndex); // Retrieve geometric features of input cursor const double* origin = inCursor->GetOrigin(); const double* _size = inCursor->GetSize(); // Check whether root cell is intersected by plane if ((origin[axis] < inter && (origin[axis] + _size[axis] > inter)) || vtkMathUtilities::FuzzyCompare(origin[axis] + _size[axis], inter)) { // Root is intersected by plane, descend into current child input->GetLevelZeroCoordinatesFromIndex(inIndex, i, j, k); // Get root index into output hyper tree grid, depending on cut axes switch (axis) { case 0: output->GetIndexFromLevelZeroCoordinates(outIndex, 0, j, k); break; case 1: output->GetIndexFromLevelZeroCoordinates(outIndex, i, 0, k); break; case 2: output->GetIndexFromLevelZeroCoordinates(outIndex, i, j, 0); break; default: vtkErrorMacro("Incorrect orientation of output: " << axis); return 0; } // switch ( axis ) // Initialize new cursor at root of current output tree output->InitializeNonOrientedCursor(outCursor, outIndex, true); // Cut tree recursively this->RecursivelyProcessTree(inCursor, outCursor); } // if origin } // it // Squeeze and set output material mask if necessary if (this->OutMask) { this->OutMask->Squeeze(); output->SetMask(this->OutMask); this->OutMask->FastDelete(); this->OutMask = nullptr; } return 1; } //------------------------------------------------------------------------------ void vtkHyperTreeGridAxisCut::RecursivelyProcessTree( vtkHyperTreeGridNonOrientedGeometryCursor* inCursor, vtkHyperTreeGridNonOrientedCursor* outCursor) { // Retrieve global index of input cursor vtkIdType inId = inCursor->GetGlobalNodeIndex(); // Increase index count on output: postfix is intended vtkIdType outId = this->CurrentId++; // Retrieve output tree and set global index of output cursor vtkHyperTree* outTree = outCursor->GetTree(); outTree->SetGlobalIndexFromLocal(outCursor->GetVertexId(), outId); // Update material mask if relevant if (this->InMask) { this->OutMask->InsertValue(outId, this->InMask->GetValue(inId)); } // Copy output cell data from that of input cell this->OutData->CopyData(this->InData, inId, outId); // Descend further into input trees only if cursor is not at leaf if (!inCursor->IsLeaf()) { // Cursor is not at leaf, subdivide output tree one level further outCursor->SubdivideLeaf(); // Initialize output children index int outChild = 0; // If cursor is not at leaf, recurse to all children int numChildren = inCursor->GetNumberOfChildren(); for (int inChild = 0; inChild < numChildren; ++inChild) { if (this->CheckAbort()) { break; } inCursor->ToChild(inChild); // Retrieve normal axis and intercept of plane int axis = this->PlaneNormalAxis; double inter = this->PlanePositionRealUse; // Retrieve geometric features of input cursor const double* origin = inCursor->GetOrigin(); const double* size = inCursor->GetSize(); // Check whether child is intersected by plane if ((origin[axis] < inter && (origin[axis] + size[axis] > inter)) || vtkMathUtilities::FuzzyCompare(origin[axis] + size[axis], inter)) { // Child is intersected by plane, descend into current child outCursor->ToChild(outChild); // Recurse this->RecursivelyProcessTree(inCursor, outCursor); // Return to parent outCursor->ToParent(); // Increment output children count ++outChild; } inCursor->ToParent(); } // inChild } // if ( ! cursor->IsLeaf() ) } VTK_ABI_NAMESPACE_END