JAL-3806 use the covers() test for each selected sequence and the complementary align...
[jalview.git] / src / jalview / util / MappingUtils.java
index 4e07a08..03a32c9 100644 (file)
@@ -29,16 +29,19 @@ import java.util.Map;
 
 import jalview.analysis.AlignmentSorter;
 import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
 import jalview.commands.OrderCommand;
 import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Mapping;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -78,7 +81,7 @@ public final class MappingUtils
       action = action.getUndoAction();
     }
     // TODO write this
-    System.err.println("MappingUtils.mapCutOrPaste not yet implemented");
+    Cache.log.error("MappingUtils.mapCutOrPaste not yet implemented");
   }
 
   /**
@@ -361,56 +364,51 @@ public final class MappingUtils
        */
       int startResiduePos = selected.findPosition(firstUngappedPos);
       int endResiduePos = selected.findPosition(lastUngappedPos);
-
-      for (AlignedCodonFrame acf : codonFrames)
+      for (SequenceI seq : mapTo.getAlignment().getSequences())
       {
-        SequenceI mappedSequence = targetIsNucleotide
-                ? acf.getDnaForAaSeq(selected)
-                : acf.getAaForDnaSeq(selected);
-        if (mappedSequence != null)
+        int mappedStartResidue = 0;
+        int mappedEndResidue = 0;
+        for (AlignedCodonFrame acf : codonFrames)
         {
-          for (SequenceI seq : mapTo.getAlignment().getSequences())
+          for (SequenceToSequenceMapping map: acf.getMappings())
+          {
+          if (map.covers(selected) && map.covers(seq))
           {
-            int mappedStartResidue = 0;
-            int mappedEndResidue = 0;
-            if (seq.getDatasetSequence() == mappedSequence)
+            /*
+             * Found a sequence mapping. Locate the start/end mapped residues.
+             */
+            List<AlignedCodonFrame> mapping = Arrays
+                    .asList(new AlignedCodonFrame[]
+                    { acf });
+            SearchResultsI sr = buildSearchResults(selected,
+                    startResiduePos, mapping);
+            for (SearchResultMatchI m : sr.getResults())
             {
-              /*
-               * Found a sequence mapping. Locate the start/end mapped residues.
-               */
-              List<AlignedCodonFrame> mapping = Arrays
-                      .asList(new AlignedCodonFrame[]
-                      { acf });
-              SearchResultsI sr = buildSearchResults(selected,
-                      startResiduePos, mapping);
-              for (SearchResultMatchI m : sr.getResults())
-              {
-                mappedStartResidue = m.getStart();
-                mappedEndResidue = m.getEnd();
-              }
-              sr = buildSearchResults(selected, endResiduePos, mapping);
-              for (SearchResultMatchI m : sr.getResults())
-              {
-                mappedStartResidue = Math.min(mappedStartResidue,
-                        m.getStart());
-                mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
-              }
-
-              /*
-               * Find the mapped aligned columns, save the range. Note findIndex
-               * returns a base 1 position, SequenceGroup uses base 0
-               */
-              int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
-              minStartCol = minStartCol == -1 ? mappedStartCol
-                      : Math.min(minStartCol, mappedStartCol);
-              int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
-              maxEndCol = maxEndCol == -1 ? mappedEndCol
-                      : Math.max(maxEndCol, mappedEndCol);
-              mappedGroup.addSequence(seq, false);
-              break;
+              mappedStartResidue = m.getStart();
+              mappedEndResidue = m.getEnd();
+            }
+            sr = buildSearchResults(selected, endResiduePos, mapping);
+            for (SearchResultMatchI m : sr.getResults())
+            {
+              mappedStartResidue = Math.min(mappedStartResidue,
+                      m.getStart());
+              mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
             }
+
+            /*
+             * Find the mapped aligned columns, save the range. Note findIndex
+             * returns a base 1 position, SequenceGroup uses base 0
+             */
+            int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
+            minStartCol = minStartCol == -1 ? mappedStartCol
+                    : Math.min(minStartCol, mappedStartCol);
+            int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
+            maxEndCol = maxEndCol == -1 ? mappedEndCol
+                    : Math.max(maxEndCol, mappedEndCol);
+            mappedGroup.addSequence(seq, false);
+            break;
           }
-        }
+        }}
       }
     }
     mappedGroup.setStartRes(minStartCol < 0 ? 0 : minStartCol);
@@ -835,7 +833,7 @@ public final class MappingUtils
     {
       if (range.length % 2 != 0)
       {
-        System.err.println(
+        Cache.log.error(
                 "Error unbalance start/end ranges: " + ranges.toString());
         return 0;
       }
@@ -991,7 +989,7 @@ public final class MappingUtils
         /*
          * not coded for [start1, end1, start2, end2, ...]
          */
-        System.err.println(
+        Cache.log.error(
                 "MappingUtils.removeEndPositions doesn't handle multiple  ranges");
         return;
       }
@@ -1002,7 +1000,7 @@ public final class MappingUtils
         /*
          * not coded for a reverse strand range (end < start)
          */
-        System.err.println(
+        Cache.log.error(
                 "MappingUtils.removeEndPositions doesn't handle reverse strand");
         return;
       }
@@ -1039,4 +1037,66 @@ public final class MappingUtils
     }
     return result;
   }
+
+  /*
+   * Returns the maximal start-end positions in the given (ordered) list of
+   * ranges which is overlapped by the given begin-end range, or null if there
+   * is no overlap.
+   * 
+   * <pre>
+   * Examples:
+   *   if ranges is {[4, 8], [10, 12], [16, 19]}
+   * then
+   *   findOverlap(ranges, 1, 20) == [4, 19]
+   *   findOverlap(ranges, 6, 11) == [6, 11]
+   *   findOverlap(ranges, 9, 15) == [10, 12]
+   *   findOverlap(ranges, 13, 15) == null
+   * </pre>
+   * 
+   * @param ranges
+   * @param begin
+   * @param end
+   * @return
+   */
+  protected static int[] findOverlap(List<int[]> ranges, final int begin,
+          final int end)
+  {
+    boolean foundStart = false;
+    int from = 0;
+    int to = 0;
+
+    /*
+     * traverse the ranges to find the first position (if any) >= begin,
+     * and the last position (if any) <= end
+     */
+    for (int[] range : ranges)
+    {
+      if (!foundStart)
+      {
+        if (range[0] >= begin)
+        {
+          /*
+           * first range that starts with, or follows, begin
+           */
+          foundStart = true;
+          from = Math.max(range[0], begin);
+        }
+        else if (range[1] >= begin)
+        {
+          /*
+           * first range that contains begin
+           */
+          foundStart = true;
+          from = begin;
+        }
+      }
+
+      if (range[0] <= end)
+      {
+        to = Math.min(end, range[1]);
+      }
+    }
+
+    return foundStart && to >= from ? new int[] { from, to } : null;
+  }
 }