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 + * + * + *
+ * @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); + } + } +}