JAL-653 MapList constructor merges any contiguous ranges
[jalview.git] / src / jalview / util / MapList.java
index 2641659..8ff640b 100644 (file)
@@ -41,12 +41,12 @@ public class MapList
   /*
    * Subregions (base 1) described as { [start1, end1], [start2, end2], ...}
    */
-  private List<int[]> fromShifts = new ArrayList<int[]>();
+  private List<int[]> fromShifts;
 
   /*
    * Same format as fromShifts, for the 'mapped to' sequence
    */
-  private List<int[]> toShifts = new ArrayList<int[]>();
+  private List<int[]> toShifts;
 
   /*
    * number of steps in fromShifts to one toRatio unit
@@ -73,6 +73,15 @@ public class MapList
   private int toHighest;
 
   /**
+   * Constructor
+   */
+  public MapList()
+  {
+    fromShifts = new ArrayList<int[]>();
+    toShifts = new ArrayList<int[]>();
+  }
+
+  /**
    * Two MapList objects are equal if they are the same object, or they both
    * have populated shift ranges and all values are the same.
    */
@@ -180,7 +189,8 @@ public class MapList
   }
 
   /**
-   * Constructor.
+   * Constructor given from and to ranges as [start1, end1, start2, end2,...].
+   * If any end is equal to the next start, the ranges will be merged.
    * 
    * @param from
    *          contiguous regions as [start1, end1, start2, end2, ...]
@@ -193,27 +203,47 @@ public class MapList
    */
   public MapList(int from[], int to[], int fromRatio, int toRatio)
   {
+    this();
     this.fromRatio = fromRatio;
     this.toRatio = toRatio;
     fromLowest = from[0];
     fromHighest = from[1];
+    int added = 0;
+
     for (int i = 0; i < from.length; i += 2)
     {
       fromLowest = Math.min(fromLowest, from[i]);
       fromHighest = Math.max(fromHighest, from[i + 1]);
-
-      fromShifts.add(new int[]
-      { from[i], from[i + 1] });
+      if (added > 0 && from[i] == fromShifts.get(added - 1)[1])
+      {
+        /*
+         * this range starts where the last ended - just extend it
+         */
+        fromShifts.get(added - 1)[1] = from[i + 1];
+      }
+      else
+      {
+        fromShifts.add(new int[] { from[i], from[i + 1] });
+        added++;
+      }
     }
 
     toLowest = to[0];
     toHighest = to[1];
+    added = 0;
     for (int i = 0; i < to.length; i += 2)
     {
       toLowest = Math.min(toLowest, to[i]);
       toHighest = Math.max(toHighest, to[i + 1]);
-      toShifts.add(new int[]
-      { to[i], to[i + 1] });
+      if (added > 0 && to[i] == toShifts.get(added - 1)[1])
+      {
+        toShifts.get(added - 1)[1] = to[i + 1];
+      }
+      else
+      {
+        toShifts.add(new int[] { to[i], to[i + 1] });
+        added++;
+      }
     }
   }
 
@@ -224,6 +254,7 @@ public class MapList
    */
   public MapList(MapList map)
   {
+    this();
     // TODO not used - remove?
     this.fromLowest = map.fromLowest;
     this.fromHighest = map.fromHighest;
@@ -236,16 +267,14 @@ public class MapList
     {
       for (int[] r : map.fromShifts)
       {
-        fromShifts.add(new int[]
-        { r[0], r[1] });
+        fromShifts.add(new int[] { r[0], r[1] });
       }
     }
     if (map.toShifts != null)
     {
       for (int[] r : map.toShifts)
       {
-        toShifts.add(new int[]
-        { r[0], r[1] });
+        toShifts.add(new int[] { r[0], r[1] });
       }
     }
   }
@@ -258,9 +287,10 @@ public class MapList
    * @param fromRatio
    * @param toRatio
    */
-  public MapList(List<int[]> fromRange, List<int[]> toRange,
-          int fromRatio, int toRatio)
+  public MapList(List<int[]> fromRange, List<int[]> toRange, int fromRatio,
+          int toRatio)
   {
+    this();
     this.fromShifts = fromRange;
     this.toShifts = toRange;
     this.fromRatio = fromRatio;
@@ -268,7 +298,8 @@ public class MapList
 
     fromLowest = Integer.MAX_VALUE;
     fromHighest = 0;
-    for (int[] range : fromRange) {
+    for (int[] range : fromRange)
+    {
       fromLowest = Math.min(fromLowest, range[0]);
       fromHighest = Math.max(fromHighest, range[1]);
     }
@@ -313,8 +344,7 @@ public class MapList
    *         returning mapped position
    */
   private int[][] posMap(List<int[]> shiftTo, int ratio,
-          List<int[]> shiftFrom,
-          int toRatio)
+          List<int[]> shiftFrom, int toRatio)
   {
     // TODO not used - remove??
     int iv = 0, ivSize = shiftTo.size();
@@ -374,9 +404,8 @@ public class MapList
       }
       mp[i] = m;
     }
-    int[][] map = new int[][]
-    { new int[]
-    { from, to, tF, tT }, new int[to - from + 2] };
+    int[][] map = new int[][] { new int[] { from, to, tF, tT },
+        new int[to - from + 2] };
 
     map[0][2] = tF;
     map[0][3] = tT;
