001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.vtk; 020 021import java.awt.Color; 022import java.awt.Rectangle; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.List; 026 027import icy.canvas.Layer; 028import icy.common.exception.TooLargeArrayException; 029import icy.image.colormap.IcyColorMap; 030import icy.image.lut.LUT.LUTChannel; 031import icy.math.Scaler; 032import icy.painter.Overlay; 033import icy.painter.VtkPainter; 034import icy.roi.BooleanMask2D; 035import icy.roi.BooleanMask3D; 036import icy.roi.ROI; 037import icy.sequence.Sequence; 038import icy.type.DataType; 039import icy.type.collection.array.Array2DUtil; 040import icy.type.collection.array.ArrayUtil; 041import icy.type.rectangle.Rectangle3D; 042import icy.type.rectangle.Rectangle5D; 043import plugins.kernel.canvas.VtkCanvas; 044import plugins.kernel.roi.roi2d.ROI2DArea; 045import plugins.kernel.roi.roi3d.ROI3DArea; 046import vtk.vtkAbstractTransform; 047import vtk.vtkActor; 048import vtk.vtkActor2D; 049import vtk.vtkActor2DCollection; 050import vtk.vtkActorCollection; 051import vtk.vtkCellArray; 052import vtk.vtkCollection; 053import vtk.vtkColorTransferFunction; 054import vtk.vtkContourFilter; 055import vtk.vtkDataArray; 056import vtk.vtkDataSet; 057import vtk.vtkDataSetSurfaceFilter; 058import vtk.vtkDoubleArray; 059import vtk.vtkFloatArray; 060import vtk.vtkIdTypeArray; 061import vtk.vtkImageConstantPad; 062import vtk.vtkImageData; 063import vtk.vtkImageStencil; 064import vtk.vtkIntArray; 065import vtk.vtkLongArray; 066import vtk.vtkOBJReader; 067import vtk.vtkObject; 068import vtk.vtkObjectBase; 069import vtk.vtkPiecewiseFunction; 070import vtk.vtkPoints; 071import vtk.vtkPolyData; 072import vtk.vtkPolyDataToImageStencil; 073import vtk.vtkProp; 074import vtk.vtkPropCollection; 075import vtk.vtkRenderer; 076import vtk.vtkShortArray; 077import vtk.vtkTransform; 078import vtk.vtkTransformPolyDataFilter; 079import vtk.vtkUnsignedCharArray; 080import vtk.vtkUnsignedIntArray; 081import vtk.vtkUnsignedLongArray; 082import vtk.vtkUnsignedShortArray; 083import vtk.vtkVertexGlyphFilter; 084 085/** 086 * @author Stephane 087 */ 088public class VtkUtil 089{ 090 // VTK type 091 public final static int VTK_VOID = 0; 092 public final static int VTK_BIT = 1; 093 public final static int VTK_CHAR = 2; 094 public final static int VTK_SIGNED_CHAR = 15; 095 public final static int VTK_UNSIGNED_CHAR = 3; 096 public final static int VTK_SHORT = 4; 097 public final static int VTK_UNSIGNED_SHORT = 5; 098 public final static int VTK_INT = 6; 099 public final static int VTK_UNSIGNED_INT = 7; 100 public final static int VTK_LONG = 8; 101 public final static int VTK_UNSIGNED_LONG = 9; 102 public final static int VTK_FLOAT = 10; 103 public final static int VTK_DOUBLE = 11; 104 public final static int VTK_ID = 12; 105 106 // VTK interpolation 107 public final static int VTK_NEAREST_INTERPOLATION = 0; 108 public final static int VTK_LINEAR_INTERPOLATION = 1; 109 public final static int VTK_CUBIC_INTERPOLATION = 2; 110 111 // VTK bounding box 112 public final static int VTK_FLY_OUTER_EDGES = 0; 113 public final static int VTK_FLY_CLOSEST_TRIAD = 1; 114 public final static int VTK_FLY_FURTHEST_TRIAD = 2; 115 public final static int VTK_FLY_STATIC_TRIAD = 3; 116 public final static int VTK_FLY_STATIC_EDGES = 4; 117 118 public final static int VTK_TICKS_INSIDE = 0; 119 public final static int VTK_TICKS_OUTSIDE = 1; 120 public final static int VTK_TICKS_BOTH = 2; 121 122 public final static int VTK_GRID_LINES_ALL = 0; 123 public final static int VTK_GRID_LINES_CLOSEST = 1; 124 public final static int VTK_GRID_LINES_FURTHEST = 2; 125 126 /** 127 * Returns the VTK type corresponding to the specified DataType 128 */ 129 public static int getVtkType(DataType type) 130 { 131 switch (type) 132 { 133 default: 134 case UBYTE: 135 case BYTE: 136 return VTK_UNSIGNED_CHAR; 137 138 // FIXME: signed char not supported by VTK java wrapper ?? 139 // case BYTE: 140 // return VTK_CHAR; 141 // return VTK_SIGNED_CHAR; 142 143 case USHORT: 144 return VTK_UNSIGNED_SHORT; 145 case SHORT: 146 return VTK_SHORT; 147 case UINT: 148 return VTK_UNSIGNED_INT; 149 case INT: 150 return VTK_INT; 151 case ULONG: 152 return VTK_UNSIGNED_LONG; 153 case LONG: 154 return VTK_LONG; 155 case FLOAT: 156 return VTK_FLOAT; 157 case DOUBLE: 158 return VTK_DOUBLE; 159 } 160 } 161 162 public static vtkDataArray getVtkArray(Object array, boolean signed) 163 { 164 switch (ArrayUtil.getDataType(array)) 165 { 166 case BYTE: 167 return getUCharArray((byte[]) array); 168 case SHORT: 169 if (signed) 170 return getUShortArray((short[]) array); 171 return getShortArray((short[]) array); 172 case INT: 173 if (signed) 174 return getUIntArray((int[]) array); 175 return getIntArray((int[]) array); 176 case LONG: 177 if (signed) 178 return getULongArray((long[]) array); 179 return getLongArray((long[]) array); 180 case FLOAT: 181 return getFloatArray((float[]) array); 182 case DOUBLE: 183 return getDoubleArray((double[]) array); 184 default: 185 return null; 186 } 187 } 188 189 public static vtkUnsignedCharArray getUCharArray(byte[] array) 190 { 191 final vtkUnsignedCharArray result = new vtkUnsignedCharArray(); 192 193 result.SetJavaArray(array); 194 195 return result; 196 } 197 198 public static vtkUnsignedShortArray getUShortArray(short[] array) 199 { 200 final vtkUnsignedShortArray result = new vtkUnsignedShortArray(); 201 202 result.SetJavaArray(array); 203 204 return result; 205 } 206 207 public static vtkUnsignedIntArray getUIntArray(int[] array) 208 { 209 final vtkUnsignedIntArray result = new vtkUnsignedIntArray(); 210 211 result.SetJavaArray(array); 212 213 return result; 214 } 215 216 public static vtkUnsignedLongArray getULongArray(long[] array) 217 { 218 final vtkUnsignedLongArray result = new vtkUnsignedLongArray(); 219 220 result.SetJavaArray(array); 221 222 return result; 223 } 224 225 public static vtkShortArray getShortArray(short[] array) 226 { 227 final vtkShortArray result = new vtkShortArray(); 228 229 result.SetJavaArray(array); 230 231 return result; 232 } 233 234 public static vtkIntArray getIntArray(int[] array) 235 { 236 final vtkIntArray result = new vtkIntArray(); 237 238 result.SetJavaArray(array); 239 240 return result; 241 } 242 243 public static vtkLongArray getLongArray(long[] array) 244 { 245 final vtkLongArray result = new vtkLongArray(); 246 247 result.SetJavaArray(array); 248 249 return result; 250 } 251 252 public static vtkFloatArray getFloatArray(float[] array) 253 { 254 final vtkFloatArray result = new vtkFloatArray(); 255 256 result.SetJavaArray(array); 257 258 return result; 259 } 260 261 public static vtkDoubleArray getDoubleArray(double[] array) 262 { 263 final vtkDoubleArray result = new vtkDoubleArray(); 264 265 result.SetJavaArray(array); 266 267 return result; 268 } 269 270 public static vtkIdTypeArray getIdTypeArray(int[] array) 271 { 272 final vtkIdTypeArray result = new vtkIdTypeArray(); 273 final vtkIntArray iarray = getIntArray(array); 274 275 result.DeepCopy(iarray); 276 iarray.Delete(); 277 278 return result; 279 } 280 281 /** 282 * Returns a native java array from the specified {@link vtkDataArray}. 283 */ 284 public static Object getJavaArray(vtkDataArray dataArray) 285 { 286 switch (dataArray.GetDataType()) 287 { 288 case VTK_UNSIGNED_CHAR: 289 return ((vtkUnsignedCharArray) dataArray).GetJavaArray(); 290 case VTK_SHORT: 291 return ((vtkShortArray) dataArray).GetJavaArray(); 292 case VTK_UNSIGNED_SHORT: 293 return ((vtkUnsignedShortArray) dataArray).GetJavaArray(); 294 case VTK_INT: 295 return ((vtkIntArray) dataArray).GetJavaArray(); 296 case VTK_UNSIGNED_INT: 297 return ((vtkUnsignedIntArray) dataArray).GetJavaArray(); 298 case VTK_LONG: 299 return ((vtkLongArray) dataArray).GetJavaArray(); 300 case VTK_UNSIGNED_LONG: 301 return ((vtkUnsignedLongArray) dataArray).GetJavaArray(); 302 case VTK_FLOAT: 303 return ((vtkFloatArray) dataArray).GetJavaArray(); 304 case VTK_DOUBLE: 305 return ((vtkDoubleArray) dataArray).GetJavaArray(); 306 default: 307 return null; 308 } 309 } 310 311 public static int[] getJavaArray(vtkIdTypeArray array) 312 { 313 final vtkIntArray iarray = new vtkIntArray(); 314 315 iarray.DeepCopy(array); 316 317 final int[] result = iarray.GetJavaArray(); 318 iarray.Delete(); 319 320 return result; 321 } 322 323 /** 324 * Transforms a vtkCollection to an array 325 */ 326 public static vtkObject[] vtkCollectionToArray(vtkCollection collection) 327 { 328 final vtkObject[] result = new vtkObject[collection.GetNumberOfItems()]; 329 330 collection.InitTraversal(); 331 for (int i = 0; i < result.length; i++) 332 result[i] = collection.GetNextItemAsObject(); 333 334 return result; 335 } 336 337 /** 338 * Get vtkPoints from double[] 339 */ 340 public static vtkPoints getPoints(double[] points) 341 { 342 final vtkPoints result = new vtkPoints(); 343 final vtkDoubleArray array = getDoubleArray(points); 344 345 array.SetNumberOfComponents(3); 346 result.SetData(array); 347 348 return result; 349 } 350 351 /** 352 * Get vtkPoints from double[][3] 353 */ 354 public static vtkPoints getPoints(double[][] points) 355 { 356 return getPoints(Array2DUtil.toDoubleArray1D(points)); 357 } 358 359 /** 360 * Get vtkPoints from float[] 361 */ 362 public static vtkPoints getPoints(float[] points) 363 { 364 final vtkPoints result = new vtkPoints(); 365 final vtkFloatArray array = getFloatArray(points); 366 367 array.SetNumberOfComponents(3); 368 result.SetData(array); 369 370 return result; 371 } 372 373 /** 374 * Get vtkPoints from float[][3] 375 */ 376 public static vtkPoints getPoints(float[][] points) 377 { 378 return getPoints(Array2DUtil.toFloatArray1D(points)); 379 } 380 381 /** 382 * Get vtkPoints from int[] 383 */ 384 public static vtkPoints getPoints(int[] points) 385 { 386 final vtkPoints result = new vtkPoints(); 387 final vtkIntArray array = getIntArray(points); 388 389 array.SetNumberOfComponents(3); 390 result.SetData(array); 391 392 return result; 393 } 394 395 /** 396 * Get vtkPoints from int[][3] 397 */ 398 public static vtkPoints getPoints(int[][] points) 399 { 400 return getPoints(Array2DUtil.toIntArray1D(points)); 401 } 402 403 /** 404 * Get vtkCellArray from a 1D prepared cells array ( {n, i1, i2, ..., n, i1, i2,...} ) 405 */ 406 public static vtkCellArray getCells(int numCell, int[] cells) 407 { 408 final vtkCellArray result = new vtkCellArray(); 409 410 result.SetCells(numCell, getIdTypeArray(cells)); 411 412 return result; 413 } 414 415 /** 416 * Returns a simple cell {@link vtkPolyData} from {@link vtkPoints} 417 */ 418 public static vtkPolyData getPolyDataFromPoints(vtkPoints points) 419 { 420 final vtkPolyData tmpPolyData = new vtkPolyData(); 421 final vtkVertexGlyphFilter vertexFilter = new vtkVertexGlyphFilter(); 422 423 tmpPolyData.SetPoints(points); 424 vertexFilter.SetInputData(tmpPolyData); 425 vertexFilter.Update(); 426 427 final vtkPolyData result = vertexFilter.GetOutput(); 428 429 vertexFilter.Delete(); 430 431 return result; 432 } 433 434 /** 435 * Returns a {@link vtkPolyData} from {@link vtkDataSet} 436 */ 437 public static vtkPolyData getPolyDataFromDataSet(vtkDataSet dataSet) 438 { 439 // transform grid to polydata first 440 final vtkDataSetSurfaceFilter surfaceFilter = new vtkDataSetSurfaceFilter(); 441 surfaceFilter.SetInputData(dataSet); 442 surfaceFilter.Update(); 443 444 final vtkPolyData result = surfaceFilter.GetOutput(); 445 446 surfaceFilter.Delete(); 447 448 return result; 449 } 450 451 /** 452 * Returns the <i>vtkProp</i> from the specified <i>Layer</i> object.<br> 453 * Returns a 0 sized array if the specified layer is <code>null</code> or does not contains any vtkProp. 454 */ 455 public static vtkProp[] getLayerProps(Layer layer) 456 { 457 if (layer != null) 458 { 459 // add painter actor from the vtk render 460 final Overlay overlay = layer.getOverlay(); 461 462 if (overlay instanceof VtkPainter) 463 return ((VtkPainter) overlay).getProps(); 464 } 465 466 return new vtkProp[0]; 467 } 468 469 /** 470 * Returns all <i>vtkProp</i> from the specified list of <i>Layer</i> object.<br> 471 * Returns a 0 sized array if specified layers does not contains any vtkProp. 472 */ 473 public static vtkProp[] getLayersProps(List<Layer> layers) 474 { 475 final List<vtkProp[]> layersProps = new ArrayList<vtkProp[]>(); 476 int totalSize = 0; 477 478 for (Layer layer : layers) 479 { 480 if (layer != null) 481 { 482 // add painter actor from the vtk render 483 final Overlay overlay = layer.getOverlay(); 484 485 if (overlay instanceof VtkPainter) 486 { 487 final vtkProp[] props = ((VtkPainter) overlay).getProps(); 488 489 if (props.length > 0) 490 { 491 layersProps.add(props); 492 totalSize += props.length; 493 } 494 } 495 } 496 } 497 498 final vtkProp[] result = new vtkProp[totalSize]; 499 int ind = 0; 500 501 for (vtkProp[] props : layersProps) 502 { 503 final int size = props.length; 504 505 System.arraycopy(props, 0, result, ind, size); 506 ind += size; 507 } 508 509 return result; 510 } 511 512 /** 513 * Return all actor / view prop from the specified renderer 514 */ 515 public static vtkProp[] getProps(vtkRenderer renderer) 516 { 517 if (renderer == null) 518 return new vtkProp[0]; 519 520 final vtkPropCollection collection = renderer.GetViewProps(); 521 final vtkProp[] result = new vtkProp[collection.GetNumberOfItems()]; 522 523 collection.InitTraversal(); 524 for (int i = 0; i < result.length; i++) 525 result[i] = collection.GetNextProp(); 526 527 return result; 528 } 529 530 /** 531 * Return true if the renderer contains the specified actor / view prop 532 */ 533 public static boolean hasProp(vtkRenderer renderer, vtkProp actor) 534 { 535 if ((renderer == null) || (actor == null)) 536 return false; 537 538 return renderer.HasViewProp(actor) != 0; 539 } 540 541 /** 542 * @deprecated Use {@link #hasProp(vtkRenderer, vtkProp)} instead. 543 */ 544 @Deprecated 545 public static boolean findProp(vtkRenderer renderer, vtkProp actor) 546 { 547 return hasProp(renderer, actor); 548 } 549 550 /** 551 * @deprecated Use {@link #hasProp(vtkRenderer, vtkProp)} instead. 552 */ 553 @Deprecated 554 public static boolean findActor(vtkRenderer renderer, vtkActor actor) 555 { 556 if ((renderer == null) || (actor == null)) 557 return false; 558 559 final vtkActorCollection actors = renderer.GetActors(); 560 561 actors.InitTraversal(); 562 for (int i = 0; i < actors.GetNumberOfItems(); i++) 563 { 564 final vtkActor curActor = actors.GetNextActor(); 565 566 // already present --> exit 567 if (curActor == actor) 568 return true; 569 570 // // search in sub actor 571 // if (findActor(curActor, actor)) 572 // return true; 573 } 574 575 return false; 576 } 577 578 /** 579 * @deprecated Use {@link #hasProp(vtkRenderer, vtkProp)} instead. 580 */ 581 @Deprecated 582 public static boolean findActor2D(vtkRenderer renderer, vtkActor2D actor) 583 { 584 if ((renderer == null) || (actor == null)) 585 return false; 586 587 final vtkActor2DCollection actors = renderer.GetActors2D(); 588 589 actors.InitTraversal(); 590 for (int i = 0; i < actors.GetNumberOfItems(); i++) 591 { 592 final vtkActor2D curActor = actors.GetNextActor2D(); 593 594 // already present --> exit 595 if (curActor == actor) 596 return true; 597 598 // // search in sub actor 599 // if (findActor2D(curActor, actor)) 600 // return true; 601 } 602 603 return false; 604 } 605 606 /** 607 * Add an actor (vtkProp) to the specified renderer.<br> 608 * If the actor is already existing in the renderer then no operation is done. 609 */ 610 public static void addProp(vtkRenderer renderer, vtkProp prop) 611 { 612 if ((renderer == null) || (prop == null)) 613 return; 614 615 // actor not yet present in renderer ? --> add it 616 if (renderer.HasViewProp(prop) == 0) 617 renderer.AddViewProp(prop); 618 } 619 620 /** 621 * @deprecated Use {@link #addProp(vtkRenderer, vtkProp)} instead. 622 */ 623 @Deprecated 624 public static void addActor(vtkRenderer renderer, vtkActor actor) 625 { 626 if ((renderer == null) || (actor == null)) 627 return; 628 629 // actor not yet present in renderer ? --> add it 630 if (!VtkUtil.findActor(renderer, actor)) 631 renderer.AddActor(actor); 632 } 633 634 /** 635 * @deprecated Use {@link #addProp(vtkRenderer, vtkProp)} instead. 636 */ 637 @Deprecated 638 public static void addActor2D(vtkRenderer renderer, vtkActor2D actor) 639 { 640 if ((renderer == null) || (actor == null)) 641 return; 642 643 // actor not yet present in renderer ? --> add it 644 if (!VtkUtil.findActor2D(renderer, actor)) 645 renderer.AddActor2D(actor); 646 } 647 648 /** 649 * Add an array of actor (vtkProp) to the specified renderer.<br> 650 * If an actor is already existing in the renderer then nothing is done for this actor. 651 */ 652 public static void addProps(vtkRenderer renderer, vtkProp[] props) 653 { 654 if ((renderer == null) || (props == null)) 655 return; 656 657 for (vtkProp prop : props) 658 { 659 // actor not yet present in renderer ? --> add it 660 if (renderer.HasViewProp(prop) == 0) 661 renderer.AddViewProp(prop); 662 } 663 } 664 665 /** 666 * Remove an actor from the specified renderer. 667 */ 668 public static void removeProp(vtkRenderer renderer, vtkProp actor) 669 { 670 renderer.RemoveViewProp(actor); 671 } 672 673 /** 674 * Return a 1D cells array from a 2D indexes array 675 */ 676 public static int[] prepareCells(int[][] indexes) 677 { 678 final int len = indexes.length; 679 680 int total_len = 0; 681 for (int i = 0; i < len; i++) 682 total_len += indexes[i].length + 1; 683 684 final int[] result = new int[total_len]; 685 686 int offset = 0; 687 for (int i = 0; i < len; i++) 688 { 689 final int[] s_cells = indexes[i]; 690 final int s_len = s_cells.length; 691 692 result[offset++] = s_len; 693 for (int j = 0; j < s_len; j++) 694 result[offset++] = s_cells[j]; 695 } 696 697 return result; 698 } 699 700 /** 701 * Return a 1D cells array from a 1D indexes array and num vertex per cell (polygon) 702 */ 703 public static int[] prepareCells(int numVertexPerCell, int[] indexes) 704 { 705 final int num_cells = indexes.length / numVertexPerCell; 706 final int[] result = new int[num_cells * (numVertexPerCell + 1)]; 707 708 int off_dst = 0; 709 int off_src = 0; 710 for (int i = 0; i < num_cells; i++) 711 { 712 result[off_dst++] = numVertexPerCell; 713 714 for (int j = 0; j < numVertexPerCell; j++) 715 result[off_dst++] = indexes[off_src + j]; 716 717 off_src += numVertexPerCell; 718 } 719 720 return result; 721 } 722 723 /** 724 * Returns a {@link BooleanMask3D} from a binary (0/1 values) {@link vtkImageData}. 725 */ 726 public static BooleanMask3D getBooleanMaskFromBinaryImage(vtkImageData image, boolean optimizeBounds) 727 { 728 final vtkDataArray data = image.GetPointData().GetScalars(); 729 final double[] origin = image.GetOrigin(); 730 final int[] dim = image.GetDimensions(); 731 final int sizeX = dim[0]; 732 final int sizeY = dim[1]; 733 final int sizeZ = dim[2]; 734 final int sizeXY = sizeX * sizeY; 735 final Rectangle bounds2D = new Rectangle((int) origin[0], (int) origin[1], sizeX, sizeY); 736 final BooleanMask2D[] masks = new BooleanMask2D[sizeZ]; 737 738 // more than 200M ? use simple iterator (slower but consume less memory) 739 if ((sizeXY * sizeZ) > (200 * 1024 * 1024)) 740 { 741 int off = 0; 742 for (int z = 0; z < sizeZ; z++) 743 { 744 final boolean[] mask = new boolean[sizeXY]; 745 746 for (int xy = 0; xy < sizeXY; xy++) 747 mask[xy] = (data.GetTuple1(off++) != 0d); 748 749 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 750 } 751 } 752 else 753 { 754 final Object javaArray = getJavaArray(data); 755 int off = 0; 756 757 switch (ArrayUtil.getDataType(javaArray)) 758 { 759 case BYTE: 760 final byte[] javaByteArray = (byte[]) javaArray; 761 762 for (int z = 0; z < sizeZ; z++) 763 { 764 final boolean[] mask = new boolean[sizeXY]; 765 766 for (int xy = 0; xy < mask.length; xy++) 767 mask[xy] = (javaByteArray[off++] != 0); 768 769 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 770 } 771 break; 772 773 case SHORT: 774 final short[] javaShortArray = (short[]) javaArray; 775 776 for (int z = 0; z < sizeZ; z++) 777 { 778 final boolean[] mask = new boolean[sizeXY]; 779 780 for (int xy = 0; xy < mask.length; xy++) 781 mask[xy] = (javaShortArray[off++] != 0); 782 783 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 784 } 785 break; 786 787 case INT: 788 final int[] javaIntArray = (int[]) javaArray; 789 790 for (int z = 0; z < sizeZ; z++) 791 { 792 final boolean[] mask = new boolean[sizeXY]; 793 794 for (int xy = 0; xy < mask.length; xy++) 795 mask[xy] = (javaIntArray[off++] != 0); 796 797 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 798 } 799 break; 800 801 case LONG: 802 final long[] javaLongArray = (long[]) javaArray; 803 804 for (int z = 0; z < sizeZ; z++) 805 { 806 final boolean[] mask = new boolean[sizeXY]; 807 808 for (int xy = 0; xy < mask.length; xy++) 809 mask[xy] = (javaLongArray[off++] != 0L); 810 811 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 812 } 813 break; 814 815 case FLOAT: 816 final float[] javaFloatArray = (float[]) javaArray; 817 818 for (int z = 0; z < sizeZ; z++) 819 { 820 final boolean[] mask = new boolean[sizeXY]; 821 822 for (int xy = 0; xy < mask.length; xy++) 823 mask[xy] = (javaFloatArray[off++] != 0f); 824 825 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 826 } 827 break; 828 829 case DOUBLE: 830 final double[] javaDoubleArray = (double[]) javaArray; 831 832 for (int z = 0; z < sizeZ; z++) 833 { 834 final boolean[] mask = new boolean[sizeXY]; 835 836 for (int xy = 0; xy < mask.length; xy++) 837 mask[xy] = (javaDoubleArray[off++] != 0d); 838 839 masks[z] = new BooleanMask2D(new Rectangle(bounds2D), mask); 840 } 841 break; 842 843 default: 844 // nothing to do here 845 break; 846 } 847 } 848 849 final BooleanMask3D result = new BooleanMask3D( 850 new Rectangle3D.Integer(bounds2D.x, bounds2D.y, (int) origin[2], sizeX, sizeY, sizeZ), masks); 851 852 if (optimizeBounds) 853 result.optimizeBounds(); 854 855 return result; 856 } 857 858 /** 859 * @deprecated Uses {@link #getBooleanMaskFromBinaryImage(vtkImageData)} then {@link ROI3DArea#ROI3DArea(BooleanMask3D)} instead. 860 */ 861 public static ROI getROIFromBinaryImage(vtkImageData image, boolean force3DROI) 862 { 863 final BooleanMask3D mask = getBooleanMaskFromBinaryImage(image, true); 864 865 if ((mask.bounds.getSizeZ() > 1) || force3DROI) 866 return new ROI3DArea(mask); 867 else 868 return new ROI2DArea(mask.getMask2D(mask.bounds.z)); 869 } 870 871 /** 872 * Build and return volume image data from given Sequence object. 873 * 874 * @param sequence 875 * the sequence object we want to get volume image data 876 * @param posT 877 * frame index 878 * @param posC 879 * channel index (-1 for all channel) 880 */ 881 public static vtkImageData getImageData(Sequence sequence, int posT, int posC) 882 throws TooLargeArrayException, OutOfMemoryError 883 { 884 if ((sequence == null) || sequence.isEmpty()) 885 return null; 886 887 final Object data; 888 final vtkImageData result; 889 890 if (posC == -1) 891 { 892 data = sequence.getDataCopyCXYZ(posT); 893 result = getImageData(data, sequence.getDataType_(), sequence.getSizeX(), sequence.getSizeY(), 894 sequence.getSizeZ(), sequence.getSizeC()); 895 } 896 else 897 { 898 data = sequence.getDataCopyXYZ(posT, posC); 899 result = getImageData(data, sequence.getDataType_(), sequence.getSizeX(), sequence.getSizeY(), 900 sequence.getSizeZ(), 1); 901 } 902 903 return result; 904 } 905 906 /** 907 * Creates and returns a {@link vtkImageData} object from the specified 1D array data. 908 */ 909 public static vtkImageData getImageData(Object data, DataType dataType, int sizeX, int sizeY, int sizeZ, int sizeC) 910 { 911 final vtkImageData result; 912 final vtkDataArray array; 913 914 // create a new image data structure 915 result = new vtkImageData(); 916 result.SetDimensions(sizeX, sizeY, sizeZ); 917 result.SetExtent(0, sizeX - 1, 0, sizeY - 1, 0, sizeZ - 1); 918 // pre-allocate data 919 result.AllocateScalars(getVtkType(dataType), sizeC); 920 // get array structure 921 array = result.GetPointData().GetScalars(); 922 923 switch (dataType) 924 { 925 case UBYTE: 926 case BYTE: 927 ((vtkUnsignedCharArray) array).SetJavaArray((byte[]) data); 928 break; 929 case USHORT: 930 ((vtkUnsignedShortArray) array).SetJavaArray((short[]) data); 931 break; 932 case SHORT: 933 ((vtkShortArray) array).SetJavaArray((short[]) data); 934 break; 935 case UINT: 936 ((vtkUnsignedIntArray) array).SetJavaArray((int[]) data); 937 break; 938 case INT: 939 ((vtkIntArray) array).SetJavaArray((int[]) data); 940 break; 941 case FLOAT: 942 ((vtkFloatArray) array).SetJavaArray((float[]) data); 943 break; 944 case DOUBLE: 945 ((vtkDoubleArray) array).SetJavaArray((double[]) data); 946 break; 947 default: 948 break; 949 } 950 951 return result; 952 } 953 954 /** 955 * Create a 3D surface in VTK polygon format from the input VTK image data. 956 * 957 * @param imageData 958 * the input image to construct surface from 959 * @param threshold 960 * the threshold intensity value used to build the surface 961 */ 962 public static vtkPolyData getSurfaceFromImage(vtkImageData imageData, double threshold) 963 { 964 // TODO: try vtkImageDataGeometryFilter 965 966 final int[] extent = imageData.GetExtent(); 967 extent[0]--; // min X 968 extent[1]++; // max X 969 extent[2]--; // min Y 970 extent[3]++; // max Y 971 extent[4]--; // min Z 972 extent[5]++; // max Z 973 974 // pad on all sides to guarantee closed meshes 975 final vtkImageConstantPad pad = new vtkImageConstantPad(); 976 977 pad.SetOutputWholeExtent(extent); 978 pad.SetInputData(imageData); 979 pad.Update(); 980 981 final vtkImageData out = pad.GetOutput(); 982 out.SetOrigin(imageData.GetOrigin()); 983 // do not delete input image 984 pad.Delete(); 985 986 final vtkContourFilter contourFilter = new vtkContourFilter(); 987 contourFilter.SetInputData(out); 988 contourFilter.SetValue(0, threshold); 989 contourFilter.Update(); 990 991 final vtkPolyData result = contourFilter.GetOutput(); 992 contourFilter.GetInput().Delete(); 993 contourFilter.Delete(); 994 995 return result; 996 } 997 998 /** 999 * Creates and returns a 3D binary (0/1 values) {@link vtkImageData} object corresponding to the ROI 3D boolean mask 1000 * (C dimension is not considered) at specified T position. 1001 * 1002 * @param roi 1003 * the roi we want to retrieve the vtkImageData mask 1004 * @param sz 1005 * the Z size to use for ROI with infinite Z dimension (if ROI has a finite Z dimension then ROI Z size is 1006 * used). 1007 * @param t 1008 * the T position we want to retrieve the 3D mask data 1009 */ 1010 public static vtkImageData getBinaryImageData(ROI roi, int sz, int t) throws IllegalArgumentException 1011 { 1012 final vtkImageData result; 1013 1014 final Rectangle5D bounds5d = roi.getBounds5D(); 1015 final int sizeX; 1016 final int sizeY; 1017 final int sizeZ; 1018 final int x; 1019 final int y; 1020 final int z; 1021 final int c; 1022 1023 x = (int) bounds5d.getX(); 1024 y = (int) bounds5d.getY(); 1025 sizeX = (int) (bounds5d.getMaxX() - x); 1026 sizeY = (int) (bounds5d.getMaxY() - y); 1027 if (bounds5d.isInfiniteZ()) 1028 { 1029 z = 0; 1030 sizeZ = sz; 1031 } 1032 else 1033 { 1034 z = (int) bounds5d.getZ(); 1035 sizeZ = (int) (bounds5d.getMaxZ() - z); 1036 } 1037 if (bounds5d.isInfiniteC()) 1038 c = 0; 1039 else 1040 c = (int) bounds5d.getC(); 1041 1042 long totalSize = sizeX; 1043 totalSize *= sizeY; 1044 totalSize *= sizeZ; 1045 1046 if (totalSize > Integer.MAX_VALUE) 1047 throw new IllegalArgumentException( 1048 "VtkUtil.getBinaryImageData(ROI, ..): Input ROI is too large, can't allocate array (size > 2^31)"); 1049 1050 // build java array 1051 final int sizeXY = sizeX * sizeY; 1052 final byte[] array = new byte[(int) totalSize]; 1053 int offset = 0; 1054 1055 if (bounds5d.isInfiniteZ()) 1056 { 1057 final boolean[] mask = roi.getBooleanMask2D(x, y, sizeX, sizeY, 0, t, c, true); 1058 1059 for (int curZ = z; curZ < (z + sizeZ); curZ++) 1060 { 1061 for (int i = 0; i < sizeXY; i++) 1062 array[offset++] = mask[i] ? (byte) 1 : (byte) 0; 1063 } 1064 } 1065 else 1066 { 1067 for (int curZ = z; curZ < (z + sizeZ); curZ++) 1068 { 1069 final boolean[] mask = roi.getBooleanMask2D(x, y, sizeX, sizeY, curZ, t, c, true); 1070 1071 for (int i = 0; i < sizeXY; i++) 1072 array[offset++] = mask[i] ? (byte) 1 : (byte) 0; 1073 } 1074 } 1075 1076 // create a new image data structure 1077 result = new vtkImageData(); 1078 result.SetDimensions(sizeX, sizeY, sizeZ); 1079 result.SetExtent(0, sizeX - 1, 0, sizeY - 1, 0, sizeZ - 1); 1080 // pre-allocate data 1081 result.AllocateScalars(VTK_UNSIGNED_CHAR, 1); 1082 // set data 1083 ((vtkUnsignedCharArray) result.GetPointData().GetScalars()).SetJavaArray(array); 1084 1085 return result; 1086 } 1087 1088 /** 1089 * Transforms a {@link vtkPolyData} object to binary (0/1 values) {@link vtkImageData} 1090 * 1091 * @param space 1092 * spacing between each image point 1093 */ 1094 public static vtkImageData getBinaryImageData(vtkPolyData polyData, double space[]) 1095 { 1096 final vtkImageData whiteImage = new vtkImageData(); 1097 1098 // get poly data bounds 1099 final double[] bounds = polyData.GetBounds(); 1100 // define spacing 1101 final double[] spacing = (space == null) ? new double[] {1d, 1d, 1d} : space; 1102 // define dimensions & origin 1103 final int[] dim = new int[3]; 1104 final double origin[] = new double[3]; 1105 1106 // compute dimensions 1107 for (int i = 0; i < dim.length; i++) 1108 dim[i] = (int) Math.ceil((bounds[(i * 2) + 1] - bounds[(i * 2) + 0]) / spacing[i]); 1109 1110 long size = dim[0]; 1111 size *= dim[1]; 1112 size *= dim[2]; 1113 1114 // negative value --> empty poly data 1115 if (size < 0) 1116 throw new IllegalArgumentException( 1117 "VtkUtil.getBinaryImageData(vtkPolyData, ..): Negative object size, cannot do the conversion !"); 1118 // can't allocate more than Integer.MAX_VALUE 1119 if (size > Integer.MAX_VALUE) 1120 throw new IllegalArgumentException( 1121 "VtkUtil.getBinaryImageData(vtkPolyData, ..): Object size is too large, can't allocate array (size > 2^31) !"); 1122 1123 // compute origin 1124 origin[0] = bounds[0]; 1125 origin[1] = bounds[2]; 1126 origin[2] = bounds[4]; 1127 1128 whiteImage.SetSpacing(spacing); 1129 whiteImage.SetDimensions(dim); 1130 whiteImage.SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1); 1131 whiteImage.SetOrigin(origin); 1132 1133 // allocate data 1134 whiteImage.AllocateScalars(VtkUtil.VTK_UNSIGNED_CHAR, 1); 1135 1136 // fill the image with foreground voxels 1137 final int len = whiteImage.GetNumberOfPoints(); 1138 // allocate java array 1139 final byte[] javaArray = new byte[len]; 1140 // get VTK array 1141 final vtkUnsignedCharArray vtkArray = (vtkUnsignedCharArray) whiteImage.GetPointData().GetScalars(); 1142 1143 // build the java array 1 filled 1144 Arrays.fill(javaArray, (byte) 1); 1145 // set to VTK array 1146 vtkArray.SetJavaArray(javaArray); 1147 1148 // polygonal data --> image stencil 1149 final vtkPolyDataToImageStencil polyToImgStencil = new vtkPolyDataToImageStencil(); 1150 1151 polyToImgStencil.SetInputData(polyData); 1152 polyToImgStencil.SetOutputOrigin(origin); 1153 polyToImgStencil.SetOutputSpacing(spacing); 1154 polyToImgStencil.SetOutputWholeExtent(whiteImage.GetExtent()); 1155 // better to set tolerance to 0 (fastest and most permissive miss) for now 1156 // as more aggressive tolerance (up to 1) can add random points (known issue from VTK 6.3, maybe fixed in VTK 7.0 or >) 1157 polyToImgStencil.SetTolerance(0); 1158 polyToImgStencil.Update(); 1159 1160 // cut the corresponding white image and set the background: 1161 final vtkImageStencil imageStencil = new vtkImageStencil(); 1162 imageStencil.SetInputData(whiteImage); 1163 imageStencil.SetStencilConnection(polyToImgStencil.GetOutputPort()); 1164 imageStencil.ReverseStencilOff(); 1165 imageStencil.SetBackgroundValue(0d); 1166 imageStencil.Update(); 1167 1168 final vtkImageData result = imageStencil.GetOutput(); 1169 1170 // release VTK objects 1171 imageStencil.Delete(); 1172 polyToImgStencil.Delete(); 1173 whiteImage.GetPointData().GetScalars().Delete(); 1174 whiteImage.GetPointData().Delete(); 1175 whiteImage.Delete(); 1176 1177 return result; 1178 } 1179 1180 /** 1181 * @deprecated Use {@link #getBinaryImageData(vtkPolyData, double[])} instead. 1182 */ 1183 @Deprecated 1184 public static vtkImageData polyDataToImageData(vtkPolyData polyData, double space[]) 1185 { 1186 return getBinaryImageData(polyData, space); 1187 } 1188 1189 /** 1190 * Get VTK transform object from specified transform infos 1191 */ 1192 public static vtkTransform getTransform(double off[], double scale[], double rot[]) 1193 { 1194 final double[] offset = (off == null) ? new double[] {0d, 0d, 0d} : off; 1195 final double[] scaling = (scale == null) ? new double[] {1d, 1d, 1d} : scale; 1196 final double[] rotation = (rot == null) ? new double[] {0d, 0d, 0d} : rot; 1197 1198 final vtkTransform result = new vtkTransform(); 1199 1200 result.Translate(offset); 1201 result.Scale(scaling); 1202 result.RotateX(rotation[0]); 1203 result.RotateY(rotation[1]); 1204 result.RotateZ(rotation[2]); 1205 result.Update(); 1206 1207 return result; 1208 } 1209 1210 /** 1211 * Transform a polyData using specified rotation, scaling and offset informations 1212 */ 1213 public static vtkPolyData transformPolyData(vtkPolyData polyData, vtkAbstractTransform transform) 1214 { 1215 final vtkTransformPolyDataFilter transformFilter = new vtkTransformPolyDataFilter(); 1216 transformFilter.SetInputData(polyData); 1217 transformFilter.SetTransform(transform); 1218 transformFilter.Update(); 1219 1220 final vtkPolyData result = transformFilter.GetOutput(); 1221 1222 transformFilter.Delete(); 1223 1224 return result; 1225 } 1226 1227 /** 1228 * Transform a polyData using specified rotation, scaling and offset informations (3D) 1229 */ 1230 public static vtkPolyData transformPolyData(vtkPolyData polyData, double off[], double scale[], double rot[]) 1231 { 1232 final vtkTransform transform = getTransform(off, scale, rot); 1233 final vtkPolyData result = transformPolyData(polyData, transform); 1234 transform.Delete(); 1235 return result; 1236 } 1237 1238 /** 1239 * Read a OBJ 3D model file and returns it in VTK mesh format ({@link vtkPolyData}) 1240 */ 1241 public static vtkPolyData getSurfaceFromOBJ(String objPath) 1242 { 1243 final vtkOBJReader reader = new vtkOBJReader(); 1244 1245 reader.SetFileName(objPath); 1246 reader.Update(); 1247 1248 final vtkPolyData result = reader.GetOutput(); 1249 1250 reader.Delete(); 1251 1252 return result; 1253 } 1254 1255 /** 1256 * Creates and returns the color map in {@link vtkColorTransferFunction} format from the 1257 * specified {@link LUTChannel}. 1258 */ 1259 public static vtkColorTransferFunction getColorMap(LUTChannel lutChannel) 1260 { 1261 final IcyColorMap colorMap = lutChannel.getColorMap(); 1262 final Scaler scaler = lutChannel.getScaler(); 1263 1264 // SCALAR COLOR FUNCTION 1265 final vtkColorTransferFunction result = new vtkColorTransferFunction(); 1266 1267 result.SetRange(scaler.getLeftIn(), scaler.getRightIn()); 1268 for (int i = 0; i < IcyColorMap.SIZE; i++) 1269 { 1270 result.AddRGBPoint(scaler.unscale(i), colorMap.getNormalizedRed(i), colorMap.getNormalizedGreen(i), 1271 colorMap.getNormalizedBlue(i)); 1272 } 1273 1274 return result; 1275 } 1276 1277 /** 1278 * Creates and returns the opacity map in {@link vtkPiecewiseFunction} format from the specified {@link LUTChannel}. 1279 */ 1280 public static vtkPiecewiseFunction getOpacityMap(LUTChannel lutChannel) 1281 { 1282 final IcyColorMap colorMap = lutChannel.getColorMap(); 1283 final Scaler scaler = lutChannel.getScaler(); 1284 1285 // SCALAR OPACITY FUNCTION 1286 final vtkPiecewiseFunction result = new vtkPiecewiseFunction(); 1287 1288 if (colorMap.isEnabled()) 1289 { 1290 for (int i = 0; i < IcyColorMap.SIZE; i++) 1291 result.AddPoint(scaler.unscale(i), colorMap.getNormalizedAlpha(i)); 1292 } 1293 else 1294 { 1295 for (int i = 0; i < IcyColorMap.SIZE; i++) 1296 result.AddPoint(scaler.unscale(i), 0d); 1297 } 1298 1299 return result; 1300 } 1301 1302 /** 1303 * Creates and returns a binary color map in {@link vtkColorTransferFunction} format where 0 value is black and 1 is 1304 * set to specified color. 1305 */ 1306 public static vtkColorTransferFunction getBinaryColorMap(Color color) 1307 { 1308 // SCALAR COLOR FUNCTION 1309 final vtkColorTransferFunction result = new vtkColorTransferFunction(); 1310 1311 result.SetRange(0, 1); 1312 result.AddRGBPoint(0d, 0d, 0d, 0d); 1313 result.AddRGBPoint(1d, color.getRed() / 255d, color.getGreen() / 255d, color.getBlue() / 255d); 1314 1315 return result; 1316 } 1317 1318 /** 1319 * Creates and returns a binary opacity map in {@link vtkPiecewiseFunction} format where 0 is 100% transparent and 1 1320 * to the specified opacity value. 1321 */ 1322 public static vtkPiecewiseFunction getBinaryOpacityMap(double opacity) 1323 { 1324 // SCALAR OPACITY FUNCTION 1325 final vtkPiecewiseFunction result = new vtkPiecewiseFunction(); 1326 1327 result.AddPoint(0d, 1d); 1328 result.AddPoint(1d, opacity); 1329 1330 return result; 1331 } 1332 1333 /** 1334 * Set the Color of the specified {@link vtkPolyData} object. 1335 * 1336 * @param polyData 1337 * the vtkPolyData we want to change color 1338 * @param color 1339 * the color to set 1340 * @param canvas 1341 * the VtkCanvas object to lock during the color change operation for safety (can be <code>null</code> if we 1342 * don't need to lock the VtkCanvas here) 1343 */ 1344 public static void setPolyDataColor(vtkPolyData polyData, Color color, VtkCanvas canvas) 1345 { 1346 final int numPts = polyData.GetNumberOfPoints(); 1347 vtkUnsignedCharArray colors = null; 1348 1349 // try to recover colors object 1350 if (polyData.GetPointData() != null) 1351 { 1352 final vtkDataArray dataArray = polyData.GetPointData().GetScalars(); 1353 1354 if (dataArray instanceof vtkUnsignedCharArray) 1355 colors = (vtkUnsignedCharArray) dataArray; 1356 // delete it 1357 else if (dataArray != null) 1358 dataArray.Delete(); 1359 } 1360 1361 // colors is not correctly defined ? --> reallocate 1362 if ((colors == null) || (colors.GetNumberOfTuples() != numPts) || (colors.GetNumberOfComponents() != 3)) 1363 { 1364 // delete first 1365 if (colors != null) 1366 colors.Delete(); 1367 1368 // and reallocate 1369 colors = new vtkUnsignedCharArray(); 1370 colors.SetNumberOfComponents(3); 1371 colors.SetNumberOfTuples(numPts); 1372 // set colors array 1373 polyData.GetPointData().SetScalars(colors); 1374 } 1375 1376 final int len = numPts * 3; 1377 1378 final byte r = (byte) color.getRed(); 1379 final byte g = (byte) color.getGreen(); 1380 final byte b = (byte) color.getBlue(); 1381 final byte[] data = new byte[len]; 1382 1383 for (int i = 0; i < len; i += 3) 1384 { 1385 data[i + 0] = r; 1386 data[i + 1] = g; 1387 data[i + 2] = b; 1388 } 1389 1390 final IcyVtkPanel vtkPanel = (canvas != null) ? canvas.getVtkPanel() : null; 1391 1392 if (vtkPanel != null) 1393 { 1394 vtkPanel.lock(); 1395 try 1396 { 1397 colors.SetJavaArray(data); 1398 colors.Modified(); 1399 } 1400 finally 1401 { 1402 vtkPanel.unlock(); 1403 } 1404 } 1405 else 1406 { 1407 colors.SetJavaArray(data); 1408 colors.Modified(); 1409 } 1410 } 1411 1412 /** 1413 * Returns a cube polydata object representing the specified bounding box coordinate 1414 * 1415 * @see #setOutlineBounds(vtkPolyData, double, double, double, double, double, double, VtkCanvas) 1416 */ 1417 public static vtkPolyData getOutline(double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) 1418 { 1419 final double points[][] = new double[8][3]; 1420 final int indexes[][] = {{0, 2, 3, 1}, {4, 5, 7, 6}, {0, 1, 5, 4}, {1, 3, 7, 5}, {0, 4, 6, 2}, {3, 2, 6, 7}}; 1421 1422 for (int i = 0; i < 8; i++) 1423 { 1424 points[i][0] = ((i & 1) == 0) ? xMin : xMax; 1425 points[i][1] = ((i & 2) == 0) ? yMin : yMax; 1426 points[i][2] = ((i & 4) == 0) ? zMin : zMax; 1427 } 1428 1429 final vtkCellArray vCells = VtkUtil.getCells(6, prepareCells(indexes)); 1430 final vtkPoints vPoints = VtkUtil.getPoints(points); 1431 final vtkPolyData result = new vtkPolyData(); 1432 1433 result.SetPolys(vCells); 1434 result.SetPoints(vPoints); 1435 1436 return result; 1437 } 1438 1439 /** 1440 * Set the bounds of specified outline polydata object (previously created with <i>VtkUtil.getOutline(..)</i>) 1441 * 1442 * @param canvas 1443 * the VtkCanvas object to lock during the color change operation for safety (can be <code>null</code> if we 1444 * don't need to lock the VtkCanvas here) 1445 * @return <code>false</code> if the specified polydata object is not a valid outline object 1446 * @see #getOutline(double, double, double, double, double, double) 1447 */ 1448 public static boolean setOutlineBounds(vtkPolyData outline, double xMin, double xMax, double yMin, double yMax, 1449 double zMin, double zMax, VtkCanvas canvas) 1450 { 1451 final vtkPoints previousPoints = outline.GetPoints(); 1452 1453 // not valid 1454 if ((previousPoints != null) && (previousPoints.GetNumberOfPoints() != 8)) 1455 return false; 1456 1457 final double newPoints[][] = new double[8][3]; 1458 for (int i = 0; i < 8; i++) 1459 { 1460 newPoints[i][0] = ((i & 1) == 0) ? xMin : xMax; 1461 newPoints[i][1] = ((i & 2) == 0) ? yMin : yMax; 1462 newPoints[i][2] = ((i & 4) == 0) ? zMin : zMax; 1463 } 1464 1465 final vtkPoints points = getPoints(newPoints); 1466 final IcyVtkPanel vtkPanel = (canvas != null) ? canvas.getVtkPanel() : null; 1467 1468 if (vtkPanel != null) 1469 { 1470 vtkPanel.lock(); 1471 try 1472 { 1473 // rebuild points 1474 outline.SetPoints(points); 1475 // changed 1476 outline.Modified(); 1477 // delete previous points 1478 if (previousPoints != null) 1479 previousPoints.Delete(); 1480 } 1481 finally 1482 { 1483 vtkPanel.unlock(); 1484 } 1485 } 1486 else 1487 { 1488 // rebuild points 1489 outline.SetPoints(points); 1490 // changed 1491 outline.Modified(); 1492 // delete previous points 1493 if (previousPoints != null) 1494 previousPoints.Delete(); 1495 } 1496 1497 return true; 1498 } 1499 1500 /** 1501 * VTK forced garbage collection 1502 */ 1503 public static void vtkGC() 1504 { 1505 vtkObjectBase.JAVA_OBJECT_MANAGER.gc(false); 1506 } 1507}