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.
470 lines
16 KiB
470 lines
16 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkUnstructuredGridPreIntegration.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.
|
|
|
|
=========================================================================*/
|
|
|
|
/*
|
|
* Copyright 2004 Sandia Corporation.
|
|
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
|
|
* license for use of this work by or on behalf of the
|
|
* U.S. Government. Redistribution and use in source and binary forms, with
|
|
* or without modification, are permitted provided that this Notice and any
|
|
* statement of authorship are reproduced on all copies.
|
|
*/
|
|
|
|
#include "vtkUnstructuredGridPreIntegration.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkVolumeProperty.h"
|
|
#include "vtkVolume.h"
|
|
#include "vtkAbstractVolumeMapper.h"
|
|
#include "vtkUnstructuredGrid.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkUnstructuredGridPartialPreIntegration.h"
|
|
|
|
#include <vtkstd/algorithm>
|
|
#include <math.h>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
vtkCxxRevisionMacro(vtkUnstructuredGridPreIntegration, "$Revision: 1.4 $");
|
|
vtkStandardNewMacro(vtkUnstructuredGridPreIntegration);
|
|
|
|
vtkCxxSetObjectMacro(vtkUnstructuredGridPreIntegration, Integrator,
|
|
vtkUnstructuredGridVolumeRayIntegrator);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
vtkUnstructuredGridPreIntegration::vtkUnstructuredGridPreIntegration()
|
|
{
|
|
this->Integrator = vtkUnstructuredGridPartialPreIntegration::New();
|
|
this->Property = NULL;
|
|
|
|
this->NumComponents = 0;
|
|
this->IntegrationTable = NULL;
|
|
this->IntegrationTableScalarShift = NULL;
|
|
this->IntegrationTableScalarScale = NULL;
|
|
|
|
this->IntegrationTableScalarResolution = 128;
|
|
this->IntegrationTableLengthResolution = 256;
|
|
|
|
this->IncrementalPreIntegration = 1;
|
|
}
|
|
|
|
vtkUnstructuredGridPreIntegration::~vtkUnstructuredGridPreIntegration()
|
|
{
|
|
this->SetIntegrator(NULL);
|
|
|
|
if (this->IntegrationTable)
|
|
{
|
|
for (int i = 0; i < this->NumComponents; i++)
|
|
{
|
|
delete[] this->IntegrationTable[i];
|
|
}
|
|
delete[] this->IntegrationTable;
|
|
}
|
|
if (this->IntegrationTableScalarShift)
|
|
{
|
|
delete[] this->IntegrationTableScalarShift;
|
|
}
|
|
if (this->IntegrationTableScalarScale)
|
|
{
|
|
delete[] this->IntegrationTableScalarScale;
|
|
}
|
|
}
|
|
|
|
void vtkUnstructuredGridPreIntegration::PrintSelf(ostream &os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "Integrator: " << this->Integrator << endl;
|
|
|
|
os << indent << "IntegrationTableScalarResolution: "
|
|
<< this->IntegrationTableScalarResolution << endl;
|
|
os << indent << "IntegrationTableLengthResolution: "
|
|
<< this->IntegrationTableLengthResolution << endl;
|
|
|
|
os << indent << "IncrementalPreIntegration: "
|
|
<< this->IncrementalPreIntegration << endl;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
double vtkUnstructuredGridPreIntegration::GetIntegrationTableScalarShift(int component)
|
|
{
|
|
return this->IntegrationTableScalarShift[component];
|
|
}
|
|
|
|
double vtkUnstructuredGridPreIntegration::GetIntegrationTableScalarScale(int component)
|
|
{
|
|
return this->IntegrationTableScalarScale[component];
|
|
}
|
|
|
|
double vtkUnstructuredGridPreIntegration::GetIntegrationTableLengthScale()
|
|
{
|
|
return this->IntegrationTableLengthScale;
|
|
}
|
|
|
|
float *vtkUnstructuredGridPreIntegration::GetPreIntegrationTable(int component)
|
|
{
|
|
return this->IntegrationTable[component];
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridPreIntegration::BuildPreIntegrationTables(vtkDataArray *scalars)
|
|
{
|
|
// Delete old tables.
|
|
if (this->IntegrationTable)
|
|
{
|
|
for (int i = 0; i < this->NumComponents; i++)
|
|
{
|
|
delete[] this->IntegrationTable[i];
|
|
}
|
|
delete[] this->IntegrationTable;
|
|
}
|
|
if (this->IntegrationTableScalarShift)
|
|
{
|
|
delete[] this->IntegrationTableScalarShift;
|
|
}
|
|
if (this->IntegrationTableScalarScale)
|
|
{
|
|
delete[] this->IntegrationTableScalarScale;
|
|
}
|
|
|
|
// Establish temporary inputs to integrator.
|
|
vtkVolume *tmpVolume = vtkVolume::New();
|
|
vtkVolumeProperty *tmpProperty = vtkVolumeProperty::New();
|
|
vtkDataArray *tmpScalars
|
|
= vtkDataArray::CreateDataArray(scalars->GetDataType());
|
|
|
|
tmpVolume->SetMapper(this->Volume->GetMapper());
|
|
tmpVolume->SetProperty(tmpProperty);
|
|
|
|
tmpProperty->IndependentComponentsOn();
|
|
tmpProperty->SetInterpolationType(this->Property->GetInterpolationType());
|
|
|
|
tmpScalars->SetNumberOfComponents(1);
|
|
tmpScalars->SetNumberOfTuples(2);
|
|
|
|
vtkDoubleArray *tmpIntersectionLengths = vtkDoubleArray::New();
|
|
vtkDataArray *tmpNearIntersections
|
|
= vtkDataArray::CreateDataArray(scalars->GetDataType());
|
|
vtkDataArray *tmpFarIntersections
|
|
= vtkDataArray::CreateDataArray(scalars->GetDataType());
|
|
|
|
tmpIntersectionLengths->SetNumberOfComponents(1);
|
|
tmpIntersectionLengths->SetNumberOfTuples(1);
|
|
tmpNearIntersections->SetNumberOfComponents(1);
|
|
tmpNearIntersections->SetNumberOfTuples(1);
|
|
tmpFarIntersections->SetNumberOfComponents(1);
|
|
tmpFarIntersections->SetNumberOfTuples(1);
|
|
|
|
this->IntegrationTable = new float*[this->NumComponents];
|
|
this->IntegrationTableScalarShift = new double[this->NumComponents];
|
|
this->IntegrationTableScalarScale = new double[this->NumComponents];
|
|
// Note that the scale set up such that a length of (this->MaxLength +
|
|
// epsilon + 0.5) will scale to this->IntegrationTableLengthResolution-1.
|
|
// Similar scaling is performed for the other dimensions of the
|
|
// pre-integration table.
|
|
this->IntegrationTableLengthScale
|
|
= (this->IntegrationTableLengthResolution-2)/this->MaxLength;
|
|
|
|
// We only do computations at one length.
|
|
float d_length = (float)(1/this->IntegrationTableLengthScale);
|
|
|
|
for (int component = 0; component < this->NumComponents; component++)
|
|
{
|
|
int d_idx, sb_idx, sf_idx;
|
|
float *c;
|
|
|
|
// Allocate table.
|
|
try
|
|
{
|
|
this->IntegrationTable[component]
|
|
= new float[4*this->IntegrationTableScalarResolution
|
|
*this->IntegrationTableScalarResolution
|
|
*this->IntegrationTableLengthResolution];
|
|
}
|
|
catch (...)
|
|
{
|
|
this->IntegrationTable[component] = NULL;
|
|
}
|
|
|
|
if (this->IntegrationTable[component] == NULL)
|
|
{
|
|
// Could not allocate memory for table.
|
|
if ( (this->IntegrationTableScalarResolution > 32)
|
|
|| (this->IntegrationTableLengthResolution > 64) )
|
|
{
|
|
vtkWarningMacro("Could not allocate integration table.\n"
|
|
"Reducing the table size and trying again.");
|
|
for (int i = 0; i < component; i++)
|
|
{
|
|
delete[] this->IntegrationTable[i];
|
|
}
|
|
delete[] this->IntegrationTable;
|
|
this->IntegrationTable = NULL;
|
|
|
|
this->IntegrationTableScalarResolution = 32;
|
|
this->IntegrationTableLengthResolution = 64;
|
|
this->BuildPreIntegrationTables(scalars);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro("Could not allocate integration table.");
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Determine scale and shift.
|
|
double *range = scalars->GetRange(component);
|
|
if (range[0] == range[1])
|
|
{
|
|
// Unusual case where the scalars are all the same.
|
|
this->IntegrationTableScalarScale[component] = 1.0;
|
|
}
|
|
else
|
|
{
|
|
this->IntegrationTableScalarScale[component]
|
|
= (this->IntegrationTableScalarResolution-2)/(range[1]-range[0]);
|
|
}
|
|
this->IntegrationTableScalarShift[component]
|
|
= -range[0]*this->IntegrationTableScalarScale[component];
|
|
|
|
// Set values for d=0 (they are all zero).
|
|
c = this->IntegrationTable[component];
|
|
for (sb_idx = 0; sb_idx < this->IntegrationTableScalarResolution; sb_idx++)
|
|
{
|
|
for (sf_idx = 0; sf_idx < this->IntegrationTableScalarResolution;
|
|
sf_idx++)
|
|
{
|
|
c[0] = c[1] = c[2] = c[3] = 0.0f;
|
|
c += 4;
|
|
}
|
|
}
|
|
|
|
// Initialize integrator.
|
|
if (this->Property->GetColorChannels(component) == 3)
|
|
{
|
|
tmpProperty->SetColor(this->Property->GetRGBTransferFunction(component));
|
|
}
|
|
else
|
|
{
|
|
tmpProperty->SetColor(this->Property->GetGrayTransferFunction(component));
|
|
}
|
|
tmpProperty->SetScalarOpacity(this->Property->GetScalarOpacity(component));
|
|
tmpProperty->SetScalarOpacityUnitDistance
|
|
(this->Property->GetScalarOpacityUnitDistance(component));
|
|
tmpProperty->SetShade(this->Property->GetShade(component));
|
|
tmpProperty->SetAmbient(this->Property->GetAmbient(component));
|
|
tmpProperty->SetDiffuse(this->Property->GetDiffuse(component));
|
|
tmpProperty->SetSpecular(this->Property->GetSpecular(component));
|
|
tmpProperty->SetSpecularPower(this->Property->GetSpecularPower(component));
|
|
tmpScalars->SetTuple1(0, range[0]);
|
|
tmpScalars->SetTuple1(1, range[1]);
|
|
this->Integrator->Initialize(tmpVolume, tmpScalars);
|
|
|
|
// Set values for next smallest d (the base values).
|
|
tmpIntersectionLengths->SetTuple1(0, d_length);
|
|
for (sb_idx = 0; sb_idx < this->IntegrationTableScalarResolution; sb_idx++)
|
|
{
|
|
tmpFarIntersections
|
|
->SetTuple1(0,
|
|
( (sb_idx - this->IntegrationTableScalarShift[component])
|
|
/ (this->IntegrationTableScalarScale[component]) ));
|
|
for (sf_idx = 0; sf_idx < this->IntegrationTableScalarResolution;
|
|
sf_idx++)
|
|
{
|
|
tmpNearIntersections
|
|
->SetTuple1(0,
|
|
( (sf_idx - this->IntegrationTableScalarShift[component])
|
|
/ (this->IntegrationTableScalarScale[component]) ));
|
|
c[0] = c[1] = c[2] = c[3] = 0;
|
|
this->Integrator->Integrate(tmpIntersectionLengths,
|
|
tmpNearIntersections, tmpFarIntersections,
|
|
c);
|
|
c += 4;
|
|
}
|
|
}
|
|
|
|
// Set rest of values using other values in table.
|
|
if (this->IncrementalPreIntegration)
|
|
{
|
|
for (d_idx = 2; d_idx < this->IntegrationTableLengthResolution; d_idx++)
|
|
{
|
|
for (sb_idx = 0; sb_idx < this->IntegrationTableScalarResolution;
|
|
sb_idx++)
|
|
{
|
|
for (sf_idx = 0; sf_idx < this->IntegrationTableScalarResolution;
|
|
sf_idx++)
|
|
{
|
|
// We are going to perform incremental pre-integration. To do
|
|
// this, we compute the integration of a ray from sf to sb of
|
|
// length d by combining two entries in the table. The first
|
|
// entry will be from sf to sm of length delta d (the smallest
|
|
// non-zero length stored in the table). The second entry will
|
|
// be from sm to sb of length d - delta d. See Weiler, et
|
|
// al. "Hardware-Based Ray Casting for Tetrahedral Meshes" for
|
|
// more details.
|
|
int sm_idx = ((d_idx-1)*sf_idx + sb_idx + d_idx/2)/d_idx;
|
|
|
|
float *colorf = this->GetIndexedTableEntry(sf_idx, sm_idx, 1,
|
|
component);
|
|
float *colorb = this->GetIndexedTableEntry(sm_idx, sb_idx, d_idx-1,
|
|
component);
|
|
|
|
c[0] = colorf[0] + colorb[0]*(1-colorf[3]);
|
|
c[1] = colorf[1] + colorb[1]*(1-colorf[3]);
|
|
c[2] = colorf[2] + colorb[2]*(1-colorf[3]);
|
|
c[3] = colorf[3] + colorb[3]*(1-colorf[3]);
|
|
c += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (d_idx = 2; d_idx < this->IntegrationTableLengthResolution; d_idx++)
|
|
{
|
|
for (sb_idx = 0; sb_idx < this->IntegrationTableScalarResolution;
|
|
sb_idx++)
|
|
{
|
|
for (sf_idx = 0; sf_idx < this->IntegrationTableScalarResolution;
|
|
sf_idx++)
|
|
{
|
|
// Compute the integration table the old-fashioned slow way.
|
|
float length = d_idx*d_length;
|
|
float sb = (float)
|
|
( (sb_idx - this->IntegrationTableScalarShift[component])
|
|
/ (this->IntegrationTableScalarScale[component]) );
|
|
float sf = (float)
|
|
( (sf_idx - this->IntegrationTableScalarShift[component])
|
|
/ (this->IntegrationTableScalarScale[component]) );
|
|
tmpIntersectionLengths->SetTuple1(0, length);
|
|
tmpFarIntersections->SetTuple1(0, sb);
|
|
tmpNearIntersections->SetTuple1(0, sf);
|
|
c[0] = c[1] = c[2] = c[3] = 0;
|
|
this->Integrator->Integrate(tmpIntersectionLengths,
|
|
tmpNearIntersections,
|
|
tmpFarIntersections,
|
|
c);
|
|
c += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get rid of temporary data.
|
|
tmpVolume->Delete();
|
|
tmpProperty->Delete();
|
|
tmpScalars->Delete();
|
|
|
|
tmpIntersectionLengths->Delete();
|
|
tmpNearIntersections->Delete();
|
|
tmpFarIntersections->Delete();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridPreIntegration::Initialize(vtkVolume *volume,
|
|
vtkDataArray *scalars)
|
|
{
|
|
vtkIdType i;
|
|
vtkVolumeProperty *property = volume->GetProperty();
|
|
|
|
if ( (property == this->Property)
|
|
&& (this->IntegrationTableBuilt > property->GetMTime())
|
|
&& (this->IntegrationTableBuilt > this->MTime) )
|
|
{
|
|
// Nothing changed from the last time Initialize was run.
|
|
return;
|
|
}
|
|
|
|
this->NumComponents = scalars->GetNumberOfComponents();
|
|
this->Property = property;
|
|
this->Volume = volume;
|
|
this->IntegrationTableBuilt.Modified();
|
|
|
|
if (!property->GetIndependentComponents())
|
|
{
|
|
vtkErrorMacro("Cannot store dependent components in pre-integration table.");
|
|
return;
|
|
}
|
|
|
|
// Determine the maximum possible length of a ray segment.
|
|
vtkDataSet *input = volume->GetMapper()->GetDataSetInput();
|
|
vtkIdType numcells = input->GetNumberOfCells();
|
|
this->MaxLength = 0;
|
|
for (i = 0; i < numcells; i++)
|
|
{
|
|
double cellbounds[6];
|
|
input->GetCellBounds(i, cellbounds);
|
|
#define SQR(x) ((x)*(x))
|
|
double diagonal_length = sqrt( SQR(cellbounds[1]-cellbounds[0])
|
|
+ SQR(cellbounds[3]-cellbounds[2])
|
|
+ SQR(cellbounds[5]-cellbounds[4]) );
|
|
#undef SQR
|
|
if (diagonal_length > this->MaxLength)
|
|
{
|
|
this->MaxLength = diagonal_length;
|
|
}
|
|
}
|
|
|
|
this->BuildPreIntegrationTables(scalars);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridPreIntegration::Integrate(
|
|
vtkDoubleArray *intersectionLengths,
|
|
vtkDataArray *nearIntersections,
|
|
vtkDataArray *farIntersections,
|
|
float color[4])
|
|
{
|
|
vtkIdType numIntersections = intersectionLengths->GetNumberOfTuples();
|
|
|
|
for (vtkIdType i = 0; i < numIntersections; i++)
|
|
{
|
|
float newcolor[4];
|
|
float *c;
|
|
c = this->GetTableEntry(nearIntersections->GetComponent(i, 0),
|
|
farIntersections->GetComponent(i, 0),
|
|
intersectionLengths->GetComponent(i, 0), 0);
|
|
newcolor[0] = c[0]; newcolor[1] = c[1];
|
|
newcolor[2] = c[2]; newcolor[3] = c[3];
|
|
for (int component = 1; component < this->NumComponents; component++)
|
|
{
|
|
c = this->GetTableEntry(nearIntersections->GetComponent(i, component),
|
|
farIntersections->GetComponent(i, component),
|
|
intersectionLengths->GetComponent(i, 0),
|
|
component);
|
|
// The blending I'm using is a combination of porter and duff xors
|
|
// and ins.
|
|
float coef1=1-0.5f*c[3];
|
|
float coef2=1-0.5f*newcolor[3];
|
|
newcolor[0] = newcolor[0]*coef1 + c[0]*coef2;
|
|
newcolor[1] = newcolor[1]*coef1 + c[1]*coef2;
|
|
newcolor[2] = newcolor[2]*coef1 + c[2]*coef2;
|
|
newcolor[3] = newcolor[3]*coef1 + c[3]*coef2;
|
|
}
|
|
|
|
float coef=1-color[3];
|
|
color[0] += newcolor[0]*coef;
|
|
color[1] += newcolor[1]*coef;
|
|
color[2] += newcolor[2]*coef;
|
|
color[3] += newcolor[3]*coef;
|
|
}
|
|
}
|
|
|
|
|