JAL-553 JAL-1557 always send selections after triggering the PaintRefreser for a...
[jalview.git] / src / jalview / util / MappingUtils.java
index 267e871..ae4e55d 100644 (file)
@@ -770,53 +770,126 @@ public final class MappingUtils
   }
 
   /**
-   * Remove the last 3 mapped positions from the given ranges
+   * Returns the total length of the supplied ranges, which may be as single
+   * [start, end] or multiple [start, end, start, end ...]
    * 
    * @param ranges
-   * @param mappedLength
+   * @return
    */
-  public static void unmapStopCodon(List<int[]> ranges,
-          int mappedLength)
+  public static int getLength(List<int[]> ranges)
   {
-    if (mappedLength < 3)
+    if (ranges == null)
     {
-      return;
+      return 0;
     }
-    boolean done = false;
-    int targetLength = mappedLength - 3;
-    int mapped = 0;
-    Iterator<int[]> it = ranges.iterator();
-    while (!done && it.hasNext())
+    int length = 0;
+    for (int[] range : ranges)
     {
-      int[] range = it.next();
-      int length = Math.abs(range[1] - range[0]) + 1;
-      if (mapped + length == targetLength)
+      if (range.length % 2 != 0)
       {
-        done = true;
+        System.err.println("Error unbalance start/end ranges: "
+                + ranges.toString());
+        return 0;
       }
-      else if (mapped + length < targetLength)
+      for (int i = 0; i < range.length - 1; i += 2)
       {
-        mapped += length;
-        continue;
+        length += Math.abs(range[i + 1] - range[i]) + 1;
+      }
+    }
+    return length;
+  }
+
+  /**
+   * Answers true if any range includes the given value
+   * 
+   * @param ranges
+   * @param value
+   * @return
+   */
+  public static boolean contains(List<int[]> ranges, int value)
+  {
+    if (ranges == null)
+    {
+      return false;
+    }
+    for (int[] range : ranges)
+    {
+      if (range[1] >= range[0] && value >= range[0] && value <= range[1])
+      {
+        /*
+         * value within ascending range
+         */
+        return true;
       }
-      else
+      if (range[1] < range[0] && value <= range[0] && value >= range[1])
       {
         /*
-         * need just a bit of this range
+         * value within descending range
          */
-        int needed = targetLength - mapped;
-        int sense = range[1] >= range[0] ? 1 : -1;
-        range[1] = range[0] + (sense * (needed - 1));
-        done = true;
+        return true;
       }
     }
-    /*
-     * remove any trailing ranges
-     */
-    while (it.hasNext())
+    return false;
+  }
+
+  /**
+   * Removes a specified number of positions from the start of a ranges list.
+   * For example, could be used to adjust cds ranges to allow for an incomplete
+   * start codon. Subranges are removed completely, or their start positions
+   * adjusted, until the required number of positions has been removed from the
+   * range. Reverse strand ranges are supported. The input array is not
+   * modified.
+   * 
+   * @param removeCount
+   * @param ranges
+   *          an array of [start, end, start, end...] positions
+   * @return a new array with the first removeCount positions removed
+   */
+  public static int[] removeStartPositions(int removeCount,
+          final int[] ranges)
+  {
+    if (removeCount <= 0)
+    {
+      return ranges;
+    }
+  
+    int[] copy = Arrays.copyOf(ranges, ranges.length);
+    int sxpos = -1;
+    int cdspos = 0;
+    for (int x = 0; x < copy.length && sxpos == -1; x += 2)
+    {
+      cdspos += Math.abs(copy[x + 1] - copy[x]) + 1;
+      if (removeCount < cdspos)
+      {
+        /*
+         * we have removed enough, time to finish
+         */
+        sxpos = x;
+
+        /*
+         * increment start of first exon, or decrement if reverse strand
+         */
+        if (copy[x] <= copy[x + 1])
+        {
+          copy[x] = copy[x + 1] - cdspos + removeCount + 1;
+        }
+        else
+        {
+          copy[x] = copy[x + 1] + cdspos - removeCount - 1;
+        }
+        break;
+      }
+    }
+  
+    if (sxpos > 0)
     {
-      it.next();
-      it.remove();
+      /*
+       * we dropped at least one entire sub-range - compact the array
+       */
+      int[] nxon = new int[copy.length - sxpos];
+      System.arraycopy(copy, sxpos, nxon, 0, copy.length - sxpos);
+      return nxon;
     }
+    return copy;
   }
 }