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.
1076 lines
26 KiB
1076 lines
26 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkVolumeShearWarpDataStructure.h,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 "vtkShearWarpBase.h"
|
|
|
|
#define VTK_X_AXIS 0
|
|
#define VTK_Y_AXIS 1
|
|
#define VTK_Z_AXIS 2
|
|
#define VTK_SHEAR_WARP_COMPOSITE_FUNCTION 0
|
|
#define VTK_SHEAR_WARP_MIP_FUNCTION 1
|
|
#define VTK_SHEAR_WARP_ISOSURFACE_FUNCTION 2
|
|
|
|
#define VTK_SHEAR_WARP_OCTREE_TRANSPARENT 0
|
|
#define VTK_SHEAR_WARP_OCTREE_NONTRANSPARENT 1
|
|
#define VTK_SHEAR_WARP_OCTREE_COMBINATION 2
|
|
#define VTK_SHEAR_WARP_OCTREE_MINIMUM_SIZE 16
|
|
|
|
// Intermediate image pixel data for early ray termination
|
|
class vtkShearWarpPixelData
|
|
{
|
|
public:
|
|
float Red;
|
|
float Green;
|
|
float Blue;
|
|
float Opacity;
|
|
float Value;
|
|
int Offset;
|
|
};
|
|
|
|
|
|
// Runlength encoded intermediate image
|
|
class vtkShearWarpRLEImage
|
|
{
|
|
public:
|
|
vtkShearWarpRLEImage(int size)
|
|
{
|
|
this->PixelData = new vtkShearWarpPixelData[size];
|
|
this->ImageSize = size;
|
|
this->Clear();
|
|
};
|
|
|
|
~vtkShearWarpRLEImage()
|
|
{
|
|
if (this->PixelData != NULL)
|
|
delete[] this->PixelData;
|
|
};
|
|
|
|
// Reset all pixels to default values
|
|
void Clear()
|
|
{
|
|
for (int i = 0; i < this->ImageSize; i++)
|
|
{
|
|
this->PixelData[i].Red = 0.0f;
|
|
this->PixelData[i].Green = 0.0f;
|
|
this->PixelData[i].Blue = 0.0f;
|
|
this->PixelData[i].Opacity = 0.0f;
|
|
this->PixelData[i].Value = 0.0f;
|
|
this->PixelData[i].Offset = 0;
|
|
}
|
|
};
|
|
|
|
// Reset the current pixel pointer to the first pixel
|
|
void First(vtkShearWarpPixelData * &ptr)
|
|
{
|
|
ptr = this->PixelData;
|
|
};
|
|
|
|
// Sets the current pixel pointer to the specified position
|
|
void Position (vtkShearWarpPixelData * &ptr, int position)
|
|
{
|
|
ptr = this->PixelData + position;
|
|
};
|
|
|
|
// Advances the current pixel pointer by the specified increment
|
|
void Advance(vtkShearWarpPixelData * &ptr, int count)
|
|
{
|
|
ptr = ptr + count;
|
|
};
|
|
|
|
// Skip over transparent voxels and returns the count of skipped voxels
|
|
int Skip(vtkShearWarpPixelData * &ptr)
|
|
{
|
|
vtkShearWarpPixelData *data = ptr;
|
|
int runLength = 0;
|
|
int pathLength = 0;
|
|
int offset = 0;
|
|
|
|
while (ptr->Offset > 0)
|
|
{
|
|
runLength += ptr->Offset;
|
|
ptr += ptr->Offset;
|
|
}
|
|
|
|
data->Offset = runLength;
|
|
|
|
while (data->Offset > 0)
|
|
{
|
|
offset = data->Offset;
|
|
data->Offset = runLength - pathLength;
|
|
pathLength += offset;
|
|
data += offset;
|
|
}
|
|
|
|
return runLength;
|
|
};
|
|
|
|
// Retrieves a pointer to the first pixel
|
|
vtkShearWarpPixelData * GetPixelData()
|
|
{
|
|
return this->PixelData;
|
|
};
|
|
|
|
// Retrieves the allocated image size
|
|
int GetSize()
|
|
{
|
|
return this->ImageSize;
|
|
};
|
|
|
|
private:
|
|
// the pixel data
|
|
vtkShearWarpPixelData *PixelData;
|
|
|
|
// the allocated image size
|
|
int ImageSize;
|
|
|
|
};
|
|
|
|
|
|
// Voxel data for runlength encoding, contains the scalar value and shading information
|
|
template <class T>
|
|
struct vtkShearWarpVoxelData
|
|
{
|
|
public:
|
|
T Value;
|
|
unsigned short EncodedNormal;
|
|
unsigned char GradientMagnitude;
|
|
};
|
|
|
|
|
|
|
|
// An RLE run. It has a length and a pointer to the first voxel.
|
|
template <class T>
|
|
class vtkShearWarpRLERun
|
|
{
|
|
public:
|
|
unsigned char Length;
|
|
vtkShearWarpVoxelData<T> *VoxelData;
|
|
};
|
|
|
|
|
|
// A runlength encoded voxel slice which provides scanline-wise access to the data
|
|
template <class T>
|
|
class vtkShearWarpRLESlice
|
|
{
|
|
public:
|
|
vtkShearWarpRLESlice()
|
|
{
|
|
this->SliceRuns = NULL;
|
|
this->VoxelData = NULL;
|
|
this->LineRuns = NULL;
|
|
};
|
|
|
|
~vtkShearWarpRLESlice()
|
|
{
|
|
if (this->LineRuns != NULL)
|
|
delete[] this->LineRuns;
|
|
|
|
if (this->SliceRuns != NULL)
|
|
delete[] this->SliceRuns;
|
|
|
|
if (this->VoxelData != NULL)
|
|
delete[] this->VoxelData;
|
|
};
|
|
|
|
|
|
// Encodes the data by opacity (for alpha compositing)
|
|
void encodeOpacity (vtkImageData* data, vtkVolume *volume, vtkEncodedGradientEstimator *gradest, int axis, int k, float opacityThreshold)
|
|
{
|
|
if (data == NULL || volume == NULL)
|
|
return;
|
|
|
|
T voxelScalar = 0;
|
|
float voxelOpacity = 0.0f;
|
|
unsigned char currentIndex = 0;
|
|
int currentRun = 0;
|
|
int location = 0;
|
|
bool transparentRun = false;
|
|
|
|
float *SOTF = volume->GetCorrectedScalarOpacityArray();
|
|
|
|
T *dptr = (T*) data->GetScalarPointer();
|
|
unsigned short *nptr = gradest->GetEncodedNormals();
|
|
unsigned char *gptr = gradest->GetGradientMagnitudes();
|
|
|
|
int i,j;
|
|
|
|
int jCount = 0;
|
|
int iCount = 0;
|
|
int voxelIndex = 0;
|
|
|
|
int *dimensions = data->GetDimensions();
|
|
int plane = dimensions[0] * dimensions[1];
|
|
int iIncrement,jIncrement;
|
|
int vi,vj,vk;
|
|
|
|
switch (axis)
|
|
{
|
|
case VTK_X_AXIS:
|
|
iCount = dimensions[1];
|
|
jCount = dimensions[2];
|
|
vk = k;
|
|
iIncrement = dimensions[0];
|
|
jIncrement = plane;
|
|
break;
|
|
|
|
case VTK_Y_AXIS:
|
|
iCount = dimensions[2];
|
|
jCount = dimensions[0];
|
|
vk = k*dimensions[0];
|
|
iIncrement = plane;
|
|
jIncrement = 1;
|
|
break;
|
|
|
|
case VTK_Z_AXIS:
|
|
default:
|
|
iCount = dimensions[0];
|
|
jCount = dimensions[1];
|
|
vk = k*plane;
|
|
iIncrement = 1;
|
|
jIncrement = dimensions[0];
|
|
break;
|
|
}
|
|
|
|
// First we determine the number of runs in the slice
|
|
for (j=0,vj=0; j<jCount;j++, vj += jIncrement)
|
|
{
|
|
for (i=0,vi=0; i<iCount;i++, vi += iIncrement)
|
|
{
|
|
location = vi + vj + vk;
|
|
voxelScalar = dptr[location];
|
|
voxelOpacity = SOTF[voxelScalar];
|
|
|
|
if (voxelOpacity > opacityThreshold)
|
|
{
|
|
if (!transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
currentIndex = 0;
|
|
currentRun++;
|
|
transparentRun = false;
|
|
}
|
|
|
|
voxelIndex++;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
currentIndex = 0;
|
|
currentRun++;
|
|
transparentRun = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this->LineRuns = new vtkShearWarpRLERun<T>*[jCount];
|
|
this->SliceRuns = new vtkShearWarpRLERun<T>[currentRun];
|
|
this->VoxelData = new vtkShearWarpVoxelData<T>[voxelIndex];
|
|
|
|
vtkShearWarpRLERun<T> *activeRun = &this->SliceRuns[0];
|
|
|
|
voxelIndex = 0;
|
|
currentRun = 0;
|
|
|
|
// Now we run-length-encode the slice
|
|
for (j=0,vj=0; j<jCount;j++, vj += jIncrement)
|
|
{
|
|
this->LineRuns[j] = activeRun;
|
|
currentIndex = 0;
|
|
|
|
for (i=0,vi=0; i<iCount;i++, vi += iIncrement)
|
|
{
|
|
location = vi + vj + vk;
|
|
voxelScalar = dptr[location];
|
|
voxelOpacity = SOTF[voxelScalar];
|
|
|
|
if (voxelOpacity > opacityThreshold)
|
|
{
|
|
|
|
if (!transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (i > 0)
|
|
{
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
currentIndex = 0;
|
|
}
|
|
|
|
activeRun->VoxelData = &this->VoxelData[voxelIndex];
|
|
transparentRun = false;
|
|
}
|
|
|
|
// Set voxel data
|
|
this->VoxelData[voxelIndex].Value = voxelScalar;
|
|
this->VoxelData[voxelIndex].EncodedNormal = nptr[location];
|
|
this->VoxelData[voxelIndex].GradientMagnitude = gptr[location];
|
|
|
|
voxelIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (i > 0)
|
|
{
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
currentIndex = 0;
|
|
}
|
|
|
|
activeRun->VoxelData = NULL;
|
|
transparentRun = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
|
|
}
|
|
};
|
|
|
|
// Encodes the data by scalar value (for isosurface display)
|
|
void encodeScalar (vtkImageData* data, vtkVolume *volume, vtkEncodedGradientEstimator *gradest, int axis, int k, float isoValue)
|
|
{
|
|
if (data == NULL || volume == NULL)
|
|
return;
|
|
|
|
T voxelScalar = 0;
|
|
unsigned char currentIndex = 0;
|
|
int currentRun = 0;
|
|
int location = 0;
|
|
bool transparentRun = false;
|
|
|
|
T *dptr = (T*) data->GetScalarPointer();
|
|
unsigned short *nptr = gradest->GetEncodedNormals();
|
|
unsigned char *gptr = gradest->GetGradientMagnitudes();
|
|
|
|
int i,j;
|
|
|
|
int jCount = 0;
|
|
int iCount = 0;
|
|
int voxelIndex = 0;
|
|
|
|
int *dimensions = data->GetDimensions();
|
|
int plane = dimensions[0] * dimensions[1];
|
|
int iIncrement,jIncrement;
|
|
int vi,vj,vk;
|
|
|
|
switch (axis)
|
|
{
|
|
case VTK_X_AXIS:
|
|
iCount = dimensions[1];
|
|
jCount = dimensions[2];
|
|
vk = k;
|
|
iIncrement = dimensions[0];
|
|
jIncrement = plane;
|
|
break;
|
|
|
|
case VTK_Y_AXIS:
|
|
iCount = dimensions[2];
|
|
jCount = dimensions[0];
|
|
vk = k*dimensions[0];
|
|
iIncrement = plane;
|
|
jIncrement = 1;
|
|
break;
|
|
|
|
case VTK_Z_AXIS:
|
|
default:
|
|
iCount = dimensions[0];
|
|
jCount = dimensions[1];
|
|
vk = k*plane;
|
|
iIncrement = 1;
|
|
jIncrement = dimensions[0];
|
|
break;
|
|
}
|
|
|
|
// First we determine the number of runs in the slice
|
|
for (j=0,vj=0; j<jCount;j++, vj += jIncrement)
|
|
{
|
|
for (i=0,vi=0; i<iCount;i++, vi += iIncrement)
|
|
{
|
|
location = vi + vj + vk;
|
|
voxelScalar = dptr[location];
|
|
|
|
if (voxelScalar >= isoValue)
|
|
{
|
|
if (!transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
currentIndex = 0;
|
|
currentRun++;
|
|
transparentRun = false;
|
|
}
|
|
|
|
voxelIndex++;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
currentIndex = 0;
|
|
currentRun++;
|
|
transparentRun = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this->LineRuns = new vtkShearWarpRLERun<T>*[jCount];
|
|
this->SliceRuns = new vtkShearWarpRLERun<T>[currentRun];
|
|
this->VoxelData = new vtkShearWarpVoxelData<T>[voxelIndex];
|
|
|
|
vtkShearWarpRLERun<T> *activeRun = this->SliceRuns;
|
|
|
|
voxelIndex = 0;
|
|
currentRun = 0;
|
|
|
|
// Now we run-length-encode the slice
|
|
for (j=0,vj=0; j<jCount;j++, vj += jIncrement)
|
|
{
|
|
this->LineRuns[j] = activeRun;
|
|
currentIndex = 0;
|
|
|
|
for (i=0,vi=0; i<iCount;i++, vi += iIncrement)
|
|
{
|
|
location = vi + vj + vk;
|
|
voxelScalar = dptr[location];
|
|
|
|
if (voxelScalar >= isoValue)
|
|
{
|
|
if (!transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (i > 0)
|
|
{
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
currentIndex = 0;
|
|
}
|
|
|
|
activeRun->VoxelData = &this->VoxelData[voxelIndex];
|
|
transparentRun = false;
|
|
}
|
|
|
|
// Set voxel data
|
|
this->VoxelData[voxelIndex].Value = voxelScalar;
|
|
this->VoxelData[voxelIndex].EncodedNormal = nptr[location];
|
|
this->VoxelData[voxelIndex].GradientMagnitude = gptr[location];
|
|
|
|
voxelIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (transparentRun && i > 0 && currentIndex < 254)
|
|
{
|
|
currentIndex++;
|
|
}
|
|
else
|
|
{
|
|
if (i > 0)
|
|
{
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
currentIndex = 0;
|
|
}
|
|
|
|
activeRun->VoxelData = NULL;
|
|
transparentRun = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
activeRun->Length = currentIndex + 1;
|
|
activeRun++;
|
|
currentRun++;
|
|
}
|
|
};
|
|
|
|
// Returns a pointer to the first run of a specified scanline
|
|
vtkShearWarpRLERun<T> * GetLineRuns(int line)
|
|
{
|
|
return this->LineRuns[line];
|
|
}
|
|
|
|
private:
|
|
// pointers to the first run for every scanline
|
|
vtkShearWarpRLERun<T> **LineRuns;
|
|
|
|
// all runs of the slice
|
|
vtkShearWarpRLERun<T> *SliceRuns;
|
|
|
|
// the voxel data of the slice
|
|
vtkShearWarpVoxelData<T> *VoxelData;
|
|
|
|
};
|
|
|
|
// Base class for encoded volume
|
|
class vtkShearWarpBase : public vtkObjectBase
|
|
{
|
|
public:
|
|
vtkShearWarpBase()
|
|
{
|
|
this->VolumeDimensions[0] = 0;
|
|
this->VolumeDimensions[1] = 0;
|
|
this->VolumeDimensions[2] = 0;
|
|
};
|
|
|
|
virtual ~vtkShearWarpBase()
|
|
{
|
|
};
|
|
vtkTypeRevisionMacro(vtkShearWarpBase,vtkObjectBase);
|
|
|
|
// Returns the volume dimensions
|
|
int * GetDimensions()
|
|
{
|
|
return this->VolumeDimensions;
|
|
};
|
|
|
|
// Returns the encoded isovalue, if the volume is scalar encoded
|
|
float GetIsoValue()
|
|
{
|
|
return this->IsoValue;
|
|
};
|
|
|
|
// Returns true if the volume is opacity encoded
|
|
bool IsOpacityEncoded()
|
|
{
|
|
return (this->OpacityEncoded == 1);
|
|
};
|
|
|
|
// Returns true if the volume is scalar encoded
|
|
bool IsScalarEncoded()
|
|
{
|
|
return (!this->OpacityEncoded && this->IsoValue >= 0.0);
|
|
}
|
|
|
|
protected:
|
|
// the volume dimensions
|
|
int VolumeDimensions[3];
|
|
|
|
// the encoded isovalue
|
|
float IsoValue;
|
|
|
|
// encoding type flag
|
|
int OpacityEncoded;
|
|
};
|
|
|
|
|
|
// A runlength encoded volume. It contains voxel data encoded for each major viewing direction.
|
|
template <class T>
|
|
class VTK_VOLUMERENDERING_EXPORT vtkShearWarpRLEVolume : public vtkShearWarpBase
|
|
{
|
|
public:
|
|
vtkShearWarpRLEVolume()
|
|
{
|
|
for (int l=0;l<3;l++)
|
|
this->EncodedSlices[l] = NULL;
|
|
|
|
this->OpacityEncoded = 0;
|
|
this->IsoValue = -1.0f;
|
|
};
|
|
|
|
virtual ~vtkShearWarpRLEVolume()
|
|
{
|
|
for (int l=0;l<3;l++)
|
|
if (this->EncodedSlices[l] != NULL)
|
|
delete[] this->EncodedSlices[l];
|
|
};
|
|
|
|
// Encodes the volume by opacity (for alpha-compositing)
|
|
void encodeOpacity(vtkImageData *data, vtkVolume *volume, vtkEncodedGradientEstimator* gradest, float opacityThreshold)
|
|
{
|
|
int l;
|
|
this->IsoValue = -1.0f;
|
|
this->OpacityEncoded = 1;
|
|
|
|
for (l=0;l<3;l++)
|
|
{
|
|
if (this->EncodedSlices[l] != NULL)
|
|
{
|
|
delete[] this->EncodedSlices[l];
|
|
}
|
|
}
|
|
|
|
int *dimensions = data->GetDimensions();
|
|
this->Volume = volume;
|
|
this->VolumeDimensions[0] = dimensions[0];
|
|
this->VolumeDimensions[1] = dimensions[1];
|
|
this->VolumeDimensions[2] = dimensions[2];
|
|
|
|
for (l=0; l<3; l++)
|
|
{
|
|
this->EncodedSlices[l] = new vtkShearWarpRLESlice<T>[dimensions[l]];
|
|
|
|
for (int k = 0; k < dimensions[l]; k++)
|
|
{
|
|
this->EncodedSlices[l][k].encodeOpacity(data,volume,gradest,l,k,opacityThreshold);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Encodes the volume by scalar (for isosurface display)
|
|
void encodeScalar(vtkImageData *data, vtkVolume *volume, vtkEncodedGradientEstimator* gradest, float isoValue)
|
|
{
|
|
int l;
|
|
this->IsoValue = isoValue;
|
|
this->OpacityEncoded = 0;
|
|
|
|
for (l=0;l<3;l++)
|
|
{
|
|
if (this->EncodedSlices[l] != NULL)
|
|
{
|
|
delete[] this->EncodedSlices[l];
|
|
}
|
|
}
|
|
|
|
int *dimensions = data->GetDimensions();
|
|
this->Volume = volume;
|
|
this->VolumeDimensions[0] = dimensions[0];
|
|
this->VolumeDimensions[1] = dimensions[1];
|
|
this->VolumeDimensions[2] = dimensions[2];
|
|
|
|
for (l=0; l<3; l++)
|
|
{
|
|
this->EncodedSlices[l] = new vtkShearWarpRLESlice<T>[dimensions[l]];
|
|
|
|
for (int k = 0; k < dimensions[l]; k++)
|
|
{
|
|
this->EncodedSlices[l][k].encodeScalar(data,volume,gradest,l,k,isoValue);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Returns the slice
|
|
vtkShearWarpRLESlice<T> * GetSlice(int axis, int slice)
|
|
{
|
|
return &this->EncodedSlices[axis][slice];
|
|
};
|
|
|
|
// Returns a pointer to the source volume
|
|
vtkVolume * GetVolume()
|
|
{
|
|
return this->Volume;
|
|
};
|
|
|
|
|
|
private:
|
|
// the encoded slices for all three principal axes
|
|
vtkShearWarpRLESlice<T> *EncodedSlices[3];
|
|
|
|
// the source volume
|
|
vtkVolume *Volume;
|
|
|
|
};
|
|
|
|
template <class T>
|
|
class vtkShearWarpSummedAreaTable
|
|
{
|
|
public:
|
|
vtkShearWarpSummedAreaTable()
|
|
{
|
|
this->Table = new float[2 << ((sizeof(T)*8)-1)];
|
|
this->Opacity = NULL;
|
|
};
|
|
|
|
~vtkShearWarpSummedAreaTable()
|
|
{
|
|
if (this->Table)
|
|
delete[] this->Table;
|
|
};
|
|
|
|
void build(float *SOTF, T upper)
|
|
{
|
|
this->Table[0] = SOTF[0];
|
|
this->Opacity = SOTF;
|
|
|
|
for (int i=1;i<=upper;i++)
|
|
{
|
|
this->Table[i] = this->Table[i-1] + SOTF[i];
|
|
}
|
|
};
|
|
|
|
float integrate(T min, T max)
|
|
{
|
|
if (min != max)
|
|
return this->Table[max] - this->Table[min];
|
|
else
|
|
return this->Opacity[min];
|
|
|
|
};
|
|
|
|
private:
|
|
float *Table;
|
|
float *Opacity;
|
|
};
|
|
|
|
struct vtkShearWarpOctreeRun
|
|
{
|
|
unsigned short Length;
|
|
unsigned char Type;
|
|
};
|
|
|
|
template <class T>
|
|
class vtkShearWarpOctreeNode
|
|
{
|
|
public:
|
|
vtkShearWarpOctreeNode()
|
|
{
|
|
this->Children = NULL;
|
|
};
|
|
|
|
~vtkShearWarpOctreeNode()
|
|
{
|
|
if (this->Children != NULL)
|
|
delete[] this->Children;
|
|
};
|
|
|
|
T GetMinimum()
|
|
{
|
|
return this->Minimum;
|
|
};
|
|
|
|
T GetMaximum()
|
|
{
|
|
return this->Maximum;
|
|
};
|
|
|
|
void build(vtkImageData *data, int min[3], int max[3], int level)
|
|
{
|
|
// cout << "minX: " << min[0] << " - minY: " << min[1] << " - minZ: " << min[2] << "\n";
|
|
// cout << "maxX: " << max[0] << " - maxY: " << max[1] << " - maxZ: " << max[2] << "\n\n";
|
|
|
|
if (this->Children != NULL)
|
|
{
|
|
delete[] this->Children;
|
|
this->Children = NULL;
|
|
}
|
|
|
|
if (max[0] <= min[0] && max[1] <= min[1] && max[2] <= min[2])
|
|
{
|
|
this->Minimum = *((T*) data->GetScalarPointer(max[0],max[1],max[2]));
|
|
this->Maximum = this->Minimum;
|
|
}
|
|
else
|
|
{
|
|
int center[3] = {(max[0]+min[0]) / 2, (max[1]+min[1]) / 2, (max[2]+min[2]) / 2};
|
|
int newMin[3];
|
|
int newMax[3];
|
|
this->Children = new vtkShearWarpOctreeNode<T>[8];
|
|
|
|
newMin[0] = min[0];
|
|
newMin[1] = min[1];
|
|
newMin[2] = min[2];
|
|
newMax[0] = center[0];
|
|
newMax[1] = center[1];
|
|
newMax[2] = center[2];
|
|
this->Children[0].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = center[0]+1;
|
|
newMin[1] = min[1];
|
|
newMin[2] = min[2];
|
|
newMax[0] = max[0];
|
|
newMax[1] = center[1];
|
|
newMax[2] = center[2];
|
|
this->Children[1].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = min[0];
|
|
newMin[1] = center[1]+1;
|
|
newMin[2] = min[2];
|
|
newMax[0] = center[0];
|
|
newMax[1] = max[1];
|
|
newMax[2] = center[2];
|
|
this->Children[2].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = center[0]+1;
|
|
newMin[1] = center[1]+1;
|
|
newMin[2] = min[2];
|
|
newMax[0] = max[0];
|
|
newMax[1] = max[1];
|
|
newMax[2] = center[2];
|
|
this->Children[3].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = min[0];
|
|
newMin[1] = min[1];
|
|
newMin[2] = center[2]+1;
|
|
newMax[0] = center[0];
|
|
newMax[1] = center[1];
|
|
newMax[2] = max[2];
|
|
this->Children[4].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = center[0]+1;
|
|
newMin[1] = min[1];
|
|
newMin[2] = center[2]+1;
|
|
newMax[0] = max[0];
|
|
newMax[1] = center[1];
|
|
newMax[2] = max[2];
|
|
this->Children[5].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = min[0];
|
|
newMin[1] = center[1]+1;
|
|
newMin[2] = center[2]+1;
|
|
newMax[0] = center[0];
|
|
newMax[1] = max[1];
|
|
newMax[2] = max[2];
|
|
this->Children[6].build(data,newMin,newMax,level+1);
|
|
|
|
newMin[0] = center[0]+1;
|
|
newMin[1] = center[1]+1;
|
|
newMin[2] = center[2]+1;
|
|
newMax[0] = max[0];
|
|
newMax[1] = max[1];
|
|
newMax[2] = max[2];
|
|
this->Children[7].build(data,newMin,newMax,level+1);
|
|
|
|
this->Minimum = this->Children[0].Minimum;
|
|
this->Maximum = this->Children[0].Maximum;
|
|
|
|
bool equalMinimum = true;
|
|
bool equalMaximum = true;
|
|
|
|
for (int i=1; i < 8; i++)
|
|
{
|
|
if (this->Minimum != this->Children[i].Minimum)
|
|
{
|
|
if (this->Children[i].Minimum < this->Minimum)
|
|
this->Minimum = this->Children[i].Minimum;
|
|
|
|
equalMinimum = false;
|
|
}
|
|
|
|
if (this->Maximum != this->Children[i].Maximum)
|
|
{
|
|
if (this->Children[i].Maximum > this->Maximum)
|
|
this->Maximum = this->Children[i].Maximum;
|
|
|
|
equalMaximum = false;
|
|
}
|
|
}
|
|
|
|
// If minimum and maximum of all children are equal, we can remove them
|
|
if (equalMinimum && equalMaximum)
|
|
{
|
|
delete[] this->Children;
|
|
this->Children = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Remove children if node already is at the lowest level
|
|
/* if ((max[0] - min[0] + 1) <= VTK_SHEAR_WARP_OCTREE_MINIMUM_SIZE &&
|
|
(max[1] - min[1] + 1) <= VTK_SHEAR_WARP_OCTREE_MINIMUM_SIZE &&
|
|
(max[2] - min[2] + 1) <= VTK_SHEAR_WARP_OCTREE_MINIMUM_SIZE)*/
|
|
if (level >= 4)
|
|
{
|
|
delete[] this->Children;
|
|
this->Children = NULL;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void classifyOpacity(vtkShearWarpSummedAreaTable<T> *table)
|
|
{
|
|
float integral = table->integrate(this->Minimum,this->Maximum);
|
|
|
|
if (integral == 0.0f)
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_TRANSPARENT;
|
|
}
|
|
else if (this->Children == NULL)
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_NONTRANSPARENT;
|
|
}
|
|
else
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_COMBINATION;
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
this->Children[i].classifyOpacity(table);
|
|
}
|
|
};
|
|
|
|
void classifyScalar(T value)
|
|
{
|
|
if (this->Minimum >= value || this->Maximum >= value)
|
|
{
|
|
if (this->Children == NULL)
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_NONTRANSPARENT;
|
|
}
|
|
else
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_COMBINATION;
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
this->Children[i].classifyScalar(value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->Status = VTK_SHEAR_WARP_OCTREE_TRANSPARENT;
|
|
}
|
|
};
|
|
|
|
int computeRuns(vtkShearWarpOctreeRun *& runs, int axis, int slices, int lines, int voxels, int slice, int line)
|
|
{
|
|
static const int increments[3][3] = {{2,4,1},{4,1,2},{1,2,4}};
|
|
|
|
if (this->Status == VTK_SHEAR_WARP_OCTREE_COMBINATION)
|
|
{
|
|
int child = 0;
|
|
// int half = size / 2;
|
|
int halfSlices = slices / 2;
|
|
int halfLines = lines / 2;
|
|
int halfVoxels = voxels / 2;
|
|
|
|
if (slice > halfSlices)
|
|
{
|
|
child += increments[axis][2];
|
|
slice -= halfSlices;
|
|
|
|
halfSlices = slices - halfSlices;
|
|
}
|
|
|
|
if (line > halfLines)
|
|
{
|
|
child += increments[axis][1];
|
|
line -= halfLines;
|
|
|
|
halfLines = lines - halfLines;
|
|
}
|
|
|
|
int a = this->Children[child].computeRuns(runs, axis, halfSlices, halfLines, halfVoxels, slice,line);
|
|
int b = this->Children[child + increments[axis][0]].computeRuns(runs, axis, halfSlices, halfLines, voxels-halfVoxels, slice,line);
|
|
|
|
if (a < b)
|
|
return a;
|
|
else
|
|
return b;
|
|
}
|
|
else
|
|
{
|
|
if (runs->Type == this->Status)
|
|
{
|
|
runs->Length += voxels;//size;
|
|
}
|
|
else
|
|
{
|
|
if (runs[0].Type != 255)
|
|
runs++;
|
|
|
|
runs->Type = this->Status;
|
|
runs->Length = voxels;//size;
|
|
}
|
|
|
|
return voxels;//size;
|
|
|
|
}
|
|
}
|
|
|
|
private:
|
|
vtkShearWarpOctreeNode<T> *Children;
|
|
unsigned char Status;
|
|
T Minimum;
|
|
T Maximum;
|
|
};
|
|
|
|
template <class T>
|
|
class VTK_VOLUMERENDERING_EXPORT vtkShearWarpOctree : public vtkShearWarpBase
|
|
{
|
|
public:
|
|
vtkTypeRevisionMacro(vtkShearWarpOctree,vtkShearWarpBase);
|
|
|
|
vtkShearWarpOctree()
|
|
{
|
|
};
|
|
|
|
virtual ~vtkShearWarpOctree()
|
|
{
|
|
|
|
};
|
|
|
|
void build(vtkImageData* data)
|
|
{
|
|
int min[3],max[3];
|
|
data->GetDimensions(this->Dimensions);
|
|
data->GetExtent(min[0],max[0],min[1],max[1],min[2],max[2]);
|
|
this->Root.build(data,min,max,0);
|
|
};
|
|
|
|
void classifyOpacity(vtkVolume* volume)
|
|
{
|
|
this->Table.build(volume->GetCorrectedScalarOpacityArray(),this->Root.GetMaximum());
|
|
this->Root.classifyOpacity(&this->Table);
|
|
this->OpacityEncoded = 1;
|
|
};
|
|
|
|
void classifyScalar(T value)
|
|
{
|
|
this->Root.classifyScalar(value);
|
|
this->OpacityEncoded = 0;
|
|
};
|
|
|
|
int GetLineRuns(vtkShearWarpOctreeRun *runs, int axis, int slice, int line)
|
|
{
|
|
static const int sizes[3][3] = {{this->Dimensions[1],this->Dimensions[2],this->Dimensions[0]},
|
|
{this->Dimensions[2],this->Dimensions[0],this->Dimensions[1]},
|
|
{this->Dimensions[0],this->Dimensions[1],this->Dimensions[2]}};
|
|
|
|
runs[0].Type = 255;
|
|
runs[0].Length = 0;
|
|
return this->Root.computeRuns(runs,axis,/*this->Dimensions[axis],*/sizes[axis][2],sizes[axis][1],sizes[axis][0],slice,line);
|
|
};
|
|
|
|
private:
|
|
vtkShearWarpOctreeNode<T> Root;
|
|
vtkShearWarpSummedAreaTable<T> Table;
|
|
int Dimensions[3];
|
|
|
|
vtkShearWarpOctree(const vtkShearWarpOctree&); // Not implemented.
|
|
void operator=(const vtkShearWarpOctree&); // Not implemented.
|
|
};
|
|
|