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.
1000 lines
26 KiB
C++
1000 lines
26 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkAMRInformation.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 "vtkAMRInformation.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkUnsignedIntArray.h"
|
|
#include "vtkIntArray.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkStructuredGrid.h"
|
|
#include "vtkBoundingBox.h"
|
|
#include "vtkAMRBox.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include <cassert>
|
|
#include <set>
|
|
|
|
vtkStandardNewMacro(vtkAMRInformation);
|
|
|
|
namespace
|
|
{
|
|
inline bool Inside(double q[3], double gbounds[6])
|
|
{
|
|
if ((q[0] < gbounds[0]) || (q[0] > gbounds[1]) ||
|
|
(q[1] < gbounds[2]) || (q[1] > gbounds[3]) ||
|
|
(q[2] < gbounds[4]) || (q[2] > gbounds[5]))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Utility class used to store bin properties
|
|
// and contents
|
|
class DataSetBinner
|
|
{
|
|
std::vector<std::vector<unsigned int> > Bins;
|
|
unsigned int NBins[3];
|
|
unsigned int LoCorner[3];
|
|
// Binsize in "extent coordinates"
|
|
unsigned int BinSize[3];
|
|
size_t TotalNumBins;
|
|
|
|
public:
|
|
|
|
// Create a set of bins given:
|
|
// - number of bins in x, y, z
|
|
// - lower extent of the binned space
|
|
// - the size of bins in "extent coordinates"
|
|
DataSetBinner(unsigned int nbins[3],
|
|
unsigned int locorner[3],
|
|
unsigned int binsize[3])
|
|
{
|
|
memcpy(this->NBins, nbins, 3*sizeof(unsigned int));
|
|
memcpy(this->LoCorner, locorner, 3*sizeof(unsigned int));
|
|
memcpy(this->BinSize, binsize, 3*sizeof(unsigned int));
|
|
this->TotalNumBins = nbins[0]*nbins[1]*nbins[2];
|
|
this->Bins.resize(this->TotalNumBins);
|
|
for (size_t i=0; i<this->TotalNumBins; i++)
|
|
{
|
|
this->Bins[i].reserve(5);
|
|
}
|
|
}
|
|
|
|
// Note that this does not check if the bin already
|
|
// contains the blockId. This works fine for what this
|
|
// class is used for.
|
|
void AddToBin(unsigned int binIndex[3], int blockId)
|
|
{
|
|
size_t idx = binIndex[2] +
|
|
binIndex[1]*this->NBins[2] +
|
|
binIndex[0]*this->NBins[2]*this->NBins[1];
|
|
std::vector<unsigned int>& bin = this->Bins[idx];
|
|
bin.push_back(blockId);
|
|
}
|
|
|
|
const std::vector<unsigned int>& GetBin(unsigned int binIndex[3]) const
|
|
{
|
|
size_t idx = binIndex[2] +
|
|
binIndex[1]*this->NBins[2] +
|
|
binIndex[0]*this->NBins[2]*this->NBins[1];
|
|
return this->Bins[idx];
|
|
}
|
|
|
|
// Given an input AMR box, return all boxes in the bins that intersect it
|
|
void GetBoxesInIntersectingBins(const vtkAMRBox& box, std::set<unsigned int>& boxes)
|
|
{
|
|
boxes.clear();
|
|
|
|
unsigned int minbin[3];
|
|
unsigned int maxbin[3];
|
|
|
|
const int* loCorner = box.GetLoCorner();
|
|
int hiCorner[3];
|
|
box.GetValidHiCorner(hiCorner);
|
|
|
|
for (int j=0; j<3; j++)
|
|
{
|
|
minbin[j] = (loCorner[j] - this->LoCorner[j]) / this->BinSize[j];
|
|
maxbin[j] = (hiCorner[j] - this->LoCorner[j]) / this->BinSize[j];
|
|
}
|
|
|
|
unsigned int idx[3];
|
|
for (idx[0]=minbin[0]; idx[0]<=maxbin[0]; idx[0]++)
|
|
for (idx[1]=minbin[1]; idx[1]<=maxbin[1]; idx[1]++)
|
|
for (idx[2]=minbin[2]; idx[2]<=maxbin[2]; idx[2]++)
|
|
{
|
|
const std::vector<unsigned int>& bin =
|
|
this->GetBin(idx);
|
|
std::vector<unsigned int>::const_iterator iter;
|
|
for(iter=bin.begin(); iter!=bin.end(); iter++)
|
|
{
|
|
boxes.insert(*iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
};
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
vtkAMRInformation::vtkAMRInformation(): NumBlocks(1,0)
|
|
{
|
|
this->Refinement = vtkSmartPointer<vtkIntArray>::New();
|
|
this->SourceIndex = NULL;
|
|
this->GridDescription = -1;
|
|
|
|
this->Origin[0] = this->Origin[1] = this->Origin[2] = DBL_MAX;
|
|
this->Spacing =NULL;
|
|
this->BlockLevel = NULL;
|
|
|
|
this->Bounds[0] = VTK_DOUBLE_MAX;
|
|
this->Bounds[1] = VTK_DOUBLE_MIN;
|
|
this->Bounds[2] = VTK_DOUBLE_MAX;
|
|
this->Bounds[3] = VTK_DOUBLE_MIN;
|
|
this->Bounds[4] = VTK_DOUBLE_MAX;
|
|
this->Bounds[5] = VTK_DOUBLE_MIN;
|
|
}
|
|
|
|
vtkAMRInformation::~vtkAMRInformation()
|
|
{
|
|
}
|
|
|
|
void vtkAMRInformation::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "Grid description: " << this->GetGridDescription()<< "\n";
|
|
os << indent << "Global origin: ("
|
|
<< this->GetOrigin()[0] <<", "
|
|
<< this->GetOrigin()[1] <<", "
|
|
<< this->GetOrigin()[2] <<")\n ";
|
|
|
|
os<< indent << "Number of blocks per level: ";
|
|
for(unsigned int i=1; i<this->NumBlocks.size();i++)
|
|
{
|
|
os<<indent<<this->NumBlocks[i]-this->NumBlocks[i-1]<<" ";
|
|
}
|
|
os<<"\n";
|
|
|
|
os<<indent<<"Refinemnt Ratio: ";
|
|
if(this->HasRefinementRatio())
|
|
{
|
|
for(unsigned int i=0; i<this->GetNumberOfLevels();i++)
|
|
{
|
|
os<<this->GetRefinementRatio(i)<<" ";
|
|
}
|
|
os<<"\n";
|
|
}
|
|
else
|
|
{
|
|
os<<"None\n";
|
|
}
|
|
for (unsigned int levelIdx=0; levelIdx<this->GetNumberOfLevels(); levelIdx++)
|
|
{
|
|
unsigned int numDataSets = this->GetNumberOfDataSets( levelIdx );
|
|
os<<indent<<"level "<<levelIdx<<"-------------------------"<<endl;
|
|
for( unsigned int dataIdx=0; dataIdx < numDataSets; ++dataIdx )
|
|
{
|
|
const vtkAMRBox& box = this->GetAMRBox(levelIdx,dataIdx);
|
|
os<<indent;
|
|
os<<"["<<box.GetLoCorner()[0]<<", "<<box.GetHiCorner()[0]<<"]"
|
|
<<"["<<box.GetLoCorner()[1]<<", "<<box.GetHiCorner()[1]<<"]"
|
|
<<"["<<box.GetLoCorner()[2]<<", "<<box.GetHiCorner()[2]<<"]"<<endl;
|
|
}
|
|
}
|
|
if(this->HasChildrenInformation())
|
|
{
|
|
os<<indent<<"Parent Child information: \n";
|
|
for (unsigned int levelIdx=0; levelIdx<this->GetNumberOfLevels(); levelIdx++)
|
|
{
|
|
unsigned int numDataSets = this->GetNumberOfDataSets( levelIdx );
|
|
for( unsigned int dataIdx=0; dataIdx < numDataSets; ++dataIdx )
|
|
{
|
|
this->PrintParentChildInfo(levelIdx,dataIdx);
|
|
}
|
|
}
|
|
}
|
|
os<<"\n";
|
|
}
|
|
|
|
bool vtkAMRInformation::Audit()
|
|
{
|
|
int emptyDimension(-1);
|
|
switch (this->GridDescription)
|
|
{
|
|
case VTK_YZ_PLANE: emptyDimension = 0; break;
|
|
case VTK_XZ_PLANE: emptyDimension = 1; break;
|
|
case VTK_XY_PLANE: emptyDimension = 2; break;
|
|
}
|
|
|
|
//Check origin
|
|
for(int d = 0; d<3; d++)
|
|
{
|
|
if(d!=emptyDimension)
|
|
{
|
|
if(this->Origin[d]!=this->Bounds[2*d])
|
|
{
|
|
vtkErrorMacro("Bound min does not match origin at dimension "<<d<<": "<<this->Origin[d]<<" != "<< this->Bounds[2*d]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//check refinement levels
|
|
if(this->HasRefinementRatio() && static_cast<unsigned int>(this->Refinement->GetNumberOfTuples())!=this->GetNumberOfLevels())
|
|
{
|
|
vtkErrorMacro("Refinement levels wrong "<< this->Refinement->GetNumberOfTuples());
|
|
}
|
|
|
|
//check spacing
|
|
for(unsigned int i=0; i<this->GetNumberOfLevels(); i++)
|
|
{
|
|
double h[3];
|
|
this->GetSpacing(i,h);
|
|
for(int d=0; d<3; d++)
|
|
{
|
|
if(h[d]<0)
|
|
{
|
|
vtkErrorMacro("Invalid spacing at level "<<i<<endl);
|
|
}
|
|
}
|
|
}
|
|
|
|
//check amr boxes
|
|
for(unsigned int i=0; i<this->Boxes.size();i++)
|
|
{
|
|
const vtkAMRBox& box = this->Boxes[i];
|
|
if(box.IsInvalid())
|
|
{
|
|
vtkErrorMacro("Invalid AMR Box");
|
|
}
|
|
bool valid(true);
|
|
switch (this->GridDescription)
|
|
{
|
|
case VTK_YZ_PLANE: valid = box.EmptyDimension(0); break;
|
|
case VTK_XZ_PLANE: valid = box.EmptyDimension(1); break;
|
|
case VTK_XY_PLANE: valid = box.EmptyDimension(2); break;
|
|
}
|
|
if(!valid)
|
|
{
|
|
vtkErrorMacro("Invalid AMRBox. Wrong dimension");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void vtkAMRInformation::Initialize(int numLevels, const int* blocksPerLevel)
|
|
{
|
|
if(numLevels<0)
|
|
{
|
|
vtkErrorMacro("Number of levels must be at least 0: "<<numLevels);
|
|
return;
|
|
}
|
|
// allocate boxes
|
|
this->NumBlocks.resize(numLevels+1,0);
|
|
for(unsigned int i=0; i<static_cast<unsigned int>(numLevels);i++)
|
|
{
|
|
this->NumBlocks[i+1] = this->NumBlocks[i] + blocksPerLevel[i];
|
|
}
|
|
|
|
int numBlocks = this->NumBlocks.back();
|
|
this->AllocateBoxes(numBlocks);
|
|
this->Spacing = vtkSmartPointer<vtkDoubleArray>::New();
|
|
this->Spacing->SetNumberOfTuples(3*numLevels);
|
|
this->Spacing->SetNumberOfComponents(3);
|
|
for(int i=0; i<numLevels; i++)
|
|
{
|
|
double h[3]={-1,-1,-1};
|
|
this->Spacing->SetTuple(i,h);
|
|
}
|
|
}
|
|
|
|
unsigned int vtkAMRInformation::GetNumberOfDataSets(unsigned int level) const
|
|
{
|
|
if( level>= this->GetNumberOfLevels())
|
|
{
|
|
cerr<<"WARNING: No data set at this level"<<endl;
|
|
return 0;
|
|
}
|
|
return this->NumBlocks[level+1]-this->NumBlocks[level];
|
|
}
|
|
|
|
void vtkAMRInformation::AllocateBoxes(unsigned int n)
|
|
{
|
|
this->Boxes.clear();
|
|
for(unsigned int i=0; i<n;i++)
|
|
{
|
|
vtkAMRBox box;
|
|
this->Boxes.push_back(box);
|
|
}
|
|
|
|
for(unsigned int i=0; i<n;i++)
|
|
{
|
|
this->Boxes[i].Invalidate();
|
|
}
|
|
|
|
}
|
|
|
|
void vtkAMRInformation::SetAMRBox(unsigned int level, unsigned int id, const vtkAMRBox& box)
|
|
{
|
|
unsigned int index = this->GetIndex(level,id);
|
|
this->Boxes[index] = box;
|
|
if(this->HasSpacing(level)) //has valid spacing
|
|
{
|
|
this->UpdateBounds(level,id);
|
|
}
|
|
}
|
|
|
|
int vtkAMRInformation::GetAMRBlockSourceIndex(int index)
|
|
{
|
|
return this->SourceIndex->GetValue(index);
|
|
}
|
|
|
|
void vtkAMRInformation::SetAMRBlockSourceIndex(int index, int sourceId)
|
|
{
|
|
if(!this->SourceIndex)
|
|
{
|
|
this->SourceIndex = vtkSmartPointer<vtkIntArray>::New();
|
|
this->SourceIndex->SetNumberOfValues(this->GetTotalNumberOfBlocks());
|
|
}
|
|
if(index>=this->SourceIndex->GetNumberOfTuples())
|
|
{
|
|
vtkErrorMacro("Invalid index");
|
|
return;
|
|
}
|
|
SourceIndex->SetValue(index,sourceId);
|
|
}
|
|
|
|
void vtkAMRInformation::ComputeIndexPair(unsigned int index, unsigned int& level, unsigned int& id)
|
|
{
|
|
this->GenerateBlockLevel();
|
|
level = this->BlockLevel->GetValue(static_cast<vtkIdType>(index));
|
|
id = index - this->NumBlocks[level] ;
|
|
}
|
|
|
|
void vtkAMRInformation::GetOrigin( double o[3] )
|
|
{
|
|
for( int i=0; i < 3; ++i )
|
|
{
|
|
o[i] = this->Origin[i];
|
|
}
|
|
}
|
|
double* vtkAMRInformation::GetOrigin()
|
|
{
|
|
if(!this->HasValidOrigin())
|
|
{
|
|
vtkErrorMacro("Invalid Origin");
|
|
}
|
|
return this->Origin;
|
|
}
|
|
|
|
void vtkAMRInformation::SetOrigin(const double* origin)
|
|
{
|
|
for(int d=0; d<3; d++)
|
|
{
|
|
this->Origin[d] = origin[d];
|
|
}
|
|
}
|
|
|
|
int vtkAMRInformation::GetRefinementRatio(unsigned int level) const
|
|
{
|
|
return this->Refinement->GetValue(level);
|
|
}
|
|
|
|
void vtkAMRInformation::SetRefinementRatio(unsigned int level, int refRatio)
|
|
{
|
|
if(!HasRefinementRatio())
|
|
{
|
|
this->Refinement->SetNumberOfTuples(this->GetNumberOfLevels());
|
|
}
|
|
this->Refinement->SetValue(level,refRatio);
|
|
}
|
|
|
|
bool vtkAMRInformation::HasRefinementRatio()
|
|
{
|
|
return this->Refinement && static_cast<unsigned int>(this->Refinement->GetNumberOfTuples())==this->GetNumberOfLevels();
|
|
}
|
|
|
|
void vtkAMRInformation::GenerateRefinementRatio()
|
|
{
|
|
this->Refinement->SetNumberOfTuples(this->GetNumberOfLevels());
|
|
|
|
// sanity check
|
|
int numLevels = this->GetNumberOfLevels();
|
|
|
|
if( numLevels < 1 )
|
|
{
|
|
// Dataset is empty!
|
|
return;
|
|
}
|
|
|
|
if( numLevels == 1)
|
|
{
|
|
// No refinement, data-set has only a single level.
|
|
// The refinement ratio is set to 2 to satisfy the
|
|
// vtkOverlappingAMR requirement.
|
|
this->Refinement->SetValue(0,2);
|
|
return;
|
|
}
|
|
|
|
for( int level=0; level < numLevels-1; ++level )
|
|
{
|
|
int childLevel = level+1;
|
|
|
|
if(this->GetNumberOfDataSets(childLevel)<1 || this->GetNumberOfDataSets(level)<1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
unsigned int id =0;
|
|
for(; id< this->GetNumberOfDataSets(level);id++)
|
|
{
|
|
if(!this->GetAMRBox(level,id).IsInvalid())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
double childSpacing[3];
|
|
this->GetSpacing(childLevel, childSpacing);
|
|
|
|
double currentSpacing[3];
|
|
this->GetSpacing(level, currentSpacing );
|
|
|
|
// Note current implementation assumes uniform spacing. The
|
|
// refinement ratio is the same in each dimension i,j,k.
|
|
int nonEmptyDimension = 0;
|
|
switch(this->GridDescription)
|
|
{
|
|
case VTK_XY_PLANE: nonEmptyDimension = 0;break;
|
|
case VTK_YZ_PLANE: nonEmptyDimension = 1;break;
|
|
case VTK_XZ_PLANE: nonEmptyDimension = 2;break;
|
|
}
|
|
int ratio = vtkMath::Round(currentSpacing[nonEmptyDimension]/childSpacing[nonEmptyDimension]);
|
|
|
|
// Set the ratio at the last level, i.e., level numLevels-1, to be the
|
|
// same as the ratio at the previous level,since the highest level
|
|
// doesn't really have a refinement ratio.
|
|
if( level==numLevels-2 )
|
|
{
|
|
this->Refinement->SetValue(level+1,ratio);
|
|
}
|
|
this->Refinement->SetValue(level,ratio);
|
|
} // END for all hi-res levels
|
|
}
|
|
|
|
bool vtkAMRInformation::HasChildrenInformation()
|
|
{
|
|
return !this->AllChildren.empty();
|
|
}
|
|
|
|
|
|
unsigned int *vtkAMRInformation::GetParents(unsigned int level, unsigned int index, unsigned int& num)
|
|
{
|
|
if(level>=this->AllParents.size() ||
|
|
index>=this->AllParents[level].size() ||
|
|
this->AllParents[level][index].empty())
|
|
{
|
|
num = 0;
|
|
return NULL;
|
|
}
|
|
|
|
num = static_cast<unsigned int>(this->AllParents[level][index].size());
|
|
|
|
return &this->AllParents[level][index][0];
|
|
|
|
}
|
|
|
|
unsigned int *vtkAMRInformation::
|
|
GetChildren(unsigned int level, unsigned int index, unsigned int& size)
|
|
{
|
|
if(level>=this->AllChildren.size() ||
|
|
index>=this->AllChildren[level].size() ||
|
|
this->AllChildren[level][index].empty())
|
|
{
|
|
size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
size = static_cast<unsigned int>(this->AllChildren[level][index].size());
|
|
|
|
return &this->AllChildren[level][index][0];
|
|
}
|
|
|
|
void vtkAMRInformation::
|
|
PrintParentChildInfo(unsigned int level, unsigned int index)
|
|
{
|
|
unsigned int *ptr, i, numParents;
|
|
std::cerr << "Parent Child Info for block " << index
|
|
<< " of Level: " << level << endl;
|
|
ptr = this->GetParents(level, index, numParents);
|
|
std::cerr << " Parents: ";
|
|
for (i = 0; i < numParents; i++)
|
|
{
|
|
std::cerr << ptr[i] << " ";
|
|
}
|
|
std::cerr << endl;
|
|
std::cerr << " Children: ";
|
|
unsigned int numChildren;
|
|
ptr = this->GetChildren(level, index,numChildren);
|
|
for (i = 0; i <numChildren; i++)
|
|
{
|
|
std::cerr << ptr[i] << " ";
|
|
}
|
|
std::cerr << endl;
|
|
}
|
|
|
|
void vtkAMRInformation::GenerateParentChildInformation()
|
|
{
|
|
if(!this->HasRefinementRatio())
|
|
{
|
|
this->GenerateRefinementRatio();
|
|
}
|
|
AllChildren.resize(this->GetNumberOfLevels());
|
|
AllParents.resize(this->GetNumberOfLevels());
|
|
|
|
unsigned int numLevels = this->GetNumberOfLevels();
|
|
for(unsigned int i=1; i<numLevels; i++)
|
|
{
|
|
this->CalculateParentChildRelationShip(i, AllChildren[i-1], AllParents[i]);
|
|
}
|
|
}
|
|
|
|
bool vtkAMRInformation::HasValidOrigin()
|
|
{
|
|
return this->Origin[0]!=DBL_MAX && this->Origin[1]!=DBL_MAX && this->Origin[2]!=DBL_MAX;
|
|
}
|
|
|
|
bool vtkAMRInformation::HasValidBounds()
|
|
{
|
|
return this->Bounds[0]!=DBL_MAX && this->Bounds[1]!=DBL_MAX && this->Bounds[2]!=DBL_MAX;
|
|
}
|
|
|
|
void vtkAMRInformation::SetGridDescription(int description)
|
|
{
|
|
if (description < VTK_SINGLE_POINT || description > VTK_EMPTY)
|
|
{
|
|
vtkErrorMacro("Invalid grid description for a vtkUniformGrid.");
|
|
return;
|
|
}
|
|
this->GridDescription = description;
|
|
}
|
|
|
|
void vtkAMRInformation::SetSpacing(unsigned int level, const double* h)
|
|
{
|
|
double* spacing = this->Spacing->GetTuple(level);
|
|
for(unsigned int i=0; i<3; i++)
|
|
{
|
|
if(spacing[i]>0 && spacing[i]!=h[i])
|
|
{
|
|
vtkWarningMacro("Inconsistent spacing: "<<spacing[i]<<" != "<<h[i]);
|
|
}
|
|
}
|
|
this->Spacing->SetTuple(level, h);
|
|
}
|
|
|
|
void vtkAMRInformation::GenerateBlockLevel()
|
|
{
|
|
if(this->BlockLevel)
|
|
{
|
|
return;
|
|
}
|
|
this->BlockLevel = vtkSmartPointer<vtkUnsignedIntArray>::New();
|
|
|
|
this->BlockLevel->SetNumberOfValues( static_cast<vtkIdType>(this->GetTotalNumberOfBlocks()));
|
|
|
|
assert(this->NumBlocks.size()==this->GetNumberOfLevels()+1);
|
|
|
|
vtkIdType index(0);
|
|
for(size_t level = 0; level< this->NumBlocks.size()-1; level++)
|
|
{
|
|
unsigned int begin = this->NumBlocks[level];
|
|
unsigned int end = this->NumBlocks[level+1];
|
|
for(unsigned int id=begin; id!=end; id++)
|
|
{
|
|
this->BlockLevel->SetValue(index++,static_cast<unsigned int>(level));
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkAMRInformation::GetBounds(unsigned int level, unsigned int id, double* bb)
|
|
{
|
|
const vtkAMRBox& box = this->Boxes[this->GetIndex(level,id)];
|
|
vtkAMRBox::GetBounds(box, this->Origin, this->Spacing->GetTuple(level), bb);
|
|
}
|
|
|
|
const vtkAMRBox& vtkAMRInformation::GetAMRBox(unsigned int level, unsigned int id) const
|
|
{
|
|
return this->Boxes[this->GetIndex(level,id)];
|
|
}
|
|
|
|
void vtkAMRInformation::GetSpacing(unsigned int level, double spacing[3])
|
|
{
|
|
return this->Spacing->GetTuple(level,spacing);
|
|
}
|
|
|
|
void vtkAMRInformation::CalculateParentChildRelationShip(
|
|
unsigned int level,
|
|
std::vector<std::vector<unsigned int> >& children,
|
|
std::vector<std::vector<unsigned int> >& parents
|
|
)
|
|
{
|
|
if (level == 0 || level > this->GetNumberOfLevels())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 1. Find the bounds of all boxes at level n-1
|
|
// 2. Find the average block size
|
|
int extents[6] = { VTK_INT_MAX, -VTK_INT_MAX,
|
|
VTK_INT_MAX, -VTK_INT_MAX,
|
|
VTK_INT_MAX, -VTK_INT_MAX};
|
|
float totalsize[3] = {0, 0, 0};
|
|
unsigned int numParentDataSets = this->GetNumberOfDataSets(level - 1);
|
|
int refinementRatio = this->GetRefinementRatio(level - 1);
|
|
for (unsigned int id=0; id<numParentDataSets; id++)
|
|
{
|
|
vtkAMRBox box = this->GetAMRBox(level - 1, id);
|
|
if (!box.IsInvalid())
|
|
{
|
|
box.Refine(refinementRatio);
|
|
const int* loCorner = box.GetLoCorner();
|
|
int hiCorner[3];
|
|
box.GetValidHiCorner(hiCorner);
|
|
for (int i = 0; i<3; i++)
|
|
{
|
|
if (loCorner[i] < extents[2*i])
|
|
{
|
|
extents[2*i] = loCorner[i];
|
|
}
|
|
if (hiCorner[i] > extents[2*i+1])
|
|
{
|
|
extents[2*i+1] = hiCorner[i];
|
|
}
|
|
totalsize[i] += (hiCorner[i] - loCorner[i] + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate number of bins and binsize. Note that bins
|
|
// are cell aligned and we use AMRBox indices to represent
|
|
// them
|
|
unsigned int nbins[3];
|
|
unsigned int binsize[3];
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
binsize[i] = vtkMath::Round(totalsize[i] / numParentDataSets);
|
|
nbins[i] = (extents[2*i+1] - extents[2*i]) / binsize[i] + 1;
|
|
}
|
|
|
|
double origin[3];
|
|
double spacing[3];
|
|
|
|
this->GetOrigin(origin);
|
|
this->GetSpacing(0,spacing);
|
|
for (unsigned int i=0; i<level; i++)
|
|
{
|
|
for (int j=0; j<3; j++)
|
|
spacing[j] /= this->GetRefinementRatio(i);
|
|
}
|
|
|
|
unsigned int loExtent[3];
|
|
loExtent[0] = extents[0];
|
|
loExtent[1] = extents[2];
|
|
loExtent[2] = extents[4];
|
|
DataSetBinner binner(nbins, loExtent, binsize);
|
|
// for(int i=0; i<3; i++)
|
|
// {
|
|
// cout<<nbins[i]<<" "<<loExtent[i]<<" "<<binsize[i]<<endl;
|
|
// }
|
|
|
|
// Bin the blocks
|
|
for (unsigned int i=0; i<numParentDataSets; i++)
|
|
{
|
|
vtkAMRBox box = this->GetAMRBox(level - 1, i);
|
|
if (!box.IsInvalid())
|
|
{
|
|
unsigned int minbin[3];
|
|
unsigned int maxbin[3];
|
|
|
|
box.Refine(refinementRatio);
|
|
|
|
const int* loCorner = box.GetLoCorner();
|
|
int hiCorner[3];
|
|
box.GetValidHiCorner(hiCorner);
|
|
|
|
for (int j=0; j<3; j++)
|
|
{
|
|
minbin[j] = (loCorner[j] - extents[2*j]) / binsize[j];
|
|
maxbin[j] = (hiCorner[j] - extents[2*j]) / binsize[j];
|
|
}
|
|
|
|
unsigned int idx[3];
|
|
for (idx[0]=minbin[0]; idx[0]<=maxbin[0]; idx[0]++)
|
|
{
|
|
for (idx[1]=minbin[1]; idx[1]<=maxbin[1]; idx[1]++)
|
|
{
|
|
for (idx[2]=minbin[2]; idx[2]<=maxbin[2]; idx[2]++)
|
|
{
|
|
binner.AddToBin(idx, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write bins for debugging
|
|
// WriteBins(origin, spacing, extents, binsize, nbins, binner);
|
|
|
|
// Actually find parent-children relationship
|
|
// between blocks in level and level-1
|
|
children.resize(this->GetNumberOfDataSets(level-1));
|
|
parents.resize(this->GetNumberOfDataSets(level));
|
|
|
|
unsigned int numDataSets = this->GetNumberOfDataSets(level);
|
|
for (unsigned int i=0; i<numDataSets; i++)
|
|
{
|
|
const vtkAMRBox& box = this->GetAMRBox(level, i);
|
|
if (!box.IsInvalid())
|
|
{
|
|
std::set<unsigned int> boxes;
|
|
binner.GetBoxesInIntersectingBins(box, boxes);
|
|
std::set<unsigned int>::iterator iter;
|
|
for (iter=boxes.begin(); iter!=boxes.end(); iter++)
|
|
{
|
|
vtkAMRBox potentialParent = this->GetAMRBox(level - 1, *iter);
|
|
if (!potentialParent.IsInvalid())
|
|
{
|
|
potentialParent.Refine(refinementRatio);
|
|
if (box.DoesIntersect(potentialParent))
|
|
{
|
|
children[*iter].push_back(i);
|
|
parents[i].push_back(*iter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool vtkAMRInformation::FindCell(double q[3],unsigned int level, unsigned int id,int &cellIdx)
|
|
{
|
|
double h[3];
|
|
this->GetSpacing(level,h);
|
|
|
|
const vtkAMRBox& box = this->GetAMRBox(level,id);
|
|
double gbounds[6];
|
|
this->GetBounds(level,id,gbounds);
|
|
if ((q[0] < gbounds[0]) || (q[0] > gbounds[1]) ||
|
|
(q[1] < gbounds[2]) || (q[1] > gbounds[3]) ||
|
|
(q[2] < gbounds[4]) || (q[2] > gbounds[5]))
|
|
{
|
|
return false;
|
|
}
|
|
int ijk[3];
|
|
double pcoords[3];
|
|
int status = vtkAMRBox::ComputeStructuredCoordinates(box, this->Origin, h, q, ijk, pcoords );
|
|
if( status == 1 )
|
|
{
|
|
int dims[3];
|
|
box.GetNumberOfNodes(dims);
|
|
cellIdx=vtkStructuredData::ComputeCellId(dims,ijk);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool vtkAMRInformation::GetCoarsenedAMRBox(unsigned int level, unsigned int id, vtkAMRBox& box) const
|
|
{
|
|
box = this->GetAMRBox(level,id);
|
|
if(box.IsInvalid())
|
|
{
|
|
std::cerr<<"Invalid AMR box."<<std::endl;
|
|
return false;
|
|
}
|
|
if(level==0)
|
|
{
|
|
std::cerr<<"Cannot get AMR box at level 0."<<std::endl;
|
|
return false;
|
|
}
|
|
|
|
int refinementRatio = this->GetRefinementRatio(level-1);
|
|
box.Coarsen(refinementRatio);
|
|
return true;
|
|
}
|
|
|
|
bool vtkAMRInformation::operator==(const vtkAMRInformation& other)
|
|
{
|
|
if(this->GridDescription!=other.GridDescription)
|
|
{
|
|
return false;
|
|
}
|
|
if(this->NumBlocks.size()!=other.NumBlocks.size())
|
|
{
|
|
return false;
|
|
}
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
if(this->Origin[i]!=other.Origin[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
for(size_t i=0; i<this->NumBlocks.size();i++)
|
|
{
|
|
if(this->NumBlocks[i]!=other.NumBlocks[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for(size_t i=0; i<this->Boxes.size(); i++)
|
|
{
|
|
if(this->Boxes[i]!=other.Boxes[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if(this->SourceIndex && other.SourceIndex)
|
|
{
|
|
for(vtkIdType i=0; i<this->SourceIndex->GetNumberOfTuples();i++)
|
|
{
|
|
if(this->SourceIndex->GetValue(i)!=other.SourceIndex->GetValue(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(this->Spacing->GetNumberOfTuples()!=other.Spacing->GetNumberOfTuples())
|
|
{
|
|
return false;
|
|
}
|
|
for(vtkIdType i=0; i<this->Spacing->GetNumberOfTuples();i++)
|
|
{
|
|
if(this->Spacing->GetValue(i)!=other.Spacing->GetValue(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool vtkAMRInformation::GetOrigin(unsigned int level, unsigned int id, double* origin)
|
|
{
|
|
const vtkAMRBox& box = this->Boxes[this->GetIndex(level,id)];
|
|
vtkAMRBox::GetBoxOrigin(box, this->Origin, this->Spacing->GetTuple(level), origin);
|
|
return true;
|
|
}
|
|
|
|
void vtkAMRInformation::UpdateBounds(const int level, const int id)
|
|
{
|
|
double bb[6];
|
|
vtkAMRBox::GetBounds(this->GetAMRBox(level,id), this->Origin, this->Spacing->GetTuple(level), bb);
|
|
for( int i=0; i < 3; ++i )
|
|
{
|
|
if( bb[i*2] < this->Bounds[i*2] )
|
|
{
|
|
this->Bounds[i*2] = bb[i*2];
|
|
}
|
|
if( bb[i*2+1] > this->Bounds[i*2+1])
|
|
{
|
|
this->Bounds[i*2+1] = bb[i*2+1];
|
|
}
|
|
} // END for each dimension
|
|
}
|
|
|
|
void vtkAMRInformation::DeepCopy(vtkAMRInformation *other)
|
|
{
|
|
this->GridDescription = other->GridDescription;
|
|
memcpy(this->Origin, other->Origin, sizeof(double)*3);
|
|
this->Boxes = other->Boxes;
|
|
this->NumBlocks = other->NumBlocks;
|
|
if(other->SourceIndex)
|
|
{
|
|
this->SourceIndex = vtkSmartPointer<vtkIntArray>::New();
|
|
this->SourceIndex->DeepCopy(other->SourceIndex);
|
|
}
|
|
if(other->Spacing)
|
|
{
|
|
this->Spacing = vtkSmartPointer<vtkDoubleArray>::New();
|
|
this->Spacing->DeepCopy(other->Spacing);
|
|
}
|
|
memcpy(this->Bounds, other->Bounds, sizeof(double)*6);
|
|
|
|
}
|
|
|
|
bool vtkAMRInformation::HasSpacing(unsigned int level)
|
|
{
|
|
return this->Spacing->GetTuple(level)[0] >=0
|
|
|| this->Spacing->GetTuple(level)[1] >=0
|
|
|| this->Spacing->GetTuple(level)[2] >=0;
|
|
}
|
|
|
|
const double* vtkAMRInformation::GetBounds()
|
|
{
|
|
if(!HasValidBounds())
|
|
{
|
|
for(unsigned int i=0; i<this->GetNumberOfLevels();i++)
|
|
{
|
|
for(unsigned int j=0; j<this->GetNumberOfDataSets(i);j++)
|
|
{
|
|
this->UpdateBounds(i,j);
|
|
}
|
|
}
|
|
}
|
|
return this->Bounds;
|
|
}
|
|
|
|
bool vtkAMRInformation::FindGrid(double q[3], unsigned int& level, unsigned int& gridId)
|
|
{
|
|
if (!this->HasChildrenInformation())
|
|
{
|
|
this->GenerateParentChildInformation();
|
|
}
|
|
|
|
if (!this->FindGrid(q, 0,gridId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
unsigned int maxLevels = this->GetNumberOfLevels();
|
|
for(level=0; level<maxLevels;level++)
|
|
{
|
|
unsigned int n;
|
|
unsigned int *children = this->GetChildren(level, gridId,n);
|
|
if (children == NULL)
|
|
{
|
|
break;
|
|
}
|
|
unsigned int i;
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
double bb[6];
|
|
this->GetBounds(level+1, children[i],bb);
|
|
if(Inside(q,bb))
|
|
{
|
|
gridId = children[i];
|
|
break;
|
|
}
|
|
}
|
|
if(i>=n)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool vtkAMRInformation::FindGrid(double q[3], int level, unsigned int& gridId)
|
|
{
|
|
for(unsigned int i = 0; i < this->GetNumberOfDataSets(level); i++ )
|
|
{
|
|
double gbounds[6];
|
|
this->GetBounds(level,i,gbounds);
|
|
bool inside = Inside(q,gbounds);
|
|
if(inside)
|
|
{
|
|
gridId = i;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|