66import ij .plugin .PointToolOptions ;
77import ij .plugin .filter .Analyzer ;
88import ij .plugin .frame .Recorder ;
9+ import ij .util .Tools ;
910import ij .util .Java2 ;
1011import java .awt .*;
1112import java .awt .image .*;
@@ -22,6 +23,8 @@ public class PointRoi extends PolygonRoi {
2223 public static final String [] sizes = {"Tiny" , "Small" , "Medium" , "Large" , "Extra Large" , "XXL" , "XXXL" };
2324 public static final String [] types = {"Hybrid" , "Cross" , "Dot" , "Circle" };
2425 public static final int HYBRID =0 , CROSS =1 , CROSSHAIR =1 , DOT =2 , CIRCLE =3 ;
26+ /** Returned by getPosition if point stack positions are different */
27+ public static final int POINTWISE_POSITION = -2 ;
2528 private static final String TYPE_KEY = "point.type" ;
2629 private static final String SIZE_KEY = "point.size" ;
2730 private static final String CROSS_COLOR_KEY = "point.cross.color" ;
@@ -215,12 +218,13 @@ public void draw(Graphics g) {
215218 if (fontSize >9 )
216219 Java2 .setAntialiasedText (g , true );
217220 }
218- int slice = imp !=null &&positions !=null &&imp .getStackSize ()>1 ?imp .getCurrentSlice ():0 ;
221+ int [] positions = this .positions ; //use a copy to avoid NullPointerException on asynchronous change to null
222+ int slice = imp !=null && positions !=null && imp .getStackSize ()>1 ?imp .getCurrentSlice ():0 ;
219223 ImageCanvas ic = imp !=null ?imp .getCanvas ():null ;
220224 if (ic !=null && overlay && ic .getShowAllList ()!=null && ic .getShowAllList ().contains (this ) && !Prefs .showAllSliceOnly )
221- slice = 0 ; // draw point irrespective of currently selected slice
225+ slice = 0 ; // In RoiManager's "show all" mode and not "associate with slice", draw point irrespective of currently selected slice
222226 if (Prefs .showAllPoints )
223- slice = 0 ;
227+ slice = 0 ; // "Show on all slices" in Point tool options
224228 //IJ.log("draw: "+positions+" "+imp.getCurrentSlice());
225229 for (int i =0 ; i <nPoints ; i ++) {
226230 //IJ.log(i+" "+slice+" "+(positions!=null?positions[i]:-1)+" "+getPosition());
@@ -690,6 +694,52 @@ public void updateCounts() {
690694 counts [(counters ==null || counters [i ]>=counts .length ) ? 0 : counters [i ]] ++;
691695 }
692696
697+ /** Sets the stack position (image number) of all points in this Roi.
698+ * The points are only displayed when the stack is at the specified position.
699+ * Set to zero to have the points displayed on all images in the stack.
700+ * The stack position, when set, determines the visibility of this Roi
701+ * (i) if it is part of an overlay (normal overlay or the RoiManager's
702+ * 'Show All' overlay), or
703+ * (ii) if it is the currently active Roi and Prefs.showAllPoints
704+ * ('Show an all slices' in the Point Tool Options dialog) is off.
705+ * Clears any association of this Roi to a hyperstack position.
706+ *
707+ * Note that the behavior differs from that of the other Roi types:
708+ * For the other Roi types, setPosition does not restrict the visibility
709+ * to stack slice 'n' if that roi is the currently active Roi; it only
710+ * affects the visibility if that Roi is part of an overlay.
711+ */
712+ public void setPosition (int n ) {
713+ if (n <0 && n !=POINTWISE_POSITION )
714+ n = 0 ;
715+ if (n == 0 ) {
716+ positions = null ;
717+ } else {
718+ if (positions == null )
719+ positions = new int [counters == null ? nPoints *2 : counters .length ];
720+ if (n != POINTWISE_POSITION )
721+ Arrays .fill (positions , n );
722+ }
723+ hyperstackPosition = false ;
724+ }
725+
726+ /** Returns the stack position (image number) of the points in this Roi, if
727+ * all points have the same position. Returns 0 if none of the points is
728+ * associated with a particular stack image, and PointRoi.POINTWISE_POSITION = -2
729+ * if there are different stack positions for different points.
730+ */
731+ public int getPosition () {
732+ if (positions == null || nPoints < 1 ) {
733+ return 0 ;
734+ } else {
735+ int position = positions [0 ];
736+ for (int i =1 ; i <nPoints ; i ++)
737+ if (positions [i ] != position )
738+ return POINTWISE_POSITION ;
739+ return position ;
740+ }
741+ }
742+
693743 /** Returns the stack slice of the point with the given index, or 0 if no slice defined for this point */
694744 public int getPointPosition (int index ) {
695745 if (positions !=null && index <nPoints )
@@ -698,6 +748,18 @@ public int getPointPosition(int index) {
698748 return 0 ;
699749 }
700750
751+ /** Returns whether this Roi contains a point associated to the given stack slice.
752+ * Returns true for (non-existant) slice 0.
753+ * Does not care whether points would be shown irrespective of the slice number
754+ * (as given by the Point Tool options "Show on all slices", Prefs.showAllPoints).
755+ */
756+ public boolean hasPointPosition (int slice ) {
757+ if (slice < 0 ) return false ;
758+ if (slice == 0 ) return true ;
759+ if (positions == null ) return true ;
760+ return Tools .indexOf (positions , slice ) >= 0 ;
761+ }
762+
701763 public void displayCounts () {
702764 ImagePlus imp = getImage ();
703765 String firstColumnHdr = "Slice" ;
0 commit comments