You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
650 lines
18 KiB
650 lines
18 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkDataSet.cxx,v $
|
|
|
|
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 "vtkDataSet.h"
|
|
|
|
#include "vtkCell.h"
|
|
#include "vtkCellData.h"
|
|
#include "vtkCellTypes.h"
|
|
#include "vtkExtentTranslator.h"
|
|
#include "vtkGenericCell.h"
|
|
#include "vtkIdList.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkSource.h"
|
|
|
|
#include <math.h>
|
|
|
|
vtkCxxRevisionMacro(vtkDataSet, "$Revision: 1.3.12.1 $");
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Constructor with default bounds (0,1, 0,1, 0,1).
|
|
vtkDataSet::vtkDataSet ()
|
|
{
|
|
vtkMath::UninitializeBounds(this->Bounds);
|
|
|
|
this->PointData = vtkPointData::New();
|
|
this->CellData = vtkCellData::New();
|
|
this->ScalarRange[0] = 0.0;
|
|
this->ScalarRange[1] = 1.0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDataSet::~vtkDataSet ()
|
|
{
|
|
this->PointData->Delete();
|
|
this->CellData->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::Initialize()
|
|
{
|
|
// We don't modify ourselves because the "ReleaseData" methods depend upon
|
|
// no modification when initialized.
|
|
vtkDataObject::Initialize();
|
|
|
|
this->CellData->Initialize();
|
|
this->PointData->Initialize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Compute the data bounding box from data points.
|
|
void vtkDataSet::ComputeBounds()
|
|
{
|
|
int j;
|
|
vtkIdType i;
|
|
double *x;
|
|
|
|
if ( this->GetMTime() > this->ComputeTime )
|
|
{
|
|
if (this->GetNumberOfPoints())
|
|
{
|
|
x = this->GetPoint(0);
|
|
this->Bounds[0] = x[0];
|
|
this->Bounds[2] = x[1];
|
|
this->Bounds[4] = x[2];
|
|
this->Bounds[1] = x[0];
|
|
this->Bounds[3] = x[1];
|
|
this->Bounds[5] = x[2];
|
|
for (i=1; i<this->GetNumberOfPoints(); i++)
|
|
{
|
|
x = this->GetPoint(i);
|
|
for (j=0; j<3; j++)
|
|
{
|
|
if ( x[j] < this->Bounds[2*j] )
|
|
{
|
|
this->Bounds[2*j] = x[j];
|
|
}
|
|
if ( x[j] > this->Bounds[2*j+1] )
|
|
{
|
|
this->Bounds[2*j+1] = x[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vtkMath::UninitializeBounds(this->Bounds);
|
|
}
|
|
this->ComputeTime.Modified();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GetScalarRange(double range[2])
|
|
{
|
|
vtkDataArray *ptScalars, *cellScalars;
|
|
ptScalars = this->PointData->GetScalars();
|
|
cellScalars = this->CellData->GetScalars();
|
|
|
|
if ( ptScalars && cellScalars)
|
|
{
|
|
double r1[2], r2[2];
|
|
ptScalars->GetRange(r1,0);
|
|
cellScalars->GetRange(r2,0);
|
|
range[0] = (r1[0] < r2[0] ? r1[0] : r2[0]);
|
|
range[1] = (r1[1] > r2[1] ? r1[1] : r2[1]);
|
|
}
|
|
else if ( ptScalars )
|
|
{
|
|
ptScalars->GetRange(range,0);
|
|
}
|
|
else if ( cellScalars )
|
|
{
|
|
cellScalars->GetRange(range,0);
|
|
}
|
|
else
|
|
{
|
|
range[0] = 0.0;
|
|
range[1] = 1.0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double *vtkDataSet::GetScalarRange()
|
|
{
|
|
this->GetScalarRange(this->ScalarRange);
|
|
return this->ScalarRange;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Return a pointer to the geometry bounding box in the form
|
|
// (xmin,xmax, ymin,ymax, zmin,zmax).
|
|
double *vtkDataSet::GetBounds()
|
|
{
|
|
this->ComputeBounds();
|
|
return this->Bounds;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GetBounds(double bounds[6])
|
|
{
|
|
this->ComputeBounds();
|
|
for (int i=0; i<6; i++)
|
|
{
|
|
bounds[i] = this->Bounds[i];
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Get the center of the bounding box.
|
|
double *vtkDataSet::GetCenter()
|
|
{
|
|
this->ComputeBounds();
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
this->Center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) / 2.0;
|
|
}
|
|
return this->Center;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GetCenter(double center[3])
|
|
{
|
|
this->ComputeBounds();
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) / 2.0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Return the length of the diagonal of the bounding box.
|
|
double vtkDataSet::GetLength()
|
|
{
|
|
double diff, l=0.0;
|
|
int i;
|
|
|
|
this->ComputeBounds();
|
|
for (i=0; i<3; i++)
|
|
{
|
|
diff = static_cast<double>(this->Bounds[2*i+1]) -
|
|
static_cast<double>(this->Bounds[2*i]);
|
|
l += diff * diff;
|
|
}
|
|
diff = sqrt(l);
|
|
return diff;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned long int vtkDataSet::GetMTime()
|
|
{
|
|
unsigned long mtime, result;
|
|
|
|
result = vtkDataObject::GetMTime();
|
|
|
|
mtime = this->PointData->GetMTime();
|
|
result = ( mtime > result ? mtime : result );
|
|
|
|
mtime = this->CellData->GetMTime();
|
|
return ( mtime > result ? mtime : result );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkCell *vtkDataSet::FindAndGetCell (double x[3], vtkCell *cell,
|
|
vtkIdType cellId, double tol2, int& subId,
|
|
double pcoords[3], double *weights)
|
|
{
|
|
int newCell = this->FindCell(x,cell,cellId,tol2,subId,pcoords,weights);
|
|
if (newCell >= 0 )
|
|
{
|
|
cell = this->GetCell (newCell);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
return cell;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GetCellNeighbors(vtkIdType cellId, vtkIdList *ptIds,
|
|
vtkIdList *cellIds)
|
|
{
|
|
vtkIdType i, numPts;
|
|
vtkIdList *otherCells = vtkIdList::New();
|
|
otherCells->Allocate(VTK_CELL_SIZE);
|
|
|
|
// load list with candidate cells, remove current cell
|
|
this->GetPointCells(ptIds->GetId(0), cellIds);
|
|
cellIds->DeleteId(cellId);
|
|
|
|
// now perform multiple intersections on list
|
|
if ( cellIds->GetNumberOfIds() > 0 )
|
|
{
|
|
for ( numPts=ptIds->GetNumberOfIds(), i=1; i < numPts; i++)
|
|
{
|
|
this->GetPointCells(ptIds->GetId(i), otherCells);
|
|
cellIds->IntersectWith(*otherCells);
|
|
}
|
|
}
|
|
|
|
otherCells->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GetCellTypes(vtkCellTypes *types)
|
|
{
|
|
vtkIdType cellId, numCells=this->GetNumberOfCells();
|
|
unsigned char type;
|
|
|
|
types->Reset();
|
|
for (cellId=0; cellId < numCells; cellId++)
|
|
{
|
|
type = this->GetCellType(cellId);
|
|
if ( ! types->IsType(type) )
|
|
{
|
|
types->InsertNextType(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Default implementation. This is very slow way to compute this information.
|
|
// Subclasses should override this method for efficiency.
|
|
void vtkDataSet::GetCellBounds(vtkIdType cellId, double bounds[6])
|
|
{
|
|
vtkGenericCell *cell = vtkGenericCell::New();
|
|
|
|
this->GetCell(cellId, cell);
|
|
cell->GetBounds(bounds);
|
|
cell->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::Squeeze()
|
|
{
|
|
this->CellData->Squeeze();
|
|
this->PointData->Squeeze();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned long vtkDataSet::GetActualMemorySize()
|
|
{
|
|
unsigned long size=this->vtkDataObject::GetActualMemorySize();
|
|
size += this->PointData->GetActualMemorySize();
|
|
size += this->CellData->GetActualMemorySize();
|
|
return size;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::ShallowCopy(vtkDataObject *dataObject)
|
|
{
|
|
vtkDataSet *dataSet = vtkDataSet::SafeDownCast(dataObject);
|
|
|
|
if ( dataSet != NULL )
|
|
{
|
|
this->InternalDataSetCopy(dataSet);
|
|
this->CellData->ShallowCopy(dataSet->GetCellData());
|
|
this->PointData->ShallowCopy(dataSet->GetPointData());
|
|
}
|
|
// Do superclass
|
|
this->vtkDataObject::ShallowCopy(dataObject);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::DeepCopy(vtkDataObject *dataObject)
|
|
{
|
|
vtkDataSet *dataSet = vtkDataSet::SafeDownCast(dataObject);
|
|
|
|
if ( dataSet != NULL )
|
|
{
|
|
this->InternalDataSetCopy(dataSet);
|
|
this->CellData->DeepCopy(dataSet->GetCellData());
|
|
this->PointData->DeepCopy(dataSet->GetPointData());
|
|
}
|
|
|
|
// Do superclass
|
|
this->vtkDataObject::DeepCopy(dataObject);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This copies all the local variables (but not objects).
|
|
void vtkDataSet::InternalDataSetCopy(vtkDataSet *src)
|
|
{
|
|
int idx;
|
|
|
|
this->ComputeTime = src->ComputeTime;
|
|
this->ScalarRange[0] = src->ScalarRange[0];
|
|
this->ScalarRange[1] = src->ScalarRange[1];
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
this->Bounds[2*idx] = src->Bounds[2*idx];
|
|
this->Bounds[2*idx+1] = src->Bounds[2*idx+1];
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDataSet::CheckAttributes()
|
|
{
|
|
int numPts, numCells;
|
|
int numArrays, idx;
|
|
vtkDataArray *array;
|
|
int numTuples;
|
|
const char* name;
|
|
|
|
numPts = this->GetNumberOfPoints();
|
|
numCells = this->GetNumberOfCells();
|
|
|
|
numArrays = this->GetPointData()->GetNumberOfArrays();
|
|
for (idx = 0; idx < numArrays; ++idx)
|
|
{
|
|
array = this->GetPointData()->GetArray(idx);
|
|
numTuples = array->GetNumberOfTuples();
|
|
name = array->GetName();
|
|
if (name == NULL)
|
|
{
|
|
name = "";
|
|
}
|
|
if (numTuples < numPts)
|
|
{
|
|
vtkErrorMacro("Point array " << name << " with "
|
|
<< array->GetNumberOfComponents()
|
|
<< " components, only has " << numTuples << " tuples but there are "
|
|
<< numPts << " points");
|
|
return 1;
|
|
}
|
|
if (numTuples > numPts)
|
|
{
|
|
vtkWarningMacro("Point array " << name << " with "
|
|
<< array->GetNumberOfComponents()
|
|
<< " components, has " << numTuples << " tuples but there are only "
|
|
<< numPts << " points");
|
|
}
|
|
}
|
|
|
|
numArrays = this->GetCellData()->GetNumberOfArrays();
|
|
for (idx = 0; idx < numArrays; ++idx)
|
|
{
|
|
array = this->GetCellData()->GetArray(idx);
|
|
numTuples = array->GetNumberOfTuples();
|
|
name = array->GetName();
|
|
if (name == NULL)
|
|
{
|
|
name = "";
|
|
}
|
|
if (numTuples < numCells)
|
|
{
|
|
vtkErrorMacro("Cell array " << name << " with "
|
|
<< array->GetNumberOfComponents()
|
|
<< " components, has only " << numTuples << " tuples but there are "
|
|
<< numCells << " cells");
|
|
return 1;
|
|
}
|
|
if (numTuples > numCells)
|
|
{
|
|
vtkWarningMacro("Cell array " << name << " with "
|
|
<< array->GetNumberOfComponents()
|
|
<< " components, has " << numTuples << " tuples but there are only "
|
|
<< numCells << " cells");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::GenerateGhostLevelArray()
|
|
{
|
|
// Make sure this is a structured data set.
|
|
if(this->GetExtentType() != VTK_3D_EXTENT)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (this->GetUpdateNumberOfPieces() == 1)
|
|
{
|
|
// Either the piece has not been used to set the update extent,
|
|
// or the whole image was requested.
|
|
return;
|
|
}
|
|
|
|
// Avoid generating these if the producer has generated them.
|
|
if(!this->PointData->GetArray("vtkGhostLevels"))
|
|
{ // Create ghost levels for cells and points.
|
|
vtkUnsignedCharArray *levels;
|
|
int zeroExt[6], extent[6];
|
|
int i, j, k, di, dj, dk, dist;
|
|
|
|
this->Information->Get(vtkDataObject::DATA_EXTENT(), extent);
|
|
vtkExtentTranslator* translator = this->GetExtentTranslator();
|
|
// Get the extent with ghost level 0.
|
|
translator->SetWholeExtent(this->GetWholeExtent());
|
|
translator->SetPiece(this->GetUpdatePiece());
|
|
translator->SetNumberOfPieces(this->GetUpdateNumberOfPieces());
|
|
translator->SetGhostLevel(0);
|
|
translator->PieceToExtent();
|
|
translator->GetExtent(zeroExt);
|
|
|
|
// ---- POINTS ----
|
|
// Allocate the appropriate number levels (number of points).
|
|
levels = vtkUnsignedCharArray::New();
|
|
levels->Allocate((extent[1]-extent[0] + 1) *
|
|
(extent[3]-extent[2] + 1) *
|
|
(extent[5]-extent[4] + 1));
|
|
|
|
//cerr << "max: " << extent[0] << ", " << extent[1] << ", "
|
|
// << extent[2] << ", " << extent[3] << ", "
|
|
// << extent[4] << ", " << extent[5] << endl;
|
|
//cerr << "zero: " << zeroExt[0] << ", " << zeroExt[1] << ", "
|
|
// << zeroExt[2] << ", " << zeroExt[3] << ", "
|
|
// << zeroExt[4] << ", " << zeroExt[5] << endl;
|
|
|
|
int wholeExtent[6] = {0,-1,0,-1,0,-1};
|
|
this->GetWholeExtent(wholeExtent);
|
|
// Loop through the points in this image.
|
|
for (k = extent[4]; k <= extent[5]; ++k)
|
|
{
|
|
dk = 0;
|
|
if (k < zeroExt[4])
|
|
{
|
|
dk = zeroExt[4] - k;
|
|
}
|
|
if (k >= zeroExt[5] && k < wholeExtent[5])
|
|
{ // Special case for last tile.
|
|
dk = k - zeroExt[5] + 1;
|
|
}
|
|
for (j = extent[2]; j <= extent[3]; ++j)
|
|
{
|
|
dj = 0;
|
|
if (j < zeroExt[2])
|
|
{
|
|
dj = zeroExt[2] - j;
|
|
}
|
|
if (j >= zeroExt[3] && j < wholeExtent[3])
|
|
{ // Special case for last tile.
|
|
dj = j - zeroExt[3] + 1;
|
|
}
|
|
for (i = extent[0]; i <= extent[1]; ++i)
|
|
{
|
|
di = 0;
|
|
if (i < zeroExt[0])
|
|
{
|
|
di = zeroExt[0] - i;
|
|
}
|
|
if (i >= zeroExt[1] && i < wholeExtent[1])
|
|
{ // Special case for last tile.
|
|
di = i - zeroExt[1] + 1;
|
|
}
|
|
// Compute Manhatten distance.
|
|
dist = di;
|
|
if (dj > dist)
|
|
{
|
|
dist = dj;
|
|
}
|
|
if (dk > dist)
|
|
{
|
|
dist = dk;
|
|
}
|
|
|
|
//cerr << " " << i << ", " << j << ", " << k << endl;
|
|
//cerr << " " << di << ", " << dj << ", " << dk << endl;
|
|
//cerr << dist << endl;
|
|
|
|
levels->InsertNextValue((unsigned char)dist);
|
|
}
|
|
}
|
|
}
|
|
levels->SetName("vtkGhostLevels");
|
|
this->PointData->AddArray(levels);
|
|
levels->Delete();
|
|
|
|
// Only generate ghost call levels if zero levels are requested.
|
|
// (Although we still need ghost points.)
|
|
if (this->GetUpdateGhostLevel() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ---- CELLS ----
|
|
// Allocate the appropriate number levels (number of cells).
|
|
levels = vtkUnsignedCharArray::New();
|
|
levels->Allocate((extent[1]-extent[0]) *
|
|
(extent[3]-extent[2]) *
|
|
(extent[5]-extent[4]));
|
|
|
|
// Loop through the cells in this image.
|
|
// Cells may be 2d or 1d ... Treat all as 3D
|
|
if (extent[0] == extent[1])
|
|
{
|
|
++extent[1];
|
|
++zeroExt[1];
|
|
}
|
|
if (extent[2] == extent[3])
|
|
{
|
|
++extent[3];
|
|
++zeroExt[3];
|
|
}
|
|
if (extent[4] == extent[5])
|
|
{
|
|
++extent[5];
|
|
++zeroExt[5];
|
|
}
|
|
|
|
// Loop
|
|
for (k = extent[4]; k < extent[5]; ++k)
|
|
{ // Determine the Manhatten distances to zero extent.
|
|
dk = 0;
|
|
if (k < zeroExt[4])
|
|
{
|
|
dk = zeroExt[4] - k;
|
|
}
|
|
if (k >= zeroExt[5])
|
|
{
|
|
dk = k - zeroExt[5] + 1;
|
|
}
|
|
for (j = extent[2]; j < extent[3]; ++j)
|
|
{
|
|
dj = 0;
|
|
if (j < zeroExt[2])
|
|
{
|
|
dj = zeroExt[2] - j;
|
|
}
|
|
if (j >= zeroExt[3])
|
|
{
|
|
dj = j - zeroExt[3] + 1;
|
|
}
|
|
for (i = extent[0]; i < extent[1]; ++i)
|
|
{
|
|
di = 0;
|
|
if (i < zeroExt[0])
|
|
{
|
|
di = zeroExt[0] - i;
|
|
}
|
|
if (i >= zeroExt[1])
|
|
{
|
|
di = i - zeroExt[1] + 1;
|
|
}
|
|
// Compute Manhatten distance.
|
|
dist = di;
|
|
if (dj > dist)
|
|
{
|
|
dist = dj;
|
|
}
|
|
if (dk > dist)
|
|
{
|
|
dist = dk;
|
|
}
|
|
|
|
levels->InsertNextValue((unsigned char)dist);
|
|
}
|
|
}
|
|
}
|
|
levels->SetName("vtkGhostLevels");
|
|
this->CellData->AddArray(levels);
|
|
levels->Delete();
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDataSet* vtkDataSet::GetData(vtkInformation* info)
|
|
{
|
|
return info? vtkDataSet::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDataSet* vtkDataSet::GetData(vtkInformationVector* v, int i)
|
|
{
|
|
return vtkDataSet::GetData(v->GetInformationObject(i));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDataSet::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
double *bounds;
|
|
|
|
os << indent << "Number Of Points: " << this->GetNumberOfPoints() << "\n";
|
|
os << indent << "Number Of Cells: " << this->GetNumberOfCells() << "\n";
|
|
|
|
os << indent << "Cell Data:\n";
|
|
this->CellData->PrintSelf(os,indent.GetNextIndent());
|
|
|
|
os << indent << "Point Data:\n";
|
|
this->PointData->PrintSelf(os,indent.GetNextIndent());
|
|
|
|
bounds = this->GetBounds();
|
|
os << indent << "Bounds: \n";
|
|
os << indent << " Xmin,Xmax: (" <<bounds[0] << ", " << bounds[1] << ")\n";
|
|
os << indent << " Ymin,Ymax: (" <<bounds[2] << ", " << bounds[3] << ")\n";
|
|
os << indent << " Zmin,Zmax: (" <<bounds[4] << ", " << bounds[5] << ")\n";
|
|
os << indent << "Compute Time: " <<this->ComputeTime.GetMTime() << "\n";
|
|
}
|
|
|
|
|