@@ -461,8 +490,7 @@ public class MapList
       return null; // throw new Error("Bad Mapping!");
     }
     // System.out.println(fromCount[0]+" "+fromCount[1]+" "+toCount);
-    return new int[]
-    { toPos[0], fromRemainder, toPos[1] };
+    return new int[] { toPos[0], fromRemainder, toPos[1] };
   }
 
   /**
@@ -482,8 +510,7 @@ public class MapList
       {
         if (pos >= intv[0] && pos <= intv[1])
         {
-          return new int[]
-          { count + pos - intv[0] + 1, +1 };
+          return new int[] { count + pos - intv[0] + 1, +1 };
         }
         else
         {
@@ -494,8 +521,7 @@ public class MapList
       {
         if (pos >= intv[1] && pos <= intv[0])
         {
-          return new int[]
-          { count + intv[0] - pos + 1, -1 };
+          return new int[] { count + intv[0] - pos + 1, -1 };
         }
         else
         {
@@ -516,8 +542,7 @@ public class MapList
   protected static int[] countToPos(List<int[]> shiftFrom, int pos)
   {
     int count = 0, diff = 0, iv = 0, ivSize = shiftFrom.size();
-    int[] intv =
-    { 0, 0 };
+    int[] intv = { 0, 0 };
     while (iv < ivSize)
     {
       intv = shiftFrom.get(iv++);
@@ -526,8 +551,7 @@ public class MapList
       {
         if (pos <= count + 1 + diff)
         {
-          return new int[]
-          { pos - count - 1 + intv[0], +1 };
+          return new int[] { pos - count - 1 + intv[0], +1 };
         }
         else
         {
@@ -538,8 +562,7 @@ public class MapList
       {
         if (pos <= count + 1 - diff)
         {
-          return new int[]
-          { intv[0] - (pos - count - 1), -1 };
+          return new int[] { intv[0] - (pos - count - 1), -1 };
         }
         else
         {
@@ -597,8 +620,7 @@ public class MapList
    *         region to final position of ending region inclusive
    */
   protected static int[] getIntervals(List<int[]> shiftFrom,
-          int[] fromStart,
-          int[] fromEnd, int fromRatio2)
+          int[] fromStart, int[] fromEnd, int fromRatio2)
   {
     if (fromStart == null || fromEnd == null)
     {
@@ -688,8 +710,7 @@ public class MapList
       i = fs;
       // truncate initial interval
       iv = shiftFrom.get(intv++);
-      iv = new int[]
-      { iv[0], iv[1] };// clone
+      iv = new int[] { iv[0], iv[1] };// clone
       if (i == fs)
       {
         iv[0] = startpos;
@@ -698,8 +719,7 @@ public class MapList
       {
         ranges.add(iv); // add initial range
         iv = shiftFrom.get(intv++); // get next interval
-        iv = new int[]
-        { iv[0], iv[1] };// clone
+        iv = new int[] { iv[0], iv[1] };// clone
         i++;
       }
       if (i == fe)
@@ -717,8 +737,7 @@ public class MapList
         i--;
       }
       iv = shiftFrom.get(i);
-      iv = new int[]
-      { iv[1], iv[0] };// reverse and clone
+      iv = new int[] { iv[1], iv[0] };// reverse and clone
       // truncate initial interval
       if (i == fs)
       {
@@ -728,8 +747,7 @@ public class MapList
       { // fix apparent logic bug when fe==-1
         ranges.add(iv); // add (truncated) reversed interval
         iv = shiftFrom.get(i);
-        iv = new int[]
-        { iv[1], iv[0] }; // reverse and clone
+        iv = new int[] { iv[1], iv[0] }; // reverse and clone
       }
       if (i == fe)
       {
@@ -788,8 +806,7 @@ public class MapList
     int[] mp = shiftTo(mpos);
     if (mp != null)
     {
-      return new int[]
-      { mp[0], mp[0] + mp[2] * (getFromRatio() - 1) };
+      return new int[] { mp[0], mp[0] + mp[2] * (getFromRatio() - 1) };
     }
     return null;
   }
@@ -818,8 +835,7 @@ public class MapList
     int[] mp = shiftFrom(pos);
     if (mp != null)
     {
-      return new int[]
-      { mp[0], mp[0] + mp[2] * (getToRatio() - 1) };
+      return new int[] { mp[0], mp[0] + mp[2] * (getToRatio() - 1) };
     }
     return null;
   }
@@ -859,4 +875,26 @@ public class MapList
               .getToHighest()));
     }
   }
+
+  /**
+   * String representation - for debugging, not guaranteed not to change
+   */
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder(64);
+    sb.append("From (").append(fromRatio).append(":").append(toRatio)
+            .append(") [");
+    for (int[] shift : fromShifts)
+    {
+      sb.append(" ").append(Arrays.toString(shift));
+    }
+    sb.append(" ] To [");
+    for (int[] shift : toShifts)
+    {
+      sb.append(" ").append(Arrays.toString(shift));
+    }
+    sb.append(" ]");
+    return sb.toString();
+  }
 }