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.
827 lines
21 KiB
827 lines
21 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkVolume.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 "vtkVolume.h"
|
|
|
|
#include "vtkCamera.h"
|
|
#include "vtkColorTransferFunction.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkLinearTransform.h"
|
|
#include "vtkMatrix4x4.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPiecewiseFunction.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkRenderer.h"
|
|
#include "vtkTransform.h"
|
|
#include "vtkVolumeCollection.h"
|
|
#include "vtkVolumeProperty.h"
|
|
#include "vtkAbstractVolumeMapper.h"
|
|
|
|
#include <math.h>
|
|
|
|
vtkCxxRevisionMacro(vtkVolume, "$Revision: 1.83 $");
|
|
vtkStandardNewMacro(vtkVolume);
|
|
|
|
// Creates a Volume with the following defaults: origin(0,0,0)
|
|
// position=(0,0,0) scale=1 visibility=1 pickable=1 dragable=1
|
|
// orientation=(0,0,0).
|
|
vtkVolume::vtkVolume()
|
|
{
|
|
this->Mapper = NULL;
|
|
this->Property = NULL;
|
|
|
|
for ( int i = 0; i < VTK_MAX_VRCOMP; i++ )
|
|
{
|
|
this->ScalarOpacityArray[i] = NULL;
|
|
this->RGBArray[i] = NULL;
|
|
this->GrayArray[i] = NULL;
|
|
this->CorrectedScalarOpacityArray[i] = NULL;
|
|
}
|
|
|
|
this->CorrectedStepSize = -1;
|
|
this->ArraySize = 0;
|
|
}
|
|
|
|
// Destruct a volume
|
|
vtkVolume::~vtkVolume()
|
|
{
|
|
if (this->Property )
|
|
{
|
|
this->Property->UnRegister(this);
|
|
}
|
|
|
|
this->SetMapper(NULL);
|
|
|
|
for ( int i = 0; i < VTK_MAX_VRCOMP; i++ )
|
|
{
|
|
if ( this->ScalarOpacityArray[i] )
|
|
{
|
|
delete [] this->ScalarOpacityArray[i];
|
|
}
|
|
|
|
if ( this->RGBArray[i] )
|
|
{
|
|
delete [] this->RGBArray[i];
|
|
}
|
|
|
|
if ( this->GrayArray[i] )
|
|
{
|
|
delete [] this->GrayArray[i];
|
|
}
|
|
|
|
if ( this->CorrectedScalarOpacityArray[i] )
|
|
{
|
|
delete [] this->CorrectedScalarOpacityArray[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkVolume::GetVolumes(vtkPropCollection *vc)
|
|
{
|
|
vc->AddItem(this);
|
|
}
|
|
|
|
// Shallow copy of an volume.
|
|
void vtkVolume::ShallowCopy(vtkProp *prop)
|
|
{
|
|
vtkVolume *v = vtkVolume::SafeDownCast(prop);
|
|
|
|
if ( v != NULL )
|
|
{
|
|
this->SetMapper(v->GetMapper());
|
|
this->SetProperty(v->GetProperty());
|
|
}
|
|
|
|
// Now do superclass
|
|
this->vtkProp3D::ShallowCopy(prop);
|
|
}
|
|
|
|
float *vtkVolume::GetScalarOpacityArray(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return NULL;
|
|
}
|
|
return this->ScalarOpacityArray[index];
|
|
}
|
|
|
|
float *vtkVolume::GetCorrectedScalarOpacityArray(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return NULL;
|
|
}
|
|
return this->CorrectedScalarOpacityArray[index];
|
|
}
|
|
|
|
float *vtkVolume::GetGradientOpacityArray(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return NULL;
|
|
}
|
|
return this->GradientOpacityArray[index];
|
|
}
|
|
|
|
float vtkVolume::GetGradientOpacityConstant(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return 0;
|
|
}
|
|
return this->GradientOpacityConstant[index];
|
|
}
|
|
|
|
float *vtkVolume::GetGrayArray(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return NULL;
|
|
}
|
|
return this->GrayArray[index];
|
|
}
|
|
|
|
float *vtkVolume::GetRGBArray(int index)
|
|
{
|
|
if ( index < 0 || index >= VTK_MAX_VRCOMP )
|
|
{
|
|
vtkErrorMacro("Index out of range [0-" << VTK_MAX_VRCOMP <<
|
|
"]: " << index );
|
|
return NULL;
|
|
}
|
|
return this->RGBArray[index];
|
|
}
|
|
|
|
void vtkVolume::SetMapper(vtkAbstractVolumeMapper *mapper)
|
|
{
|
|
if (this->Mapper != mapper)
|
|
{
|
|
if (this->Mapper != NULL)
|
|
{
|
|
this->Mapper->UnRegister(this);
|
|
}
|
|
this->Mapper = mapper;
|
|
if (this->Mapper != NULL)
|
|
{
|
|
this->Mapper->Register(this);
|
|
}
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
float vtkVolume::ComputeScreenCoverage( vtkViewport *vp )
|
|
{
|
|
float coverage = 1.0;
|
|
|
|
vtkRenderer *ren = vtkRenderer::SafeDownCast( vp );
|
|
|
|
if ( ren )
|
|
{
|
|
vtkCamera *cam = ren->GetActiveCamera();
|
|
ren->ComputeAspect();
|
|
double *aspect = ren->GetAspect();
|
|
vtkMatrix4x4 *mat = cam->GetCompositePerspectiveTransformMatrix(
|
|
aspect[0]/aspect[1], 0.0, 1.0 );
|
|
double *bounds = this->GetBounds();
|
|
float minX = 1.0;
|
|
float maxX = -1.0;
|
|
float minY = 1.0;
|
|
float maxY = -1.0;
|
|
int i, j, k;
|
|
float p[4];
|
|
for ( k = 0; k < 2; k++ )
|
|
{
|
|
for ( j = 0; j < 2; j++ )
|
|
{
|
|
for ( i = 0; i < 2; i++ )
|
|
{
|
|
p[0] = bounds[i];
|
|
p[1] = bounds[2+j];
|
|
p[2] = bounds[4+k];
|
|
p[3] = 1.0;
|
|
mat->MultiplyPoint( p, p );
|
|
if ( p[3] )
|
|
{
|
|
p[0] /= p[3];
|
|
p[1] /= p[3];
|
|
p[2] /= p[3];
|
|
}
|
|
|
|
minX = (p[0] < minX)?(p[0]):(minX);
|
|
minY = (p[1] < minY)?(p[1]):(minY);
|
|
maxX = (p[0] > maxX)?(p[0]):(maxX);
|
|
maxY = (p[1] > maxY)?(p[1]):(maxY);
|
|
}
|
|
}
|
|
}
|
|
|
|
coverage = (maxX-minX)*(maxY-minY)*.25;
|
|
coverage = (coverage > 1.0 )?(1.0):(coverage);
|
|
coverage = (coverage < 0.0 )?(0.0):(coverage);
|
|
}
|
|
|
|
|
|
return coverage;
|
|
}
|
|
|
|
// Get the bounds for this Volume as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
|
|
double *vtkVolume::GetBounds()
|
|
{
|
|
int i,n;
|
|
double *bounds, bbox[24], *fptr;
|
|
|
|
// get the bounds of the Mapper if we have one
|
|
if (!this->Mapper)
|
|
{
|
|
return this->Bounds;
|
|
}
|
|
|
|
bounds = this->Mapper->GetBounds();
|
|
// Check for the special case when the mapper's bounds are unknown
|
|
if (!bounds)
|
|
{
|
|
return bounds;
|
|
}
|
|
|
|
// fill out vertices of a bounding box
|
|
bbox[ 0] = bounds[1]; bbox[ 1] = bounds[3]; bbox[ 2] = bounds[5];
|
|
bbox[ 3] = bounds[1]; bbox[ 4] = bounds[2]; bbox[ 5] = bounds[5];
|
|
bbox[ 6] = bounds[0]; bbox[ 7] = bounds[2]; bbox[ 8] = bounds[5];
|
|
bbox[ 9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5];
|
|
bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4];
|
|
bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4];
|
|
bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4];
|
|
bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4];
|
|
|
|
// save the old transform
|
|
this->Transform->Push();
|
|
this->Transform->SetMatrix(this->GetMatrix());
|
|
|
|
// and transform into actors coordinates
|
|
fptr = bbox;
|
|
for (n = 0; n < 8; n++)
|
|
{
|
|
this->Transform->TransformPoint(fptr,fptr);
|
|
fptr += 3;
|
|
}
|
|
|
|
this->Transform->Pop();
|
|
|
|
// now calc the new bounds
|
|
this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = VTK_DOUBLE_MAX;
|
|
this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = -VTK_DOUBLE_MAX;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
for (n = 0; n < 3; n++)
|
|
{
|
|
if (bbox[i*3+n] < this->Bounds[n*2])
|
|
{
|
|
this->Bounds[n*2] = bbox[i*3+n];
|
|
}
|
|
if (bbox[i*3+n] > this->Bounds[n*2+1])
|
|
{
|
|
this->Bounds[n*2+1] = bbox[i*3+n];
|
|
}
|
|
}
|
|
}
|
|
|
|
return this->Bounds;
|
|
}
|
|
|
|
// Get the minimum X bound
|
|
double vtkVolume::GetMinXBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[0];
|
|
}
|
|
|
|
// Get the maximum X bound
|
|
double vtkVolume::GetMaxXBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[1];
|
|
}
|
|
|
|
// Get the minimum Y bound
|
|
double vtkVolume::GetMinYBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[2];
|
|
}
|
|
|
|
// Get the maximum Y bound
|
|
double vtkVolume::GetMaxYBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[3];
|
|
}
|
|
|
|
// Get the minimum Z bound
|
|
double vtkVolume::GetMinZBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[4];
|
|
}
|
|
|
|
// Get the maximum Z bound
|
|
double vtkVolume::GetMaxZBound( )
|
|
{
|
|
this->GetBounds();
|
|
return this->Bounds[5];
|
|
}
|
|
|
|
// If the volume mapper is of type VTK_FRAMEBUFFER_VOLUME_MAPPER, then
|
|
// this is its opportunity to render
|
|
int vtkVolume::RenderTranslucentGeometry( vtkViewport *vp )
|
|
{
|
|
this->Update();
|
|
|
|
if ( !this->Mapper )
|
|
{
|
|
vtkErrorMacro( << "You must specify a mapper!\n" );
|
|
return 0;
|
|
}
|
|
|
|
// If we don't have any input return silently
|
|
if ( !this->Mapper->GetDataSetInput() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Force the creation of a property
|
|
if( !this->Property )
|
|
{
|
|
this->GetProperty();
|
|
}
|
|
|
|
if( !this->Property )
|
|
{
|
|
vtkErrorMacro( << "Error generating a property!\n" );
|
|
return 0;
|
|
}
|
|
|
|
this->Mapper->Render( (vtkRenderer *)vp, this );
|
|
this->EstimatedRenderTime += this->Mapper->GetTimeToDraw();
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
void vtkVolume::ReleaseGraphicsResources(vtkWindow *win)
|
|
{
|
|
// pass this information onto the mapper
|
|
if (this->Mapper)
|
|
{
|
|
this->Mapper->ReleaseGraphicsResources(win);
|
|
}
|
|
}
|
|
|
|
void vtkVolume::Update()
|
|
{
|
|
if ( this->Mapper )
|
|
{
|
|
this->Mapper->Update();
|
|
}
|
|
}
|
|
|
|
void vtkVolume::SetProperty(vtkVolumeProperty *property)
|
|
{
|
|
if( this->Property != property )
|
|
{
|
|
if (this->Property != NULL) {this->Property->UnRegister(this);}
|
|
this->Property = property;
|
|
if (this->Property != NULL)
|
|
{
|
|
this->Property->Register(this);
|
|
this->Property->UpdateMTimes();
|
|
}
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
vtkVolumeProperty *vtkVolume::GetProperty()
|
|
{
|
|
if( this->Property == NULL )
|
|
{
|
|
this->Property = vtkVolumeProperty::New();
|
|
this->Property->Register(this);
|
|
this->Property->Delete();
|
|
}
|
|
return this->Property;
|
|
}
|
|
|
|
unsigned long int vtkVolume::GetMTime()
|
|
{
|
|
unsigned long mTime=this->vtkObject::GetMTime();
|
|
unsigned long time;
|
|
|
|
if ( this->Property != NULL )
|
|
{
|
|
time = this->Property->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
|
|
if ( this->UserMatrix != NULL )
|
|
{
|
|
time = this->UserMatrix->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
|
|
if ( this->UserTransform != NULL )
|
|
{
|
|
time = this->UserTransform->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
|
|
return mTime;
|
|
}
|
|
|
|
unsigned long int vtkVolume::GetRedrawMTime()
|
|
{
|
|
unsigned long mTime=this->GetMTime();
|
|
unsigned long time;
|
|
|
|
if ( this->Mapper != NULL )
|
|
{
|
|
time = this->Mapper->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
if (this->GetMapper()->GetDataSetInput() != NULL)
|
|
{
|
|
this->GetMapper()->GetDataSetInput()->Update();
|
|
time = this->Mapper->GetDataSetInput()->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
}
|
|
|
|
if ( this->Property != NULL )
|
|
{
|
|
time = this->Property->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
|
|
int numComponents;
|
|
|
|
if ( this->Mapper && this->Mapper->GetDataSetInput() &&
|
|
this->Mapper->GetDataSetInput()->GetPointData() &&
|
|
this->Mapper->GetDataSetInput()->GetPointData()->GetScalars() )
|
|
{
|
|
numComponents = this->Mapper->GetDataSetInput()->GetPointData()->
|
|
GetScalars()->GetNumberOfComponents();
|
|
}
|
|
else
|
|
{
|
|
numComponents = 0;
|
|
}
|
|
|
|
for ( int i = 0; i < numComponents; i++ )
|
|
{
|
|
// Check the color transfer function (gray or rgb)
|
|
if ( this->Property->GetColorChannels(i) == 1 )
|
|
{
|
|
time = this->Property->GetGrayTransferFunction(i)->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
else
|
|
{
|
|
time = this->Property->GetRGBTransferFunction(i)->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
|
|
// check the scalar opacity function
|
|
time = this->Property->GetScalarOpacity(i)->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
|
|
// check the gradient opacity function
|
|
time = this->Property->GetGradientOpacity(i)->GetMTime();
|
|
mTime = ( time > mTime ? time : mTime );
|
|
}
|
|
}
|
|
|
|
return mTime;
|
|
}
|
|
|
|
void vtkVolume::UpdateTransferFunctions( vtkRenderer *vtkNotUsed(ren) )
|
|
{
|
|
int dataType;
|
|
vtkPiecewiseFunction *sotf;
|
|
vtkPiecewiseFunction *gotf;
|
|
vtkPiecewiseFunction *graytf;
|
|
vtkColorTransferFunction *rgbtf;
|
|
int colorChannels;
|
|
|
|
int arraySize;
|
|
|
|
// Check that we have scalars
|
|
if ( this->Mapper == NULL ||
|
|
this->Mapper->GetDataSetInput() == NULL ||
|
|
this->Mapper->GetDataSetInput()->GetPointData() == NULL ||
|
|
this->Mapper->GetDataSetInput()->GetPointData()->GetScalars() == NULL )
|
|
{
|
|
vtkErrorMacro(<<"Need scalar data to volume render");
|
|
return;
|
|
}
|
|
|
|
// What is the type of the data?
|
|
dataType = this->Mapper->GetDataSetInput()->
|
|
GetPointData()->GetScalars()->GetDataType();
|
|
|
|
if (dataType == VTK_UNSIGNED_CHAR)
|
|
{
|
|
arraySize = 256;
|
|
}
|
|
else if (dataType == VTK_UNSIGNED_SHORT)
|
|
{
|
|
arraySize = 65536;
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro("Unsupported data type");
|
|
return;
|
|
}
|
|
|
|
int numComponents = this->Mapper->GetDataSetInput()->GetPointData()->
|
|
GetScalars()->GetNumberOfComponents();
|
|
|
|
for ( int c = 0; c < numComponents; c++ )
|
|
{
|
|
|
|
// Did our array size change? If so, free up all our previous arrays
|
|
// and create new ones for the scalar opacity and corrected scalar
|
|
// opacity
|
|
if ( arraySize != this->ArraySize )
|
|
{
|
|
if ( this->ScalarOpacityArray[c] )
|
|
{
|
|
delete [] this->ScalarOpacityArray[c];
|
|
this->ScalarOpacityArray[c] = NULL;
|
|
}
|
|
if ( this->CorrectedScalarOpacityArray[c] )
|
|
{
|
|
delete [] this->CorrectedScalarOpacityArray[c];
|
|
this->CorrectedScalarOpacityArray[c] = NULL;
|
|
}
|
|
if ( this->GrayArray[c] )
|
|
{
|
|
delete [] this->GrayArray[c];
|
|
this->GrayArray[c] = NULL;
|
|
}
|
|
if ( this->RGBArray[c] )
|
|
{
|
|
delete [] this->RGBArray[c];
|
|
this->RGBArray[c] = NULL;
|
|
}
|
|
|
|
// Allocate these two because we know we need them
|
|
this->ScalarOpacityArray[c] = new float[arraySize];
|
|
this->CorrectedScalarOpacityArray[c] = new float[arraySize];
|
|
}
|
|
|
|
// How many color channels for this component?
|
|
colorChannels = this->Property->GetColorChannels(c);
|
|
|
|
// If we have 1 color channel and no gray array, create it.
|
|
// Free the rgb array if there is one.
|
|
if ( colorChannels == 1 )
|
|
{
|
|
if ( this->RGBArray[c] )
|
|
{
|
|
delete [] this->RGBArray[c];
|
|
this->RGBArray[c] = NULL;
|
|
}
|
|
if ( !this->GrayArray[c] )
|
|
{
|
|
this->GrayArray[c] = new float[arraySize];
|
|
}
|
|
}
|
|
|
|
// If we have 3 color channels and no rgb array, create it.
|
|
// Free the gray array if there is one.
|
|
if ( colorChannels == 3 )
|
|
{
|
|
if ( this->GrayArray[c] )
|
|
{
|
|
delete [] this->GrayArray[c];
|
|
this->GrayArray[c] = NULL;
|
|
}
|
|
if ( !this->RGBArray[c] )
|
|
{
|
|
this->RGBArray[c] = new float[3*arraySize];
|
|
}
|
|
}
|
|
|
|
// Get the various functions for this index. There is no chance of
|
|
// these being NULL since the property will create them if they were
|
|
// not defined
|
|
sotf = this->Property->GetScalarOpacity(c);
|
|
gotf = this->Property->GetGradientOpacity(c);
|
|
|
|
if ( colorChannels == 1 )
|
|
{
|
|
rgbtf = NULL;
|
|
graytf = this->Property->GetGrayTransferFunction(c);
|
|
}
|
|
else
|
|
{
|
|
rgbtf = this->Property->GetRGBTransferFunction(c);
|
|
graytf = NULL;
|
|
}
|
|
|
|
|
|
// Update the scalar opacity array if necessary
|
|
if ( sotf->GetMTime() >
|
|
this->ScalarOpacityArrayMTime[c] ||
|
|
this->Property->GetScalarOpacityMTime(c) >
|
|
this->ScalarOpacityArrayMTime[c] )
|
|
{
|
|
sotf->GetTable( 0.0, static_cast<double>(arraySize-1),
|
|
arraySize, this->ScalarOpacityArray[c] );
|
|
this->ScalarOpacityArrayMTime[c].Modified();
|
|
}
|
|
|
|
// Update the gradient opacity array if necessary
|
|
if ( gotf->GetMTime() >
|
|
this->GradientOpacityArrayMTime[c] ||
|
|
this->Property->GetGradientOpacityMTime(c) >
|
|
this->GradientOpacityArrayMTime[c] )
|
|
{
|
|
// Get values according to scale/bias from mapper 256 values are
|
|
// in the table, the scale / bias values control what those 256 values
|
|
// mean.
|
|
float scale = this->Mapper->GetGradientMagnitudeScale(c);
|
|
float bias = this->Mapper->GetGradientMagnitudeBias(c);
|
|
|
|
float low = -bias;
|
|
float high = 255 / scale - bias;
|
|
|
|
gotf->GetTable( low, high, (int)(0x100), this->GradientOpacityArray[c] );
|
|
|
|
if ( !strcmp(gotf->GetType(), "Constant") )
|
|
{
|
|
this->GradientOpacityConstant[c] = this->GradientOpacityArray[c][0];
|
|
}
|
|
else
|
|
{
|
|
this->GradientOpacityConstant[c] = -1.0;
|
|
}
|
|
|
|
this->GradientOpacityArrayMTime[c].Modified();
|
|
}
|
|
|
|
// Update the RGB or Gray transfer function if necessary
|
|
if ( colorChannels == 1 )
|
|
{
|
|
if ( graytf->GetMTime() >
|
|
this->GrayArrayMTime[c] ||
|
|
this->Property->GetGrayTransferFunctionMTime(c) >
|
|
this->GrayArrayMTime[c] )
|
|
{
|
|
graytf->GetTable( 0.0, static_cast<float>(arraySize-1),
|
|
arraySize, this->GrayArray[c] );
|
|
this->GrayArrayMTime[c].Modified();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( rgbtf->GetMTime() >
|
|
this->RGBArrayMTime[c] ||
|
|
this->Property->GetRGBTransferFunctionMTime(c) >
|
|
this->RGBArrayMTime[c] )
|
|
{
|
|
rgbtf->GetTable( 0.0, static_cast<float>(arraySize-1),
|
|
arraySize, this->RGBArray[c] );
|
|
this->RGBArrayMTime[c].Modified();
|
|
}
|
|
}
|
|
}
|
|
|
|
// reset the array size to the current size
|
|
this->ArraySize = arraySize;
|
|
}
|
|
|
|
// This method computes the corrected alpha blending for a given
|
|
// step size. The ScalarOpacityArray reflects step size 1.
|
|
// The CorrectedScalarOpacityArray reflects step size CorrectedStepSize.
|
|
void vtkVolume::UpdateScalarOpacityforSampleSize( vtkRenderer *vtkNotUsed(ren),
|
|
float sample_distance )
|
|
{
|
|
int i;
|
|
int needsRecomputing;
|
|
float originalAlpha,correctedAlpha;
|
|
float ray_scale;
|
|
|
|
ray_scale = sample_distance;
|
|
|
|
// step size changed
|
|
needsRecomputing =
|
|
this->CorrectedStepSize-ray_scale > 0.0001;
|
|
|
|
needsRecomputing = needsRecomputing ||
|
|
this->CorrectedStepSize-ray_scale < -0.0001;
|
|
|
|
// Check that we have scalars
|
|
if ( this->Mapper == NULL ||
|
|
this->Mapper->GetDataSetInput() == NULL ||
|
|
this->Mapper->GetDataSetInput()->GetPointData() == NULL ||
|
|
this->Mapper->GetDataSetInput()->GetPointData()->GetScalars() == NULL )
|
|
{
|
|
vtkErrorMacro(<<"Need scalar data to volume render");
|
|
return;
|
|
}
|
|
|
|
int numComponents = this->Mapper->GetDataSetInput()->GetPointData()->
|
|
GetScalars()->GetNumberOfComponents();
|
|
|
|
if ( needsRecomputing )
|
|
{
|
|
this->CorrectedStepSize = ray_scale;
|
|
}
|
|
|
|
for ( int c = 0; c < numComponents; c++ )
|
|
{
|
|
if (needsRecomputing ||
|
|
this->ScalarOpacityArrayMTime[c] >
|
|
this->CorrectedScalarOpacityArrayMTime[c])
|
|
{
|
|
this->CorrectedScalarOpacityArrayMTime[c].Modified();
|
|
|
|
for (i = 0; i < this->ArraySize; i++)
|
|
{
|
|
originalAlpha = *(this->ScalarOpacityArray[c]+i);
|
|
|
|
// this test is to accelerate the Transfer function correction
|
|
if (originalAlpha > 0.0001)
|
|
{
|
|
correctedAlpha =
|
|
1.0-pow((double)(1.0-originalAlpha),
|
|
double(this->CorrectedStepSize));
|
|
}
|
|
else
|
|
{
|
|
correctedAlpha = originalAlpha;
|
|
}
|
|
*(this->CorrectedScalarOpacityArray[c]+i) = correctedAlpha;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void vtkVolume::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
if( this->Property )
|
|
{
|
|
os << indent << "Property:\n";
|
|
this->Property->PrintSelf(os,indent.GetNextIndent());
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Property: (not defined)\n";
|
|
}
|
|
|
|
if( this->Mapper )
|
|
{
|
|
os << indent << "Mapper:\n";
|
|
this->Mapper->PrintSelf(os,indent.GetNextIndent());
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Mapper: (not defined)\n";
|
|
}
|
|
|
|
// make sure our bounds are up to date
|
|
if ( this->Mapper )
|
|
{
|
|
this->GetBounds();
|
|
os << indent << "Bounds: (" << this->Bounds[0] << ", "
|
|
<< this->Bounds[1] << ") (" << this->Bounds[2] << ") ("
|
|
<< this->Bounds[3] << ") (" << this->Bounds[4] << ") ("
|
|
<< this->Bounds[5] << ")\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Bounds: (not defined)\n";
|
|
}
|
|
}
|
|
|
|
|