001/**
002 * 
003 */
004package icy.vtk;
005
006import icy.image.colormap.IcyColorMap;
007import icy.image.lut.LUT;
008import icy.image.lut.LUT.LUTChannel;
009import icy.math.Scaler;
010import icy.type.DataType;
011
012import vtk.vtkColorTransferFunction;
013import vtk.vtkFixedPointVolumeRayCastMapper;
014import vtk.vtkGPUVolumeRayCastMapper;
015import vtk.vtkImageData;
016import vtk.vtkOpenGLGPUVolumeRayCastMapper;
017import vtk.vtkPiecewiseFunction;
018import vtk.vtkRenderer;
019import vtk.vtkVolume;
020import vtk.vtkVolumeMapper;
021import vtk.vtkVolumeProperty;
022import vtk.vtkVolumeRayCastMapper;
023
024/**
025 * Class to represent a 3D image as a 3D VTK volume object.
026 * 
027 * @author Stephane
028 */
029public class VtkImageVolume
030{
031    /**
032     * @deprecated
033     */
034    @Deprecated
035    public static enum VtkVolumeMapperType
036    {
037        RAYCAST_CPU_FIXEDPOINT
038        {
039            @Override
040            public String toString()
041            {
042                return "Raycaster (CPU)";
043            }
044        },
045        RAYCAST_GPU_OPENGL
046        {
047            @Override
048            public String toString()
049            {
050                return "Raycaster (OpenGL)";
051            }
052        },
053        TEXTURE2D_OPENGL
054        {
055            @Override
056            public String toString()
057            {
058                return "Texture 2D (OpenGL)";
059            }
060        },
061        TEXTURE3D_OPENGL
062        {
063            @Override
064            public String toString()
065            {
066                return "Texture 3D (OpenGL)";
067            }
068        };
069    }
070
071    public static enum VtkVolumeBlendType
072    {
073        COMPOSITE
074        {
075            @Override
076            public String toString()
077            {
078                return "Composite";
079            }
080        },
081        MAXIMUM_INTENSITY
082        {
083            @Override
084            public String toString()
085            {
086                return "Maximum intensity";
087            }
088        },
089        MINIMUM_INTENSITY
090        {
091            @Override
092            public String toString()
093            {
094                return "Minimum intensity";
095            }
096        },
097
098        ADDITIVE
099        {
100            @Override
101            public String toString()
102            {
103                return "Additive";
104            }
105        };
106    }
107
108    /**
109     * volume data
110     */
111    protected vtkVolumeMapper volumeMapper;
112    protected vtkVolume volume;
113    protected vtkVolumeProperty volumeProperty;
114    protected vtkImageData imageData;
115
116    public VtkImageVolume()
117    {
118        super();
119
120        // build volume property object
121        volumeProperty = new vtkVolumeProperty();
122        // default volume setup
123        volumeProperty.IndependentComponentsOn();
124        volumeProperty.DisableGradientOpacityOn();
125        setShade(false);
126        setAmbient(0.5d);
127        setDiffuse(0.4d);
128        setSpecular(0.4d);
129        setInterpolationMode(VtkUtil.VTK_LINEAR_INTERPOLATION);
130
131        // build default volume mapper
132        volumeMapper = new vtkFixedPointVolumeRayCastMapper();
133        ((vtkFixedPointVolumeRayCastMapper) volumeMapper).IntermixIntersectingGeometryOn();
134        setSampleResolution(0);
135
136        // initialize volume data
137        volume = new vtkVolume();
138        volume.SetProperty(volumeProperty);
139        // setup volume connection
140        volume.SetMapper(volumeMapper);
141        // volume should not be "pickable" by default
142        volume.SetPickable(0);
143
144        imageData = null;
145    }
146
147    public void release()
148    {
149        // delete all VTK objects
150        volume.Delete();
151        volumeMapper.RemoveAllInputs();
152        volumeMapper.Delete();
153        volumeProperty.Delete();
154
155        if (imageData != null)
156        {
157            imageData.GetPointData().GetScalars().Delete();
158            imageData.GetPointData().Delete();
159            imageData.Delete();
160        }
161
162        // after Delete we need to release reference
163        volume = null;
164        volumeMapper = null;
165        volumeProperty = null;
166        imageData = null;
167    }
168
169    public vtkVolume getVolume()
170    {
171        return volume;
172    }
173
174    /**
175     * Return the number of channel contained in image data.
176     */
177    protected int getChannelCount()
178    {
179        if (imageData != null)
180            return imageData.GetNumberOfScalarComponents();
181
182        // assume 1 by default
183        return 1;
184    }
185
186    /**
187     * Sets the color map ({@link vtkColorTransferFunction}) used to render the specified channel of
188     * image volume.
189     */
190    public void setColorMap(vtkColorTransferFunction map, int channel)
191    {
192        vtkColorTransferFunction oldMap = volumeProperty.GetRGBTransferFunction(channel);
193        // global colormap, don't release it
194        if (volumeProperty.GetRGBTransferFunction() == oldMap)
195            oldMap = null;
196
197        volumeProperty.SetColor(channel, map);
198        // delete previous color transfer function if any
199        if (oldMap != null)
200            oldMap.Delete();
201    }
202
203    /**
204     * Sets the opacity map ({@link vtkPiecewiseFunction}) used to render the specified channel of
205     * image volume.
206     */
207    public void setOpacityMap(vtkPiecewiseFunction map, int channel)
208    {
209        vtkPiecewiseFunction oldMap = volumeProperty.GetScalarOpacity(channel);
210        // global opacity, don't release it
211        if (volumeProperty.GetScalarOpacity() == oldMap)
212            oldMap = null;
213
214        volumeProperty.SetScalarOpacity(channel, map);
215        // delete previous opacity function if any
216        if (oldMap != null)
217            oldMap.Delete();
218    }
219
220    /**
221     * Sets the {@link LUT} used to render the image volume.
222     */
223    public void setLUT(LUT value)
224    {
225        for (int channel = 0; channel < Math.min(value.getNumChannel(), getChannelCount()); channel++)
226            setLUT(value.getLutChannel(channel), channel);
227    }
228
229    /**
230     * Sets the {@link LUTChannel} used to render the specified channel of image volume.
231     */
232    public void setLUT(LUTChannel lutChannel, int channel)
233    {
234        final IcyColorMap colorMap = lutChannel.getColorMap();
235        final Scaler scaler = lutChannel.getScaler();
236
237        // SCALAR COLOR FUNCTION
238        final vtkColorTransferFunction newColorMap = new vtkColorTransferFunction();
239
240        newColorMap.SetRange(scaler.getLeftIn(), scaler.getRightIn());
241        for (int i = 0; i < IcyColorMap.SIZE; i++)
242        {
243            newColorMap.AddRGBPoint(scaler.unscale(i), colorMap.getNormalizedRed(i), colorMap.getNormalizedGreen(i),
244                    colorMap.getNormalizedBlue(i));
245        }
246
247        vtkColorTransferFunction oldColorMap = volumeProperty.GetRGBTransferFunction(channel);
248        // global colormap, don't release it
249        if (volumeProperty.GetRGBTransferFunction() == oldColorMap)
250            oldColorMap = null;
251
252        volumeProperty.SetColor(channel, newColorMap);
253        // delete previous color transfer function if any
254        if (oldColorMap != null)
255            oldColorMap.Delete();
256
257        // SCALAR OPACITY FUNCTION
258        final vtkPiecewiseFunction newOpacity = new vtkPiecewiseFunction();
259
260        if (colorMap.isEnabled())
261        {
262            for (int i = 0; i < IcyColorMap.SIZE; i++)
263                newOpacity.AddPoint(scaler.unscale(i), colorMap.getNormalizedAlpha(i));
264        }
265        else
266        {
267            for (int i = 0; i < IcyColorMap.SIZE; i++)
268                newOpacity.AddPoint(scaler.unscale(i), 0d);
269        }
270
271        vtkPiecewiseFunction oldOpacity = volumeProperty.GetScalarOpacity(channel);
272        // global opacity, don't release it
273        if (volumeProperty.GetScalarOpacity() == oldOpacity)
274            oldOpacity = null;
275
276        volumeProperty.SetScalarOpacity(channel, newOpacity);
277        // delete previous opacity function if any
278        if (oldOpacity != null)
279            oldOpacity.Delete();
280    }
281
282    /**
283     * Get the sample resolution of the raycaster volume rendering.<br>
284     * <ul>
285     * <li>0 = automatic</li>
286     * <li>1 = finest (slow)</li>
287     * <li>10 = coarse (fast)</li>
288     * </ul>
289     */
290    public double getSampleResolution()
291    {
292        if (volumeMapper instanceof vtkFixedPointVolumeRayCastMapper)
293        {
294            final vtkFixedPointVolumeRayCastMapper mapper = (vtkFixedPointVolumeRayCastMapper) volumeMapper;
295
296            if (mapper.GetAutoAdjustSampleDistances() != 0)
297                return 0d;
298
299            return mapper.GetImageSampleDistance();
300        }
301        else if (volumeMapper instanceof vtkVolumeRayCastMapper)
302        {
303            final vtkVolumeRayCastMapper mapper = (vtkVolumeRayCastMapper) volumeMapper;
304
305            if (mapper.GetAutoAdjustSampleDistances() != 0)
306                return 0d;
307
308            return mapper.GetImageSampleDistance();
309        }
310        else if (volumeMapper instanceof vtkGPUVolumeRayCastMapper)
311        {
312            final vtkGPUVolumeRayCastMapper mapper = (vtkGPUVolumeRayCastMapper) volumeMapper;
313
314            if (mapper.GetAutoAdjustSampleDistances() != 0)
315                return 0d;
316
317            return mapper.GetImageSampleDistance();
318        }
319        else if (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper)
320        {
321            final vtkOpenGLGPUVolumeRayCastMapper mapper = (vtkOpenGLGPUVolumeRayCastMapper) volumeMapper;
322
323            if (mapper.GetAutoAdjustSampleDistances() != 0)
324                return 0d;
325
326            return mapper.GetImageSampleDistance();
327        }
328
329        return 0d;
330    }
331
332    /**
333     * Set sample resolution for the raycaster volume rendering.<br>
334     * <ul>
335     * <li>0 = automatic</li>
336     * <li>1 = finest (slow)</li>
337     * <li>10 = coarse (fast)</li>
338     * </ul>
339     */
340    public void setSampleResolution(double value)
341    {
342        if (volumeMapper instanceof vtkFixedPointVolumeRayCastMapper)
343        {
344            final vtkFixedPointVolumeRayCastMapper mapper = (vtkFixedPointVolumeRayCastMapper) volumeMapper;
345
346            if (value == 0d)
347                mapper.AutoAdjustSampleDistancesOn();
348            else
349            {
350                mapper.AutoAdjustSampleDistancesOff();
351                mapper.SetImageSampleDistance(value);
352            }
353        }
354        else if (volumeMapper instanceof vtkVolumeRayCastMapper)
355        {
356            final vtkVolumeRayCastMapper mapper = (vtkVolumeRayCastMapper) volumeMapper;
357
358            if (value == 0d)
359                mapper.AutoAdjustSampleDistancesOn();
360            else
361            {
362                mapper.AutoAdjustSampleDistancesOff();
363                mapper.SetImageSampleDistance(value);
364            }
365        }
366        else if (volumeMapper instanceof vtkGPUVolumeRayCastMapper)
367        {
368            final vtkGPUVolumeRayCastMapper mapper = (vtkGPUVolumeRayCastMapper) volumeMapper;
369
370            if (value == 0d)
371                mapper.AutoAdjustSampleDistancesOn();
372            else
373            {
374                mapper.AutoAdjustSampleDistancesOff();
375                mapper.SetImageSampleDistance(value);
376            }
377        }
378        else if (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper)
379        {
380            final vtkOpenGLGPUVolumeRayCastMapper mapper = (vtkOpenGLGPUVolumeRayCastMapper) volumeMapper;
381
382            if (value == 0d)
383                mapper.AutoAdjustSampleDistancesOn();
384            else
385            {
386                mapper.AutoAdjustSampleDistancesOff();
387                mapper.SetImageSampleDistance(value);
388            }
389        }
390    }
391
392    public boolean isPickable()
393    {
394        return (volume.GetPickable() != 0) ? true : false;
395    }
396
397    public void setPickable(boolean value)
398    {
399        volume.SetPickable(value ? 1 : 0);
400    }
401
402    /**
403     * Returns the XYZ scaling of the volume image
404     */
405    public double[] getScale()
406    {
407        return volume.GetScale();
408    }
409
410    /**
411     * Sets the XYZ scaling of the volume image
412     */
413    public void setScale(double x, double y, double z)
414    {
415        volume.SetScale(x, y, z);
416    }
417
418    /**
419     * Sets the XYZ scaling of the volume image
420     */
421    public void setScale(double[] xyz)
422    {
423        volume.SetScale(xyz);
424    }
425
426    /**
427     * Returns <code>true</code> if shading is enabled (global)
428     */
429    public boolean getShade()
430    {
431        return (volumeProperty.GetShade() == 1) ? true : false;
432    }
433
434    /**
435     * Returns <code>true</code> if shading is enabled for the specified component
436     */
437    // public boolean getShade(int index)
438    // {
439    // return (volumeProperty.GetShade(index) == 1) ? true : false;
440    // }
441
442    /**
443     * Enable / Disable the shading (global)
444     */
445    public void setShade(boolean value)
446    {
447        final int num = getChannelCount();
448        for (int ch = 0; ch < num; ch++)
449            volumeProperty.SetShade(ch, value ? 1 : 0);
450
451        volumeProperty.SetShade(value ? 1 : 0);
452    }
453
454    /**
455     * Enable / Disable the shading for the specified component
456     */
457    // public void setShade(int index, boolean value)
458    // {
459    // volumeProperty.SetShade(index, value ? 1 : 0);
460    // }
461
462    /**
463     * Returns the ambient lighting coefficient (global)
464     */
465    public double getAmbient()
466    {
467        return volumeProperty.GetAmbient();
468    }
469
470    /**
471     * Returns the ambient lighting coefficient for the specified component
472     */
473    // public double getAmbient(int index)
474    // {
475    // return volumeProperty.GetAmbient(index);
476    // }
477
478    /**
479     * Sets the ambient lighting coefficient (global)
480     */
481    public void setAmbient(double value)
482    {
483        final int num = getChannelCount();
484        for (int ch = 0; ch < num; ch++)
485            volumeProperty.SetAmbient(ch, value);
486
487        volumeProperty.SetAmbient(value);
488    }
489
490    /**
491     * Sets the ambient lighting coefficient for the specified component
492     */
493    // public void setAmbient(int index, double value)
494    // {
495    // volumeProperty.SetAmbient(index, value);
496    // }
497
498    /**
499     * Returns the diffuse lighting coefficient (global)
500     */
501    public double getDiffuse()
502    {
503        return volumeProperty.GetDiffuse();
504    }
505
506    /**
507     * Returns the diffuse lighting coefficient for the specified component
508     */
509    // public double getDiffuse(int index)
510    // {
511    // return volumeProperty.GetDiffuse(index);
512    // }
513
514    /**
515     * Sets the diffuse lighting coefficient (global)
516     */
517    public void setDiffuse(double value)
518    {
519        final int num = getChannelCount();
520        for (int ch = 0; ch < num; ch++)
521            volumeProperty.SetDiffuse(ch, value);
522
523        volumeProperty.SetDiffuse(value);
524    }
525
526    /**
527     * Sets the diffuse lighting coefficient for the specified component
528     */
529    // public void setDiffuse(int index, double value)
530    // {
531    // volumeProperty.SetDiffuse(index, value);
532    // }
533
534    /**
535     * Returns the specular lighting coefficient (global)
536     */
537    public double getSpecular()
538    {
539        return volumeProperty.GetSpecular();
540    }
541
542    /**
543     * Returns the specular lighting coefficient for the specified component
544     */
545    // public double getSpecular(int index)
546    // {
547    // return volumeProperty.GetSpecular(index);
548    // }
549
550    /**
551     * Sets the specular lighting coefficient (global)
552     */
553    public void setSpecular(double value)
554    {
555        final int num = getChannelCount();
556        for (int ch = 0; ch < num; ch++)
557            volumeProperty.SetSpecular(ch, value);
558
559        volumeProperty.SetSpecular(value);
560    }
561
562    /**
563     * Sets the specular lighting coefficient for the specified component
564     */
565    // public void setSpecular(int index, double value)
566    // {
567    // volumeProperty.SetSpecular(index, value);
568    // }
569
570    /**
571     * Returns the specular power (global)
572     */
573    public double getSpecularPower()
574    {
575        return volumeProperty.GetSpecularPower();
576    }
577
578    /**
579     * Returns the specular power for the specified component
580     */
581    // public double getSpecularPower(int index)
582    // {
583    // return volumeProperty.GetSpecularPower(index);
584    // }
585
586    /**
587     * Sets the specular power (global)
588     */
589    public void setSpecularPower(double value)
590    {
591        final int num = getChannelCount();
592        for (int ch = 0; ch < num; ch++)
593            volumeProperty.SetSpecularPower(ch, value);
594
595        volumeProperty.SetSpecularPower(value);
596    }
597
598    /**
599     * Sets the specular power for the specified component
600     */
601    // public void setSpecularPower(int index, double value)
602    // {
603    // volumeProperty.SetSpecularPower(index, value);
604    // }
605
606    /**
607     * Returns the interpolation method for rendering.<br>
608     * Possible values are:
609     * <ul>
610     * <li>VTK_NEAREST_INTERPOLATION</li>
611     * <li>VTK_LINEAR_INTERPOLATION</li>
612     * <li>VTK_CUBIC_INTERPOLATION</li>
613     * </ul>
614     */
615    public int getInterpolationMode()
616    {
617        return volumeProperty.GetInterpolationType();
618    }
619
620    /**
621     * Sets the interpolation method for rendering.<br>
622     * Possible values are:
623     * <ul>
624     * <li>VTK_NEAREST_INTERPOLATION</li>
625     * <li>VTK_LINEAR_INTERPOLATION</li>
626     * <li>VTK_CUBIC_INTERPOLATION</li>
627     * </ul>
628     */
629    public void setInterpolationMode(int value)
630    {
631        volumeProperty.SetInterpolationType(value);
632    }
633
634    /**
635     * Returns true if selected volume mapper is the GPU accelerated raycaster.
636     */
637    public boolean getGPURendering()
638    {
639        return (volumeMapper instanceof vtkOpenGLGPUVolumeRayCastMapper);
640    }
641
642    /**
643     * Enable GPU volume rendering.
644     * 
645     * @param value
646     *        if <code>true</code> then the GPU accelerated raycaster will be used otherwise the classical CPU
647     *        rayscaster is used.
648     */
649    public boolean setGPURendering(boolean value)
650    {
651        // volume mapper changed ?
652        if (getGPURendering() != value)
653        {
654            // save the parameters as they can be modified when mapper change
655            final VtkVolumeBlendType blendingMode = getBlendingMode();
656            final double sampleResolution = getSampleResolution();
657            final vtkVolumeMapper newMapper;
658
659            if (value)
660            {
661                // GPU raycaster
662                newMapper = new vtkOpenGLGPUVolumeRayCastMapper();
663            }
664            else
665            {
666                // CPU raycaster
667                newMapper = new vtkFixedPointVolumeRayCastMapper();
668                ((vtkFixedPointVolumeRayCastMapper) newMapper).IntermixIntersectingGeometryOn();
669            }
670
671            // setup volume connection
672            volume.SetMapper(newMapper);
673
674            // release previous mapper if any
675            if (volumeMapper != null)
676            {
677                volumeMapper.RemoveAllInputs();
678                volumeMapper.Delete();
679            }
680
681            // update volume mapper
682            volumeMapper = newMapper;
683            // and connect the image data
684            if (imageData != null)
685                newMapper.SetInputData(imageData);
686
687            // restore blending and sample resolution
688            setBlendingMode(blendingMode);
689            setSampleResolution(sampleResolution);
690
691            return true;
692        }
693
694        return false;
695    }
696
697    /**
698     * @deprecated Should always return true now.
699     */
700    @Deprecated
701    public static boolean isMapperSupported(vtkRenderer renderer)
702    {
703        return true;
704    }
705
706    /**
707     * Returns the blending method for rendering.
708     */
709    public VtkVolumeBlendType getBlendingMode()
710    {
711        return VtkVolumeBlendType.values()[volumeMapper.GetBlendMode()];
712    }
713
714    /**
715     * Sets the blending method for rendering.
716     */
717    public void setBlendingMode(VtkVolumeBlendType value)
718    {
719        volumeMapper.SetBlendMode(value.ordinal());
720    }
721
722    /**
723     * Get the current volume image data object.
724     * 
725     * @see VtkUtil#getImageData(Object, DataType, int, int, int, int)
726     */
727    public vtkImageData getVolumeData()
728    {
729        return imageData;
730    }
731
732    /**
733     * Set the volume image data.
734     * 
735     * @see VtkUtil#getImageData(Object, DataType, int, int, int, int)
736     */
737    public void setVolumeData(vtkImageData data)
738    {
739        if (imageData != data)
740        {
741            // set connection
742            volumeMapper.SetInputData(data);
743
744            // release previous volume data memory
745            if (imageData != null)
746            {
747                imageData.GetPointData().GetScalars().Delete();
748                imageData.GetPointData().Delete();
749                imageData.Delete();
750            }
751
752            // set to new image data
753            imageData = data;
754        }
755
756        updateChannelProperties();
757    }
758
759    /**
760     * Refresh channel properties
761     */
762    protected void updateChannelProperties()
763    {
764        setShade(getShade());
765        setAmbient(getAmbient());
766        setDiffuse(getDiffuse());
767        setSpecular(getSpecular());
768        setSpecularPower(getSpecularPower());
769    }
770
771    /**
772     * Sets the visible state of the image volume object
773     */
774    public void setVisible(boolean value)
775    {
776        volume.SetVisibility(value ? 1 : 0);
777    }
778
779    /**
780     * @return visible state of the image volume object
781     */
782    public boolean isVisible()
783    {
784        return (volume.GetVisibility() != 0) ? true : false;
785    }
786}