JAL-2418 source formatting
[jalview.git] / src / jalview / util / MapList.java
index bf66b91..4658724 100644 (file)
@@ -88,8 +88,6 @@ public class MapList
   @Override
   public boolean equals(Object o)
   {
-    // TODO should also override hashCode to ensure equal objects have equal
-    // hashcodes
     if (o == null || !(o instanceof MapList))
     {
       return false;
@@ -105,10 +103,22 @@ public class MapList
     {
       return false;
     }
-    return Arrays
-            .deepEquals(fromShifts.toArray(), obj.fromShifts.toArray())
-            && Arrays
-                    .deepEquals(toShifts.toArray(), obj.toShifts.toArray());
+    return Arrays.deepEquals(fromShifts.toArray(), obj.fromShifts.toArray())
+            && Arrays.deepEquals(toShifts.toArray(),
+                    obj.toShifts.toArray());
+  }
+
+  /**
+   * Returns a hashcode made from the fromRatio, toRatio, and from/to ranges
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = 31 * fromRatio;
+    hashCode = 31 * hashCode + toRatio;
+    hashCode = 31 * hashCode + fromShifts.toArray().hashCode();
+    hashCode = 31 * hashCode + toShifts.toArray().hashCode();
+    return hashCode;
   }
 
   /**
@@ -215,7 +225,7 @@ public class MapList
     {
       /*
        * note lowest and highest values - bearing in mind the
-       * direction may be revesed
+       * direction may be reversed
        */
       fromLowest = Math.min(fromLowest, Math.min(from[i], from[i + 1]));
       fromHighest = Math.max(fromHighest, Math.max(from[i], from[i + 1]));
@@ -322,14 +332,17 @@ public class MapList
   }
 
   /**
-   * Consolidates a list of ranges so that any contiguous ranges are merged
+   * Consolidates a list of ranges so that any contiguous ranges are merged.
+   * This assumes the ranges are already in start order (does not sort them).
    * 
    * @param ranges
-   * @return
+   * @return the same list (if unchanged), else a new merged list, leaving the
+   *         input list unchanged
    */
-  public static List<int[]> coalesceRanges(List<int[]> ranges)
+  public static List<int[]> coalesceRanges(final List<int[]> ranges)
   {
-    if (ranges == null || ranges.size() < 2) {
+    if (ranges == null || ranges.size() < 2)
+    {
       return ranges;
     }
 
@@ -337,36 +350,66 @@ public class MapList
     List<int[]> merged = new ArrayList<int[]>();
     int[] lastRange = ranges.get(0);
     int lastDirection = lastRange[1] >= lastRange[0] ? 1 : -1;
+    lastRange = new int[] { lastRange[0], lastRange[1] };
     merged.add(lastRange);
-    
-    for (int[] range : ranges)
+    boolean first = true;
+
+    for (final int[] range : ranges)
     {
-      if (range == lastRange)
+      if (first)
       {
+        first = false;
         continue;
       }
+      if (range[0] == lastRange[0] && range[1] == lastRange[1])
+      {
+        // drop duplicate range
+        changed = true;
+        continue;
+      }
+
+      /*
+       * drop this range if it lies within the last range
+       */
+      if ((lastDirection == 1 && range[0] >= lastRange[0]
+              && range[0] <= lastRange[1] && range[1] >= lastRange[0]
+              && range[1] <= lastRange[1])
+              || (lastDirection == -1 && range[0] <= lastRange[0]
+                      && range[0] >= lastRange[1]
+                      && range[1] <= lastRange[0]
+                      && range[1] >= lastRange[1]))
+      {
+        changed = true;
+        continue;
+      }
+
       int direction = range[1] >= range[0] ? 1 : -1;
 
       /*
        * if next range is in the same direction as last and contiguous,
        * just update the end position of the last range
        */
-      if ((range[1] == range[0] || direction == lastDirection)
-              && (range[0] == lastRange[1] || range[0] == lastRange[1]
-                      + lastDirection))
+      boolean sameDirection = range[1] == range[0]
+              || direction == lastDirection;
+      boolean extending = range[0] == lastRange[1] + lastDirection;
+      boolean overlapping = (lastDirection == 1 && range[0] >= lastRange[0]
+              && range[0] <= lastRange[1])
+              || (lastDirection == -1 && range[0] <= lastRange[0]
+                      && range[0] >= lastRange[1]);
+      if (sameDirection && (overlapping || extending))
       {
         lastRange[1] = range[1];
         changed = true;
       }
       else
       {
-        merged.add(range);
-        lastRange = range;
+        lastRange = new int[] { range[0], range[1] };
+        merged.add(lastRange);
         // careful: merging [5, 5] after [7, 6] should keep negative direction
         lastDirection = (range[1] == range[0]) ? lastDirection : direction;
       }
     }
-    
+
     return changed ? merged : ranges;
   }
 
@@ -921,15 +964,17 @@ public class MapList
     // TODO not used - remove?
     if (local)
     {
-      return ((getFromLowest() >= map.getFromLowest() && getFromHighest() <= map
-              .getFromHighest()) || (getFromLowest() <= map.getFromLowest() && getFromHighest() >= map
-              .getFromHighest()));
+      return ((getFromLowest() >= map.getFromLowest()
+              && getFromHighest() <= map.getFromHighest())
+              || (getFromLowest() <= map.getFromLowest()
+                      && getFromHighest() >= map.getFromHighest()));
     }
     else
     {
-      return ((getToLowest() >= map.getToLowest() && getToHighest() <= map
-              .getToHighest()) || (getToLowest() <= map.getToLowest() && getToHighest() >= map
-              .getToHighest()));
+      return ((getToLowest() >= map.getToLowest()
+              && getToHighest() <= map.getToHighest())
+              || (getToLowest() <= map.getToLowest()
+                      && getToHighest() >= map.getToHighest()));
     }
   }
 
@@ -945,7 +990,9 @@ public class MapList
     {
       sb.append(" ").append(Arrays.toString(shift));
     }
-    sb.append(" ] To [");
+    sb.append(" ] ");
+    sb.append(fromRatio).append(":").append(toRatio);
+    sb.append(" to [");
     for (int[] shift : toShifts)
     {
       sb.append(" ").append(Arrays.toString(shift));
@@ -963,6 +1010,10 @@ public class MapList
    */
   public void addMapList(MapList map)
   {
+    if (this.equals(map))
+    {
+      return;
+    }
     this.fromLowest = Math.min(fromLowest, map.fromLowest);
     this.toLowest = Math.min(toLowest, map.toLowest);
     this.fromHighest = Math.max(fromHighest, map.fromHighest);
@@ -978,7 +1029,14 @@ public class MapList
     }
   }
 
-  public static void addRange(int[] range, List<int[]> addTo)
+  /**
+   * Adds the given range to a list of ranges. If the new range just extends
+   * existing ranges, the current endpoint is updated instead.
+   * 
+   * @param range
+   * @param addTo
+   */
+  static void addRange(int[] range, List<int[]> addTo)
   {
     /*
      * list is empty - add to it!
@@ -1051,4 +1109,15 @@ public class MapList
     }
     return forwardStrand;
   }
+
+  /**
+   * 
+   * @return true if from, or to is a three to 1 mapping
+   */
+  public boolean isTripletMap()
+  {
+    return (toRatio == 3 && fromRatio == 1)
+            || (fromRatio == 3 && toRatio == 1);
+  }
+
 }