2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.rbvi.chimera;
23 import jalview.util.IntRangeComparator;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.List;
30 import java.util.TreeMap;
33 * A class to model a Chimera atomspec pattern, for example
36 * #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
41 * <li>#0 is a model number</li>
42 * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
43 * <li>.A is a chain identifier</li>
44 * <li>residue ranges are separated by comma</li>
45 * <li>atomspecs for distinct models are separated by | (or)</li>
49 * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
52 public class AtomSpecModel
54 private Map<Integer, Map<String, List<int[]>>> atomSpec;
59 public AtomSpecModel()
61 atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
65 * Adds one contiguous range to this atom spec
72 public void addRange(int model, int startPos, int endPos, String chain)
75 * Get/initialize map of data for the colour and model
77 Map<String, List<int[]>> modelData = atomSpec.get(model);
78 if (modelData == null)
80 atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
84 * Get/initialize map of data for colour, model and chain
86 List<int[]> chainData = modelData.get(chain);
87 if (chainData == null)
89 chainData = new ArrayList<int[]>();
90 modelData.put(chain, chainData);
94 * Add the start/end positions
96 chainData.add(new int[] { startPos, endPos });
97 // TODO add intelligently, using a RangeList class
101 * Returns the range(s) formatted as a Chimera atomspec
105 public String getAtomSpec()
107 StringBuilder sb = new StringBuilder(128);
108 boolean firstModel = true;
109 for (Integer model : atomSpec.keySet())
116 sb.append("#").append(model).append(":");
118 boolean firstPositionForModel = true;
119 final Map<String, List<int[]>> modelData = atomSpec.get(model);
121 for (String chain : modelData.keySet())
123 chain = chain.trim();
125 List<int[]> rangeList = modelData.get(chain);
128 * sort ranges into ascending start position order
130 Collections.sort(rangeList, IntRangeComparator.ASCENDING);
132 int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
133 int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
135 Iterator<int[]> iterator = rangeList.iterator();
136 while (iterator.hasNext())
138 int[] range = iterator.next();
139 if (range[0] <= end + 1)
142 * range overlaps or is contiguous with the last one
143 * - so just extend the end position, and carry on
144 * (unless this is the last in the list)
146 end = Math.max(end, range[1]);
151 * we have a break so append the last range
153 appendRange(sb, start, end, chain, firstPositionForModel);
154 firstPositionForModel = false;
161 * and append the last range
163 if (!rangeList.isEmpty())
165 appendRange(sb, start, end, chain, firstPositionForModel);
166 firstPositionForModel = false;
170 return sb.toString();
178 * @param firstPositionForModel
180 protected void appendRange(StringBuilder sb, int start, int end,
181 String chain, boolean firstPositionForModel)
183 if (!firstPositionForModel)
193 sb.append(start).append("-").append(end);
195 if (chain.length() > 0)
197 sb.append(".").append(chain);