1 package jalview.ext.rbvi.chimera;
3 import jalview.util.IntRangeComparator;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Iterator;
10 import java.util.TreeMap;
13 * A class to model a Chimera atomspec pattern, for example
16 * #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
21 * <li>#0 is a model number</li>
22 * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
23 * <li>.A is a chain identifier</li>
24 * <li>residue ranges are separated by comma</li>
25 * <li>atomspecs for distinct models are separated by | (or)</li>
29 * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
32 public class AtomSpecModel
34 private Map<Integer, Map<String, List<int[]>>> atomSpec;
39 public AtomSpecModel()
41 atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
45 * Adds one contiguous range to this atom spec
52 public void addRange(int model, int startPos, int endPos, String chain)
55 * Get/initialize map of data for the colour and model
57 Map<String, List<int[]>> modelData = atomSpec.get(model);
58 if (modelData == null)
60 atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
64 * Get/initialize map of data for colour, model and chain
66 List<int[]> chainData = modelData.get(chain);
67 if (chainData == null)
69 chainData = new ArrayList<int[]>();
70 modelData.put(chain, chainData);
74 * Add the start/end positions
76 chainData.add(new int[] { startPos, endPos });
77 // TODO add intelligently, using a RangeList class
81 * Returns the range(s) formatted as a Chimera atomspec
85 public String getAtomSpec()
87 StringBuilder sb = new StringBuilder(128);
88 boolean firstModel = true;
89 for (Integer model : atomSpec.keySet())
96 sb.append("#").append(model).append(":");
98 boolean firstPositionForModel = true;
99 final Map<String, List<int[]>> modelData = atomSpec.get(model);
101 for (String chain : modelData.keySet())
103 chain = chain.trim();
105 List<int[]> rangeList = modelData.get(chain);
108 * sort ranges into ascending start position order
110 Collections.sort(rangeList, IntRangeComparator.ASCENDING);
112 int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
113 int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
115 Iterator<int[]> iterator = rangeList.iterator();
116 while (iterator.hasNext())
118 int[] range = iterator.next();
119 if (range[0] <= end + 1)
122 * range overlaps or is contiguous with the last one
123 * - so just extend the end position, and carry on
124 * (unless this is the last in the list)
126 end = Math.max(end, range[1]);
131 * we have a break so append the last range
133 appendRange(sb, start, end, chain, firstPositionForModel);
134 firstPositionForModel = false;
141 * and append the last range
143 if (!rangeList.isEmpty())
145 appendRange(sb, start, end, chain, firstPositionForModel);
146 firstPositionForModel = false;
150 return sb.toString();
158 * @param firstPositionForModel
160 protected void appendRange(StringBuilder sb, int start, int end,
161 String chain, boolean firstPositionForModel)
163 if (!firstPositionForModel)
173 sb.append(start).append("-").append(end);
175 if (chain.length() > 0)
177 sb.append(".").append(chain);