/**
*
*/
package icy.vtk;
import icy.image.colormap.IcyColorMap;
import icy.image.lut.LUT;
import icy.image.lut.LUT.LUTChannel;
import icy.math.Scaler;
import icy.type.DataType;
import vtk.vtkColorTransferFunction;
import vtk.vtkFixedPointVolumeRayCastMapper;
import vtk.vtkGPUVolumeRayCastMapper;
import vtk.vtkImageData;
import vtk.vtkOpenGLGPUVolumeRayCastMapper;
import vtk.vtkPiecewiseFunction;
import vtk.vtkRenderer;
import vtk.vtkVolume;
import vtk.vtkVolumeMapper;
import vtk.vtkVolumeProperty;
import vtk.vtkVolumeRayCastMapper;
/**
* Class to represent a 3D image as a 3D VTK volume object.
*
* @author Stephane
*/
public class VtkImageVolume
{
/**
* @deprecated
*/
@Deprecated
public static enum VtkVolumeMapperType
{
RAYCAST_CPU_FIXEDPOINT
{
@Override
public String toString()
{
return "Raycaster (CPU)";
}
},
RAYCAST_GPU_OPENGL
{
@Override
public String toString()
{
return "Raycaster (OpenGL)";
}
},
TEXTURE2D_OPENGL
{
@Override
public String toString()
{
return "Texture 2D (OpenGL)";
}
},
TEXTURE3D_OPENGL
{
@Override
public String toString()
{
return "Texture 3D (OpenGL)";
}
};
}
public static enum VtkVolumeBlendType
{
COMPOSITE
{
@Override
public String toString()
{
return "Composite";
}
},
MAXIMUM_INTENSITY
{
@Override
public String toString()
{
return "Maximum intensity";
}
},
MINIMUM_INTENSITY
{
@Override
public String toString()
{
return "Minimum intensity";
}
},
ADDITIVE
{
@Override
public String toString()
{
return "Additive";
}
};
}
/**
* volume data
*/
protected vtkVolumeMapper volumeMapper;
protected vtkVolume volume;
protected vtkVolumeProperty volumeProperty;
protected vtkImageData imageData;
public VtkImageVolume()
{
super();
// build volume property object
volumeProperty = new vtkVolumeProperty();
// default volume setup
volumeProperty.IndependentComponentsOn();
volumeProperty.DisableGradientOpacityOn();
setShade(false);
setAmbient(0.5d);
setDiffuse(0.4d);
setSpecular(0.4d);
setInterpolationMode(VtkUtil.VTK_LINEAR_INTERPOLATION);
// build default volume mapper
volumeMapper = new vtkFixedPointVolumeRayCastMapper();
((vtkFixedPointVolumeRayCastMapper) volumeMapper).IntermixIntersectingGeometryOn();
setSampleResolution(0);
// initialize volume data
volume = new vtkVolume();
volume.SetProperty(volumeProperty);
// setup volume connection
volume.SetMapper(volumeMapper);
// volume should not be "pickable" by default
volume.SetPickable(0);
imageData = null;
}
public void release()
{
// delete all VTK objects
volume.Delete();
volumeMapper.RemoveAllInputs();
volumeMapper.Delete();
volumeProperty.Delete();
if (imageData != null)
{
imageData.GetPointData().GetScalars().Delete();
imageData.GetPointData().Delete();
imageData.Delete();
}
// after Delete we need to release reference
volume = null;
volumeMapper = null;
volumeProperty = null;
imageData = null;
}
public vtkVolume getVolume()
{
return volume;
}
/**
* Return the number of channel contained in image data.
*/
protected int getChannelCount()
{
if (imageData != null)
return imageData.GetNumberOfScalarComponents();
// assume 1 by default
return 1;
}
/**
* Sets the color map ({@link vtkColorTransferFunction}) used to render the specified channel of
* image volume.
*/
public void setColorMap(vtkColorTransferFunction map, int channel)
{
vtkColorTransferFunction oldMap = volumeProperty.GetRGBTransferFunction(channel);
// global colormap, don't release it
if (volumeProperty.GetRGBTransferFunction() == oldMap)
oldMap = null;
volumeProperty.SetColor(channel, map);
// delete previous color transfer function if any
if (oldMap != null)
oldMap.Delete();
}
/**
* Sets the opacity map ({@link vtkPiecewiseFunction}) used to render the specified channel of
* image volume.
*/
public void setOpacityMap(vtkPiecewiseFunction map, int channel)
{
vtkPiecewiseFunction oldMap = volumeProperty.GetScalarOpacity(channel);
// global opacity, don't release it
if (volumeProperty.GetScalarOpacity() == oldMap)
oldMap = null;
volumeProperty.SetScalarOpacity(channel, map);
// delete previous opacity function if any
if (oldMap != null)
oldMap.Delete();
}
/**
* Sets the {@link LUT} used to render the image volume.
*/
public void setLUT(LUT value)
{
for (int channel = 0; channel < Math.min(value.getNumChannel(), getChannelCount()); channel++)
setLUT(value.getLutChannel(channel), channel);
}
/**
* Sets the {@link LUTChannel} used to render the specified channel of image volume.
*/
public void setLUT(LUTChannel lutChannel, int channel)
{
final IcyColorMap colorMap = lutChannel.getColorMap();
final Scaler scaler = lutChannel.getScaler();
// SCALAR COLOR FUNCTION
final vtkColorTransferFunction newColorMap = new vtkColorTransferFunction();
newColorMap.SetRange(scaler.getLeftIn(), scaler.getRightIn());
for (int i = 0; i < IcyColorMap.SIZE; i++)
{
newColorMap.AddRGBPoint(scaler.unscale(i), colorMap.getNormalizedRed(i), colorMap.getNormalizedGreen(i),
colorMap.getNormalizedBlue(i));
}
vtkColorTransferFunction oldColorMap = volumeProperty.GetRGBTransferFunction(channel);
// global colormap, don't release it
if (volumeProperty.GetRGBTransferFunction() == oldColorMap)
oldColorMap = null;
volumeProperty.SetColor(channel, newColorMap);
// delete previous color transfer function if any
if (oldColorMap != null)
oldColorMap.Delete();
// SCALAR OPACITY FUNCTION
final vtkPiecewiseFunction newOpacity = new vtkPiecewiseFunction();
if (colorMap.isEnabled())
{
for (int i = 0; i < IcyColorMap.SIZE; i++)
newOpacity.AddPoint(scaler.unscale(i), colorMap.getNormalizedAlpha(i));
}
else
{
for (int i = 0; i < IcyColorMap.SIZE; i++)
newOpacity.AddPoint(scaler.unscale(i), 0d);
}
vtkPiecewiseFunction oldOpacity = volumeProperty.GetScalarOpacity(channel);
// global opacity, don't release it
if (volumeProperty.GetScalarOpacity() == oldOpacity)
oldOpacity = null;
volumeProperty.SetScalarOpacity(channel, newOpacity);
// delete previous opacity function if any
if (oldOpacity != null)
oldOpacity.Delete();
}
/**
* Get the sample resolution of the raycaster volume rendering.<br>
* <ul>
* <li>0 = automatic</li>
* <li>1 = finest (slow)</li>
* <li>10 = coarse (fast)</li>
* </ul>
*/
public double getSampleResolution()
{
if (volumeMapper instanceof vtkFixedPointVolumeRayCastMapper)
{
final vtkFixedPointVolumeRayCastMapper mapper = (vtkFixedPointVolumeRayCastMapper) volumeMapper;
if (mapper.GetAutoAdjustSampleDistances() != 0)
return 0d;
return mapper.GetImageSampleDistance();
}
else if (volumeMapper instanceof vtkVolumeRayCastMapper)
{
final vtkVolumeRayCastMapper mapper = (vtkVolumeRayCastMapper) volumeMapper;
if (mapper.GetAutoAdjustSampleDistances() != 0)
return 0d;
return mapper.GetImageSampleDistance();
}
else if (volumeMapper instanceof vtkGPUVolumeRayCastMapper)
{
final vtkGPUVolumeRayCastMapper mapper = (vtkGPUVolumeRayCastMapper) volumeMapper;
if (mapper.GetAutoAdjustSampleDistances() != 0)
return 0d;
return mapper.GetImageSampleDistance();
}
else if (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper)
{
final vtkOpenGLGPUVolumeRayCastMapper mapper = (vtkOpenGLGPUVolumeRayCastMapper) volumeMapper;
if (mapper.GetAutoAdjustSampleDistances() != 0)
return 0d;
return mapper.GetImageSampleDistance();
}
return 0d;
}
/**
* Set sample resolution for the raycaster volume rendering.<br>
* <ul>
* <li>0 = automatic</li>
* <li>1 = finest (slow)</li>
* <li>10 = coarse (fast)</li>
* </ul>
*/
public void setSampleResolution(double value)
{
if (volumeMapper instanceof vtkFixedPointVolumeRayCastMapper)
{
final vtkFixedPointVolumeRayCastMapper mapper = (vtkFixedPointVolumeRayCastMapper) volumeMapper;
if (value == 0d)
mapper.AutoAdjustSampleDistancesOn();
else
{
mapper.AutoAdjustSampleDistancesOff();
mapper.SetImageSampleDistance(value);
}
}
else if (volumeMapper instanceof vtkVolumeRayCastMapper)
{
final vtkVolumeRayCastMapper mapper = (vtkVolumeRayCastMapper) volumeMapper;
if (value == 0d)
mapper.AutoAdjustSampleDistancesOn();
else
{
mapper.AutoAdjustSampleDistancesOff();
mapper.SetImageSampleDistance(value);
}
}
else if (volumeMapper instanceof vtkGPUVolumeRayCastMapper)
{
final vtkGPUVolumeRayCastMapper mapper = (vtkGPUVolumeRayCastMapper) volumeMapper;
if (value == 0d)
mapper.AutoAdjustSampleDistancesOn();
else
{
mapper.AutoAdjustSampleDistancesOff();
mapper.SetImageSampleDistance(value);
}
}
else if (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper)
{
final vtkOpenGLGPUVolumeRayCastMapper mapper = (vtkOpenGLGPUVolumeRayCastMapper) volumeMapper;
if (value == 0d)
mapper.AutoAdjustSampleDistancesOn();
else
{
mapper.AutoAdjustSampleDistancesOff();
mapper.SetImageSampleDistance(value);
}
}
}
public boolean isPickable()
{
return (volume.GetPickable() != 0) ? true : false;
}
public void setPickable(boolean value)
{
volume.SetPickable(value ? 1 : 0);
}
/**
* Returns the XYZ scaling of the volume image
*/
public double[] getScale()
{
return volume.GetScale();
}
/**
* Sets the XYZ scaling of the volume image
*/
public void setScale(double x, double y, double z)
{
volume.SetScale(x, y, z);
}
/**
* Sets the XYZ scaling of the volume image
*/
public void setScale(double[] xyz)
{
volume.SetScale(xyz);
}
/**
* Returns <code>true</code> if shading is enabled (global)
*/
public boolean getShade()
{
return (volumeProperty.GetShade() == 1) ? true : false;
}
/**
* Returns <code>true</code> if shading is enabled for the specified component
*/
// public boolean getShade(int index)
// {
// return (volumeProperty.GetShade(index) == 1) ? true : false;
// }
/**
* Enable / Disable the shading (global)
*/
public void setShade(boolean value)
{
final int num = getChannelCount();
for (int ch = 0; ch < num; ch++)
volumeProperty.SetShade(ch, value ? 1 : 0);
volumeProperty.SetShade(value ? 1 : 0);
}
/**
* Enable / Disable the shading for the specified component
*/
// public void setShade(int index, boolean value)
// {
// volumeProperty.SetShade(index, value ? 1 : 0);
// }
/**
* Returns the ambient lighting coefficient (global)
*/
public double getAmbient()
{
return volumeProperty.GetAmbient();
}
/**
* Returns the ambient lighting coefficient for the specified component
*/
// public double getAmbient(int index)
// {
// return volumeProperty.GetAmbient(index);
// }
/**
* Sets the ambient lighting coefficient (global)
*/
public void setAmbient(double value)
{
final int num = getChannelCount();
for (int ch = 0; ch < num; ch++)
volumeProperty.SetAmbient(ch, value);
volumeProperty.SetAmbient(value);
}
/**
* Sets the ambient lighting coefficient for the specified component
*/
// public void setAmbient(int index, double value)
// {
// volumeProperty.SetAmbient(index, value);
// }
/**
* Returns the diffuse lighting coefficient (global)
*/
public double getDiffuse()
{
return volumeProperty.GetDiffuse();
}
/**
* Returns the diffuse lighting coefficient for the specified component
*/
// public double getDiffuse(int index)
// {
// return volumeProperty.GetDiffuse(index);
// }
/**
* Sets the diffuse lighting coefficient (global)
*/
public void setDiffuse(double value)
{
final int num = getChannelCount();
for (int ch = 0; ch < num; ch++)
volumeProperty.SetDiffuse(ch, value);
volumeProperty.SetDiffuse(value);
}
/**
* Sets the diffuse lighting coefficient for the specified component
*/
// public void setDiffuse(int index, double value)
// {
// volumeProperty.SetDiffuse(index, value);
// }
/**
* Returns the specular lighting coefficient (global)
*/
public double getSpecular()
{
return volumeProperty.GetSpecular();
}
/**
* Returns the specular lighting coefficient for the specified component
*/
// public double getSpecular(int index)
// {
// return volumeProperty.GetSpecular(index);
// }
/**
* Sets the specular lighting coefficient (global)
*/
public void setSpecular(double value)
{
final int num = getChannelCount();
for (int ch = 0; ch < num; ch++)
volumeProperty.SetSpecular(ch, value);
volumeProperty.SetSpecular(value);
}
/**
* Sets the specular lighting coefficient for the specified component
*/
// public void setSpecular(int index, double value)
// {
// volumeProperty.SetSpecular(index, value);
// }
/**
* Returns the specular power (global)
*/
public double getSpecularPower()
{
return volumeProperty.GetSpecularPower();
}
/**
* Returns the specular power for the specified component
*/
// public double getSpecularPower(int index)
// {
// return volumeProperty.GetSpecularPower(index);
// }
/**
* Sets the specular power (global)
*/
public void setSpecularPower(double value)
{
final int num = getChannelCount();
for (int ch = 0; ch < num; ch++)
volumeProperty.SetSpecularPower(ch, value);
volumeProperty.SetSpecularPower(value);
}
/**
* Sets the specular power for the specified component
*/
// public void setSpecularPower(int index, double value)
// {
// volumeProperty.SetSpecularPower(index, value);
// }
/**
* Returns the interpolation method for rendering.<br>
* Possible values are:
* <ul>
* <li>VTK_NEAREST_INTERPOLATION</li>
* <li>VTK_LINEAR_INTERPOLATION</li>
* <li>VTK_CUBIC_INTERPOLATION</li>
* </ul>
*/
public int getInterpolationMode()
{
return volumeProperty.GetInterpolationType();
}
/**
* Sets the interpolation method for rendering.<br>
* Possible values are:
* <ul>
* <li>VTK_NEAREST_INTERPOLATION</li>
* <li>VTK_LINEAR_INTERPOLATION</li>
* <li>VTK_CUBIC_INTERPOLATION</li>
* </ul>
*/
public void setInterpolationMode(int value)
{
volumeProperty.SetInterpolationType(value);
}
/**
* Returns true if selected volume mapper is the GPU accelerated raycaster.
*/
public boolean getGPURendering()
{
return (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper);
}
/**
* Enable GPU volume rendering.
*
* @param value
* if <code>true</code> then the GPU accelerated raycaster will be used otherwise the classical CPU
* rayscaster is used.
*/
public boolean setGPURendering(boolean value)
{
// volume mapper changed ?
if (getGPURendering() != value)
{
// save the parameters as they can be modified when mapper change
final VtkVolumeBlendType blendingMode = getBlendingMode();
final double sampleResolution = getSampleResolution();
final vtkVolumeMapper newMapper;
if (value)
{
// GPU raycaster
newMapper = new vtkOpenGLGPUVolumeRayCastMapper();
}
else
{
// CPU raycaster
newMapper = new vtkFixedPointVolumeRayCastMapper();
((vtkFixedPointVolumeRayCastMapper) newMapper).IntermixIntersectingGeometryOn();
}
// setup volume connection
volume.SetMapper(newMapper);
// release previous mapper if any
if (volumeMapper != null)
{
volumeMapper.RemoveAllInputs();
volumeMapper.Delete();
}
// update volume mapper
volumeMapper = newMapper;
// and connect the image data
if (imageData != null)
newMapper.SetInputData(imageData);
// restore blending and sample resolution
setBlendingMode(blendingMode);
setSampleResolution(sampleResolution);
return true;
}
return false;
}
/**
* @deprecated Should always return true now.
*/
@Deprecated
public static boolean isMapperSupported(vtkRenderer renderer)
{
return true;
}
/**
* Returns the blending method for rendering.
*/
public VtkVolumeBlendType getBlendingMode()
{
return VtkVolumeBlendType.values()[volumeMapper.GetBlendMode()];
}
/**
* Sets the blending method for rendering.
*/
public void setBlendingMode(VtkVolumeBlendType value)
{
volumeMapper.SetBlendMode(value.ordinal());
}
/**
* Get the current volume image data object.
*
* @see VtkUtil#getImageData(Object, DataType, int, int, int, int)
*/
public vtkImageData getVolumeData()
{
return imageData;
}
/**
* Set the volume image data.
*
* @see VtkUtil#getImageData(Object, DataType, int, int, int, int)
*/
public void setVolumeData(vtkImageData data)
{
if (imageData != data)
{
// set connection
volumeMapper.SetInputData(data);
// release previous volume data memory
if (imageData != null)
{
imageData.GetPointData().GetScalars().Delete();
imageData.GetPointData().Delete();
imageData.Delete();
}
// set to new image data
imageData = data;
}
updateChannelProperties();
}
/**
* Refresh channel properties
*/
protected void updateChannelProperties()
{
setShade(getShade());
setAmbient(getAmbient());
setDiffuse(getDiffuse());
setSpecular(getSpecular());
setSpecularPower(getSpecularPower());
}
/**
* Sets the visible state of the image volume object
*/
public void setVisible(boolean value)
{
volume.SetVisibility(value ? 1 : 0);
}
/**
* @return visible state of the image volume object
*/
public boolean isVisible()
{
return (volume.GetVisibility() != 0) ? true : false;
}
}