X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fext%2Frbvi%2Fchimera%2FAtomSpecModel.java;fp=src%2Fjalview%2Fext%2Frbvi%2Fchimera%2FAtomSpecModel.java;h=d62cc3c695922b5cdc65793e2f16b1fdd7150664;hb=2595e9d4ee0dbbd3406a98c4e49a61ccde806479;hp=0000000000000000000000000000000000000000;hpb=e20075ba805d744d7cc4976e2b8d5e5840fb0a8d;p=jalview.git
diff --git a/src/jalview/ext/rbvi/chimera/AtomSpecModel.java b/src/jalview/ext/rbvi/chimera/AtomSpecModel.java
new file mode 100644
index 0000000..d62cc3c
--- /dev/null
+++ b/src/jalview/ext/rbvi/chimera/AtomSpecModel.java
@@ -0,0 +1,180 @@
+package jalview.ext.rbvi.chimera;
+
+import jalview.util.RangeComparator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class to model a Chimera atomspec pattern, for example
+ *
+ *
+ * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
+ *
+ *
+ * where
+ *
+ * - #0 is a model number
+ * - 15 or 70-72 is a residue number, or range of residue numbers
+ * - .A is a chain identifier
+ * - residue ranges are separated by comma
+ * - atomspecs for distinct models are separated by | (or)
+ *
+ *
+ *
+ * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ *
+ */
+public class AtomSpecModel
+{
+ private Map>> atomSpec;
+
+ /**
+ * Constructor
+ */
+ public AtomSpecModel()
+ {
+ atomSpec = new TreeMap>>();
+ }
+
+ /**
+ * Adds one contiguous range to this atom spec
+ *
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public void addRange(int model, int startPos, int endPos, String chain)
+ {
+ /*
+ * Get/initialize map of data for the colour and model
+ */
+ Map> modelData = atomSpec.get(model);
+ if (modelData == null)
+ {
+ atomSpec.put(model, modelData = new TreeMap>());
+ }
+
+ /*
+ * Get/initialize map of data for colour, model and chain
+ */
+ List chainData = modelData.get(chain);
+ if (chainData == null)
+ {
+ chainData = new ArrayList();
+ modelData.put(chain, chainData);
+ }
+
+ /*
+ * Add the start/end positions
+ */
+ chainData.add(new int[] { startPos, endPos });
+ // TODO add intelligently, using a RangeList class
+ }
+
+ /**
+ * Returns the range(s) formatted as a Chimera atomspec
+ *
+ * @return
+ */
+ public String getAtomSpec()
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.keySet())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ sb.append("#").append(model).append(":");
+
+ boolean firstPositionForModel = true;
+ final Map> modelData = atomSpec.get(model);
+
+ for (String chain : modelData.keySet())
+ {
+ chain = chain.trim();
+
+ List rangeList = modelData.get(chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, new RangeComparator(true));
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator 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, firstPositionForModel);
+ firstPositionForModel = false;
+ start = range[0];
+ end = range[1];
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @param sb
+ * @param start
+ * @param end
+ * @param chain
+ * @param firstPositionForModel
+ */
+ protected void appendRange(StringBuilder sb, int start, int end,
+ String chain, boolean firstPositionForModel)
+ {
+ if (!firstPositionForModel)
+ {
+ sb.append(",");
+ }
+ if (end == start)
+ {
+ sb.append(start);
+ }
+ else
+ {
+ sb.append(start).append("-").append(end);
+ }
+ if (chain.length() > 0)
+ {
+ sb.append(".").append(chain);
+ }
+ }
+}