001/**
002 * 
003 */
004package icy.roi;
005
006import icy.type.Position5DIterator;
007import icy.type.point.Point5D;
008import icy.type.rectangle.Rectangle5D;
009
010import java.util.NoSuchElementException;
011
012/**
013 * ROI iterator.<br>
014 * This class permit to use simple iterator to navigate each point of specified ROI in XYCZT
015 * <i>([T[Z[C[Y[X]]]]])</i> dimension order.<br>
016 * <b>If the ROI is modified during iteration the iterator becomes invalid and exception can
017 * happen.</b>
018 * 
019 * @author Stephane
020 */
021public class ROIIterator implements Position5DIterator
022{
023    protected final ROI roi;
024    protected final Rectangle5D.Integer bounds;
025    protected final boolean inclusive;
026    protected int c, z, t;
027    protected boolean done;
028    protected BooleanMask2DIterator maskIterator;
029
030    /**
031     * Create a new ROI iterator to iterate through each point of the specified ROI.
032     * 
033     * @param roi
034     *        ROI defining the region to iterate.
035     * @param region
036     *        A 5D region to limit the ROI region area to iterate for.<br/>
037     *        Keep it to <code>null</code> to iterate all over the ROI.
038     * @param inclusive
039     *        If true then all partially contained (intersected) pixels in the ROI are included.
040     */
041    public ROIIterator(ROI roi, Rectangle5D region, boolean inclusive)
042    {
043        super();
044
045        this.roi = roi;
046        // get final bounds
047        if (region != null)
048            bounds = region.createIntersection(roi.getBounds5D()).toInteger();
049        else
050            bounds = roi.getBounds5D().toInteger();
051        this.inclusive = inclusive;
052
053        // fix infinite dimensions
054        if (bounds.isInfiniteZ())
055        {
056            bounds.z = -1;
057            bounds.sizeZ = 1;
058        }
059        if (bounds.isInfiniteT())
060        {
061            bounds.t = -1;
062            bounds.sizeT = 1;
063        }
064        if (bounds.isInfiniteC())
065        {
066            bounds.c = -1;
067            bounds.sizeC = 1;
068        }
069
070        // start iterator
071        reset();
072    }
073
074    /**
075     * Create a new ROI iterator to iterate through each point of the specified ROI.
076     * 
077     * @param roi
078     *        ROI defining the region to iterate.
079     * @param inclusive
080     *        If true then all partially contained (intersected) pixels in the ROI are included.
081     */
082    public ROIIterator(ROI roi, boolean inclusive)
083    {
084        this(roi, null, inclusive);
085    }
086
087    public int getMinZ()
088    {
089        return bounds.z;
090    }
091
092    public int getMaxZ()
093    {
094        return (bounds.z + bounds.sizeZ) - 1;
095    }
096
097    public int getMinT()
098    {
099        return bounds.t;
100    }
101
102    public int getMaxT()
103    {
104        return (bounds.t + bounds.sizeT) - 1;
105    }
106
107    public int getMinC()
108    {
109        return bounds.c;
110    }
111
112    public int getMaxC()
113    {
114        return (bounds.c + bounds.sizeC) - 1;
115    }
116
117    @Override
118    public void reset()
119    {
120        done = bounds.isEmpty();
121
122        if (!done)
123        {
124            z = getMinZ();
125            t = getMinT();
126            c = getMinC();
127
128            prepareXY();
129            nextXYIfNeeded();
130        }
131    }
132
133    /**
134     * Prepare for XY iteration.
135     */
136    protected void prepareXY()
137    {
138        maskIterator = new BooleanMask2DIterator(roi.getBooleanMask2D(z, t, c, inclusive));
139    }
140
141    @Override
142    public void next()
143    {
144        if (done)
145            throw new NoSuchElementException();
146
147        maskIterator.next();
148        nextXYIfNeeded();
149    }
150
151    /**
152     * Advance one image position.
153     */
154    protected void nextXYIfNeeded()
155    {
156        while (maskIterator.done() && !done)
157        {
158            if (++c > getMaxC())
159            {
160                c = getMinC();
161
162                if (++z > getMaxZ())
163                {
164                    z = getMinZ();
165
166                    if (++t > getMaxT())
167                    {
168                        done = true;
169                        return;
170                    }
171                }
172            }
173
174            prepareXY();
175        }
176    }
177
178    @Override
179    public boolean done()
180    {
181        return done;
182    }
183
184    @Override
185    public Point5D get()
186    {
187        if (done)
188            throw new NoSuchElementException();
189
190        return new Point5D.Integer(maskIterator.getX(), maskIterator.getY(), z, t, c);
191    }
192
193    @Override
194    public int getX()
195    {
196        if (done)
197            throw new NoSuchElementException();
198
199        return maskIterator.getX();
200    }
201
202    @Override
203    public int getY()
204    {
205        if (done)
206            throw new NoSuchElementException();
207
208        return maskIterator.getY();
209    }
210
211    @Override
212    public int getC()
213    {
214        if (done)
215            throw new NoSuchElementException();
216
217        return c;
218    }
219
220    @Override
221    public int getZ()
222    {
223        if (done)
224            throw new NoSuchElementException();
225
226        return z;
227    }
228
229    @Override
230    public int getT()
231    {
232        if (done)
233            throw new NoSuchElementException();
234
235        return t;
236    }
237
238}