Merge branch 'features/JAL-2446NCList' into
[jalview.git] / src / jalview / datamodel / Sequence.java
index d7ac7a7..c53319e 100755 (executable)
@@ -31,9 +31,11 @@ import jalview.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Vector;
 
 import com.stevesoft.pat.Regex;
@@ -662,7 +664,7 @@ public class Sequence extends ASequence implements SequenceI
     // Rely on end being at least as long as the length of the sequence.
     while ((i < sequence.length) && (j <= end) && (j <= pos))
     {
-      if (!jalview.util.Comparison.isGap(sequence[i]))
+      if (!Comparison.isGap(sequence[i]))
       {
         j++;
       }
@@ -688,7 +690,7 @@ public class Sequence extends ASequence implements SequenceI
     int seqlen = sequence.length;
     while ((j < i) && (j < seqlen))
     {
-      if (!jalview.util.Comparison.isGap(sequence[j]))
+      if (!Comparison.isGap(sequence[j]))
       {
         pos++;
       }
@@ -783,6 +785,40 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
+  public BitSet getInsertionsAsBits()
+  {
+    BitSet map = new BitSet();
+    int lastj = -1, j = 0;
+    int pos = start;
+    int seqlen = sequence.length;
+    while ((j < seqlen))
+    {
+      if (jalview.util.Comparison.isGap(sequence[j]))
+      {
+        if (lastj == -1)
+        {
+          lastj = j;
+        }
+      }
+      else
+      {
+        if (lastj != -1)
+        {
+          map.set(lastj, j);
+          lastj = -1;
+        }
+      }
+      j++;
+    }
+    if (lastj != -1)
+    {
+      map.set(lastj, j);
+      lastj = -1;
+    }
+    return map;
+  }
+
+  @Override
   public void deleteChars(int i, int j)
   {
     int newstart = start, newend = end;
@@ -1443,13 +1479,55 @@ public class Sequence extends ASequence implements SequenceI
    * {@inheritDoc}
    */
   @Override
-  public List<SequenceFeature> findFeatures(int from, int to,
+  public List<SequenceFeature> findFeatures(int fromColumn, int toColumn,
           String... types)
   {
+    int startPos = findPosition(fromColumn - 1); // convert base 1 to base 0
+    int endPos = findPosition(toColumn - 1);
+
+    List<SequenceFeature> result = new ArrayList<>();
     if (datasetSequence != null)
     {
-      return datasetSequence.findFeatures(from, to, types);
+      result = datasetSequence.getFeatures().findFeatures(startPos, endPos,
+              types);
     }
-    return sequenceFeatureStore.findFeatures(from, to, types);
+    else
+    {
+      result = sequenceFeatureStore.findFeatures(startPos, endPos, types);
+    }
+
+    /*
+     * if the start or end column is gapped, startPos or endPos may be to the 
+     * left or right, and we may have included adjacent or enclosing features;
+     * remove any that are not enclosing, non-contact features
+     */
+    if (endPos > this.end || Comparison.isGap(sequence[fromColumn - 1])
+            || Comparison.isGap(sequence[toColumn - 1]))
+    {
+      ListIterator<SequenceFeature> it = result.listIterator();
+      while (it.hasNext())
+      {
+        SequenceFeature sf = it.next();
+        int featureStartColumn = findIndex(sf.getBegin());
+        int featureEndColumn = findIndex(sf.getEnd());
+        boolean noOverlap = featureStartColumn > toColumn
+                        || featureEndColumn < fromColumn;
+
+        /*
+         * reject an 'enclosing' feature if it is actually a contact feature
+         */
+        if (sf.isContactFeature() && featureStartColumn < fromColumn
+                && featureEndColumn > toColumn)
+        {
+          noOverlap = true;
+        }
+        if (noOverlap)
+        {
+          it.remove();
+        }
+      }
+    }
+
+    return result;
   }
 }