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}