/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.ext.rbvi.chimera; import jalview.util.IntRangeComparator; 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 = " ".equals(chain) ? chain : chain.trim(); List 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 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); } sb.append("."); if (!" ".equals(chain)) { sb.append(chain); } } }