Cloned library of VTK-5.0.0 with extra build files for internal package management.
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.
 
 
 
 
 
 

379 lines
11 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkEncodedGradientEstimator.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 "vtkEncodedGradientEstimator.h"
#include "vtkGarbageCollector.h"
#include "vtkImageData.h"
#include "vtkMultiThreader.h"
#include "vtkRecursiveSphereDirectionEncoder.h"
#include "vtkTimerLog.h"
#include <math.h>
vtkCxxRevisionMacro(vtkEncodedGradientEstimator, "$Revision: 1.1 $");
vtkCxxSetObjectMacro(vtkEncodedGradientEstimator, Input, vtkImageData );
// Construct a vtkEncodedGradientEstimator with initial values of NULL for
// the Input, EncodedNormal, and GradientMagnitude. Also,
// indicate that the IndexTable has not yet been initialized. The
// GradientMagnitudeRange and the GradientMangitudeTable are
// initialized to default values - these will change in the future
// when magnitude of gradient opacities are included
vtkEncodedGradientEstimator::vtkEncodedGradientEstimator()
{
this->Input = NULL;
this->EncodedNormals = NULL;
this->EncodedNormalsSize[0] = 0;
this->EncodedNormalsSize[1] = 0;
this->EncodedNormalsSize[2] = 0;
this->GradientMagnitudes = NULL;
this->GradientMagnitudeScale = 1.0;
this->GradientMagnitudeBias = 0.0;
this->Threader = vtkMultiThreader::New();
this->NumberOfThreads = this->Threader->GetNumberOfThreads();
this->DirectionEncoder = vtkRecursiveSphereDirectionEncoder::New();
this->ComputeGradientMagnitudes = 1;
this->CylinderClip = 0;
this->CircleLimits = NULL;
this->CircleLimitsSize = -1;
this->UseCylinderClip = 0;
this->LastUpdateTimeInSeconds = -1.0;
this->LastUpdateTimeInCPUSeconds = -1.0;
this->ZeroNormalThreshold = 0.0;
this->ZeroPad = 1;
this->BoundsClip = 0;
this->Bounds[0] =
this->Bounds[1] =
this->Bounds[2] =
this->Bounds[3] =
this->Bounds[4] =
this->Bounds[5] = 0;
}
// Destruct a vtkEncodedGradientEstimator - free up any memory used
vtkEncodedGradientEstimator::~vtkEncodedGradientEstimator()
{
this->SetInput(NULL);
this->Threader->Delete();
this->Threader = NULL;
if ( this->EncodedNormals )
{
delete [] this->EncodedNormals;
}
if ( this->GradientMagnitudes )
{
delete [] this->GradientMagnitudes;
}
if ( this->DirectionEncoder )
{
this->DirectionEncoder->UnRegister( this );
}
if ( this->CircleLimits )
{
delete [] this->CircleLimits;
}
}
void vtkEncodedGradientEstimator::SetZeroNormalThreshold( float v )
{
if ( this->ZeroNormalThreshold != v )
{
if ( v < 0.0 )
{
vtkErrorMacro( << "The ZeroNormalThreshold must be a value >= 0.0" );
return;
}
this->ZeroNormalThreshold = v;
this->Modified();
}
}
void
vtkEncodedGradientEstimator::SetDirectionEncoder(vtkDirectionEncoder *direnc)
{
// If we are setting it to its current value, don't do anything
if ( this->DirectionEncoder == direnc )
{
return;
}
// If we already have a direction encoder, unregister it.
if ( this->DirectionEncoder )
{
this->DirectionEncoder->UnRegister(this);
this->DirectionEncoder = NULL;
}
// If we are passing in a non-NULL encoder, register it
if ( direnc )
{
direnc->Register( this );
}
// Actually set the encoder, and consider the object Modified
this->DirectionEncoder = direnc;
this->Modified();
}
int vtkEncodedGradientEstimator::GetEncodedNormalIndex( int xyzIndex )
{
this->Update();
return *(this->EncodedNormals + xyzIndex);
}
int vtkEncodedGradientEstimator::GetEncodedNormalIndex( int xIndex,
int yIndex,
int zIndex )
{
int ystep, zstep;
this->Update();
// Compute steps through the volume in x, y, and z
ystep = this->InputSize[0];
zstep = this->InputSize[0] * this->InputSize[1];
return *(this->EncodedNormals + zIndex * zstep + yIndex * ystep + xIndex);
}
unsigned short *vtkEncodedGradientEstimator::GetEncodedNormals()
{
this->Update();
return this->EncodedNormals;
}
unsigned char *vtkEncodedGradientEstimator::GetGradientMagnitudes()
{
this->Update();
return this->GradientMagnitudes;
}
void vtkEncodedGradientEstimator::Update( )
{
int scalarInputSize[3];
double scalarInputAspect[3];
double startSeconds, endSeconds;
double startCPUSeconds, endCPUSeconds;
if ( !this->Input )
{
vtkErrorMacro(<< "No input in gradient estimator.");
return;
}
if ( this->GetMTime() > this->BuildTime ||
this->DirectionEncoder->GetMTime() > this->BuildTime ||
this->Input->GetMTime() > this->BuildTime ||
!this->EncodedNormals )
{
this->Input->UpdateInformation();
this->Input->SetUpdateExtentToWholeExtent();
this->Input->Update();
startSeconds = vtkTimerLog::GetUniversalTime();
startCPUSeconds = vtkTimerLog::GetCPUTime();
// Get the dimensions of the data and its aspect ratio
this->Input->GetDimensions( scalarInputSize );
this->Input->GetSpacing( scalarInputAspect );
// If we previously have allocated space for the encoded normals,
// and this space is no longer the right size, delete it
if ( this->EncodedNormalsSize[0] != scalarInputSize[0] ||
this->EncodedNormalsSize[1] != scalarInputSize[1] ||
this->EncodedNormalsSize[2] != scalarInputSize[2] )
{
if ( this->EncodedNormals )
{
delete [] this->EncodedNormals;
this->EncodedNormals = NULL;
}
if ( this->GradientMagnitudes )
{
delete [] this->GradientMagnitudes;
this->GradientMagnitudes = NULL;
}
}
// Allocate space for the encoded normals if necessary
if ( !this->EncodedNormals )
{
this->EncodedNormals = new unsigned short[ scalarInputSize[0] *
scalarInputSize[1] *
scalarInputSize[2] ];
this->EncodedNormalsSize[0] = scalarInputSize[0];
this->EncodedNormalsSize[1] = scalarInputSize[1];
this->EncodedNormalsSize[2] = scalarInputSize[2];
}
if ( !this->GradientMagnitudes && this->ComputeGradientMagnitudes )
{
this->GradientMagnitudes = new unsigned char[ scalarInputSize[0] *
scalarInputSize[1] *
scalarInputSize[2] ];
}
// Copy info that multi threaded function will need into temp variables
memcpy( this->InputSize, scalarInputSize, 3 * sizeof(int) );
// TODO cleanup when double changes are further along
this->InputAspect[0] = static_cast<float>(scalarInputAspect[0]);
this->InputAspect[1] = static_cast<float>(scalarInputAspect[1]);
this->InputAspect[2] = static_cast<float>(scalarInputAspect[2]);
// memcpy( this->InputAspect, scalarInputAspect, 3 * sizeof(float) );
if ( this->CylinderClip &&
(this->InputSize[0] == this->InputSize[1]) )
{
this->UseCylinderClip = 1;
this->ComputeCircleLimits( this->InputSize[0] );
}
else
{
this->UseCylinderClip = 0;
}
this->UpdateNormals();
this->BuildTime.Modified();
endSeconds = vtkTimerLog::GetUniversalTime();
endCPUSeconds = vtkTimerLog::GetCPUTime();
this->LastUpdateTimeInSeconds = (float)(endSeconds - startSeconds);
this->LastUpdateTimeInCPUSeconds = (float)(endCPUSeconds - startCPUSeconds);
}
}
void vtkEncodedGradientEstimator::ComputeCircleLimits( int size )
{
int *ptr, y;
double w, halfsize, length, start, end;
if ( this->CircleLimitsSize != size )
{
if ( this->CircleLimits )
{
delete [] this->CircleLimits;
}
this->CircleLimits = new int[2*size];
this->CircleLimitsSize = size;
}
ptr = this->CircleLimits;
halfsize = (double)(size-1)/2.0;
for ( y = 0; y < size; y++ )
{
w = halfsize - (double)y;
length = (int)( sqrt( (halfsize*halfsize) - (w*w) ) + 0.5 );
start = halfsize - length - 1;
end = halfsize + length + 1;
start = (start<0)?(0):(start);
end = (end>(size-1))?(size-1):(end);
*(ptr++) = (int) start;
*(ptr++) = (int) end;
}
}
// Print the vtkEncodedGradientEstimator
void vtkEncodedGradientEstimator::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
if ( this->Input )
{
os << indent << "Input: (" << this->Input << ")\n";
}
else
{
os << indent << "Input: (none)\n";
}
if ( this->DirectionEncoder )
{
os << indent << "DirectionEncoder: (" << this->DirectionEncoder << ")\n";
}
else
{
os << indent << "DirectionEncoder: (none)\n";
}
os << indent << "Build Time: "
<< this->BuildTime.GetMTime() << endl;
os << indent << "Gradient Magnitude Scale: "
<< this->GradientMagnitudeScale << endl;
os << indent << "Gradient Magnitude Bias: "
<< this->GradientMagnitudeBias << endl;
os << indent << "Zero Pad: "
<< ((this->ZeroPad)?"On":"Off") << endl;
os << indent << "Bounds Clip: "
<< ((this->BoundsClip)?"On":"Off") << endl;
os << indent << "Bounds: ("
<< this->Bounds[0] << ", " << this->Bounds[1] << ", "
<< this->Bounds[2] << ", " << this->Bounds[3] << ", "
<< this->Bounds[4] << ", " << this->Bounds[5] << ")\n";
os << indent << "Zero Normal Threshold: "
<< this->ZeroNormalThreshold << endl;
os << indent << "Compute Gradient Magnitudes: "
<< ((this->ComputeGradientMagnitudes)?"On":"Off") << endl;
os << indent << "Cylinder Clip: "
<< ((this->CylinderClip)?"On":"Off") << endl;
os << indent << "Number Of Threads: "
<< this->NumberOfThreads << endl;
os << indent << "Last Update Time In Seconds: "
<< this->LastUpdateTimeInSeconds << endl;
os << indent << "Last Update Time In CPU Seconds: "
<< this->LastUpdateTimeInCPUSeconds << endl;
// I don't want to print out these variables - they are
// internal and the get methods are included only for access
// within the threaded function
// os << indent << "Use Cylinder Clip: "
// << this->UseCylinderClip << endl;
// os << indent << " Input Size: "
// << this->InputSize << endl;
// os << indent << " Input Aspect Clip: "
// << this->InputAspect << endl;
}
//----------------------------------------------------------------------------
void
vtkEncodedGradientEstimator::ReportReferences(vtkGarbageCollector* collector)
{
this->Superclass::ReportReferences(collector);
vtkGarbageCollectorReport(collector, this->Input, "Input");
}