JAL-2422 basic proof of concept of ChimeraX opened/coloured by Jalview
[jalview.git] / src / jalview / ext / rbvi / chimera / AtomSpecModel.java
index 39d6704..a72844e 100644 (file)
@@ -58,7 +58,7 @@ public class AtomSpecModel
    */
   public AtomSpecModel()
   {
-    atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+    atomSpec = new TreeMap<>();
   }
 
   /**
@@ -77,7 +77,7 @@ public class AtomSpecModel
     Map<String, List<int[]>> modelData = atomSpec.get(model);
     if (modelData == null)
     {
-      atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+      atomSpec.put(model, modelData = new TreeMap<>());
     }
 
     /*
@@ -86,7 +86,7 @@ public class AtomSpecModel
     List<int[]> chainData = modelData.get(chain);
     if (chainData == null)
     {
-      chainData = new ArrayList<int[]>();
+      chainData = new ArrayList<>();
       modelData.put(chain, chainData);
     }
 
@@ -150,7 +150,8 @@ public class AtomSpecModel
             /*
              * we have a break so append the last range
              */
-            appendRange(sb, start, end, chain, firstPositionForModel);
+            appendRange(sb, start, end, chain, firstPositionForModel,
+                    false);
             firstPositionForModel = false;
             start = range[0];
             end = range[1];
@@ -162,7 +163,7 @@ public class AtomSpecModel
          */
         if (!rangeList.isEmpty())
         {
-          appendRange(sb, start, end, chain, firstPositionForModel);
+          appendRange(sb, start, end, chain, firstPositionForModel, false);
           firstPositionForModel = false;
         }
       }
@@ -178,7 +179,7 @@ public class AtomSpecModel
    * @param firstPositionForModel
    */
   protected void appendRange(StringBuilder sb, int start, int end,
-          String chain, boolean firstPositionForModel)
+          String chain, boolean firstPositionForModel, boolean isChimeraX)
   {
     if (!firstPositionForModel)
     {
@@ -193,9 +194,88 @@ public class AtomSpecModel
       sb.append(start).append("-").append(end);
     }
 
-    sb.append(".");
-    if (!" ".equals(chain)) {
-      sb.append(chain);
+    if (!isChimeraX)
+    {
+      sb.append(".");
+      if (!" ".equals(chain))
+      {
+        sb.append(chain);
+      }
     }
   }
+
+  /**
+   * Returns the range(s) formatted as a ChimeraX atomspec, for example
+   * <p>
+   * #1/A:2-20,30-40/B:10-20|#2/A:12-30
+   * 
+   * @return
+   */
+  public String getAtomSpecX()
+  {
+    StringBuilder sb = new StringBuilder(128);
+    boolean firstModel = true;
+    for (Integer model : atomSpec.keySet())
+    {
+      if (!firstModel)
+      {
+        sb.append("|");
+      }
+      firstModel = false;
+      sb.append("#").append(model);
+  
+      final Map<String, List<int[]>> modelData = atomSpec.get(model);
+  
+      for (String chain : modelData.keySet())
+      {
+        boolean firstPositionForChain = true;
+        chain = " ".equals(chain) ? chain : chain.trim();
+        sb.append("/").append(chain).append(":");
+        List<int[]> rangeList = modelData.get(chain);
+  
+        /*
+         * sort ranges into ascending start position order
+         */
+        Collections.sort(rangeList, IntRangeComparator.ASCENDING);
+  
+        int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+        int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+  
+        Iterator<int[]> iterator = rangeList.iterator();
+        while (iterator.hasNext())
+        {
+          int[] range = iterator.next();
+          if (range[0] <= end + 1)
+          {
+            /*
+             * range overlaps or is contiguous with the last one
+             * - so just extend the end position, and carry on
+             * (unless this is the last in the list)
+             */
+            end = Math.max(end, range[1]);
+          }
+          else
+          {
+            /*
+             * we have a break so append the last range
+             */
+            appendRange(sb, start, end, chain, firstPositionForChain, true);
+            start = range[0];
+            end = range[1];
+            firstPositionForChain = false;
+          }
+        }
+  
+        /*
+         * and append the last range
+         */
+        if (!rangeList.isEmpty())
+        {
+          appendRange(sb, start, end, chain, firstPositionForChain, true);
+        }
+        firstPositionForChain = false;
+      }
+    }
+    return sb.toString();
+  }
 }