+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ext.rbvi.chimera;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * A class to model a Chimera or Jmol residue set, as
- * {@code Map<modelNumber, Map<chainId, List<residueRange>>>}. This can then be
- * traversed to generate the required display command in Chimera or Jmol syntax.
- */
-public class AtomSpecModel
-{
- private Map<Integer, Map<String, List<int[]>>> atomSpec;
-
- /**
- * Constructor
- */
- public AtomSpecModel()
- {
- atomSpec = new TreeMap<>();
- }
-
- public Map<Integer, Map<String, List<int[]>>> getMap()
- {
- return atomSpec;
- }
-
- /**
- * 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<String, List<int[]>> modelData = atomSpec.get(model);
- if (modelData == null)
- {
- atomSpec.put(model, modelData = new TreeMap<>());
- }
-
- /*
- * Get/initialize map of data for colour, model and chain
- */
- List<int[]> 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
- }
-
- /**
- * Answers an iterable set of the structure models in this model
- *
- * @return
- */
- public Iterable<Integer> getModels()
- {
- return atomSpec.keySet();
- }
-
- /**
- * Answers an iterable set of the chains in this model for the given structure
- * model, or an empty set if none
- *
- * @param model
- * @return
- */
- public Iterable<String> getChains(Integer model)
- {
- if (atomSpec.containsKey(model))
- {
- return atomSpec.get(model).keySet();
- }
- return Collections.emptySet();
- }
-
- public List<int[]> getRanges(Integer model, String chain)
- {
- Map<String, List<int[]>> modelData = atomSpec.get(model);
- if (modelData != null)
- {
- List<int[]> chainData = modelData.get(chain);
- if (chainData != null)
- {
- return chainData;
- }
- }
- return Collections.EMPTY_LIST;
- }
-}
+++ /dev/null
-package jalview.util;
-
-import jalview.api.AlignViewportI;
-import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
-import jalview.api.SequenceRenderer;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.HiddenColumns;
-import jalview.datamodel.SequenceI;
-import jalview.ext.rbvi.chimera.AtomSpecModel;
-import jalview.renderer.seqfeatures.FeatureColourFinder;
-import jalview.structure.StructureMapping;
-import jalview.structures.models.AAStructureBindingModel;
-
-import java.awt.Color;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class with common methods for building commands for Jmol, Chimera, or other
- *
- * @author gmcarstairs
- */
-public abstract class StructureCommands
-{
-
- /**
- * Helper method to add one contiguous range to the AtomSpec model for the given
- * value (creating the model if necessary). As used by Jalview, {@code value} is
- * <ul>
- * <li>a colour, when building a 'colour structure by sequence' command</li>
- * <li>a feature value, when building a 'set Chimera attributes from features'
- * command</li>
- * </ul>
- *
- * @param map
- * @param value
- * @param model
- * @param startPos
- * @param endPos
- * @param chain
- */
- public static void addAtomSpecRange(Map<Object, AtomSpecModel> map,
- Object value,
- int model, int startPos, int endPos, String chain)
- {
- /*
- * Get/initialize map of data for the colour
- */
- AtomSpecModel atomSpec = map.get(value);
- if (atomSpec == null)
- {
- atomSpec = new AtomSpecModel();
- map.put(value, atomSpec);
- }
-
- atomSpec.addRange(model, startPos, endPos, chain);
- }
-
- /**
- * Build a data structure which records contiguous subsequences by colour, model
- * and chain. From this we can easily generate the Chimera or Jmol specific
- * selection expression.
- *
- * <pre>
- * Color
- * Model number
- * Chain
- * list of start/end ranges
- * </pre>
- *
- * Ordering is by order of addition (for colours and positions), natural
- * ordering (for models and chains)
- *
- * @param viewPanel
- * @return
- */
- public static Map<Object, AtomSpecModel> buildColoursMap(
- AAStructureBindingModel binding, AlignmentViewPanel viewPanel)
- {
- FeatureRenderer fr = viewPanel.getFeatureRenderer();
- FeatureColourFinder finder = new FeatureColourFinder(fr);
- AlignViewportI viewport = viewPanel.getAlignViewport();
- HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
- AlignmentI al = viewport.getAlignment();
- SequenceRenderer sr = binding.getSequenceRenderer(viewPanel);
- String[] files = binding.getStructureFiles();
- SequenceI[][] sequence = binding.getSequence();
-
- Map<Object, AtomSpecModel> colourMap = new LinkedHashMap<>();
- Color lastColour = null;
-
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- String fileName = files[pdbfnum];
- final int modelNumber = binding.getModelForPdbFile(fileName, pdbfnum);
- StructureMapping[] mapping = binding.getSsm()
- .getMapping(fileName);
-
- if (mapping == null || mapping.length < 1)
- {
- continue;
- }
-
- int startPos = -1, lastPos = -1;
- String lastChain = "";
- for (int s = 0; s < sequence[pdbfnum].length; s++)
- {
- for (int sp, m = 0; m < mapping.length; m++)
- {
- final SequenceI seq = sequence[pdbfnum][s];
- if (mapping[m].getSequence() == seq
- && (sp = al.findIndex(seq)) > -1)
- {
- SequenceI asp = al.getSequenceAt(sp);
- for (int r = 0; r < asp.getLength(); r++)
- {
- // no mapping to gaps in sequence
- if (Comparison.isGap(asp.getCharAt(r)))
- {
- continue;
- }
- int pos = mapping[m].getPDBResNum(asp.findPosition(r));
-
- if (pos < 1 || pos == lastPos)
- {
- continue;
- }
-
- Color colour = sr.getResidueColour(seq, r, finder);
-
- /*
- * hidden regions are shown gray or, optionally, ignored
- */
- if (!cs.isVisible(r))
- {
- if (binding.isHideHiddenRegions())
- {
- continue;
- }
- else
- {
- colour = Color.GRAY;
- }
- }
-
- final String chain = mapping[m].getChain();
-
- /*
- * Just keep incrementing the end position for this colour range
- * _unless_ colour, PDB model or chain has changed, or there is a
- * gap in the mapped residue sequence
- */
- final boolean newColour = !colour.equals(lastColour);
- final boolean nonContig = lastPos + 1 != pos;
- final boolean newChain = !chain.equals(lastChain);
- if (newColour || nonContig || newChain)
- {
- if (startPos != -1)
- {
- StructureCommands.addAtomSpecRange(colourMap, lastColour,
- modelNumber, startPos, lastPos, lastChain);
- }
- startPos = pos;
- }
- lastColour = colour;
- lastPos = pos;
- lastChain = chain;
- }
- // final colour range
- if (lastColour != null)
- {
- StructureCommands.addAtomSpecRange(colourMap, lastColour,
- modelNumber, startPos, lastPos, lastChain);
- }
- }
- }
- }
- }
- return colourMap;
- }
-
- /**
- * A helper method that takes a list of [start-end] ranges, format them as
- * s1-e1,s2-e2 etc and appends to the string buffer. Ranges are sorted, and
- * coalesced if they overlap. The chain token, if not null, is appended to each
- * resulting subrange.
- *
- * @param sb
- * @param rangeList
- * @param chainToken
- * @param firstPositionForModel
- */
- protected static void appendResidueRange(StringBuilder sb, List<int[]> rangeList,
- String chainToken, boolean firstPositionForModel)
- {
- /*
- * 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<int[]> 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, chainToken, firstPositionForModel);
- firstPositionForModel = false;
- start = range[0];
- end = range[1];
- }
- }
-
- /*
- * and append the last range
- */
- if (!rangeList.isEmpty())
- {
- appendRange(sb, start, end, chainToken, firstPositionForModel);
- }
- }
-
- /**
- * A helper method that appends one start-end range, and an (optional) chain
- * token to an atomspec (a null token is not appended)
- *
- * @param sb
- * @param start
- * @param end
- * @param chainToken
- * @param firstPositionForModel
- */
- protected static void appendRange(StringBuilder sb, int start, int end,
- String chainToken, boolean firstPositionForModel)
- {
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (end == start)
- {
- sb.append(start);
- }
- else
- {
- sb.append(start).append("-").append(end);
- }
- if (chainToken != null)
- {
- sb.append(chainToken);
- }
- }
-
-}