// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkHyperTreeGrid.h" #include "vtkBitArray.h" #include "vtkBoundingBox.h" #include "vtkCellData.h" #include "vtkCollection.h" #include "vtkDoubleArray.h" #include "vtkFieldData.h" #include "vtkHyperTree.h" #include "vtkHyperTreeGridNonOrientedCursor.h" #include "vtkHyperTreeGridNonOrientedGeometryCursor.h" #include "vtkHyperTreeGridNonOrientedMooreSuperCursor.h" #include "vtkHyperTreeGridNonOrientedMooreSuperCursorLight.h" #include "vtkHyperTreeGridNonOrientedUnlimitedGeometryCursor.h" #include "vtkHyperTreeGridNonOrientedUnlimitedMooreSuperCursor.h" #include "vtkHyperTreeGridNonOrientedVonNeumannSuperCursor.h" #include "vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight.h" #include "vtkHyperTreeGridOrientedCursor.h" #include "vtkHyperTreeGridOrientedGeometryCursor.h" #include "vtkHyperTreeGridScales.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationDoubleVectorKey.h" #include "vtkInformationIntegerKey.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include "vtkStructuredData.h" #include "vtkUnsignedCharArray.h" #include #include #include VTK_ABI_NAMESPACE_BEGIN vtkInformationKeyMacro(vtkHyperTreeGrid, LEVELS, Integer); vtkInformationKeyMacro(vtkHyperTreeGrid, DIMENSION, Integer); vtkInformationKeyMacro(vtkHyperTreeGrid, ORIENTATION, Integer); vtkInformationKeyRestrictedMacro(vtkHyperTreeGrid, SIZES, DoubleVector, 3); vtkStandardNewMacro(vtkHyperTreeGrid); vtkCxxSetSmartPointerMacro(vtkHyperTreeGrid, XCoordinates, vtkDataArray); vtkCxxSetSmartPointerMacro(vtkHyperTreeGrid, YCoordinates, vtkDataArray); vtkCxxSetSmartPointerMacro(vtkHyperTreeGrid, ZCoordinates, vtkDataArray); void vtkHyperTreeGrid::CopyCoordinates(const vtkHyperTreeGrid* output) { this->SetXCoordinates(output->XCoordinates); this->SetYCoordinates(output->YCoordinates); this->SetZCoordinates(output->ZCoordinates); } void vtkHyperTreeGrid::SetFixedCoordinates(unsigned int axis, double value) { vtkNew zeros; zeros->SetNumberOfValues(1); zeros->SetValue(0, value); switch (axis) { case 0: { this->SetXCoordinates(zeros); break; } case 1: { this->SetYCoordinates(zeros); break; } case 2: { this->SetZCoordinates(zeros); break; } default: { assert("pre: invalid_axis" && axis < 3); } } } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetMask(vtkBitArray* mask) { vtkSetSmartPointerBodyMacro(Mask, vtkBitArray, mask); this->CleanPureMask(); } //------------------------------------------------------------------------------ vtkBitArray* vtkHyperTreeGrid::GetMask() { return this->Mask; } //------------------------------------------------------------------------------ vtkDataArray* vtkHyperTreeGrid::GetXCoordinates() { return this->XCoordinates; } //------------------------------------------------------------------------------ vtkDataArray* vtkHyperTreeGrid::GetYCoordinates() { return this->YCoordinates; } //------------------------------------------------------------------------------ vtkDataArray* vtkHyperTreeGrid::GetZCoordinates() { return this->ZCoordinates; } // Helper macros to quickly fetch a HT at a given index or iterator #define GetHyperTreeFromOtherMacro(_obj_, _index_) \ (static_cast(_obj_->HyperTrees.find(_index_) != _obj_->HyperTrees.end() \ ? _obj_->HyperTrees[_index_] \ : nullptr)) #define GetHyperTreeFromThisMacro(_index_) GetHyperTreeFromOtherMacro(this, _index_) //------------------------------------------------------------------------------ vtkHyperTreeGrid::vtkHyperTreeGrid() : XCoordinates(vtkSmartPointer::New()) , YCoordinates(vtkSmartPointer::New()) , ZCoordinates(vtkSmartPointer::New()) { // Interface array names // Primal grid geometry this->WithCoordinates = true; this->XCoordinates->SetNumberOfTuples(1); this->XCoordinates->SetTuple1(0, 0.0); this->YCoordinates->SetNumberOfTuples(1); this->YCoordinates->SetTuple1(0, 0.0); this->ZCoordinates->SetNumberOfTuples(1); this->ZCoordinates->SetTuple1(0, 0.0); this->TreeGhostArrayCached = false; // ----------------------------------------------- // RectilinearGrid // ----------------------------------------------- // Invalid default grid parameters to force actual initialization this->Dimension = 0; this->Dimensions[0] = 0; // Just used by GetDimensions this->Dimensions[1] = 0; this->Dimensions[2] = 0; this->CellDims[0] = 0; // Just used by GetCellDims this->CellDims[1] = 0; this->CellDims[2] = 0; this->Axis[0] = std::numeric_limits::max(); this->Axis[1] = std::numeric_limits::max(); int extent[6] = { 0, -1, 0, -1, 0, -1 }; memcpy(this->Extent, extent, 6 * sizeof(int)); this->DataDescription = vtkStructuredData::VTK_STRUCTURED_EMPTY; this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_3D_EXTENT); this->Information->Set(vtkDataObject::DATA_EXTENT(), this->Extent, 6); // Generate default information vtkMath::UninitializeBounds(this->Bounds); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::Initialize() { this->Superclass::Initialize(); // DataObject Initialize will not do CellData this->CellData->Initialize(); // Delete existing trees this->HyperTrees.clear(); // Grid topology this->TransposedRootIndexing = false; // Invalid default grid parameters to force actual initialization this->Orientation = std::numeric_limits::max(); this->BranchFactor = 0; this->NumberOfChildren = 0; // Depth limiter this->DepthLimiter = std::numeric_limits::max(); // Masked primal leaves this->SetMask(nullptr); // No interface by default this->HasInterface = false; // Interface array names this->InterfaceNormalsName = nullptr; this->InterfaceInterceptsName = nullptr; // Primal grid geometry this->WithCoordinates = true; // Might be better to set coordinates using this->SetXCoordinates(), // but there is currently a conflict with vtkUniformHyperTreeGrid // which inherits from vtkHyperTreeGrid. // To be fixed when a better inheritance tree is implemented. this->XCoordinates = vtkSmartPointer::New(); this->XCoordinates->SetNumberOfTuples(1); this->XCoordinates->SetTuple1(0, 0.0); this->YCoordinates = vtkSmartPointer::New(); this->YCoordinates->SetNumberOfTuples(1); this->YCoordinates->SetTuple1(0, 0.0); this->ZCoordinates = vtkSmartPointer::New(); this->ZCoordinates->SetNumberOfTuples(1); this->ZCoordinates->SetTuple1(0, 0.0); // ----------------------------------------------- // RectilinearGrid // ----------------------------------------------- // Invalid default grid parameters to force actual initialization this->Dimension = 0; this->Dimensions[0] = 0; // Just used by GetDimensions this->Dimensions[1] = 0; this->Dimensions[2] = 0; this->CellDims[0] = 0; // Just used by GetCellDims this->CellDims[1] = 0; this->CellDims[2] = 0; this->Axis[0] = std::numeric_limits::max(); this->Axis[1] = std::numeric_limits::max(); int extent[6] = { 0, -1, 0, -1, 0, -1 }; memcpy(this->Extent, extent, 6 * sizeof(int)); this->DataDescription = vtkStructuredData::VTK_STRUCTURED_EMPTY; this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_3D_EXTENT); this->Information->Set(vtkDataObject::DATA_EXTENT(), this->Extent, 6); // Generate default information vtkMath::UninitializeBounds(this->Bounds); this->Center[0] = 0.0; this->Center[1] = 0.0; this->Center[2] = 0.0; } //------------------------------------------------------------------------------ vtkHyperTreeGrid::~vtkHyperTreeGrid() { this->CleanPureMask(); this->vtkHyperTreeGrid::SetInterfaceNormalsName(nullptr); this->vtkHyperTreeGrid::SetInterfaceInterceptsName(nullptr); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Dimension: " << this->Dimension << endl; os << indent << "Orientation: " << this->Orientation << endl; os << indent << "BranchFactor: " << this->BranchFactor << endl; os << indent << "Dimensions: " << this->Dimensions[0] << "," << this->Dimensions[1] << "," << this->Dimensions[2] << endl; os << indent << "Extent: " << this->Extent[0] << "," << this->Extent[1] << "," << this->Extent[2] << "," << this->Extent[3] << "," << this->Extent[4] << "," << this->Extent[5] << endl; os << indent << "CellDims: " << this->CellDims[0] << "," << this->CellDims[1] << "," << this->CellDims[2] << endl; os << indent << "Axis: " << this->Axis[0] << "," << this->Axis[1] << endl; os << indent << "Mask:\n"; if (this->Mask) { this->Mask->PrintSelf(os, indent.GetNextIndent()); } if (this->PureMask) { this->PureMask->PrintSelf(os, indent.GetNextIndent()); } os << indent << "HasInterface: " << (this->HasInterface ? "true" : "false") << endl; if (this->WithCoordinates) { os << indent << "XCoordinates:" << endl; if (this->XCoordinates) { this->XCoordinates->PrintSelf(os, indent.GetNextIndent()); } os << indent << "YCoordinates:" << endl; if (this->YCoordinates) { this->YCoordinates->PrintSelf(os, indent.GetNextIndent()); } os << indent << "ZCoordinates:" << endl; if (this->ZCoordinates) { this->ZCoordinates->PrintSelf(os, indent.GetNextIndent()); } } else { os << indent << "Non explicit coordinates" << endl; } os << indent << "HyperTrees: " << this->HyperTrees.size() << endl; os << indent << "CellData:" << endl; this->CellData->PrintSelf(os, indent.GetNextIndent()); } //------------------------------------------------------------------------------ vtkHyperTreeGrid* vtkHyperTreeGrid::GetData(vtkInformation* info) { return info ? vtkHyperTreeGrid::SafeDownCast(info->Get(DATA_OBJECT())) : nullptr; } //------------------------------------------------------------------------------ vtkHyperTreeGrid* vtkHyperTreeGrid::GetData(vtkInformationVector* v, int i) { return vtkHyperTreeGrid::GetData(v->GetInformationObject(i)); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::CopyEmptyStructure(vtkDataObject* ds) { vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast(ds); if (!htg) { vtkErrorMacro("Unable to copy empty structure of a non-HTG or empty data object in an HTG"); return; } // RectilinearGrid memcpy(this->Dimensions, htg->GetDimensions(), 3 * sizeof(unsigned int)); this->SetExtent(htg->GetExtent()); memcpy(this->CellDims, htg->GetCellDims(), 3 * sizeof(unsigned int)); this->DataDescription = htg->DataDescription; this->WithCoordinates = htg->WithCoordinates; if (this->WithCoordinates) { this->GetXCoordinates()->DeepCopy(htg->XCoordinates); this->GetYCoordinates()->DeepCopy(htg->YCoordinates); this->GetZCoordinates()->DeepCopy(htg->ZCoordinates); } // Copy grid parameters this->BranchFactor = htg->BranchFactor; this->Dimension = htg->Dimension; this->Orientation = htg->Orientation; memcpy(this->Extent, htg->GetExtent(), 6 * sizeof(int)); memcpy(this->Axis, htg->GetAxes(), 2 * sizeof(unsigned int)); this->NumberOfChildren = htg->NumberOfChildren; this->DepthLimiter = htg->DepthLimiter; this->TransposedRootIndexing = htg->TransposedRootIndexing; this->HasInterface = htg->HasInterface; this->SetInterfaceNormalsName(htg->InterfaceNormalsName); this->SetInterfaceInterceptsName(htg->InterfaceInterceptsName); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::CopyStructure(vtkDataObject* ds) { vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast(ds); if (!htg) { vtkErrorMacro("Unable to copy structure of a non-HTG or empty data object in an HTG"); return; } // RectilinearGrid memcpy(this->Dimensions, htg->GetDimensions(), 3 * sizeof(unsigned int)); this->SetExtent(htg->GetExtent()); memcpy(this->CellDims, htg->GetCellDims(), 3 * sizeof(unsigned int)); this->DataDescription = htg->DataDescription; this->WithCoordinates = htg->WithCoordinates; if (this->WithCoordinates) { this->GetXCoordinates()->DeepCopy(htg->XCoordinates); this->GetYCoordinates()->DeepCopy(htg->YCoordinates); this->GetZCoordinates()->DeepCopy(htg->ZCoordinates); } // Copy grid parameters this->BranchFactor = htg->BranchFactor; this->Dimension = htg->Dimension; this->Orientation = htg->Orientation; memcpy(this->Extent, htg->GetExtent(), 6 * sizeof(int)); memcpy(this->Axis, htg->GetAxes(), 2 * sizeof(unsigned int)); this->NumberOfChildren = htg->NumberOfChildren; this->DepthLimiter = htg->DepthLimiter; this->TransposedRootIndexing = htg->TransposedRootIndexing; this->HasInterface = htg->HasInterface; this->SetInterfaceNormalsName(htg->InterfaceNormalsName); this->SetInterfaceInterceptsName(htg->InterfaceInterceptsName); // Shallow copy masked if needed this->SetMask(htg->GetMask()); vtkSetObjectBodyMacro(PureMask, vtkBitArray, htg->GetPureMask()); // Search for hyper tree with given index this->HyperTrees.clear(); for (std::map>::const_iterator it = htg->HyperTrees.begin(); it != htg->HyperTrees.end(); ++it) { vtkNew tree; if (!tree->Initialize(this->BranchFactor, this->Dimension)) { vtkGenericWarningMacro("Failed to copy structure."); break; } tree->CopyStructure(it->second); this->HyperTrees[it->first] = tree; } if (htg->HasAnyGhostCells()) { this->GetCellData()->AddArray(htg->GetGhostCells()); } } // ============================================================================ // BEGIN - RectilinearGrid common API // ============================================================================ void vtkHyperTreeGrid::SetDimensions(const int dim[3]) { this->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetDimensions(int i, int j, int k) { this->SetExtent(0, i - 1, 0, j - 1, 0, k - 1); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetDimensions(const unsigned int dim[3]) { this->SetExtent(0, static_cast(dim[0]) - 1, 0, static_cast(dim[1]) - 1, 0, static_cast(dim[2]) - 1); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetDimensions(unsigned int i, unsigned int j, unsigned int k) { this->SetExtent( 0, static_cast(i) - 1, 0, static_cast(j) - 1, 0, static_cast(k) - 1); } //------------------------------------------------------------------------------ const unsigned int* vtkHyperTreeGrid::GetDimensions() const { return this->Dimensions; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetDimensions(int dim[3]) const { dim[0] = static_cast(this->Dimensions[0]); dim[1] = static_cast(this->Dimensions[1]); dim[2] = static_cast(this->Dimensions[2]); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetDimensions(unsigned int dim[3]) const { dim[0] = this->Dimensions[0]; dim[1] = this->Dimensions[1]; dim[2] = this->Dimensions[2]; } //------------------------------------------------------------------------------ const unsigned int* vtkHyperTreeGrid::GetCellDims() const { return this->CellDims; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetCellDims(int cellDims[3]) const { cellDims[0] = static_cast(this->CellDims[0]); cellDims[1] = static_cast(this->CellDims[1]); cellDims[2] = static_cast(this->CellDims[2]); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetCellDims(unsigned int cellDims[3]) const { cellDims[0] = this->CellDims[0]; cellDims[1] = this->CellDims[1]; cellDims[2] = this->CellDims[2]; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetExtent(const int extent[6]) { int description = vtkStructuredData::SetExtent(const_cast(extent), this->Extent); // why vtkStructuredData::SetExtent don't take const int* ? if (description < 0) // improperly specified { vtkErrorMacro(<< "Bad extent, retaining previous values"); return; } this->Dimension = 0; this->Axis[0] = std::numeric_limits::max(); this->Axis[1] = std::numeric_limits::max(); for (unsigned int i = 0; i < 3; ++i) { this->Dimensions[i] = static_cast(extent[2 * i + 1] - extent[2 * i] + 1); if (this->Dimensions[i] == 1) { this->CellDims[i] = 1; } else { this->CellDims[i] = this->Dimensions[i] - 1; if (this->Dimension == 2) { this->Axis[0] = std::numeric_limits::max(); this->Axis[1] = std::numeric_limits::max(); } else { this->Axis[this->Dimension] = i; } ++this->Dimension; } } assert("post: valid_axis" && (this->Dimension != 3 || (this->Axis[0] == std::numeric_limits::max() && this->Axis[1] == std::numeric_limits::max()))); assert("post: valid_axis" && (this->Dimension != 2 || (this->Axis[0] != std::numeric_limits::max() && this->Axis[1] != std::numeric_limits::max()))); assert("post: valid_axis" && (this->Dimension != 1 || (this->Axis[0] != std::numeric_limits::max() && this->Axis[1] == std::numeric_limits::max()))); switch (this->Dimension) { case 1: this->Orientation = this->Axis[0]; break; case 2: this->Orientation = 0; for (unsigned int i = 0; i < 2; ++i) { if (this->Orientation == this->Axis[i]) { ++this->Orientation; } } // If normal to the HTG is y, we right now have HTG spanned by (x,y) // We swap them to have a direct frame spanning the HTG if (this->Orientation == 1) { std::swap(this->Axis[0], this->Axis[1]); } break; default: break; } assert("post: valid_axis" && (this->Dimension != 2 || (this->Axis[0] == (this->Orientation + 1) % 3 && this->Axis[1] == (this->Orientation + 2) % 3))); // Make sure that number of children is factor^dimension this->NumberOfChildren = this->BranchFactor; for (unsigned int i = 1; i < this->Dimension; ++i) { this->NumberOfChildren *= this->BranchFactor; } if (description == vtkStructuredData::VTK_STRUCTURED_UNCHANGED) { return; } this->Modified(); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetExtent(int i0, int i1, int j0, int j1, int k0, int k1) { int extent[6]; extent[0] = i0; extent[1] = i1; extent[2] = j0; extent[3] = j1; extent[4] = k0; extent[5] = k1; this->SetExtent(extent); } // ============================================================================ // END - RectilinearGrid common API // ============================================================================ //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetBranchFactor(unsigned int factor) { assert("pre: valid_factor" && factor >= 2 && factor <= 3); // Make sure that number of children is factor^dimension unsigned int num = factor; for (unsigned int i = 1; i < this->Dimension; ++i) { num *= factor; } // Bail out early if nothing was changed if (this->BranchFactor == factor && this->NumberOfChildren == num) { return; } // Otherwise modify as needed this->BranchFactor = factor; this->NumberOfChildren = num; this->Modified(); } //------------------------------------------------------------------------------ bool vtkHyperTreeGrid::HasMask() { return this->Mask && this->Mask->GetNumberOfTuples() != 0; } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetMaxNumberOfTrees() const { return this->CellDims[0] * this->CellDims[1] * this->CellDims[2]; } //------------------------------------------------------------------------------ unsigned int vtkHyperTreeGrid::GetNumberOfLevels(vtkIdType index) { vtkHyperTree* tree = GetHyperTreeFromThisMacro(index); return tree ? tree->GetNumberOfLevels() : 0; } //------------------------------------------------------------------------------ unsigned int vtkHyperTreeGrid::GetNumberOfLevels() { vtkIdType nLevels = 0; // Iterate over all individual trees vtkHyperTreeGrid::vtkHyperTreeGridIterator it; this->InitializeTreeIterator(it); vtkHyperTree* tree = nullptr; while ((tree = it.GetNextTree()) != nullptr) { const vtkIdType nl = tree->GetNumberOfLevels(); nLevels = std::max(nl, nLevels); } // while (it.GetNextTree(inIndex)) return nLevels; } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetNumberOfNonEmptyTrees() { return this->HyperTrees.size(); } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetNumberOfCells() { vtkIdType nVertices = 0; // Iterate over all trees in grid vtkHyperTreeGridIterator it; it.Initialize(this); while (vtkHyperTree* tree = it.GetNextTree()) { nVertices += tree->GetNumberOfVertices(); } return nVertices; } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetNumberOfLeaves() { vtkIdType nLeaves = 0; // Iterate over all trees in grid vtkHyperTreeGridIterator it; it.Initialize(this); while (vtkHyperTree* tree = it.GetNextTree()) { nLeaves += tree->GetNumberOfLeaves(); } return nLeaves; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeTreeIterator(vtkHyperTreeGridIterator& it) { it.Initialize(this); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeOrientedCursor( vtkHyperTreeGridOrientedCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridOrientedCursor* vtkHyperTreeGrid::NewOrientedCursor(vtkIdType index, bool create) { vtkHyperTreeGridOrientedCursor* cursor = vtkHyperTreeGridOrientedCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeOrientedGeometryCursor( vtkHyperTreeGridOrientedGeometryCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridOrientedGeometryCursor* vtkHyperTreeGrid::NewOrientedGeometryCursor( vtkIdType index, bool create) { vtkHyperTreeGridOrientedGeometryCursor* cursor = vtkHyperTreeGridOrientedGeometryCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedCursor( vtkHyperTreeGridNonOrientedCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedCursor* vtkHyperTreeGrid::NewNonOrientedCursor( vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedCursor* cursor = vtkHyperTreeGridNonOrientedCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedGeometryCursor( vtkHyperTreeGridNonOrientedGeometryCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedGeometryCursor* vtkHyperTreeGrid::NewNonOrientedGeometryCursor( vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedGeometryCursor* cursor = vtkHyperTreeGridNonOrientedGeometryCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedUnlimitedGeometryCursor( vtkHyperTreeGridNonOrientedUnlimitedGeometryCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedUnlimitedGeometryCursor* vtkHyperTreeGrid::NewNonOrientedUnlimitedGeometryCursor(vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedUnlimitedGeometryCursor* cursor = vtkHyperTreeGridNonOrientedUnlimitedGeometryCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ unsigned int vtkHyperTreeGrid::RecurseDichotomic( double value, vtkDoubleArray* coord, double tol, unsigned int iBegin, unsigned int iEnd) const { if (iBegin == iEnd - 1) { return iBegin; } unsigned int iMid = iBegin + (iEnd - iBegin) / 2; double currentTol = (iMid == static_cast(coord->GetNumberOfTuples() - 1)) ? tol : 0.0; if (value < (coord->GetValue(iMid) + currentTol)) { return this->RecurseDichotomic(value, coord, tol, iBegin, iMid); } else { return this->RecurseDichotomic(value, coord, tol, iMid, iEnd); } } unsigned int vtkHyperTreeGrid::FindDichotomic(double value, vtkDataArray* tmp, double tol) const { vtkDoubleArray* coord = vtkDoubleArray::SafeDownCast(tmp); if (value < (coord->GetValue(0) - tol) || value > (coord->GetValue(coord->GetNumberOfTuples() - 1) + tol)) { return std::numeric_limits::max(); } return RecurseDichotomic(value, coord, tol, 0, coord->GetNumberOfTuples()); } unsigned int vtkHyperTreeGrid::FindDichotomicX(double value, double tol) const { assert("pre: exist_coordinates_explict" && this->WithCoordinates); return this->FindDichotomic(value, this->XCoordinates, tol); } unsigned int vtkHyperTreeGrid::FindDichotomicY(double value, double tol) const { assert("pre: exist_coordinates_explict" && this->WithCoordinates); return this->FindDichotomic(value, this->YCoordinates, tol); } unsigned int vtkHyperTreeGrid::FindDichotomicZ(double value, double tol) const { assert("pre: exist_coordinates_explict" && this->WithCoordinates); return this->FindDichotomic(value, this->ZCoordinates, tol); } vtkHyperTreeGridNonOrientedGeometryCursor* vtkHyperTreeGrid::FindNonOrientedGeometryCursor( double x[3]) { unsigned int i = this->FindDichotomicX(x[0]); if (i == std::numeric_limits::max()) { return nullptr; } unsigned int j = this->FindDichotomicY(x[1]); if (j == std::numeric_limits::max()) { return nullptr; } unsigned int k = this->FindDichotomicZ(x[2]); if (k == std::numeric_limits::max()) { return nullptr; } vtkIdType index; this->GetIndexFromLevelZeroCoordinates(index, i, j, k); vtkHyperTreeGridNonOrientedGeometryCursor* cursor = vtkHyperTreeGridNonOrientedGeometryCursor::New(); cursor->Initialize(this, index, false); switch (this->BranchFactor) { case 2: { while (!cursor->IsLeaf()) { double p[3]; cursor->GetPoint(p); unsigned int ichild = 0; if (x[0] <= p[0]) { } else { ichild = 1; } if (x[1] <= p[1]) { } else { ichild = 2 + ichild; } if (x[2] <= p[2]) { } else { ichild = 4 + ichild; } cursor->ToChild(ichild); } break; } case 3: { assert("pre: not_implemented_raf_3" && false); break; } default: break; } return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedVonNeumannSuperCursor( vtkHyperTreeGridNonOrientedVonNeumannSuperCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedVonNeumannSuperCursor* vtkHyperTreeGrid::NewNonOrientedVonNeumannSuperCursor(vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedVonNeumannSuperCursor* cursor = vtkHyperTreeGridNonOrientedVonNeumannSuperCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedVonNeumannSuperCursorLight( vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight* vtkHyperTreeGrid::NewNonOrientedVonNeumannSuperCursorLight(vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight* cursor = vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedMooreSuperCursor( vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedMooreSuperCursor* vtkHyperTreeGrid::NewNonOrientedMooreSuperCursor( vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor = vtkHyperTreeGridNonOrientedMooreSuperCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedMooreSuperCursorLight( vtkHyperTreeGridNonOrientedMooreSuperCursorLight* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedMooreSuperCursorLight* vtkHyperTreeGrid::NewNonOrientedMooreSuperCursorLight(vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedMooreSuperCursorLight* cursor = vtkHyperTreeGridNonOrientedMooreSuperCursorLight::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeNonOrientedUnlimitedMooreSuperCursor( vtkHyperTreeGridNonOrientedUnlimitedMooreSuperCursor* cursor, vtkIdType index, bool create) { cursor->Initialize(this, index, create); } //------------------------------------------------------------------------------ vtkHyperTreeGridNonOrientedUnlimitedMooreSuperCursor* vtkHyperTreeGrid::NewNonOrientedUnlimitedMooreSuperCursor(vtkIdType index, bool create) { vtkHyperTreeGridNonOrientedUnlimitedMooreSuperCursor* cursor = vtkHyperTreeGridNonOrientedUnlimitedMooreSuperCursor::New(); cursor->Initialize(this, index, create); return cursor; } //------------------------------------------------------------------------------ vtkHyperTree* vtkHyperTreeGrid::GetTree(vtkIdType index, bool create) { assert("pre: not_tree" && index < this->GetMaxNumberOfTrees()); // Wrap convenience macro for outside use vtkHyperTree* tree = GetHyperTreeFromThisMacro(index); // Create a new cursor if only required to do so if (create && !tree) { tree = vtkHyperTree::New(); if (!tree->Initialize(this->BranchFactor, this->Dimension)) { vtkGenericWarningMacro("Failed to create hyper tree."); return nullptr; } tree->SetTreeIndex(index); this->HyperTrees[index] = tree; tree->Delete(); if (!tree->HasScales()) { double origin[3]; double scale[3]; this->GetLevelZeroOriginAndSizeFromIndex(tree->GetTreeIndex(), origin, scale); tree->SetScales(std::make_shared(this->BranchFactor, scale)); } } return tree; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::SetTree(vtkIdType index, vtkHyperTree* tree) { // Assign given tree at given index of hyper tree grid tree->SetTreeIndex(index); this->HyperTrees[index] = tree; } //------------------------------------------------------------------------------ size_t vtkHyperTreeGrid::RemoveTree(vtkIdType index) { return this->HyperTrees.erase(index); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::ShallowCopy(vtkDataObject* src) { vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast(src); assert("src_same_type" && htg); // Copy member variables this->CopyStructure(htg); this->CellData->ShallowCopy(htg->GetCellData()); // Call superclass this->Superclass::ShallowCopy(src); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::DeepCopy(vtkDataObject* src) { assert("pre: src_exists" && src != nullptr); vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast(src); assert("pre: same_type" && htg != nullptr); // Copy grid parameters this->Dimension = htg->Dimension; this->Orientation = htg->Orientation; this->BranchFactor = htg->BranchFactor; this->NumberOfChildren = htg->NumberOfChildren; this->DepthLimiter = htg->DepthLimiter; this->TransposedRootIndexing = htg->TransposedRootIndexing; memcpy(this->Axis, htg->GetAxes(), 2 * sizeof(unsigned int)); this->HasInterface = htg->HasInterface; this->SetInterfaceNormalsName(htg->InterfaceNormalsName); this->SetInterfaceInterceptsName(htg->InterfaceInterceptsName); if (htg->Mask) { vtkNew mask; this->SetMask(mask); this->Mask->DeepCopy(htg->Mask); } if (htg->PureMask) { if (!this->PureMask) { this->PureMask = vtkBitArray::New(); } this->PureMask->DeepCopy(htg->PureMask); } this->CellData->DeepCopy(htg->GetCellData()); // Rectilinear part memcpy(this->Dimensions, htg->GetDimensions(), 3 * sizeof(unsigned int)); memcpy(this->Extent, htg->GetExtent(), 6 * sizeof(int)); memcpy(this->CellDims, htg->GetCellDims(), 3 * sizeof(unsigned int)); this->DataDescription = htg->DataDescription; this->WithCoordinates = htg->WithCoordinates; if (this->WithCoordinates) { vtkDoubleArray* s; s = vtkDoubleArray::New(); s->DeepCopy(htg->XCoordinates); this->SetXCoordinates(s); s->Delete(); s = vtkDoubleArray::New(); s->DeepCopy(htg->YCoordinates); this->SetYCoordinates(s); s->Delete(); s = vtkDoubleArray::New(); s->DeepCopy(htg->ZCoordinates); this->SetZCoordinates(s); s->Delete(); } // Call superclass this->Superclass::DeepCopy(src); this->HyperTrees.clear(); for (std::map>::const_iterator it = htg->HyperTrees.begin(); it != htg->HyperTrees.end(); ++it) { vtkNew tree; if (!tree->Initialize(this->BranchFactor, this->Dimension)) { vtkGenericWarningMacro("Failed to deep copy."); break; } tree->CopyStructure(it->second); this->HyperTrees[it->first] = tree; } } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::CleanPureMask() { if (this->PureMask) { this->PureMask->Delete(); this->PureMask = nullptr; } } //------------------------------------------------------------------------------ bool vtkHyperTreeGrid::RecursivelyInitializePureMask( vtkHyperTreeGridNonOrientedCursor* cursor, vtkDataArray* intercepts) { // Retrieve mask value at cursor vtkIdType id = cursor->GetGlobalNodeIndex(); // 0 isn't masked : if not exist Mask or no masked // 1 is masked : if exist Mask and masked bool mask = this->HasMask() && this->Mask->GetValue(id); // Check masked if (mask) { // If the cell is masked then the cell is not a pure material cell, // set PureMask to true this->PureMask->SetTuple1(id, true); return true; } // Check is leaf if (cursor->IsLeaf()) { // Check exist material interface intercepts if (intercepts) { if (intercepts->GetNumberOfComponents() != 3) { vtkErrorMacro("Intercepts array must have 3 components, but has " << intercepts->GetNumberOfComponents()); return mask; } double values[3]; intercepts->GetTuple(id, values); // If the type value is less than 2 then the cell has // one or two interfaces, it is not a pure material cell // (this cell is mixed), set PureMask to true; // else set PureMask to false mask = (values[2] < 2); } this->PureMask->SetTuple1(id, mask); return mask; } // The cell is coarse, iterate over all children unsigned int numChildren = this->GetNumberOfChildren(); for (unsigned int child = 0; child < numChildren; ++child) { cursor->ToChild(child); // Recursively initialize pure material mask // The initialization of the PureMask for a coarse cell // depends on the values associated with each of // its children. As soon as one of her daughters is PureMask // then she is too. // WARNING Nevertheless, it is essential to continue the // in-depth journey in order to update all the values of // PureMask offering the possibility of optimization at // a higher level. mask |= this->RecursivelyInitializePureMask(cursor, intercepts); cursor->ToParent(); } // Set and return pure material mask with recursively computed value this->PureMask->SetTuple1(id, mask); return mask; } //------------------------------------------------------------------------------ vtkBitArray* vtkHyperTreeGrid::GetPureMask() { // Check whether a pure material mask was initialized // If not, then create one if (this->PureMask) { // Return existing pure material mask return this->PureMask; } else { this->PureMask = vtkBitArray::New(); this->PureMask->SetName("vtkPureMask"); } // Do not use GetNumberOfCells method because it is not the real size of a value // field due to the possible use of an indirection array (GlobalNodeIndex // not implicit). // Prefer to use GetGlobalNodeIndexMax()+1 which is one value above the highest // index this->PureMask->SetNumberOfTuples(this->GetGlobalNodeIndexMax() + 1); // Check material interface intercepts // The first two fields of Intercepts describe the first and the // second distance interface to origin. // The third field describes the type of interface. If the type // value is greater than or equal to 2, the cell does not describe // an interface. She is pure material. // For more detail look at the vtkHyperTreeGridGeometry filter. vtkDataArray* intercepts = nullptr; if (this->HasInterface) { intercepts = this->GetCellData()->GetArray(this->InterfaceInterceptsName); if (intercepts) { if (intercepts->GetNumberOfComponents() != 3) { intercepts = nullptr; } else { vtkDataArray* normals = this->GetCellData()->GetArray(this->InterfaceNormalsName); if (!normals || normals->GetNumberOfComponents() != 3) { intercepts = nullptr; } } } } // Iterate over hyper tree grid vtkIdType index; vtkHyperTreeGridIterator it; it.Initialize(this); vtkNew cursor; while (it.GetNextTree(index)) { // Create cursor instance over current hyper tree this->InitializeNonOrientedCursor(cursor, index); // Recursively initialize pure material mask this->RecursivelyInitializePureMask(cursor, intercepts); } // Return created pure material mask return this->PureMask; } //------------------------------------------------------------------------------ unsigned long vtkHyperTreeGrid::GetActualMemorySizeBytes() { size_t size = 0; // in bytes size += this->vtkDataObject::GetActualMemorySize() << 10; // Iterate over all trees in grid vtkHyperTreeGridIterator it; it.Initialize(this); while (vtkHyperTree* tree = it.GetNextTree()) { size += tree->GetActualMemorySizeBytes(); } // Approximate map memory size size += this->HyperTrees.size() * sizeof(vtkIdType) * 3; size += sizeof(bool); if (this->XCoordinates) { size += this->XCoordinates->GetActualMemorySize() << 10; } if (this->YCoordinates) { size += this->YCoordinates->GetActualMemorySize() << 10; } if (this->ZCoordinates) { size += this->ZCoordinates->GetActualMemorySize() << 10; } if (this->Mask) { size += this->Mask->GetActualMemorySize() << 10; } size += this->CellData->GetActualMemorySize() << 10; return static_cast(size); } //------------------------------------------------------------------------------ unsigned long vtkHyperTreeGrid::GetActualMemorySize() { // in kilibytes return (this->GetActualMemorySizeBytes() >> 10); } //------------------------------------------------------------------------------ bool vtkHyperTreeGrid::SupportsGhostArray(int type) { if (type == CELL) { return true; } return false; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetIndexFromLevelZeroCoordinates( vtkIdType& treeindex, unsigned int i, unsigned int j, unsigned int k) const { // Distinguish between two cases depending on indexing order if (this->TransposedRootIndexing) { treeindex = static_cast(k) + static_cast(this->CellDims[2]) * (static_cast(j) + static_cast(i) * static_cast(this->CellDims[1])); } else { treeindex = static_cast(i) + static_cast(this->CellDims[0]) * (static_cast(j) + static_cast(k) * static_cast(this->CellDims[1])); } } //------------------------------------------------------------------------------ // The shift is a request along each of the axes I,J,K // which in 2D depending on the Orientation corresponds to an IJ request which // translates according to the orientation value // The call to this method must be consistent with the existence of a neighboring // cell following the requested shift. vtkIdType vtkHyperTreeGrid::GetShiftedLevelZeroIndex( vtkIdType treeindex, int di, int dj, int dk) const { unsigned int local_i, local_j, local_k; // It is very important to use the GetLevelZeroCoordinatesFromIndex method // to convert HyperTree indexes to HyperTree coordinates. // This method takes into account the choice made for TransposedRootIndexing. this->GetLevelZeroCoordinatesFromIndex(treeindex, local_i, local_j, local_k); std::array local_ijk{ local_i, local_j, local_k }; switch (this->Dimension) { case 1: { // The axis used for 1D assert(di >= 0 || ("there is no neighbor axis 0" && local_ijk[this->GetAxes()[0]] >= static_cast(-di))); local_ijk[this->GetAxes()[0]] += di; // No expected values assert(dj == 0); assert(dk == 0); break; } case 2: { // Axes used for 2D assert(di >= 0 || ("there is no neighbor axis 0" && local_ijk[this->GetAxes()[0]] >= static_cast(-di))); local_ijk[this->GetAxes()[0]] += di; assert(dj >= 0 || ("there is no neighbor axis 1" && local_ijk[this->GetAxes()[1]] >= static_cast(-dj))); local_ijk[this->GetAxes()[1]] += dj; // No expected values assert(dk == 0); break; } case 3: { assert(di >= 0 || ("there is no neighbor before axis i" && local_ijk[0] >= static_cast(-di))); local_ijk[0] += di; assert(dj >= 0 || ("there is no neighbor before axis j" && local_ijk[1] >= static_cast(-dj))); local_ijk[1] += dj; assert(dk >= 0 || ("there is no neighbor before axis k" && local_ijk[2] >= static_cast(-dk))); local_ijk[2] += dk; break; } default: break; } vtkIdType shifttreeindex; // It is very important to use the GetIndexFromLevelZeroCoordinates method, // GetLevelZeroCoordinatesFromIndex's reciprocal method to convert HyperTree // coordinates to HyperTree indexes. // This method takes into account the choice made for TransposedRootIndexing. this->GetIndexFromLevelZeroCoordinates(shifttreeindex, local_ijk[0], local_ijk[1], local_ijk[2]); return shifttreeindex; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetLevelZeroCoordinatesFromIndex( vtkIdType treeindex, unsigned int& i, unsigned int& j, unsigned int& k) const { // Distinguish between two cases depending on indexing order if (this->TransposedRootIndexing) { unsigned long nbKxJ = static_cast(this->CellDims[2]) * static_cast(this->CellDims[1]); i = static_cast(treeindex / nbKxJ); vtkIdType reste = treeindex - i * nbKxJ; j = static_cast(reste / this->CellDims[2]); k = static_cast(reste - j * this->CellDims[2]); } else { unsigned long nbIxJ = this->CellDims[0] * this->CellDims[1]; k = static_cast(treeindex / nbIxJ); vtkIdType reste = treeindex - k * nbIxJ; j = static_cast(reste / this->CellDims[0]); i = static_cast(reste - j * this->CellDims[0]); } assert(i < this->CellDims[0]); assert(j < this->CellDims[1]); assert(k < this->CellDims[2]); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetLevelZeroOriginAndSizeFromIndex( vtkIdType treeindex, double* Origin, double* Size) { assert("pre: exist_coordinates_explict" && this->WithCoordinates); // Compute origin and size of the cursor unsigned int i, j, k; this->GetLevelZeroCoordinatesFromIndex(treeindex, i, j, k); vtkDataArray* xCoords = this->XCoordinates; vtkDataArray* yCoords = this->YCoordinates; vtkDataArray* zCoords = this->ZCoordinates; Origin[0] = xCoords->GetTuple1(i); Origin[1] = yCoords->GetTuple1(j); Origin[2] = zCoords->GetTuple1(k); if (this->Dimensions[0] == 1) { Size[0] = 0.; } else { Size[0] = xCoords->GetTuple1(i + 1) - Origin[0]; } if (this->Dimensions[1] == 1) { Size[1] = 0.; } else { Size[1] = yCoords->GetTuple1(j + 1) - Origin[1]; } if (this->Dimensions[2] == 1) { Size[2] = 0.; } else { Size[2] = zCoords->GetTuple1(k + 1) - Origin[2]; } } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetLevelZeroOriginFromIndex(vtkIdType treeindex, double* Origin) { assert("pre: exist_coordinates_explict" && this->WithCoordinates); // Compute origin and size of the cursor unsigned int i, j, k; this->GetLevelZeroCoordinatesFromIndex(treeindex, i, j, k); vtkDataArray* xCoords = this->XCoordinates; vtkDataArray* yCoords = this->YCoordinates; vtkDataArray* zCoords = this->ZCoordinates; Origin[0] = xCoords->GetTuple1(i); Origin[1] = yCoords->GetTuple1(j); Origin[2] = zCoords->GetTuple1(k); } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetGlobalNodeIndexMax() { // Iterate over all hyper trees vtkIdType max = 0; vtkHyperTree* crtTree = nullptr; vtkHyperTreeGridIterator it; this->InitializeTreeIterator(it); while ((crtTree = it.GetNextTree())) { max = std::max(max, crtTree->GetGlobalNodeIndexMax()); } // it return max; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::InitializeLocalIndexNode() { // Iterate over all hyper trees vtkIdType local = 0; vtkHyperTree* crtTree = nullptr; vtkHyperTreeGridIterator it; this->InitializeTreeIterator(it); while ((crtTree = it.GetNextTree())) { crtTree->SetGlobalIndexStart(local); local += crtTree->GetNumberOfVertices(); } // it } //============================================================================= // Hyper tree grid iterator // Implemented here because it needs access to the internal classes. // Remark: // - Iterator reference on next HyperTree, // - hence the need to call Initialize() then call GetNextTree(), // with or without output argument, to access the first HT, // - the second HyperTree is accessed by a new call to GetNextTree(), // with or without output argument, // - GetNextTree() when all HypeTrees have been iterated //------------------------------------------------------------------------------ void vtkHyperTreeGrid::vtkHyperTreeGridIterator::Initialize(vtkHyperTreeGrid* grid) { assert(grid != nullptr); this->Grid = grid; this->Iterator = grid->HyperTrees.begin(); } //------------------------------------------------------------------------------ vtkHyperTree* vtkHyperTreeGrid::vtkHyperTreeGridIterator::GetNextTree(vtkIdType& index) { if (this->Iterator == this->Grid->HyperTrees.end()) { return nullptr; } vtkHyperTree* tree = this->Iterator->second.GetPointer(); index = this->Iterator->first; ++this->Iterator; return tree; } //------------------------------------------------------------------------------ vtkHyperTree* vtkHyperTreeGrid::vtkHyperTreeGridIterator::GetNextTree() { vtkIdType index{ 0 }; return GetNextTree(index); } //============================================================================= // Hard-coded child mask bitcodes static constexpr unsigned int HyperTreeGridMask_1_2[2] = { 0x80000000, 0x20000000 }; static constexpr unsigned int HyperTreeGridMask_1_3[3] = { 0x80000000, 0x40000000, 0x20000000 }; static constexpr unsigned int HyperTreeGridMask_2_2[4] = { 0xd0000000, 0x64000000, 0x13000000, 0x05800000 }; static constexpr unsigned int HyperTreeGridMask_2_3[9] = { 0xd0000000, 0x40000000, 0x64000000, 0x10000000, 0x08000000, 0x04000000, 0x13000000, 0x01000000, 0x05800000 }; static constexpr unsigned int HyperTreeGridMask_3_2[8] = { 0xd8680000, 0x6c320000, 0x1b098000, 0x0d82c000, 0x00683600, 0x00321b00, 0x000986c0, 0x0002c360 }; static constexpr unsigned int HyperTreeGridMask_3_3[27] = { 0xd8680000, 0x48200000, 0x6c320000, 0x18080000, 0x08000000, 0x0c020000, 0x1b098000, 0x09008000, 0x0d82c000, 0x00680000, 0x00200000, 0x00320000, 0x00080000, 0x00040000, 0x00020000, 0x00098000, 0x00008000, 0x0002c000, 0x00683600, 0x00201200, 0x00321b00, 0x00080600, 0x00000200, 0x00020300, 0x000986c0, 0x00008240, 0x0002c360 }; static const unsigned int* HyperTreeGridMask[3][2] = { { HyperTreeGridMask_1_2, HyperTreeGridMask_1_3 }, { HyperTreeGridMask_2_2, HyperTreeGridMask_2_3 }, { HyperTreeGridMask_3_2, HyperTreeGridMask_3_3 } }; //------------------------------------------------------------------------------ unsigned int vtkHyperTreeGrid::GetChildMask(unsigned int child) { int i = this->GetDimension() - 1; int j = this->GetBranchFactor() - 2; return HyperTreeGridMask[i][j][child]; } //------------------------------------------------------------------------------ // Helper functions for vtkHyperTreeGrid::GetBounds() namespace { //------------------------------------------------------------------------------ // Recursively traverses a hyper tree, appending geometry bounds to non-masked leaf nodes. void RecursivelyExpandTreeBounds( vtkHyperTreeGridNonOrientedGeometryCursor* cursor, vtkBoundingBox& bounds) { if (cursor->IsLeaf()) { double cursorBounds[6]; cursor->GetBounds(cursorBounds); bounds.AddBounds(cursorBounds); return; } auto childNb = cursor->GetNumberOfChildren(); for (unsigned char itChild = 0; itChild < childNb; itChild++) { cursor->ToChild(itChild); if (!cursor->IsMasked()) { ::RecursivelyExpandTreeBounds(cursor, bounds); } cursor->ToParent(); } } } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::ComputeBounds() { if (this->GetMTime() > this->ComputeTime) { vtkIdType inIndex; vtkHyperTreeGrid::vtkHyperTreeGridIterator it; this->InitializeTreeIterator(it); vtkBoundingBox mergedBounds; while (it.GetNextTree(inIndex)) { auto cursor = vtk::TakeSmartPointer(this->NewNonOrientedGeometryCursor(inIndex)); if (!cursor->IsMasked()) { vtkBoundingBox bounds; ::RecursivelyExpandTreeBounds(cursor, bounds); mergedBounds.AddBox(bounds); } } mergedBounds.GetBounds(this->Bounds); this->ComputeTime.Modified(); } } //------------------------------------------------------------------------------ double* vtkHyperTreeGrid::GetBounds() { this->ComputeBounds(); return this->Bounds; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetBounds(double* obds) { this->ComputeBounds(); memcpy(obds, this->Bounds, 6 * sizeof(double)); } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetGridBounds(double* bounds) { assert("pre: exist_coordinates_explict" && this->WithCoordinates); // Recompute each call // Retrieve coordinate arrays vtkDataArray* coords[3] = { this->XCoordinates, this->YCoordinates, this->ZCoordinates }; for (unsigned int i = 0; i < 3; ++i) { if (!coords[i] || !coords[i]->GetNumberOfTuples()) { return; } } // Get grid bounds from coordinate arrays for (unsigned int i = 0; i < 3; ++i) { unsigned int di = 2 * i; unsigned int dip = di + 1; bounds[di] = coords[i]->GetComponent(0, 0); bounds[dip] = coords[i]->GetComponent(coords[i]->GetNumberOfTuples() - 1, 0); // Ensure that the bounds are increasing if (bounds[di] > bounds[dip]) { std::swap(bounds[di], bounds[dip]); } } } //------------------------------------------------------------------------------ double* vtkHyperTreeGrid::GetCenter() { double* bds = this->GetBounds(); this->Center[0] = bds[0] + (bds[1] - bds[0]) / 2.0; this->Center[1] = bds[2] + (bds[3] - bds[2]) / 2.0; this->Center[2] = bds[4] + (bds[5] - bds[4]) / 2.0; return this->Center; } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GetCenter(double* octr) { double* ctr = this->GetCenter(); memcpy(octr, ctr, 3 * sizeof(double)); } //------------------------------------------------------------------------------ vtkCellData* vtkHyperTreeGrid::GetCellData() { return this->CellData.GetPointer(); } //------------------------------------------------------------------------------ vtkFieldData* vtkHyperTreeGrid::GetAttributesAsFieldData(int type) { return type == vtkDataObject::AttributeTypes::CELL ? this->CellData.GetPointer() : this->Superclass::GetAttributesAsFieldData(type); } //------------------------------------------------------------------------------ vtkIdType vtkHyperTreeGrid::GetNumberOfElements(int type) { return type == vtkDataObject::AttributeTypes::CELL ? this->CellData->GetNumberOfTuples() : this->Superclass::GetNumberOfElements(type); } //------------------------------------------------------------------------------ vtkUnsignedCharArray* vtkHyperTreeGrid::GetTreeGhostArray() { if (!this->TreeGhostArrayCached) { this->TreeGhostArray = vtkArrayDownCast( this->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName())); this->TreeGhostArrayCached = true; } assert(this->TreeGhostArray == vtkArrayDownCast( this->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName()))); return this->TreeGhostArray; } //------------------------------------------------------------------------------ vtkUnsignedCharArray* vtkHyperTreeGrid::AllocateTreeGhostArray() { if (!this->GetTreeGhostArray()) { this->TreeGhostArray = vtkSmartPointer::New(); this->TreeGhostArray->SetName(vtkDataSetAttributes::GhostArrayName()); this->TreeGhostArray->SetNumberOfComponents(1); this->TreeGhostArray->SetNumberOfTuples(this->GetNumberOfCells()); this->TreeGhostArray->Fill(0); this->GetCellData()->AddArray(this->TreeGhostArray); this->TreeGhostArrayCached = true; } return this->TreeGhostArray; } //------------------------------------------------------------------------------ vtkUnsignedCharArray* vtkHyperTreeGrid::GetGhostCells() { return vtkUnsignedCharArray::SafeDownCast( this->CellData->GetArray(vtkDataSetAttributes::GhostArrayName())); } //------------------------------------------------------------------------------ bool vtkHyperTreeGrid::HasAnyGhostCells() const { return this->CellData->GetArray(vtkDataSetAttributes::GhostArrayName()) != nullptr; } //------------------------------------------------------------------------------ namespace { void MarkEntireTreeAsGhost( vtkHyperTreeGridNonOrientedCursor* cursor, vtkUnsignedCharArray* ghostCells) { vtkIdType id = cursor->GetGlobalNodeIndex(); unsigned char val = ghostCells->GetValue(id) | vtkDataSetAttributes::DUPLICATECELL; ghostCells->SetValue(id, val); if (!cursor->IsLeaf()) { for (unsigned int c = 0; c < cursor->GetNumberOfChildren(); ++c) { cursor->ToChild(c); ::MarkEntireTreeAsGhost(cursor, ghostCells); cursor->ToParent(); } } } } //------------------------------------------------------------------------------ void vtkHyperTreeGrid::GenerateGhostArray(int zeroExt[6]) { if (this->GetNumberOfCells() == 0) { vtkDebugMacro("No cells in vtkHyperTreeGrid, skipping ghost generation."); return; } this->AllocateTreeGhostArray(); auto markGhost = [&](int imin, int imax, int jmin, int jmax, int kmin, int kmax) { vtkNew cursor; for (int i = imin; i < imax; ++i) { for (int j = jmin; j < jmax; ++j) { for (int k = kmin; k < kmax; ++k) { vtkIdType treeIdx; this->GetIndexFromLevelZeroCoordinates(treeIdx, i, j, k); this->InitializeNonOrientedCursor(cursor, treeIdx, false); if (cursor->HasTree()) { ::MarkEntireTreeAsGhost(cursor, this->TreeGhostArray); } } } } }; if (zeroExt[0] > this->Extent[0]) { markGhost(this->Extent[0], zeroExt[0], zeroExt[2], zeroExt[3], zeroExt[4], zeroExt[5]); } if (zeroExt[1] < this->Extent[1]) { markGhost(zeroExt[1], this->Extent[1], zeroExt[2], zeroExt[3], zeroExt[4], zeroExt[5]); } if (zeroExt[2] > this->Extent[2]) { markGhost( this->Extent[0], this->Extent[1], this->Extent[2], zeroExt[2], zeroExt[4], zeroExt[5]); } if (zeroExt[3] < this->Extent[3]) { markGhost( this->Extent[0], this->Extent[1], zeroExt[3], this->Extent[3], zeroExt[4], zeroExt[5]); } if (zeroExt[4] > this->Extent[4]) { markGhost(this->Extent[0], this->Extent[1], this->Extent[2], this->Extent[3], this->Extent[4], zeroExt[4]); } if (zeroExt[5] < this->Extent[5]) { markGhost(this->Extent[0], this->Extent[1], this->Extent[2], this->Extent[3], zeroExt[5], this->Extent[5]); } } VTK_ABI_NAMESPACE_END