update author list in license for (JAL-826)
[jalview.git] / src / jalview / datamodel / CigarArray.java
index 33e91a8..dea0d72 100644 (file)
@@ -1,35 +1,62 @@
+/*\r
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
+ * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
+ * \r
+ * This file is part of Jalview.\r
+ * \r
+ * Jalview is free software: you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License \r
+ * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
+ * \r
+ * Jalview is distributed in the hope that it will be useful, but \r
+ * WITHOUT ANY WARRANTY; without even the implied warranty \r
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
+ * PURPOSE.  See the GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
 package jalview.datamodel;\r
 \r
+import java.util.Vector;\r
+\r
 public class CigarArray extends CigarBase\r
 {\r
-    /**\r
-     * Do CIGAR operations on a set of sequences from many other cigars\r
-     * BAD THINGS WILL HAPPEN IF A CIGARARRAY IS PASSED TO A CIGARARRAY\r
-     * or a CIGARCIGAR is given a CIGARARRAY to insert gaps into.\r
-     */\r
-    /**\r
-     * array of subject cigars\r
-     */\r
-    public CigarSimple refCigars[]=null;\r
-    private boolean seqcigararray=false;\r
-  private CigarArray() {\r
+  /**\r
+   * Do CIGAR operations on a set of sequences from many other cigars BAD THINGS\r
+   * WILL HAPPEN IF A CIGARARRAY IS PASSED TO A CIGARARRAY or a CIGARCIGAR is\r
+   * given a CIGARARRAY to insert gaps into.\r
+   */\r
+  /**\r
+   * array of subject cigars\r
+   */\r
+  public CigarSimple refCigars[] = null;\r
+\r
+  private boolean seqcigararray = false;\r
+\r
+  private CigarArray()\r
+  {\r
     super();\r
   }\r
 \r
   /**\r
    * isSeqCigarArray()\r
+   * \r
    * @return boolean true if all refCigars resolve to a SeqCigar or a CigarCigar\r
    */\r
   public boolean isSeqCigarArray()\r
   {\r
     return seqcigararray;\r
   }\r
+\r
   /**\r
-   * Apply CIGAR operations to several cigars in parallel\r
-   * will throw an error if any of cigar are actually CigarArrays.\r
-   * @param cigar Cigar[]\r
+   * Apply CIGAR operations to several cigars in parallel will throw an error if\r
+   * any of cigar are actually CigarArrays.\r
+   * \r
+   * @param cigar\r
+   *          Cigar[]\r
    */\r
-  public CigarArray(CigarSimple[] cigars) {\r
+  public CigarArray(CigarSimple[] cigars)\r
+  {\r
     super();\r
     seqcigararray = true;\r
     if (cigars != null && cigars.length > 0)\r
@@ -38,151 +65,315 @@ public class CigarArray extends CigarBase
       for (int c = 0; c < cigars.length; c++)\r
       {\r
         refCigars[c] = cigars[c];\r
-        if (! ( (cigars[c] instanceof SeqCigar)\r
-               || cigars[c] instanceof CigarCigar))\r
+        if (!((cigars[c] instanceof SeqCigar) || cigars[c] instanceof CigarCigar))\r
         {\r
           seqcigararray = false;\r
         }\r
       }\r
     }\r
   }\r
+\r
+  /**\r
+   * construct a cigar array from the current alignment, or just the subset of the current alignment specified by selectionGroup. Any columns marked as hidden in columnSelection will be marked as deleted in the array.\r
+   * @param alignment\r
+   * @param columnSelection \r
+   * @param selectionGroup\r
+   */\r
+  public CigarArray(AlignmentI alignment, ColumnSelection columnSelection, SequenceGroup selectionGroup)\r
+  {\r
+    this(constructSeqCigarArray(alignment, selectionGroup));\r
+    constructFromAlignment(alignment, columnSelection!=null ? columnSelection.getHiddenColumns() : null, selectionGroup);\r
+  }\r
+  private static int[] _calcStartEndBounds(AlignmentI alignment, SequenceGroup selectionGroup)\r
+  {\r
+    int[] startend = new int[] { 0,0,0};\r
+    if (selectionGroup != null)\r
+    {\r
+      startend[0] = selectionGroup.getSize();\r
+      startend[1] = selectionGroup.getStartRes();\r
+      startend[2] = selectionGroup.getEndRes(); // inclusive for start and end in\r
+      // SeqCigar constructor\r
+    }\r
+    else\r
+    {\r
+      startend[0] = alignment.getHeight();\r
+      startend[2] = alignment.getWidth() - 1;\r
+    }\r
+    return startend;\r
+  }\r
+  public static SeqCigar[] constructSeqCigarArray(AlignmentI alignment, SequenceGroup selectionGroup)\r
+  {\r
+    SequenceI[] seqs = null;\r
+    int i, iSize;\r
+    int _startend[] = _calcStartEndBounds(alignment, selectionGroup);\r
+    int start = _startend[1],end=_startend[2];\r
+    if (selectionGroup != null)\r
+    {\r
+      iSize = selectionGroup.getSize();\r
+      seqs = selectionGroup.getSequencesInOrder(alignment);\r
+      start = selectionGroup.getStartRes();\r
+      end = selectionGroup.getEndRes(); // inclusive for start and end in\r
+      // SeqCigar constructor\r
+    }\r
+    else\r
+    {\r
+      iSize = alignment.getHeight();\r
+      seqs = alignment.getSequencesArray();\r
+      end = alignment.getWidth() - 1;\r
+    }\r
+    SeqCigar[] selseqs = new SeqCigar[iSize];\r
+    for (i = 0; i < iSize; i++)\r
+    {\r
+      selseqs[i] = new SeqCigar(seqs[i], start, end);\r
+    }\r
+    return selseqs;\r
+  }\r
+  /**\r
+   * internal constructor function - called by CigarArray(AlignmentI, ...);\r
+   * @param alignment\r
+   * @param columnSelection - vector of visible regions as returned from columnSelection.getHiddenColumns() \r
+   * @param selectionGroup\r
+   */\r
+  private void constructFromAlignment(AlignmentI alignment, Vector columnSelection, SequenceGroup selectionGroup)\r
+  {\r
+    int[] _startend = _calcStartEndBounds(alignment, selectionGroup);\r
+    int start = _startend[1],end=_startend[2];\r
+    // now construct the CigarArray operations\r
+    if (columnSelection!=null)\r
+    {\r
+      int[] region;\r
+      int hideStart, hideEnd;\r
+      int last = start;\r
+      for (int j = 0; last < end & j < columnSelection.size(); j++)\r
+      {\r
+        region = (int[]) columnSelection.elementAt(j);\r
+        hideStart = region[0];\r
+        hideEnd = region[1];\r
+        // edit hidden regions to selection range\r
+        if (hideStart < last)\r
+        {\r
+          if (hideEnd > last)\r
+          {\r
+            hideStart = last;\r
+          }\r
+          else\r
+          {\r
+            continue;\r
+          }\r
+        }\r
+\r
+        if (hideStart > end)\r
+        {\r
+          break;\r
+        }\r
+\r
+        if (hideEnd > end)\r
+        {\r
+          hideEnd = end;\r
+        }\r
+\r
+        if (hideStart > hideEnd)\r
+        {\r
+          break;\r
+        }\r
+        /**\r
+         * form operations...\r
+         */\r
+        if (last < hideStart)\r
+        {\r
+          addOperation(CigarArray.M, hideStart - last);\r
+        }\r
+        addOperation(CigarArray.D, 1 + hideEnd - hideStart);\r
+        last = hideEnd + 1;\r
+      }\r
+      // Final match if necessary.\r
+      if (last < end)\r
+      {\r
+        addOperation(CigarArray.M, end - last + 1);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      addOperation(CigarArray.M, end - start + 1);\r
+    }\r
+  }\r
+\r
   /**\r
    * @see Cigar.getSequenceAndDeletions\r
-   * @param GapChar char\r
+   * @param GapChar\r
+   *          char\r
    * @return Object[][]\r
    */\r
-  protected Object[][] getArrayofSequenceAndDeletions(char GapChar) {\r
-      if (refCigars == null || refCigars.length == 0 || length == 0) {\r
-        return null;\r
+  protected Object[][] getArrayofSequenceAndDeletions(char GapChar)\r
+  {\r
+    if (refCigars == null || refCigars.length == 0 || length == 0)\r
+    {\r
+      return null;\r
+    }\r
+    Object[][] sqanddels = new Object[refCigars.length][];\r
+    for (int c = 0; c < refCigars.length; c++)\r
+    {\r
+      String refString = refCigars[c].getSequenceString(GapChar);\r
+      if (refString != null)\r
+      {\r
+        sqanddels[c] = getSequenceAndDeletions(refString, GapChar);\r
       }\r
-      Object[][] sqanddels = new Object[refCigars.length][];\r
-      for (int c=0; c<refCigars.length; c++) {\r
-        String refString = refCigars[c].getSequenceString(GapChar);\r
-        if (refString != null)\r
-        {\r
-          sqanddels[c] = getSequenceAndDeletions(refString, GapChar);\r
-        } else {\r
-          sqanddels[c] = null;\r
-        }\r
+      else\r
+      {\r
+        sqanddels[c] = null;\r
       }\r
-      return sqanddels;\r
     }\r
+    return sqanddels;\r
+  }\r
+\r
   /**\r
    * NOTE: this is an improper sequence string function\r
-   * @return String formed by newline concatenated results of applying CIGAR operations to each reference object in turn.\r
-   * @param GapChar char\r
+   * \r
+   * @return String formed by newline concatenated results of applying CIGAR\r
+   *         operations to each reference object in turn.\r
+   * @param GapChar\r
+   *          char\r
    * @return '\n' separated strings (empty results included as \n\n)\r
    */\r
   public String getSequenceString(char GapChar)\r
   {\r
-    if (length==0 || refCigars==null)\r
+    if (length == 0 || refCigars == null)\r
+    {\r
       return "";\r
+    }\r
     StringBuffer seqStrings = new StringBuffer();\r
     Object[][] sqanddels = getArrayofSequenceAndDeletions(GapChar);\r
-    for (int c=0; c<refCigars.length; c++) {\r
-      if (sqanddels[c]!=null) {\r
-        seqStrings.append( (String) sqanddels[c][0]);\r
+    for (int c = 0; c < refCigars.length; c++)\r
+    {\r
+      if (sqanddels[c] != null)\r
+      {\r
+        seqStrings.append((String) sqanddels[c][0]);\r
         sqanddels[c][0] = null;\r
       }\r
       seqStrings.append('\n');\r
     }\r
     return seqStrings.toString();\r
   }\r
+\r
   /**\r
    * return string results of applying cigar string to all reference cigars\r
-   * @param GapChar char\r
+   * \r
+   * @param GapChar\r
+   *          char\r
    * @return String[]\r
    */\r
-  public String[] getSequenceStrings(char GapChar) {\r
+  public String[] getSequenceStrings(char GapChar)\r
+  {\r
 \r
-    if (length==0 || refCigars==null || refCigars.length==0)\r
+    if (length == 0 || refCigars == null || refCigars.length == 0)\r
+    {\r
       return null;\r
+    }\r
     Object[][] sqanddels = getArrayofSequenceAndDeletions(GapChar);\r
     String[] seqs = new String[sqanddels.length];\r
-    for (int c=0; c<refCigars.length; c++) {\r
+    for (int c = 0; c < refCigars.length; c++)\r
+    {\r
       seqs[c] = (String) sqanddels[c][0];\r
     }\r
     return seqs;\r
   }\r
+\r
   /**\r
    * Combines the CigarArray cigar operations with the operations in each\r
    * reference cigar - creating a new reference cigar\r
+   * \r
    * @return Cigar[]\r
-\r
-  public CigarBase[] getEditedCigars() {\r
-\r
-    return new CigarBase[] {};\r
-  }\r
-*/\r
+   * \r
+   *         public CigarBase[] getEditedCigars() {\r
+   * \r
+   *         return new CigarBase[] {}; }\r
+   */\r
   /**\r
-   * applyDeletions\r
-   * edits underlying refCigars to propagate deleted regions, and removes deletion\r
-   * operations from CigarArray operation list.\r
-   * @return int[] position after deletion occured and range of deletion in cigarArray or null if none occured\r
+   * applyDeletions edits underlying refCigars to propagate deleted regions, and\r
+   * removes deletion operations from CigarArray operation list.\r
+   * \r
+   * @return int[] position after deletion occured and range of deletion in\r
+   *         cigarArray or null if none occured\r
    */\r
   public int[] applyDeletions()\r
   {\r
-    java.util.Vector delpos=null;\r
-    if (length==0)\r
+    java.util.Vector delpos = null;\r
+    if (length == 0)\r
+    {\r
       return null;\r
-    int cursor=0; // range counter for deletions\r
-    int vcursor=0; // visible column index\r
-    int offset=0; // shift in visible column index as deletions are made\r
-    int i=0;\r
-    while (i<length) {\r
-      if (operation[i]!=D) {\r
-        if (operation[i]==M)\r
-          cursor+=range[i];\r
-        vcursor+=range[i++];\r
+    }\r
+    int cursor = 0; // range counter for deletions\r
+    int vcursor = 0; // visible column index\r
+    int offset = 0; // shift in visible column index as deletions are made\r
+    int i = 0;\r
+    while (i < length)\r
+    {\r
+      if (operation[i] != D)\r
+      {\r
+        if (operation[i] == M)\r
+        {\r
+          cursor += range[i];\r
+        }\r
+        vcursor += range[i++];\r
       }\r
       else\r
       {\r
-        if (delpos==null)\r
-          delpos=new java.util.Vector();\r
-        int delstart=cursor, delend=cursor+range[i]-1; // inclusive\r
-        delpos.addElement(new int[] { vcursor+offset, range[i]}); // index of right hand column after hidden region boundary\r
-        offset+=range[i]-1; // shift in visible column coordinates\r
-        System.arraycopy(operation, i+1, operation, i, length-i);\r
-        System.arraycopy(range, i+1, range, i, length-i);\r
+        if (delpos == null)\r
+        {\r
+          delpos = new java.util.Vector();\r
+        }\r
+        int delstart = cursor, delend = cursor + range[i] - 1; // inclusive\r
+        delpos.addElement(new int[]\r
+        { vcursor + offset, range[i] }); // index of right hand column after\r
+        // hidden region boundary\r
+        offset += range[i] - 1; // shift in visible column coordinates\r
+        System.arraycopy(operation, i + 1, operation, i, length - i);\r
+        System.arraycopy(range, i + 1, range, i, length - i);\r
         length--;\r
-        /*        int dmax=0;\r
-         for (int s=0; s<refCigars.length; s++) {\r
-           int d = refCigars[s].deleteRange(delstart, delend);\r
-           if (d>dmax)\r
-             dmax=d;\r
-         }\r
-         offset+=dmax; // shift in visible column coordinates\r
+        /*\r
+         * int dmax=0; for (int s=0; s<refCigars.length; s++) { int d =\r
+         * refCigars[s].deleteRange(delstart, delend); if (d>dmax) dmax=d; }\r
+         * offset+=dmax; // shift in visible column coordinates\r
          */\r
-        for (int s=0; s<refCigars.length; s++) {\r
+        for (int s = 0; s < refCigars.length; s++)\r
+        {\r
           int d = refCigars[s].deleteRange(delstart, delend);\r
         }\r
 \r
       }\r
     }\r
-    if (delpos!=null)\r
+    if (delpos != null)\r
     {\r
-      int[] pos=new int[delpos.size()*2];\r
-      for (int k = 0, l = delpos.size(); k < l; k++) {\r
+      int[] pos = new int[delpos.size() * 2];\r
+      for (int k = 0, l = delpos.size(); k < l; k++)\r
+      {\r
         int[] dr = ((int[]) delpos.elementAt(k));\r
-        pos[k*2] = dr[0];\r
-        pos[k*2+1] = dr[1];\r
-        delpos.setElementAt(null,k);\r
+        pos[k * 2] = dr[0];\r
+        pos[k * 2 + 1] = dr[1];\r
+        delpos.setElementAt(null, k);\r
       }\r
-      delpos=null;\r
+      delpos = null;\r
       return pos;\r
     }\r
     return null;\r
   }\r
+\r
   /**\r
-   *\r
-   * @return SeqCigar[] or null if CigarArray is not a SeqCigarArray (ie it does not resolve to set of seqCigars)\r
+   * \r
+   * @return SeqCigar[] or null if CigarArray is not a SeqCigarArray (ie it does\r
+   *         not resolve to set of seqCigars)\r
    */\r
-  public SeqCigar[] getSeqCigarArray() {\r
+  public SeqCigar[] getSeqCigarArray()\r
+  {\r
     if (!isSeqCigarArray())\r
+    {\r
       return null;\r
+    }\r
     SeqCigar[] sa = new SeqCigar[refCigars.length];\r
-    for (int i=0; i<refCigars.length; i++)\r
+    for (int i = 0; i < refCigars.length; i++)\r
+    {\r
       sa[i] = (SeqCigar) refCigars[i];\r
+    }\r
     return sa;\r
   }\r
 }\r