* extent of the sequence
*
* @param seq
- * @return int[] { visible start, visible end, first seqpos, last seqpos,
- * alignment index for seq start, alignment index for seq end }
+ * @return int[] { visible start, first seqpos, last seqpos }
*/
- public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+ public int locateVisibleBoundsOfSequence(SequenceI seq)
{
try
{
LOCK.readLock().lock();
- int fpos = seq.getStart();
- int lpos = seq.getEnd();
int start = 0;
if (hiddenColumns == null || hiddenColumns.size() == 0)
{
- int ifpos = seq.findIndex(fpos) - 1;
- int ilpos = seq.findIndex(lpos) - 1;
- return new int[] { ifpos, ifpos, ilpos };
+ return seq.findIndex(seq.getStart()) - 1;
}
// Simply walk along the sequence whilst watching for hidden column
// boundaries
Iterator<int[]> regions = iterator();
- int spos = fpos;
+ int spos = seq.getStart();
int hideStart = seq.getLength();
int hideEnd = -1;
int visPrev = 0;
int visNext = 0;
- int firstP = -1;
- int lastP = -1;
+
boolean foundStart = false;
- for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
- && p < pLen; p++)
+ for (int p = 0; spos <= seq.getEnd() && p < seq.getLength(); p++)
{
if (!Comparison.isGap(seq.getCharAt(p)))
{
- // keep track of first/last column
- // containing sequence data regardless of visibility
- if (firstP == -1)
- {
- firstP = p;
- }
- lastP = p;
// update hidden region start/end
while (hideEnd < p && regions.hasNext())
{
hideStart = seq.getLength();
}
// update visible boundary for sequence
- if (p < hideStart)
+ if ((p < hideStart) && (!foundStart))
{
- if (!foundStart)
- {
- fpos = spos;
start = p;
foundStart = true;
- }
- lpos = spos;
}
// look for next sequence position
spos++;
}
if (foundStart)
{
- return new int[] { findColumnPosition(start), firstP, lastP };
+ return findColumnPosition(start);
}
// otherwise, sequence was completely hidden
- return new int[] { visPrev, firstP, lastP };
+ return visPrev;
} finally
{
LOCK.readLock().unlock();
}
/**
+ * return an iterator over visible segments between the given start and end
+ * boundaries
+ *
+ * @param start
+ * (first column - inclusive from 0)
+ * @param end
+ * (last column - inclusive)
+ * @param useVisibleCoords
+ * if true, start and end are visible column positions, not absolute
+ * positions
+ */
+ public Iterator<int[]> getVisibleBlocksIterator(int start, int end,
+ boolean useVisibleCoords)
+ {
+ if (useVisibleCoords)
+ {
+ // TODO
+ // we should really just convert start and end here with
+ // adjustForHiddenColumns
+ // and then create a VisibleBlocksIterator
+ // but without a cursor this will be horribly slow in some situations
+ // ... so until then...
+ return new VisibleBlocksVisBoundsIterator(start, end, true);
+ }
+ else
+ {
+ return new VisibleBlocksIterator(start, end, true);
+ }
+ }
+
+ /**
* An iterator which iterates over hidden column regions in a range.
*/
private class BoundedHiddenColsIterator implements Iterator<int[]>
private List<int[]> localHidden = new ArrayList<>();
- private int lasthiddenregion;
+ private int nexthiddenregion;
VisibleColsIterator(int firstcol, int lastcol, boolean useCopy)
{
last = lastcol;
current = firstcol;
next = firstcol;
- lasthiddenregion = -1;
+ nexthiddenregion = 0;
try
{
{
int i = 0;
for (i = 0; i < hiddenColumns.size()
- && (current < hiddenColumns.get(i)[0]); ++i)
+ && (current <= hiddenColumns.get(i)[0]); ++i)
{
if (current >= hiddenColumns.get(i)[0]
&& current <= hiddenColumns.get(i)[1])
// current is hidden, move to right
current = hiddenColumns.get(i)[1] + 1;
next = current;
+ nexthiddenregion = i + 1;
}
}
- lasthiddenregion = i - 1;
-
for (i = hiddenColumns.size() - 1; i >= 0
- && (last > hiddenColumns.get(i)[1]); --i)
+ && (last >= hiddenColumns.get(i)[1]); --i)
{
if (last >= hiddenColumns.get(i)[0]
&& last <= hiddenColumns.get(i)[1])
}
// make a local copy of the bit we need
- i = lasthiddenregion + 1;
+ i = nexthiddenregion;
while (i < hiddenColumns.size()
&& hiddenColumns.get(i)[0] <= last)
{
localHidden.add(region);
i++;
}
- lasthiddenregion = -1;
}
} finally
{
}
current = next;
if ((localHidden != null)
- && (lasthiddenregion + 1 < localHidden.size()))
+ && (nexthiddenregion < localHidden.size()))
{
// still some more hidden regions
- if (next + 1 < localHidden.get(lasthiddenregion + 1)[0])
+ if (next + 1 < localHidden.get(nexthiddenregion)[0])
{
// next+1 is still before the next hidden region
next++;
}
- else if ((next + 1 >= localHidden.get(lasthiddenregion + 1)[0])
- && (next + 1 <= localHidden.get(lasthiddenregion + 1)[1]))
+ else if ((next + 1 >= localHidden.get(nexthiddenregion)[0])
+ && (next + 1 <= localHidden.get(nexthiddenregion)[1]))
{
// next + 1 is in the next hidden region
- next = localHidden.get(lasthiddenregion + 1)[1] + 1;
- lasthiddenregion++;
+ next = localHidden.get(nexthiddenregion)[1] + 1;
+ nexthiddenregion++;
}
}
else
}
}
+ /**
+ * An iterator which iterates over visible regions in a range. The range is
+ * specified in terms of visible column positions. Provides a special
+ * "endsAtHidden" indicator to allow callers to determine if the final visible
+ * column is adjacent to a hidden region.
+ */
+ public class VisibleBlocksVisBoundsIterator implements Iterator<int[]>
+ {
+ private List<int[]> vcontigs = new ArrayList<>();
+
+ private int currentPosition = 0;
+
+ private boolean endsAtHidden = false;
+
+ /**
+ * Constructor for iterator over visible regions in a range.
+ *
+ * @param start
+ * start position in terms of visible column position
+ * @param end
+ * end position in terms of visible column position
+ * @param usecopy
+ * whether to use a local copy of hidden columns
+ */
+ VisibleBlocksVisBoundsIterator(int start, int end, boolean usecopy)
+ {
+ /* actually this implementation always uses a local copy but this may change in future */
+ try
+ {
+ if (usecopy)
+ {
+ LOCK.readLock().lock();
+ }
+
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ int blockStart = start;
+ int blockEnd = end;
+ int hiddenSoFar = 0;
+ int visSoFar = 0;
+
+ // iterate until a region begins within (start,end]
+ int i = 0;
+ while ((i < hiddenColumns.size())
+ && (hiddenColumns.get(i)[0] <= blockStart + hiddenSoFar))
+ {
+ hiddenSoFar += hiddenColumns.get(i)[1] - hiddenColumns.get(i)[0]
+ + 1;
+ i++;
+ }
+
+ blockStart += hiddenSoFar; // convert start to absolute position
+ blockEnd += hiddenSoFar; // convert end to absolute position
+
+ // iterate from start to end, adding each visible region. Positions
+ // are
+ // absolute, and all hidden regions which overlap [start,end] are
+ // used.
+ while (i < hiddenColumns.size()
+ && (hiddenColumns.get(i)[0] <= blockEnd))
+ {
+ int[] region = hiddenColumns.get(i);
+
+ // end position of this visible region is either just before the
+ // start of the next hidden region, or the absolute position of
+ // 'end', whichever is lowest
+ blockEnd = Math.min(blockEnd, region[0] - 1);
+
+ vcontigs.add(new int[] { blockStart, blockEnd });
+
+ visSoFar += blockEnd - blockStart + 1;
+
+ // next visible region starts after this hidden region
+ blockStart = region[1] + 1;
+
+ hiddenSoFar += region[1] - region[0] + 1;
+
+ // reset blockEnd to absolute position of 'end', assuming we've now
+ // passed all hidden regions before end
+ blockEnd = end + hiddenSoFar;
+
+ i++;
+ }
+ if (visSoFar < end - start)
+ {
+ // the number of visible columns we've accounted for is less than
+ // the number specified by end-start; work out the end position of
+ // the last visible region
+ blockEnd = blockStart + end - start - visSoFar;
+ vcontigs.add(new int[] { blockStart, blockEnd });
+
+ // if the last visible region ends at the next hidden region, set
+ // endsAtHidden=true
+ if (i < hiddenColumns.size()
+ && hiddenColumns.get(i)[0] - 1 == blockEnd)
+ {
+ endsAtHidden = true;
+ }
+ }
+ }
+ else
+ {
+ // there are no hidden columns, return a single visible contig
+ vcontigs.add(new int[] { start, end });
+ endsAtHidden = false;
+ }
+ } finally
+ {
+ if (usecopy)
+ {
+ LOCK.readLock().unlock();
+ }
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return (currentPosition < vcontigs.size());
+ }
+
+ @Override
+ public int[] next()
+ {
+ int[] result = vcontigs.get(currentPosition);
+ currentPosition++;
+ return result;
+ }
+
+ public boolean endsAtHidden()
+ {
+ return endsAtHidden;
+ }
+ }
+
}