You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1950 lines
58 KiB
C++
1950 lines
58 KiB
C++
|
2 weeks ago
|
/*=========================================================================
|
||
|
|
|
||
|
|
Program: Visualization Toolkit
|
||
|
|
Module: vtkHyperTreeGrid.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 "vtkHyperTreeGrid.h"
|
||
|
|
|
||
|
|
#include "vtkBitArray.h"
|
||
|
|
#include "vtkCellData.h"
|
||
|
|
#include "vtkCellLinks.h"
|
||
|
|
#include "vtkCellType.h"
|
||
|
|
#include "vtkCollection.h"
|
||
|
|
#include "vtkDoubleArray.h"
|
||
|
|
#include "vtkDataSetAttributes.h"
|
||
|
|
#include "vtkGenericCell.h"
|
||
|
|
#include "vtkHyperTree.h"
|
||
|
|
#include "vtkHyperTreeCursor.h"
|
||
|
|
#include "vtkIdTypeArray.h"
|
||
|
|
#include "vtkInformation.h"
|
||
|
|
#include "vtkInformationDoubleVectorKey.h"
|
||
|
|
#include "vtkInformationIntegerKey.h"
|
||
|
|
#include "vtkInformationVector.h"
|
||
|
|
#include "vtkLine.h"
|
||
|
|
#include "vtkMath.h"
|
||
|
|
#include "vtkNew.h"
|
||
|
|
#include "vtkObjectFactory.h"
|
||
|
|
#include "vtkPixel.h"
|
||
|
|
#include "vtkPointData.h"
|
||
|
|
#include "vtkPoints.h"
|
||
|
|
#include "vtkStructuredData.h"
|
||
|
|
#include "vtkTimerLog.h"
|
||
|
|
#include "vtkVoxel.h"
|
||
|
|
|
||
|
|
#include <cassert>
|
||
|
|
|
||
|
|
|
||
|
|
vtkInformationKeyMacro( vtkHyperTreeGrid, LEVELS, Integer );
|
||
|
|
vtkInformationKeyMacro( vtkHyperTreeGrid, DIMENSION, Integer );
|
||
|
|
vtkInformationKeyRestrictedMacro( vtkHyperTreeGrid, SIZES, DoubleVector, 3 );
|
||
|
|
|
||
|
|
vtkStandardNewMacro( vtkHyperTreeGrid );
|
||
|
|
|
||
|
|
vtkCxxSetObjectMacro( vtkHyperTreeGrid, MaterialMask, vtkBitArray );
|
||
|
|
vtkCxxSetObjectMacro( vtkHyperTreeGrid, MaterialMaskIndex, vtkIdTypeArray );
|
||
|
|
vtkCxxSetObjectMacro( vtkHyperTreeGrid, XCoordinates, vtkDataArray );
|
||
|
|
vtkCxxSetObjectMacro( vtkHyperTreeGrid, YCoordinates, vtkDataArray );
|
||
|
|
vtkCxxSetObjectMacro( vtkHyperTreeGrid, ZCoordinates, vtkDataArray );
|
||
|
|
|
||
|
|
// Helpers to quickly fetch a HT at a given index or iterator
|
||
|
|
#define GetHTGHyperTreeAtIndexMacro( _obj_, _index_ ) \
|
||
|
|
( static_cast<vtkHyperTree*>( \
|
||
|
|
_obj_->HyperTrees.find( _index_ ) != _obj_->HyperTrees.end() ? \
|
||
|
|
_obj_->HyperTrees[ _index_ ] : 0 ) )
|
||
|
|
|
||
|
|
#define GetHyperTreeAtIndexMacro( _index_ ) \
|
||
|
|
GetHTGHyperTreeAtIndexMacro( this, _index_ )
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkHyperTreeGrid::vtkHyperTreeGrid()
|
||
|
|
{
|
||
|
|
// Dual grid corners (primal grid leaf centers)
|
||
|
|
this->Points = 0;
|
||
|
|
this->Connectivity = 0;
|
||
|
|
|
||
|
|
// Internal links
|
||
|
|
this->Links = 0;
|
||
|
|
|
||
|
|
// Grid topology
|
||
|
|
this->GridSize[0] = 0;
|
||
|
|
this->GridSize[1] = 0;
|
||
|
|
this->GridSize[2] = 0;
|
||
|
|
this->TransposedRootIndexing = false;
|
||
|
|
|
||
|
|
// Grid parameters
|
||
|
|
this->BranchFactor = 2;
|
||
|
|
this->Dimension = 1;
|
||
|
|
this->NumberOfChildren = 2;
|
||
|
|
|
||
|
|
// Masked primal leaves
|
||
|
|
this->MaterialMask = vtkBitArray::New();
|
||
|
|
this->MaterialMaskIndex = 0;
|
||
|
|
|
||
|
|
// Grid geometry
|
||
|
|
this->XCoordinates = vtkDoubleArray::New();
|
||
|
|
this->YCoordinates = vtkDoubleArray::New();
|
||
|
|
this->ZCoordinates = vtkDoubleArray::New();
|
||
|
|
|
||
|
|
// For dataset API
|
||
|
|
this->Voxel = vtkVoxel::New();
|
||
|
|
this->Pixel = vtkPixel::New();
|
||
|
|
this->Line = vtkLine::New();
|
||
|
|
int extent[6];
|
||
|
|
extent[0] = 0;
|
||
|
|
extent[1] = this->GridSize[0] - 1;
|
||
|
|
extent[2] = 0;
|
||
|
|
extent[3] = this->GridSize[1] - 1;
|
||
|
|
extent[4] = 0;
|
||
|
|
extent[5] = this->GridSize[2] - 1;
|
||
|
|
|
||
|
|
memcpy( this->Extent, extent, 6 * sizeof(int) );
|
||
|
|
|
||
|
|
this->Information->Set( vtkDataObject::DATA_EXTENT_TYPE(), VTK_3D_EXTENT) ;
|
||
|
|
this->Information->Set( vtkDataObject::DATA_EXTENT(), this->Extent, 6 );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkHyperTreeGrid::~vtkHyperTreeGrid()
|
||
|
|
{
|
||
|
|
if ( this->MaterialMask )
|
||
|
|
{
|
||
|
|
this->MaterialMask->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->MaterialMaskIndex )
|
||
|
|
{
|
||
|
|
this->MaterialMaskIndex->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->XCoordinates )
|
||
|
|
{
|
||
|
|
this->XCoordinates->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->YCoordinates )
|
||
|
|
{
|
||
|
|
this->YCoordinates->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->ZCoordinates )
|
||
|
|
{
|
||
|
|
this->ZCoordinates->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Voxel )
|
||
|
|
{
|
||
|
|
this->Voxel->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Pixel )
|
||
|
|
{
|
||
|
|
this->Pixel->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Line )
|
||
|
|
{
|
||
|
|
this->Line->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
this->DeleteInternalArrays();
|
||
|
|
this->DeleteTrees();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::PrintSelf( ostream& os, vtkIndent indent )
|
||
|
|
{
|
||
|
|
this->Superclass::PrintSelf( os, indent );
|
||
|
|
os << indent << "Dimension: " << this->Dimension << endl;
|
||
|
|
os << indent << "GridSize: "
|
||
|
|
<< this->GridSize[0] <<","
|
||
|
|
<< this->GridSize[1] <<","
|
||
|
|
<< this->GridSize[2] << endl;
|
||
|
|
|
||
|
|
if ( this->XCoordinates )
|
||
|
|
{
|
||
|
|
this->XCoordinates->PrintSelf( os, indent.GetNextIndent() );
|
||
|
|
}
|
||
|
|
if ( this->YCoordinates )
|
||
|
|
{
|
||
|
|
this->YCoordinates->PrintSelf( os, indent.GetNextIndent() );
|
||
|
|
}
|
||
|
|
if ( this->ZCoordinates )
|
||
|
|
{
|
||
|
|
this->ZCoordinates->PrintSelf( os, indent.GetNextIndent() );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Description:
|
||
|
|
// Return what type of dataset this is.
|
||
|
|
int vtkHyperTreeGrid::GetDataObjectType()
|
||
|
|
{
|
||
|
|
return VTK_HYPER_TREE_GRID;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void vtkHyperTreeGrid::DeleteTrees()
|
||
|
|
{
|
||
|
|
if ( this->HyperTrees.size() )
|
||
|
|
{
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( vtkHyperTree* tree = it.GetNextTree() )
|
||
|
|
{
|
||
|
|
tree->UnRegister( this );
|
||
|
|
}
|
||
|
|
this->HyperTrees.clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Description:
|
||
|
|
// Copy the geometric and topological structure of a hyper tree grid
|
||
|
|
// object.
|
||
|
|
void vtkHyperTreeGrid::CopyStructure( vtkDataSet* ds )
|
||
|
|
{
|
||
|
|
assert( "pre: ds_exists" && ds!=0 );
|
||
|
|
assert( "pre: same_type" && vtkHyperTreeGrid::SafeDownCast(ds)!=0 );
|
||
|
|
|
||
|
|
vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast( ds );
|
||
|
|
assert(htg);
|
||
|
|
|
||
|
|
// Copy grid parameters
|
||
|
|
this->Dimension = htg->Dimension;
|
||
|
|
this->BranchFactor = htg->BranchFactor;
|
||
|
|
this->NumberOfChildren = htg->NumberOfChildren;
|
||
|
|
this->TransposedRootIndexing = htg->TransposedRootIndexing;
|
||
|
|
memcpy( this->GridSize, htg->GetGridSize(), 3 * sizeof( int ) );
|
||
|
|
|
||
|
|
// Un-register existing trees
|
||
|
|
DeleteTrees();
|
||
|
|
|
||
|
|
// Shallow copy and register new trees
|
||
|
|
this->HyperTrees = htg->HyperTrees;
|
||
|
|
|
||
|
|
if ( this->HyperTrees.size() )
|
||
|
|
{
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( vtkHyperTree* tree = it.GetNextTree() )
|
||
|
|
{
|
||
|
|
tree->Register( this );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
this->DeleteInternalArrays();
|
||
|
|
|
||
|
|
if ( htg->Points )
|
||
|
|
{
|
||
|
|
this->Points = htg->Points;
|
||
|
|
this->Points->Register( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( htg->Connectivity )
|
||
|
|
{
|
||
|
|
this->Connectivity = htg->Connectivity;
|
||
|
|
this->Connectivity->Register( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( htg->Links )
|
||
|
|
{
|
||
|
|
this->Links = htg->Links;
|
||
|
|
this->Links->Register( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Shallow copy masked leaf IDs
|
||
|
|
this->SetMaterialMask( htg->MaterialMask );
|
||
|
|
|
||
|
|
// Shallow copy masked leaf IDs
|
||
|
|
this->SetMaterialMaskIndex( htg->MaterialMaskIndex );
|
||
|
|
|
||
|
|
// Shallow copy coordinates
|
||
|
|
this->SetXCoordinates( htg->XCoordinates );
|
||
|
|
this->SetYCoordinates( htg->YCoordinates );
|
||
|
|
this->SetZCoordinates( htg->ZCoordinates );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::SetGridSize( unsigned int dim[3] )
|
||
|
|
{
|
||
|
|
this->SetGridExtent( 0, dim[0]-1, 0, dim[1]-1, 0, dim[2]-1 );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::SetGridSize( unsigned int i, unsigned int j, unsigned int k )
|
||
|
|
{
|
||
|
|
this->SetGridExtent( 0, i-1, 0, j-1, 0, k-1 );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::SetGridExtent( int extent[6] )
|
||
|
|
{
|
||
|
|
int description;
|
||
|
|
|
||
|
|
description = vtkStructuredData::SetExtent( extent, this->Extent );
|
||
|
|
if ( description < 0 ) //improperly specified
|
||
|
|
{
|
||
|
|
vtkErrorMacro ( << "Bad Extent, retaining previous values" );
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( description == VTK_UNCHANGED )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this->GridSize[0] = extent[1] - extent[0] + 1;
|
||
|
|
this->GridSize[1] = extent[3] - extent[2] + 1;
|
||
|
|
this->GridSize[2] = extent[5] - extent[4] + 1;
|
||
|
|
|
||
|
|
this->Modified();
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::SetGridExtent(int iMin, int iMax, int jMin, int jMax,
|
||
|
|
int kMin, int kMax)
|
||
|
|
{
|
||
|
|
int extent[6];
|
||
|
|
|
||
|
|
extent[0] = iMin; extent[1] = iMax;
|
||
|
|
extent[2] = jMin; extent[3] = jMax;
|
||
|
|
extent[4] = kMin; extent[5] = kMax;
|
||
|
|
|
||
|
|
this->SetGridExtent( extent );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Set the dimension of the tree with `dim'. See GetDimension() for details.
|
||
|
|
// \pre valid_dim: dim >= 1 && dim <= 3
|
||
|
|
// \post dimension_is_set: GetDimension()==dim
|
||
|
|
void vtkHyperTreeGrid::SetDimension( unsigned int dim )
|
||
|
|
{
|
||
|
|
assert( "pre: valid_dim" && dim >= 1 && dim <= 3 );
|
||
|
|
if ( this->Dimension == dim )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this->Dimension = dim;
|
||
|
|
|
||
|
|
// Number of children is factor^dimension
|
||
|
|
this->NumberOfChildren = this->BranchFactor;
|
||
|
|
for ( unsigned int i = 1; i < this->Dimension; ++ i )
|
||
|
|
{
|
||
|
|
this->NumberOfChildren *= this->BranchFactor;
|
||
|
|
}
|
||
|
|
|
||
|
|
this->Modified();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// \pre valid_dim: factor == 2 or factor == 3;
|
||
|
|
// \post dimension_is_set: GetBranchFactor()==dim
|
||
|
|
void vtkHyperTreeGrid::SetBranchFactor( unsigned int factor )
|
||
|
|
{
|
||
|
|
assert( "pre: valid_factor" && factor >= 2 && factor <= 3 );
|
||
|
|
if ( this->BranchFactor == factor )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this->BranchFactor = factor;
|
||
|
|
|
||
|
|
// Number of children is factor^dimension
|
||
|
|
this->NumberOfChildren = this->BranchFactor;
|
||
|
|
for ( unsigned int i = 1; i < this->Dimension; ++ i )
|
||
|
|
{
|
||
|
|
this->NumberOfChildren *= this->BranchFactor;
|
||
|
|
}
|
||
|
|
|
||
|
|
this->Modified();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GenerateTrees()
|
||
|
|
{
|
||
|
|
// Clean up existing trees
|
||
|
|
this->DeleteTrees();
|
||
|
|
|
||
|
|
// Generate concrete instance of hyper tree and append it to list of roots
|
||
|
|
vtkIdType nr = this->GetNumberOfTrees();
|
||
|
|
|
||
|
|
for ( vtkIdType r = 0; r < nr; ++ r )
|
||
|
|
{
|
||
|
|
vtkIdType idx = this->MaterialMaskIndex ?
|
||
|
|
this->MaterialMaskIndex->GetValue(r) : r;
|
||
|
|
this->HyperTrees[ idx ] =
|
||
|
|
vtkHyperTree::CreateInstance( this->BranchFactor, this->Dimension );
|
||
|
|
}
|
||
|
|
|
||
|
|
this->Modified();
|
||
|
|
this->DeleteInternalArrays();
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::ComputeBounds()
|
||
|
|
{
|
||
|
|
// 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 bounds from coordinate arrays
|
||
|
|
vtkMath::UninitializeBounds( this->Bounds );
|
||
|
|
for ( unsigned int i = 0; i < 3; ++ i )
|
||
|
|
{
|
||
|
|
unsigned int di = 2 * i;
|
||
|
|
unsigned int dip = di + 1;
|
||
|
|
this->Bounds[di] = coords[i]->GetComponent( 0, 0 );
|
||
|
|
this->Bounds[dip] = coords[i]->GetComponent( coords[i]->GetNumberOfTuples() - 1, 0 );
|
||
|
|
|
||
|
|
// Ensure that the bounds are increasing
|
||
|
|
if ( this->Bounds[di] > this->Bounds[dip] )
|
||
|
|
{
|
||
|
|
std::swap( this->Bounds[di], this->Bounds[dip] );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::GetNumberOfLeaves()
|
||
|
|
{
|
||
|
|
vtkIdType nLeaves = 0;
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( vtkHyperTree* tree = it.GetNextTree() )
|
||
|
|
{
|
||
|
|
nLeaves += tree->GetNumberOfLeaves();
|
||
|
|
}
|
||
|
|
return nLeaves;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::GetNumberOfLevels( vtkIdType id )
|
||
|
|
{
|
||
|
|
vtkHyperTree* tree = GetHyperTreeAtIndexMacro( id );
|
||
|
|
return tree ? tree->GetNumberOfLevels() : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::GetNumberOfTrees()
|
||
|
|
{
|
||
|
|
return this->MaterialMaskIndex ?
|
||
|
|
this->MaterialMaskIndex->GetNumberOfTuples() :
|
||
|
|
this->GridSize[0] * this->GridSize[1] * this->GridSize[2];
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::InitializeTreeIterator( vtkHyperTreeIterator& it )
|
||
|
|
{
|
||
|
|
it.Initialize( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkHyperTreeCursor* vtkHyperTreeGrid::NewCursor( vtkIdType id )
|
||
|
|
{
|
||
|
|
vtkHyperTree* tree = GetHyperTreeAtIndexMacro( id );
|
||
|
|
return tree ? tree->NewCursor() : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::SubdivideLeaf( vtkHyperTreeCursor* leaf, vtkIdType id )
|
||
|
|
{
|
||
|
|
assert( "pre: leaf_exists" && leaf );
|
||
|
|
assert( "pre: is_a_leaf" && leaf->IsLeaf() );
|
||
|
|
vtkHyperTree* tree = GetHyperTreeAtIndexMacro( id );
|
||
|
|
if ( tree )
|
||
|
|
{
|
||
|
|
tree->SubdivideLeaf( leaf );
|
||
|
|
this->DeleteInternalArrays();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::Initialize()
|
||
|
|
{
|
||
|
|
if ( this->HyperTrees.size() )
|
||
|
|
{
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( vtkHyperTree* tree = it.GetNextTree() )
|
||
|
|
{
|
||
|
|
tree->Initialize();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
this->DeleteInternalArrays();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
int vtkHyperTreeGrid::GetMaxCellSize()
|
||
|
|
{
|
||
|
|
switch( this->Dimension )
|
||
|
|
{
|
||
|
|
case 3:
|
||
|
|
// Hexahedron, 8 vertices
|
||
|
|
return 8;
|
||
|
|
case 2:
|
||
|
|
// Quadrangle, 4 vertices
|
||
|
|
return 4;
|
||
|
|
case 1:
|
||
|
|
// Line segment, 2 vertices
|
||
|
|
return 2;
|
||
|
|
default:
|
||
|
|
// This is useless, just to avoid a warning
|
||
|
|
assert( "check: bad grid dimension" && 0 );
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Description:
|
||
|
|
// Shallow and Deep copy.
|
||
|
|
void vtkHyperTreeGrid::ShallowCopy( vtkDataObject* src )
|
||
|
|
{
|
||
|
|
assert( "src_same_type" && vtkHyperTreeGrid::SafeDownCast( src ) );
|
||
|
|
this->CopyStructure(vtkHyperTreeGrid::SafeDownCast( src ) );
|
||
|
|
|
||
|
|
// Call superclass
|
||
|
|
this->Superclass::ShallowCopy( src );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::DeepCopy( vtkDataObject* src )
|
||
|
|
{
|
||
|
|
assert( "src_same_type" && vtkHyperTreeGrid::SafeDownCast( src ) );
|
||
|
|
this->CopyStructure( vtkHyperTreeGrid::SafeDownCast( src ) );
|
||
|
|
|
||
|
|
// Call superclass
|
||
|
|
this->Superclass::DeepCopy( src );
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
// DataSet API that returns dual grid.
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Description:
|
||
|
|
// Return the number of leaves.
|
||
|
|
// \post positive_result: result>=0
|
||
|
|
vtkIdType vtkHyperTreeGrid::GetNumberOfCells()
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
return this->GetConnectivity()->GetNumberOfTuples();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::GetNumberOfPoints()
|
||
|
|
{
|
||
|
|
return this->GetNumberOfLeaves();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
double* vtkHyperTreeGrid::GetPoint( vtkIdType ptId )
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
vtkPoints* leafCenters = this->GetPoints();
|
||
|
|
assert( "Index out of bounds." &&
|
||
|
|
ptId >= 0 && ptId < leafCenters->GetNumberOfPoints() );
|
||
|
|
return leafCenters->GetPoint( ptId );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetPoint( vtkIdType ptId, double x[3] )
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
vtkPoints* leafCenters = this->GetPoints();
|
||
|
|
assert( "Index out of bounds." &&
|
||
|
|
ptId >= 0 && ptId < leafCenters->GetNumberOfPoints() );
|
||
|
|
leafCenters->GetPoint( ptId, x );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetCell( vtkIdType cellId, vtkCell* cell )
|
||
|
|
{
|
||
|
|
assert( "Null cell ptr." && cell != 0 );
|
||
|
|
|
||
|
|
int numPts = 1 << this->Dimension;
|
||
|
|
double x[3];
|
||
|
|
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
vtkIdTypeArray* cornerLeafIds = this->GetConnectivity();
|
||
|
|
assert( "Index out of bounds." &&
|
||
|
|
cellId >= 0 && cellId < cornerLeafIds->GetNumberOfTuples() );
|
||
|
|
vtkPoints* leafCenters = this->GetPoints();
|
||
|
|
vtkIdType* ptr = cornerLeafIds->GetPointer( 0 ) + cellId*numPts;
|
||
|
|
for ( int ptIdx = 0; ptIdx < numPts; ++ptIdx, ++ptr )
|
||
|
|
{
|
||
|
|
cell->PointIds->SetId( ptIdx, *ptr );
|
||
|
|
leafCenters->GetPoint( *ptr, x );
|
||
|
|
cell->Points->SetPoint( ptIdx, x );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkCell* vtkHyperTreeGrid::GetCell( vtkIdType cellId )
|
||
|
|
{
|
||
|
|
vtkCell* cell = 0;
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
cell = this->Line;
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
cell = this->Pixel;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
cell = this->Voxel;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
assert( "post: bad grid dimension" && false );
|
||
|
|
return 0; // impossible case
|
||
|
|
}
|
||
|
|
|
||
|
|
GetCell( cellId, cell );
|
||
|
|
return cell;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetCell( vtkIdType cellId, vtkGenericCell* cell )
|
||
|
|
{
|
||
|
|
assert( "GetCell on null cell." && cell != 0 );
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
cell->SetCellTypeToLine();
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
cell->SetCellTypeToPixel();
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
cell->SetCellTypeToVoxel();
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
assert( "post: bad grid dimension" && false );
|
||
|
|
return; // impossible case
|
||
|
|
}
|
||
|
|
|
||
|
|
GetCell( cellId, static_cast<vtkCell*>( cell ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
int vtkHyperTreeGrid::GetCellType( vtkIdType vtkNotUsed(cellId) )
|
||
|
|
{
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 3:
|
||
|
|
return VTK_VOXEL; // hexahedron = 8 points
|
||
|
|
case 2:
|
||
|
|
return VTK_PIXEL; // quad = 4 points
|
||
|
|
case 1:
|
||
|
|
return VTK_LINE; // line = 2 points
|
||
|
|
default:
|
||
|
|
assert( "post: bad grid dimension" && false );
|
||
|
|
return 0; // impossible case
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetCellPoints( vtkIdType cellId, vtkIdList* ptIds )
|
||
|
|
{
|
||
|
|
int numPts = 1 << this->Dimension;
|
||
|
|
ptIds->Initialize();
|
||
|
|
ptIds->SetNumberOfIds( numPts );
|
||
|
|
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
vtkIdTypeArray* cornerLeafIds = this->GetConnectivity();
|
||
|
|
assert( "Index out of bounds." &&
|
||
|
|
cellId >= 0 && cellId < cornerLeafIds->GetNumberOfTuples() );
|
||
|
|
vtkIdType* ptr = cornerLeafIds->GetPointer( 0 ) + cellId * numPts;
|
||
|
|
memcpy( ptIds->GetPointer(0), ptr, numPts * sizeof( vtkIdType ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetCellPoints( vtkIdType cellId,
|
||
|
|
vtkIdType& npts,
|
||
|
|
vtkIdType* &pts )
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
vtkIdTypeArray* cornerLeafIds = this->GetConnectivity();
|
||
|
|
assert( "Index out of bounds." &&
|
||
|
|
cellId >= 0 && cellId < cornerLeafIds->GetNumberOfTuples() );
|
||
|
|
npts = static_cast<vtkIdType>( 1 << this->Dimension );
|
||
|
|
pts = cornerLeafIds->GetPointer( 0 ) + cellId * npts;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetPointCells( vtkIdType ptId, vtkIdList* cellIds )
|
||
|
|
{
|
||
|
|
if ( ! this->Links )
|
||
|
|
{
|
||
|
|
this->BuildLinks();
|
||
|
|
}
|
||
|
|
cellIds->Reset();
|
||
|
|
|
||
|
|
int numCells = this->Links->GetNcells( ptId );
|
||
|
|
cellIds->SetNumberOfIds( numCells );
|
||
|
|
|
||
|
|
vtkIdType* cells = this->Links->GetCells( ptId );
|
||
|
|
for ( int i = 0; i < numCells; ++ i )
|
||
|
|
{
|
||
|
|
cellIds->SetId( i, cells[i] );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::BuildLinks()
|
||
|
|
{
|
||
|
|
this->Links = vtkCellLinks::New();
|
||
|
|
this->Links->Allocate( this->GetNumberOfPoints() );
|
||
|
|
this->Links->Register( this );
|
||
|
|
this->Links->BuildLinks( this );
|
||
|
|
this->Links->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetCellNeighbors( vtkIdType cellId,
|
||
|
|
vtkIdList* ptIds,
|
||
|
|
vtkIdList* cellIds )
|
||
|
|
{
|
||
|
|
if ( ! this->Links )
|
||
|
|
{
|
||
|
|
this->BuildLinks();
|
||
|
|
}
|
||
|
|
|
||
|
|
cellIds->Reset();
|
||
|
|
|
||
|
|
vtkIdType numPts = ptIds->GetNumberOfIds();
|
||
|
|
if (numPts <= 0)
|
||
|
|
{
|
||
|
|
vtkErrorMacro("input point ids empty.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int minNumCells = VTK_INT_MAX;
|
||
|
|
vtkIdType* pts = ptIds->GetPointer( 0 );
|
||
|
|
vtkIdType* minCells = 0;
|
||
|
|
vtkIdType minPtId = 0;
|
||
|
|
// Find the point used by the fewest number of cells
|
||
|
|
for ( vtkIdType i = 0; i < numPts; i++ )
|
||
|
|
{
|
||
|
|
vtkIdType ptId = pts[i];
|
||
|
|
int numCells = this->Links->GetNcells( ptId );
|
||
|
|
if ( numCells < minNumCells )
|
||
|
|
{
|
||
|
|
minNumCells = numCells;
|
||
|
|
minCells = this->Links->GetCells( ptId );
|
||
|
|
minPtId = ptId;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
cellIds->Allocate( minNumCells );
|
||
|
|
|
||
|
|
// For all cells that contNow for each cell, see if it contains all the points
|
||
|
|
// in the ptIds list.
|
||
|
|
for ( int i = 0; i < minNumCells; i++ )
|
||
|
|
{
|
||
|
|
// Do not include current cell
|
||
|
|
if ( minCells[i] != cellId )
|
||
|
|
{
|
||
|
|
vtkIdType *cellPts;
|
||
|
|
vtkIdType npts;
|
||
|
|
this->GetCellPoints( minCells[i], npts, cellPts );
|
||
|
|
// Iterate over all points in input cell
|
||
|
|
bool match = true;
|
||
|
|
for ( vtkIdType j = 0; j < numPts && match; j++ )
|
||
|
|
{
|
||
|
|
// Skip point with index minPtId which is contained by current cell
|
||
|
|
if ( pts[j] != minPtId )
|
||
|
|
{
|
||
|
|
// Iterate over all points in current cell
|
||
|
|
match = false;
|
||
|
|
for ( vtkIdType k = 0; k < npts; ++ k )
|
||
|
|
{
|
||
|
|
if ( pts[j] == cellPts[k] )
|
||
|
|
{
|
||
|
|
// A match was found
|
||
|
|
match = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
} // For all points in current cell
|
||
|
|
} // If not guaranteed match
|
||
|
|
} // For all points in input cell
|
||
|
|
if ( match )
|
||
|
|
{
|
||
|
|
cellIds->InsertNextId( minCells[i] );
|
||
|
|
}
|
||
|
|
} // If not the reference cell
|
||
|
|
} // For all candidate cells attached to point
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::FindPoint( double x[3] )
|
||
|
|
{
|
||
|
|
vtkIdType ix = 0;
|
||
|
|
vtkIdType nx = this->XCoordinates->GetNumberOfTuples();
|
||
|
|
while ( ix < nx && x[0] > this->XCoordinates->GetTuple1( ix ) )
|
||
|
|
{
|
||
|
|
++ ix;
|
||
|
|
}
|
||
|
|
if ( ix )
|
||
|
|
{
|
||
|
|
-- ix;
|
||
|
|
}
|
||
|
|
|
||
|
|
vtkIdType iy = 0;
|
||
|
|
vtkIdType ny = this->YCoordinates->GetNumberOfTuples();
|
||
|
|
while ( iy < ny && x[1] > this->YCoordinates->GetTuple1( iy ) )
|
||
|
|
{
|
||
|
|
++ iy;
|
||
|
|
}
|
||
|
|
if ( iy )
|
||
|
|
{
|
||
|
|
-- iy;
|
||
|
|
}
|
||
|
|
|
||
|
|
vtkIdType iz = 0;
|
||
|
|
vtkIdType nz = this->ZCoordinates->GetNumberOfTuples();
|
||
|
|
while ( iz < nz && x[2] > this->ZCoordinates->GetTuple1( iz ) )
|
||
|
|
{
|
||
|
|
++ iz;
|
||
|
|
}
|
||
|
|
if ( iz )
|
||
|
|
{
|
||
|
|
-- iz;
|
||
|
|
}
|
||
|
|
|
||
|
|
int index = ( this->TransposedRootIndexing ) ?
|
||
|
|
( ix * this->GridSize[1] + iy ) * this->GridSize[2] + iz :
|
||
|
|
( iz * this->GridSize[1] + iy ) * this->GridSize[0] + ix;
|
||
|
|
|
||
|
|
vtkHyperTreeSimpleCursor cursor;
|
||
|
|
int pos[] = { 0, 0, 0 };
|
||
|
|
cursor.Initialize( this, index, pos );
|
||
|
|
|
||
|
|
// Geometry of the cell
|
||
|
|
double origin[3] =
|
||
|
|
{
|
||
|
|
this->XCoordinates->GetTuple1( ix ),
|
||
|
|
this->YCoordinates->GetTuple1( iy ),
|
||
|
|
this->ZCoordinates->GetTuple1( iz )
|
||
|
|
};
|
||
|
|
|
||
|
|
double extreme[3] =
|
||
|
|
{
|
||
|
|
this->XCoordinates->GetTuple1( ix + 1 ),
|
||
|
|
this->YCoordinates->GetTuple1( iy + 1 ),
|
||
|
|
this->ZCoordinates->GetTuple1( iz + 1 )
|
||
|
|
};
|
||
|
|
|
||
|
|
double size[3] =
|
||
|
|
{
|
||
|
|
extreme[0] - origin[0],
|
||
|
|
extreme[1] - origin[1],
|
||
|
|
extreme[2] - origin[2]
|
||
|
|
};
|
||
|
|
|
||
|
|
return this->RecursiveFindPoint( x, &cursor, origin, size );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::RecursiveFindPoint( double x[3],
|
||
|
|
vtkHyperTreeSimpleCursor* cursor,
|
||
|
|
double* origin,
|
||
|
|
double* size )
|
||
|
|
{
|
||
|
|
if ( cursor->IsLeaf() )
|
||
|
|
{
|
||
|
|
return cursor->GetLeafIndex();
|
||
|
|
}
|
||
|
|
|
||
|
|
vtkHyperTreeSimpleCursor newCursor = *cursor;
|
||
|
|
double newSize[3];
|
||
|
|
double newOrigin[3];
|
||
|
|
int child = 0;
|
||
|
|
for ( int i = 0; i < 3; ++ i )
|
||
|
|
{
|
||
|
|
newSize[i] = size[i] * 0.5;
|
||
|
|
newOrigin[i] = origin[i];
|
||
|
|
if ( x[i] >= origin[i] + newSize[i] )
|
||
|
|
{
|
||
|
|
child = child | ( 1 << i );
|
||
|
|
newOrigin[i] += newSize[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
newCursor.ToChild( child );
|
||
|
|
|
||
|
|
return this->RecursiveFindPoint( x, &newCursor, newOrigin, newSize );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::FindCell( double x[3], vtkCell* cell,
|
||
|
|
vtkGenericCell* gencell, vtkIdType cellId,
|
||
|
|
double tol2, int& subId, double pcoords[3],
|
||
|
|
double* weights )
|
||
|
|
{
|
||
|
|
vtkIdType ptId = this->FindPoint( x );
|
||
|
|
if ( ptId < 0 )
|
||
|
|
{
|
||
|
|
// Return invalid Id if point is completely outside of data set
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
vtkNew<vtkIdList> cellIds;
|
||
|
|
cellIds->Allocate( 8, 100 );
|
||
|
|
this->GetPointCells( ptId, cellIds.GetPointer() );
|
||
|
|
if ( cellIds->GetNumberOfIds() <= 0 )
|
||
|
|
{
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
double closestPoint[3];
|
||
|
|
double dist2;
|
||
|
|
vtkIdType num = cellIds->GetNumberOfIds();
|
||
|
|
for ( vtkIdType i = 0; i < num; ++ i )
|
||
|
|
{
|
||
|
|
cellId = cellIds->GetId( i );
|
||
|
|
if ( gencell )
|
||
|
|
{
|
||
|
|
this->GetCell( cellId, gencell );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
cell = this->GetCell( cellId );
|
||
|
|
}
|
||
|
|
|
||
|
|
// See whether this cell contains the point
|
||
|
|
if ( ( gencell &&
|
||
|
|
gencell->EvaluatePosition( x, closestPoint, subId,
|
||
|
|
pcoords, dist2, weights ) == 1
|
||
|
|
&& dist2 <= tol2 ) ||
|
||
|
|
( !gencell &&
|
||
|
|
cell->EvaluatePosition( x, closestPoint, subId,
|
||
|
|
pcoords, dist2, weights ) == 1
|
||
|
|
&& dist2 <= tol2 ) )
|
||
|
|
{
|
||
|
|
return cellId;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// This should never happen.
|
||
|
|
vtkErrorMacro( "Could not find cell." );
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::FindCell( double x[3], vtkCell* cell,
|
||
|
|
vtkIdType cellId, double tol2,
|
||
|
|
int& subId, double pcoords[3],
|
||
|
|
double* weights )
|
||
|
|
{
|
||
|
|
return this->FindCell( x, cell, NULL, cellId, tol2, subId, pcoords, weights );
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
unsigned long vtkHyperTreeGrid::GetActualMemorySize()
|
||
|
|
{
|
||
|
|
unsigned long size = this->vtkDataSet::GetActualMemorySize();
|
||
|
|
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( vtkHyperTree* tree = it.GetNextTree() )
|
||
|
|
{
|
||
|
|
size += tree->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Approximate map memory size
|
||
|
|
size += static_cast<unsigned long>(
|
||
|
|
( this->HyperTrees.size() * sizeof(vtkIdType) * 3 ) / 1024 );
|
||
|
|
|
||
|
|
if ( this->XCoordinates )
|
||
|
|
{
|
||
|
|
size += this->XCoordinates->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->YCoordinates )
|
||
|
|
{
|
||
|
|
size += this->YCoordinates->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->ZCoordinates )
|
||
|
|
{
|
||
|
|
size += this->ZCoordinates->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Points )
|
||
|
|
{
|
||
|
|
size += this->Points->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Connectivity )
|
||
|
|
{
|
||
|
|
size += this->Connectivity->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->MaterialMask )
|
||
|
|
{
|
||
|
|
size += this->MaterialMask->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->MaterialMaskIndex )
|
||
|
|
{
|
||
|
|
size += this->MaterialMaskIndex->GetActualMemorySize();
|
||
|
|
}
|
||
|
|
|
||
|
|
return size;
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
// Internal arrays used to generate dual grid. Random access to cells
|
||
|
|
// requires the cell leaves connectively array which costs memory.
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkPoints* vtkHyperTreeGrid::GetPoints()
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
return this->Points;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdTypeArray* vtkHyperTreeGrid::GetConnectivity()
|
||
|
|
{
|
||
|
|
this->ComputeDualGrid();
|
||
|
|
return this->Connectivity;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::GetLevelZeroCoordsFromIndex( vtkIdType index,
|
||
|
|
unsigned int &i,
|
||
|
|
unsigned int &j,
|
||
|
|
unsigned int &k )
|
||
|
|
{
|
||
|
|
if ( !this->TransposedRootIndexing )
|
||
|
|
{
|
||
|
|
k = index / ( this->GridSize[0] * this->GridSize[1] );
|
||
|
|
vtkIdType rk = k * ( this->GridSize[0] * this->GridSize[1] );
|
||
|
|
j = ( index - rk ) / this->GridSize[0];
|
||
|
|
i = index - ( j * this->GridSize[0] ) - rk;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
i = index / ( this->GridSize[2] * this->GridSize[1] );
|
||
|
|
vtkIdType rk = i * ( this->GridSize[2] * this->GridSize[1] );
|
||
|
|
j = ( index - rk ) / this->GridSize[2];
|
||
|
|
k = index - ( j * this->GridSize[2] ) - rk;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::InitializeSuperCursor( vtkHyperTreeGridSuperCursor* sc,
|
||
|
|
vtkIdType index )
|
||
|
|
{
|
||
|
|
unsigned int i, j, k;
|
||
|
|
this->GetLevelZeroCoordsFromIndex( index, i, j, k );
|
||
|
|
// Initialize center cursor
|
||
|
|
this->InitializeSuperCursor( sc, i, j, k, index );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::InitializeSuperCursor( vtkHyperTreeGridSuperCursor* sc,
|
||
|
|
unsigned int i,
|
||
|
|
unsigned int j,
|
||
|
|
unsigned int k,
|
||
|
|
vtkIdType index )
|
||
|
|
{
|
||
|
|
// Location and size of the middle cursor/node
|
||
|
|
double origin[3] =
|
||
|
|
{
|
||
|
|
this->XCoordinates->GetTuple1( i ),
|
||
|
|
this->YCoordinates->GetTuple1( j ),
|
||
|
|
this->ZCoordinates->GetTuple1( k )
|
||
|
|
};
|
||
|
|
|
||
|
|
double extreme[3] =
|
||
|
|
{
|
||
|
|
this->XCoordinates->GetTuple1( i + 1 ),
|
||
|
|
this->YCoordinates->GetTuple1( j + 1 ),
|
||
|
|
this->ZCoordinates->GetTuple1( k + 1 )
|
||
|
|
};
|
||
|
|
|
||
|
|
memcpy( sc->Origin, origin, 3 * sizeof( double ) );
|
||
|
|
sc->Size[0] = extreme[0] - origin[0];
|
||
|
|
sc->Size[1] = extreme[1] - origin[1];
|
||
|
|
sc->Size[2] = extreme[2] - origin[2];
|
||
|
|
|
||
|
|
// Initialize middle cursors and bounds for other cursors
|
||
|
|
sc->NumberOfCursors = 3;
|
||
|
|
for ( unsigned int c = 1; c < this->Dimension; ++ c )
|
||
|
|
{
|
||
|
|
sc->NumberOfCursors *= 3;
|
||
|
|
}
|
||
|
|
sc->MiddleCursorId = sc->NumberOfCursors / 2;
|
||
|
|
|
||
|
|
int lowI = -1;
|
||
|
|
int highI = 1;
|
||
|
|
int lowJ = this->Dimension > 1 ? -1 : 0;
|
||
|
|
int highJ = this->Dimension > 1 ? 1 : 0;
|
||
|
|
int lowK = this->Dimension > 2 ? -1 : 0;
|
||
|
|
int highK = this->Dimension > 2 ? 1 : 0;
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 3:
|
||
|
|
lowK = ( k == 0 ) ? 0 : -1;
|
||
|
|
highK = ( k + 1 < this->GridSize[2] ) ? 1 : 0;
|
||
|
|
VTK_FALLTHROUGH;
|
||
|
|
case 2:
|
||
|
|
lowJ = ( j == 0 ) ? 0 : -1;
|
||
|
|
highJ = ( j + 1 < this->GridSize[1] ) ? 1 : 0;
|
||
|
|
VTK_FALLTHROUGH;
|
||
|
|
case 1:
|
||
|
|
lowI = ( i == 0 ) ? 0 : -1;
|
||
|
|
highI = ( i + 1 < this->GridSize[0] ) ? 1 : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize all connectivity cursors
|
||
|
|
for ( int ck = lowK; ck <= highK; ++ ck )
|
||
|
|
{
|
||
|
|
for ( int cj = lowJ; cj <= highJ; ++ cj )
|
||
|
|
{
|
||
|
|
for ( int ci = lowI; ci <= highI; ++ ci )
|
||
|
|
{
|
||
|
|
int pos[3] = { ci, cj, ck };
|
||
|
|
int d = ci + 3 * cj + 9 * ck;
|
||
|
|
sc->GetCursor( d )->Initialize( this, index, pos );
|
||
|
|
} // i
|
||
|
|
} // j
|
||
|
|
} // k
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::InitializeSuperCursorChild( vtkHyperTreeGridSuperCursor* parent,
|
||
|
|
vtkHyperTreeGridSuperCursor* child,
|
||
|
|
unsigned int childIdx )
|
||
|
|
{
|
||
|
|
// Retrieve child's parameters that are identical to parent's ones
|
||
|
|
child->NumberOfCursors = parent->NumberOfCursors;
|
||
|
|
child->MiddleCursorId = parent->MiddleCursorId;
|
||
|
|
|
||
|
|
// Compute size of child
|
||
|
|
child->Size[0] = parent->Size[0] / double( this->BranchFactor );
|
||
|
|
child->Size[1] = parent->Size[1] / double( this->BranchFactor );
|
||
|
|
child->Size[2] = parent->Size[2] / double( this->BranchFactor );
|
||
|
|
|
||
|
|
// Compute origin of child
|
||
|
|
unsigned int x, y, z;
|
||
|
|
if ( this->BranchFactor == 2 )
|
||
|
|
{
|
||
|
|
x = childIdx & 1;
|
||
|
|
y = ( childIdx & 2 ) >> 1;
|
||
|
|
z = ( childIdx & 4 ) >> 2;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
div_t d = div( childIdx, 9 );
|
||
|
|
z = d.quot;
|
||
|
|
y = d.rem / 3;
|
||
|
|
x = childIdx % 3;
|
||
|
|
}
|
||
|
|
child->Origin[0] = parent->Origin[0] + ( x * child->Size[0] );
|
||
|
|
child->Origin[1] = parent->Origin[1] + ( y * child->Size[1] );
|
||
|
|
child->Origin[2] = parent->Origin[2] + ( z * child->Size[2] );
|
||
|
|
|
||
|
|
// Move each cursor in the superCursor down to a child
|
||
|
|
vtkSuperCursorEntry* cursorPtr =
|
||
|
|
this->SuperCursorTraversalTable + ( childIdx * 27 );
|
||
|
|
for ( int cursorIdx = 0; cursorIdx < child->NumberOfCursors; ++ cursorIdx )
|
||
|
|
{
|
||
|
|
// Extract the parent and child of the new node from the traversal table
|
||
|
|
// Child is encoded in the first three bits for all dimensions
|
||
|
|
int tParent = cursorPtr[cursorIdx].Parent;
|
||
|
|
child->Cursors[cursorIdx] = parent->Cursors[tParent];
|
||
|
|
if ( parent->Cursors[tParent].GetTree()
|
||
|
|
&& ! parent->Cursors[tParent].IsLeaf() )
|
||
|
|
{
|
||
|
|
// Move to child
|
||
|
|
child->Cursors[cursorIdx] = parent->Cursors[tParent];
|
||
|
|
int tChild = cursorPtr[cursorIdx].Child;
|
||
|
|
child->Cursors[cursorIdx].ToChild( tChild );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Traverse tree with 3x3x3 super cursor. Center cursor generates dual point
|
||
|
|
// Smallest leaf (highest level) owns corners/dual cell. Ties are given to
|
||
|
|
// smallest index (z,y,x order)
|
||
|
|
// post: Generate Points and Connectivity.
|
||
|
|
void vtkHyperTreeGrid::ComputeDualGrid()
|
||
|
|
{
|
||
|
|
// Check if we can break out early
|
||
|
|
vtkIdType numPoints = this->GetNumberOfPoints();
|
||
|
|
if ( this->Points )
|
||
|
|
{
|
||
|
|
if ( this->Points->GetNumberOfPoints() == numPoints )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this->Points->UnRegister( this );
|
||
|
|
this->Connectivity->UnRegister( this );
|
||
|
|
}
|
||
|
|
|
||
|
|
vtkNew<vtkTimerLog> timer;
|
||
|
|
timer->StartTimer();
|
||
|
|
|
||
|
|
// Primal cell centers are dual points
|
||
|
|
this->Points = vtkPoints::New();
|
||
|
|
this->Points->SetNumberOfPoints( numPoints );
|
||
|
|
|
||
|
|
this->Connectivity = vtkIdTypeArray::New();
|
||
|
|
int numVerts = 1 << this->Dimension;
|
||
|
|
this->Connectivity->SetNumberOfComponents( numVerts );
|
||
|
|
|
||
|
|
// Create an array of cursors that occupy 1 3x3x3 neighborhood
|
||
|
|
// Will traverse the tree as one
|
||
|
|
// NB: Lower dimensions will not use them all
|
||
|
|
this->GenerateSuperCursorTraversalTable();
|
||
|
|
|
||
|
|
// Initialize grid depth
|
||
|
|
vtkIdType gridDepth = 0;
|
||
|
|
|
||
|
|
// Compute and assign scales of all tree roots
|
||
|
|
double scale[] = { 1., 1., 1. };
|
||
|
|
|
||
|
|
// Check whether coordinate arrays match grid size
|
||
|
|
// If coordinates array are complete, compute all tree scales
|
||
|
|
if ( static_cast<int>( this->GridSize[0] ) + 1 == this->XCoordinates->GetNumberOfTuples()
|
||
|
|
&& static_cast<int>( this->GridSize[1] ) + 1 == this->YCoordinates->GetNumberOfTuples()
|
||
|
|
&& static_cast<int>( this->GridSize[2] ) + 1 == this->ZCoordinates->GetNumberOfTuples() )
|
||
|
|
{
|
||
|
|
// Iterate over all hyper trees depending on indexing mode
|
||
|
|
|
||
|
|
std::map<vtkIdType, vtkHyperTree*>::iterator it = this->HyperTrees.begin();
|
||
|
|
std::map<vtkIdType, vtkHyperTree*>::iterator endit = this->HyperTrees.end();
|
||
|
|
|
||
|
|
if ( this->TransposedRootIndexing )
|
||
|
|
{
|
||
|
|
// I-J-K indexing
|
||
|
|
for ( unsigned int i = 0; i < this->GridSize[0] && it != endit; ++ i )
|
||
|
|
{
|
||
|
|
// Compute scale along x-axis
|
||
|
|
scale[0] = this->XCoordinates->GetTuple1( i + 1 ) -
|
||
|
|
this->XCoordinates->GetTuple1( i );
|
||
|
|
|
||
|
|
for ( unsigned int j = 0; j < this->GridSize[1] && it != endit; ++ j )
|
||
|
|
{
|
||
|
|
// Compute scale along y-axis
|
||
|
|
scale[1] = this->YCoordinates->GetTuple1( j + 1 ) -
|
||
|
|
this->YCoordinates->GetTuple1( j );
|
||
|
|
|
||
|
|
for ( unsigned int k = 0; k < this->GridSize[2] && it != endit; ++ k )
|
||
|
|
{
|
||
|
|
// Retrieve hyper tree
|
||
|
|
vtkHyperTree* tree = it->second;
|
||
|
|
++ it;
|
||
|
|
if ( !tree )
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Compute scale along z-axis and set tree scale
|
||
|
|
scale[2] = this->ZCoordinates->GetTuple1( k + 1 ) -
|
||
|
|
this->ZCoordinates->GetTuple1( k );
|
||
|
|
tree->SetScale( scale );
|
||
|
|
|
||
|
|
// Update hyper tree grid depth
|
||
|
|
vtkIdType treeDepth = tree->GetNumberOfLevels();
|
||
|
|
if ( treeDepth > gridDepth )
|
||
|
|
{
|
||
|
|
gridDepth = treeDepth;
|
||
|
|
}
|
||
|
|
} // i
|
||
|
|
} // j
|
||
|
|
} // k
|
||
|
|
} // if ( this->TransposedRootIndexing )
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// K-J-I indexing
|
||
|
|
for ( unsigned int k = 0; k < this->GridSize[2] && it != endit; ++ k )
|
||
|
|
{
|
||
|
|
// Compute scale along z-axis
|
||
|
|
scale[2] = this->ZCoordinates->GetTuple1( k + 1 ) -
|
||
|
|
this->ZCoordinates->GetTuple1( k );
|
||
|
|
|
||
|
|
for ( unsigned int j = 0; j < this->GridSize[1] && it != endit; ++ j )
|
||
|
|
{
|
||
|
|
// Compute scale along y-axis
|
||
|
|
scale[1] = this->YCoordinates->GetTuple1( j + 1 ) -
|
||
|
|
this->YCoordinates->GetTuple1( j );
|
||
|
|
|
||
|
|
for ( unsigned int i = 0; i < this->GridSize[0] && it != endit; ++ i )
|
||
|
|
{
|
||
|
|
// Retrieve hyper tree
|
||
|
|
vtkHyperTree* tree = it->second;
|
||
|
|
++ it;
|
||
|
|
if ( !tree )
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Compute scale along x-axis and set tree scale
|
||
|
|
scale[0] = this->XCoordinates->GetTuple1( i + 1 ) -
|
||
|
|
this->XCoordinates->GetTuple1( i );
|
||
|
|
tree->SetScale( scale );
|
||
|
|
|
||
|
|
// Update hyper tree grid depth
|
||
|
|
vtkIdType treeDepth = tree->GetNumberOfLevels();
|
||
|
|
if ( treeDepth > gridDepth )
|
||
|
|
{
|
||
|
|
gridDepth = treeDepth;
|
||
|
|
}
|
||
|
|
} // i
|
||
|
|
} // j
|
||
|
|
} // k
|
||
|
|
} // else indexing mode
|
||
|
|
} // if coordinate cardinalities match
|
||
|
|
|
||
|
|
// Compute and store reduction factors for speed
|
||
|
|
double factor = 1.;
|
||
|
|
for ( unsigned short p = 0; p < gridDepth; ++ p )
|
||
|
|
{
|
||
|
|
this->ReductionFactors[p] = .5 * factor;
|
||
|
|
factor /= this->BranchFactor;
|
||
|
|
} // p
|
||
|
|
|
||
|
|
// Iterate over all hyper trees
|
||
|
|
vtkIdType index;
|
||
|
|
vtkHyperTreeIterator it;
|
||
|
|
this->InitializeTreeIterator( it );
|
||
|
|
while ( it.GetNextTree( index ) )
|
||
|
|
{
|
||
|
|
// Storage for super cursors
|
||
|
|
vtkHyperTreeGridSuperCursor superCursor;
|
||
|
|
|
||
|
|
// Initialize center cursor
|
||
|
|
this->InitializeSuperCursor( &superCursor, index );
|
||
|
|
|
||
|
|
// Traverse and populate dual recursively
|
||
|
|
this->TraverseDualRecursively( &superCursor, 0 );
|
||
|
|
} // it
|
||
|
|
|
||
|
|
// Adjust dual points as needed to fit the primal boundary
|
||
|
|
for ( unsigned int d = 0; d < this->Dimension; ++ d )
|
||
|
|
{
|
||
|
|
// Iterate over all adjustments for current dimension
|
||
|
|
for ( std::map<vtkIdType, double>::const_iterator itps =
|
||
|
|
this->PointShifts[d].begin();
|
||
|
|
itps != this->PointShifts[d].end(); ++ itps )
|
||
|
|
{
|
||
|
|
double pt[3];
|
||
|
|
this->Points->GetPoint( itps->first, pt );
|
||
|
|
pt[d] += itps->second;
|
||
|
|
this->Points->SetPoint( itps->first, pt );
|
||
|
|
} // it
|
||
|
|
this->PointShifts[d].clear();
|
||
|
|
} // d
|
||
|
|
this->PointShifted.clear();
|
||
|
|
|
||
|
|
timer->StopTimer();
|
||
|
|
vtkDebugMacro(<< "Internal dual update : " << timer->GetElapsedTime());
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Iterate over leaves. Generate dual point. Highest level (smallest leaf)
|
||
|
|
// owns the corner and generates that dual cell.
|
||
|
|
void vtkHyperTreeGrid::TraverseDualRecursively(
|
||
|
|
vtkHyperTreeGridSuperCursor* superCursor, unsigned int level )
|
||
|
|
{
|
||
|
|
// Get cursor at super cursor center
|
||
|
|
vtkHyperTreeSimpleCursor* cursor0 = superCursor->GetCursor( 0 );
|
||
|
|
|
||
|
|
// Retrieve global index of center cursor
|
||
|
|
vtkIdType id0 = cursor0->GetGlobalNodeIndex();
|
||
|
|
|
||
|
|
// Initialize non leaf point coordinates
|
||
|
|
double pt[3] = { 0., 0., 0. };
|
||
|
|
for ( unsigned int d = 0; d < this->Dimension; ++ d )
|
||
|
|
{
|
||
|
|
pt[d] = superCursor->Origin[d] + superCursor->Size[d] / 2.;
|
||
|
|
}
|
||
|
|
// Retrieve global index of center cursor
|
||
|
|
this->Points->SetPoint( id0, pt );
|
||
|
|
if ( !cursor0->IsLeaf() )
|
||
|
|
{
|
||
|
|
// If cursor 0 is not at leaf, recurse to all children
|
||
|
|
for ( unsigned int child = 0; child < this->NumberOfChildren; ++ child )
|
||
|
|
{
|
||
|
|
vtkHyperTreeGridSuperCursor newSuperCursor;
|
||
|
|
this->InitializeSuperCursorChild( superCursor, &newSuperCursor, child );
|
||
|
|
this->TraverseDualRecursively( &newSuperCursor, level + 1 );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Center is a leaf, create a dual point
|
||
|
|
if ( this->MaterialMask->GetValue( id0 ) )
|
||
|
|
{
|
||
|
|
this->TraverseDualMaskedLeaf( superCursor );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
this->TraverseDualLeaf( superCursor );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::TraverseDualMaskedLeaf(
|
||
|
|
vtkHyperTreeGridSuperCursor* superCursor )
|
||
|
|
{
|
||
|
|
// Get cursor at super cursor center
|
||
|
|
vtkHyperTreeSimpleCursor* cursor0 = superCursor->GetCursor( 0 );
|
||
|
|
|
||
|
|
// Check across D-face neighbors whether point must be adjusted
|
||
|
|
int f = 1;
|
||
|
|
for ( unsigned int d = 0; d < this->Dimension; ++ d, f *= 3 )
|
||
|
|
{
|
||
|
|
// For each direction, check both orientations
|
||
|
|
for ( int o = -1; o < 2; o += 2 )
|
||
|
|
{
|
||
|
|
// Retrieve face neighbor cursor
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o * f );
|
||
|
|
|
||
|
|
// Detect faces shared by an unmasked cell, break ties at same level
|
||
|
|
if ( cursor->GetTree()
|
||
|
|
&& cursor->IsLeaf()
|
||
|
|
&& cursor->GetLevel() < cursor0->GetLevel() )
|
||
|
|
{
|
||
|
|
vtkIdType id = cursor->GetGlobalNodeIndex();
|
||
|
|
if ( ! this->MaterialMask->GetValue( id ) )
|
||
|
|
{
|
||
|
|
// Move to corresponding D-face
|
||
|
|
this->PointShifted[id] = true;
|
||
|
|
this->PointShifts[d][id] = - o
|
||
|
|
* this->ReductionFactors[cursor->GetLevel()]
|
||
|
|
* cursor->GetTree()->GetScale( d );
|
||
|
|
}
|
||
|
|
} // if cursor
|
||
|
|
} // o
|
||
|
|
} // d
|
||
|
|
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 2:
|
||
|
|
{
|
||
|
|
// Check across (D-1)-face neighbors (corners)
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = o2 + 3;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( cursor->GetTree()
|
||
|
|
&&
|
||
|
|
cursor->IsLeaf()
|
||
|
|
&& cursor->GetLevel() < cursor0->GetLevel() )
|
||
|
|
{
|
||
|
|
vtkIdType id = cursor->GetGlobalNodeIndex();
|
||
|
|
if ( ! this->MaterialMask->GetValue( id )
|
||
|
|
&& ! this->PointShifted[id] )
|
||
|
|
{
|
||
|
|
// Move to corresponding corner
|
||
|
|
double halfL[3];
|
||
|
|
cursor->GetTree()->GetScale( halfL );
|
||
|
|
double fac = this->ReductionFactors[cursor->GetLevel()];
|
||
|
|
this->PointShifts[0][id] = - o1 * o2 * fac * halfL[0];
|
||
|
|
this->PointShifts[1][id] = - o1 * fac * halfL[1];
|
||
|
|
}
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
break;
|
||
|
|
} // case 2
|
||
|
|
case 3:
|
||
|
|
{
|
||
|
|
// Check across (D-1)-face neighbors (edges)
|
||
|
|
int tpa1 = 1;
|
||
|
|
for ( int a1 = 0; a1 < 2; ++ a1, tpa1 *= 3 )
|
||
|
|
{
|
||
|
|
int tpa2 = 3 * tpa1;
|
||
|
|
for ( int a2 = a1 + 1; a2 < 3; ++ a2, tpa2 *= 3 )
|
||
|
|
{
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = tpa1 * o2 + tpa2;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( cursor->GetTree()
|
||
|
|
&&
|
||
|
|
cursor->IsLeaf()
|
||
|
|
&& cursor->GetLevel() < cursor0->GetLevel() )
|
||
|
|
{
|
||
|
|
vtkIdType id = cursor->GetGlobalNodeIndex();
|
||
|
|
if ( ! this->MaterialMask->GetValue( id )
|
||
|
|
&& ! this->PointShifted[id] )
|
||
|
|
{
|
||
|
|
// Move to corresponding edge
|
||
|
|
double halfL[3];
|
||
|
|
cursor->GetTree()->GetScale( halfL );
|
||
|
|
double fac = this->ReductionFactors[cursor->GetLevel()];
|
||
|
|
this->PointShifts[a1][id] = - o1 * o2 * fac * halfL[a1];
|
||
|
|
this->PointShifts[a2][id] = - o1 * fac * halfL[a2];
|
||
|
|
this->PointShifted[id] = true;
|
||
|
|
}
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
} // a2
|
||
|
|
} // a1
|
||
|
|
|
||
|
|
// Check across (D-2)-face neighbors (corners)
|
||
|
|
for ( int o3 = -1; o3 < 2; o3 += 2 )
|
||
|
|
{
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = o2 * ( o3 + 3 ) + 9;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( cursor->GetTree()
|
||
|
|
&&
|
||
|
|
cursor->IsLeaf()
|
||
|
|
&& cursor->GetLevel() < cursor0->GetLevel() )
|
||
|
|
{
|
||
|
|
vtkIdType id = cursor->GetGlobalNodeIndex();
|
||
|
|
if ( ! this->MaterialMask->GetValue( id )
|
||
|
|
&& ! this->PointShifted[id] )
|
||
|
|
{
|
||
|
|
// Move to corresponding corner
|
||
|
|
double halfL[3];
|
||
|
|
cursor->GetTree()->GetScale( halfL );
|
||
|
|
double fac = this->ReductionFactors[cursor->GetLevel()];
|
||
|
|
this->PointShifts[0][id] = - o1 * o2 * o3 * fac * halfL[0];
|
||
|
|
this->PointShifts[1][id] = - o1 * o2 * fac * halfL[1];
|
||
|
|
this->PointShifts[2][id] = - o1 * fac * halfL[2];
|
||
|
|
this->PointShifted[id] = true;
|
||
|
|
}
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
} // o3
|
||
|
|
break;
|
||
|
|
} // case 3
|
||
|
|
} // switch ( this->Dimension )
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::TraverseDualLeaf( vtkHyperTreeGridSuperCursor* superCursor )
|
||
|
|
{
|
||
|
|
// Get cursor at super cursor center
|
||
|
|
vtkHyperTreeSimpleCursor* cursor0 = superCursor->GetCursor( 0 );
|
||
|
|
|
||
|
|
// Initialize dual point coordinates and D-face adjustment flag
|
||
|
|
double pt[] = { 0., 0., 0. };
|
||
|
|
double halfL[] = { 0., 0., 0. };
|
||
|
|
bool movedToDFace = false;
|
||
|
|
|
||
|
|
// In 1D:
|
||
|
|
// (D-0)-faces are corners, neighbors are +/- 1
|
||
|
|
// (D-1)-faces do not exist
|
||
|
|
// (D-2)-faces do not exist
|
||
|
|
// In 2D:
|
||
|
|
// (D-0)-faces are edges, neighbors are +/- 1, 3
|
||
|
|
// (D-1)-faces are corners, neighbors are +/- 2, 4
|
||
|
|
// (D-2)-faces do not exist
|
||
|
|
// In 3D:
|
||
|
|
// (D-0)-faces are faces, neighbors are +/- 1, 3, 9
|
||
|
|
// (D-1)-faces are edges, neighbors are +/- 2, 4, 6, 8, 10, 12
|
||
|
|
// (D-2)-faces are corners, neighbors are +/- 5, 7, 11, 13
|
||
|
|
|
||
|
|
// Check across D-face neighbors whether point must be adjusted
|
||
|
|
int f = 1;
|
||
|
|
for ( unsigned int d = 0; d < this->Dimension; ++ d, f *= 3 )
|
||
|
|
{
|
||
|
|
// Start at center
|
||
|
|
halfL[d] = .5 * superCursor->Size[d];
|
||
|
|
pt[d] = superCursor->Origin[d] + halfL[d];
|
||
|
|
|
||
|
|
// Check
|
||
|
|
for ( int o = -1; o < 2; o += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o * f );
|
||
|
|
if ( ! cursor->GetTree()
|
||
|
|
||
|
||
|
|
( cursor->IsLeaf()
|
||
|
|
&& this->MaterialMask->GetValue( cursor->GetGlobalNodeIndex() ) ) )
|
||
|
|
{
|
||
|
|
// Move to corresponding D-face
|
||
|
|
pt[d] += o * halfL[d];
|
||
|
|
movedToDFace = true;
|
||
|
|
} // if cursor
|
||
|
|
} // o
|
||
|
|
} // d
|
||
|
|
|
||
|
|
// Only when point was not moved to D-face, check D-1 and D-2 neighbors
|
||
|
|
if ( ! movedToDFace )
|
||
|
|
{
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 2:
|
||
|
|
{
|
||
|
|
// Check across (D-1)-face neighbors (corners)
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = o2 + 3;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( ! cursor->GetTree()
|
||
|
|
||
|
||
|
|
( cursor->IsLeaf()
|
||
|
|
&& this->MaterialMask->GetValue( cursor->GetGlobalNodeIndex() ) ) )
|
||
|
|
{
|
||
|
|
// Move to corresponding corner
|
||
|
|
pt[0] += o1 * o2 * halfL[0];
|
||
|
|
pt[1] += o1 * halfL[1];
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
break;
|
||
|
|
} // case 2
|
||
|
|
case 3:
|
||
|
|
{
|
||
|
|
// Initialize edge adjustment flag
|
||
|
|
bool movedToEdge = false;
|
||
|
|
|
||
|
|
// Check across (D-1)-face neighbors (edges)
|
||
|
|
int tpa1 = 1;
|
||
|
|
for ( int a1 = 0; a1 < 2; ++ a1, tpa1 *= 3 )
|
||
|
|
{
|
||
|
|
int tpa2 = 3 * tpa1;
|
||
|
|
for ( int a2 = a1 + 1; a2 < 3; ++ a2, tpa2 *= 3 )
|
||
|
|
{
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = tpa1 * o2 + tpa2;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( ! cursor->GetTree()
|
||
|
|
||
|
||
|
|
( cursor->IsLeaf()
|
||
|
|
&& this->MaterialMask->GetValue( cursor->GetGlobalNodeIndex() ) ) )
|
||
|
|
{
|
||
|
|
// Move to corresponding edge
|
||
|
|
pt[a1] += o1 * o2 * halfL[a1];
|
||
|
|
pt[a2] += o1 * halfL[a2];
|
||
|
|
movedToEdge = true;
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
} // a2
|
||
|
|
} // a1
|
||
|
|
|
||
|
|
// Only when point was not moved to edge, check across corners
|
||
|
|
if ( ! movedToEdge )
|
||
|
|
{
|
||
|
|
for ( int o3 = -1; o3 < 2; o3 += 2 )
|
||
|
|
{
|
||
|
|
for ( int o2 = -1; o2 < 2; o2 += 2 )
|
||
|
|
{
|
||
|
|
int c = o2 * ( o3 + 3 ) + 9;
|
||
|
|
for ( int o1 = -1; o1 < 2; o1 += 2 )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->GetCursor( o1 * c );
|
||
|
|
if ( ! cursor->GetTree()
|
||
|
|
||
|
||
|
|
( cursor->IsLeaf()
|
||
|
|
&& this->MaterialMask->GetValue( cursor->GetGlobalNodeIndex() ) ) )
|
||
|
|
{
|
||
|
|
// Move to corresponding corner
|
||
|
|
pt[0] += o1 * o2 * o3 * halfL[0];
|
||
|
|
pt[1] += o1 * o2 * halfL[1];
|
||
|
|
pt[2] += o1 * halfL[2];
|
||
|
|
} // if cursor
|
||
|
|
} // o1
|
||
|
|
} // o2
|
||
|
|
} // o3
|
||
|
|
} // if ( ! movedToEdge )
|
||
|
|
break;
|
||
|
|
} // case 3
|
||
|
|
} // switch ( this->Dimension )
|
||
|
|
} // if ( ! movedToDFace )
|
||
|
|
|
||
|
|
// Retrieve global index of center cursor
|
||
|
|
vtkIdType id0 = cursor0->GetGlobalNodeIndex();
|
||
|
|
|
||
|
|
// Insert dual point corresponding to current primal cell
|
||
|
|
this->Points->SetPoint( id0, pt );
|
||
|
|
|
||
|
|
// If cell is masked, terminate recursion, no dual cell will be generated
|
||
|
|
if ( this->MaterialMask->GetValue( id0 ) )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Now see if the center leaf owns any of the corners
|
||
|
|
// If it does, create the dual cell
|
||
|
|
// Iterate over the corners around the middle leaf
|
||
|
|
int numLeavesCorners = 1 << this->Dimension;
|
||
|
|
for ( int cornerIdx = 0; cornerIdx < numLeavesCorners; ++ cornerIdx )
|
||
|
|
{
|
||
|
|
bool owner = true;
|
||
|
|
vtkIdType leaves[8];
|
||
|
|
// Iterate over every leaf touching the corner
|
||
|
|
for ( int leafIdx = 0; leafIdx < numLeavesCorners && owner; ++ leafIdx )
|
||
|
|
{
|
||
|
|
// Compute the cursor index into the superCursor
|
||
|
|
int cursorIdx = 0;
|
||
|
|
switch ( this->Dimension )
|
||
|
|
{
|
||
|
|
case 3:
|
||
|
|
cursorIdx += 9 * ( ( ( cornerIdx >> 2 ) & 1 ) + ( ( leafIdx >> 2 ) & 1 ) );
|
||
|
|
VTK_FALLTHROUGH;
|
||
|
|
case 2:
|
||
|
|
cursorIdx += 3 * ( ( ( cornerIdx >> 1 ) & 1 ) + ( ( leafIdx >> 1 ) & 1 ) );
|
||
|
|
VTK_FALLTHROUGH;
|
||
|
|
case 1:
|
||
|
|
cursorIdx += ( cornerIdx & 1) + ( leafIdx & 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Collect the leaf indices for the dual cell
|
||
|
|
leaves[leafIdx] = superCursor->Cursors[cursorIdx].GetGlobalNodeIndex();
|
||
|
|
|
||
|
|
// Compute if the mid leaf owns the corner
|
||
|
|
if ( cursorIdx != superCursor->MiddleCursorId )
|
||
|
|
{
|
||
|
|
vtkHyperTreeSimpleCursor* cursor = superCursor->Cursors + cursorIdx;
|
||
|
|
if ( ! cursor->GetTree() || ! cursor->IsLeaf() )
|
||
|
|
{
|
||
|
|
// If neighbor leaf is out of bounds or has not been
|
||
|
|
// refined to a leaf, this leaf does not own the corner
|
||
|
|
owner = false;
|
||
|
|
}
|
||
|
|
else if ( this->MaterialMask->GetValue( cursor->GetGlobalNodeIndex() ) )
|
||
|
|
{
|
||
|
|
owner = false;
|
||
|
|
}
|
||
|
|
else if ( cursor->GetLevel() == cursor0->GetLevel()
|
||
|
|
&& superCursor->MiddleCursorId < cursorIdx )
|
||
|
|
{
|
||
|
|
// A level tie is broken in favor of the largest index
|
||
|
|
// All points are set before defining the cell
|
||
|
|
owner = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} // leafIdx
|
||
|
|
|
||
|
|
if ( owner )
|
||
|
|
{
|
||
|
|
this->Connectivity->InsertNextTypedTuple( leaves );
|
||
|
|
}
|
||
|
|
} // cornerIdx
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------------------------------------
|
||
|
|
// This table is used to move a 3x3x3 neighborhood of cursors through the tree.
|
||
|
|
void vtkHyperTreeGrid::GenerateSuperCursorTraversalTable()
|
||
|
|
{
|
||
|
|
int bf = static_cast<int>( this->BranchFactor );
|
||
|
|
|
||
|
|
int xChildDim = bf;
|
||
|
|
int yChildDim = this->Dimension > 1 ? bf : 1;
|
||
|
|
int zChildDim = this->Dimension > 2 ? bf : 1;
|
||
|
|
int xCursorDim = 3;
|
||
|
|
int yCursorDim = this->Dimension > 1 ? 3 : 1;
|
||
|
|
int zCursorDim = this->Dimension > 2 ? 3 : 1;
|
||
|
|
|
||
|
|
int childId = 0;
|
||
|
|
for ( int zChild = 0; zChild < zChildDim; ++ zChild )
|
||
|
|
{
|
||
|
|
for ( int yChild = 0; yChild < yChildDim; ++ yChild )
|
||
|
|
{
|
||
|
|
for ( int xChild = 0; xChild < xChildDim; ++ xChild, ++ childId )
|
||
|
|
{
|
||
|
|
int cursorId = 0;
|
||
|
|
for ( int zCursor = 0; zCursor < zCursorDim; ++ zCursor )
|
||
|
|
{
|
||
|
|
for ( int yCursor = 0; yCursor < yCursorDim; ++ yCursor )
|
||
|
|
{
|
||
|
|
for ( int xCursor = 0; xCursor < xCursorDim; ++ xCursor, ++ cursorId )
|
||
|
|
{
|
||
|
|
// Compute the x, y, z index into the
|
||
|
|
// 6x6x6 (9x9x9) neighborhood of children.
|
||
|
|
int xNeighbor = xCursor + xChild + xChildDim - 1;
|
||
|
|
int yNeighbor = yCursor + yChild + yChildDim - 1;
|
||
|
|
int zNeighbor = zCursor + zChild + zChildDim - 1;
|
||
|
|
|
||
|
|
// Separate neighbor index into Cursor/Child index.
|
||
|
|
div_t dx = div( xNeighbor, bf );
|
||
|
|
div_t dy = div( yNeighbor, bf );
|
||
|
|
div_t dz = div( zNeighbor, bf );
|
||
|
|
int tableId = childId * 27 + cursorId;
|
||
|
|
this->SuperCursorTraversalTable[tableId].Parent
|
||
|
|
= dx.quot + 3 * ( dy.quot + 3 * dz.quot );
|
||
|
|
this->SuperCursorTraversalTable[tableId].Child
|
||
|
|
= dx.rem + bf * ( dy.rem + bf * dz.rem );
|
||
|
|
} // xCursor
|
||
|
|
} // yCursor
|
||
|
|
} // zCursor
|
||
|
|
} // xChild
|
||
|
|
} // yChild
|
||
|
|
} // zChild
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::DeleteInternalArrays()
|
||
|
|
{
|
||
|
|
if ( this->Points )
|
||
|
|
{
|
||
|
|
this->Points->UnRegister( this );
|
||
|
|
this->Points = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Connectivity )
|
||
|
|
{
|
||
|
|
this->Connectivity->UnRegister( this );
|
||
|
|
this->Connectivity = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( this->Links )
|
||
|
|
{
|
||
|
|
this->Links->UnRegister( this );
|
||
|
|
this->Links = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
// Hyper tree grid iterator
|
||
|
|
// Implemented here because it needs access to the internal classes.
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::vtkHyperTreeIterator::Initialize( vtkHyperTreeGrid* tree )
|
||
|
|
{
|
||
|
|
this->Tree = tree;
|
||
|
|
this->Iterator = tree->HyperTrees.begin();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkHyperTree* vtkHyperTreeGrid::vtkHyperTreeIterator::GetNextTree( vtkIdType &index )
|
||
|
|
{
|
||
|
|
if ( this->Iterator == this->Tree->HyperTrees.end() )
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
vtkHyperTree* t = this->Iterator->second;
|
||
|
|
index = this->Iterator->first;
|
||
|
|
++ this->Iterator;
|
||
|
|
return t;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkHyperTree* vtkHyperTreeGrid::vtkHyperTreeIterator::GetNextTree()
|
||
|
|
{
|
||
|
|
vtkIdType index;
|
||
|
|
return GetNextTree( index );
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
// Hyper tree grid cursor
|
||
|
|
// Implemented here because it needs access to the internal classes.
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Constructor.
|
||
|
|
vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::vtkHyperTreeSimpleCursor()
|
||
|
|
{
|
||
|
|
this->Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Set the state back to the initial constructed state
|
||
|
|
void vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::Clear()
|
||
|
|
{
|
||
|
|
this->Tree = 0;
|
||
|
|
this->Index = 0;
|
||
|
|
this->Leaf = false;
|
||
|
|
this->Level = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::Initialize( vtkHyperTreeGrid* grid,
|
||
|
|
vtkIdType index,
|
||
|
|
int pos[3] )
|
||
|
|
{
|
||
|
|
// Convert local index into global one
|
||
|
|
unsigned int n[3];
|
||
|
|
grid->GetGridSize( n );
|
||
|
|
vtkIdType globalIndex = grid->GetTransposedRootIndexing() ?
|
||
|
|
index + pos[2] +
|
||
|
|
pos[1] * static_cast<int>( n[2] ) +
|
||
|
|
pos[0] * static_cast<int>( n[2] ) * static_cast<int>( n[1] ) :
|
||
|
|
index + pos[0] +
|
||
|
|
pos[1] * static_cast<int>( n[0] ) +
|
||
|
|
pos[2] * static_cast<int>( n[0] ) * static_cast<int>( n[1] );
|
||
|
|
|
||
|
|
// Assign hypertree to this cursor
|
||
|
|
this->Tree = GetHTGHyperTreeAtIndexMacro( grid, globalIndex );
|
||
|
|
this->ToRoot();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
bool vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::IsLeaf()
|
||
|
|
{
|
||
|
|
// Empty cursors appear like a leaf so that recursion stop
|
||
|
|
return this->Tree ? this->Leaf : true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::ToRoot()
|
||
|
|
{
|
||
|
|
if ( ! this->Tree )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return to root level
|
||
|
|
this->Level = 0;
|
||
|
|
this->Index = 0;
|
||
|
|
|
||
|
|
this->Leaf = ( this->Tree->GetNumberOfLeaves() == 1 );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::ToChild( int child )
|
||
|
|
{
|
||
|
|
if ( ! this->Tree || this->Leaf )
|
||
|
|
{
|
||
|
|
// Leaves do not have children.
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this->Tree->FindChildParameters( child, this->Index, this->Leaf );
|
||
|
|
this->Level++;
|
||
|
|
|
||
|
|
assert( "Bad index" && this->Index >= 0 );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
vtkIdType vtkHyperTreeGrid::vtkHyperTreeSimpleCursor::GetGlobalNodeIndex()
|
||
|
|
{
|
||
|
|
return this->Tree ?
|
||
|
|
this->Tree->GetGlobalIndexFromLocal( this->Index ) : 0;
|
||
|
|
}
|