/*
* 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
* Chimera format: * #1.2:12-20.A model 1, submodel 2, chain A, atoms 12-20 ** * @param spec * @return * @throw IllegalArgumentException if the spec cannot be parsed, or represents * more than one residue * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html */ public static AtomSpec fromChimeraAtomspec(String spec) { int modelSeparatorPos = spec.indexOf(":"); if (modelSeparatorPos == -1) { throw new IllegalArgumentException(spec); } int hashPos = spec.indexOf("#"); if (hashPos == -1 && modelSeparatorPos != 0) { // # is missing but something precedes : - reject throw new IllegalArgumentException(spec); } String modelSubmodel = spec.substring(hashPos + 1, modelSeparatorPos); int modelId = 0; try { int subModelPos = modelSubmodel.indexOf("."); modelId = Integer.valueOf( subModelPos > 0 ? modelSubmodel.substring(0, subModelPos) : modelSubmodel); } catch (NumberFormatException e) { // ignore, default to model 0 } /* * now process what follows the model, either * Chimera: atoms.chain * ChimeraX: chain:atoms */ String atomsAndChain = spec.substring(modelSeparatorPos + 1); String[] tokens = atomsAndChain.split("\\."); String atoms = tokens.length == 1 ? atomsAndChain : (tokens[0]); int resNum = 0; try { resNum = Integer.parseInt(atoms); } catch (NumberFormatException e) { // could be a range e.g. #1:4-7.B throw new IllegalArgumentException(spec); } String chainId = tokens.length == 1 ? "" : (tokens[1]); return new AtomSpec(modelId, chainId, resNum, 0); } /** * Constructor * * @param pdbFile * @param chain * @param resNo * @param atomNo */ public AtomSpec(String pdbFile, String chain, int resNo, int atomNo) { this.pdbFile = pdbFile; this.chain = chain; this.pdbResNum = resNo; this.atomIndex = atomNo; } /** * Constructor * * @param modelId * @param chainId * @param resNo * @param atomNo */ public AtomSpec(int modelId, String chainId, int resNo, int atomNo) { this.modelNo = modelId; this.chain = chainId; this.pdbResNum = resNo; this.atomIndex = atomNo; } public String getPdbFile() { return pdbFile; } public String getChain() { return chain; } public int getPdbResNum() { return pdbResNum; } public int getAtomIndex() { return atomIndex; } public int getModelNumber() { return modelNo; } public void setPdbFile(String file) { pdbFile = file; } @Override public String toString() { return "pdbFile: " + pdbFile + ", chain: " + chain + ", res: " + pdbResNum + ", atom: " + atomIndex; } /** * Parses a ChimeraX atomspec to construct an AtomSpec model (with null pdb * file name) * *
* ChimeraX format: * #1.2/A:12-20 model 1, submodel 2, chain A, atoms 12-20 ** * @param spec * @return * @throw IllegalArgumentException if the spec cannot be parsed, or represents * more than one residue * @see http://rbvi.ucsf.edu/chimerax/docs/user/commands/atomspec.html */ public static AtomSpec fromChimeraXAtomspec(String spec) { int modelSeparatorPos = spec.indexOf("/"); if (modelSeparatorPos == -1) { throw new IllegalArgumentException(spec); } int hashPos = spec.indexOf("#"); if (hashPos == -1 && modelSeparatorPos != 0) { // # is missing but something precedes : - reject throw new IllegalArgumentException(spec); } String modelSubmodel = spec.substring(hashPos + 1, modelSeparatorPos); int modelId = 0; try { int subModelPos = modelSubmodel.indexOf("."); modelId = Integer.valueOf( subModelPos > 0 ? modelSubmodel.substring(0, subModelPos) : modelSubmodel); } catch (NumberFormatException e) { // ignore, default to model 0 } /* * now process what follows the model, either * Chimera: atoms.chain * ChimeraX: chain:atoms */ String atomsAndChain = spec.substring(modelSeparatorPos + 1); String[] tokens = atomsAndChain.split("\\:"); String atoms = tokens.length == 1 ? atomsAndChain : (tokens[1]); int resNum = 0; try { resNum = Integer.parseInt(atoms); } catch (NumberFormatException e) { // could be a range e.g. #1:4-7.B throw new IllegalArgumentException(spec); } String chainId = tokens.length == 1 ? "" : (tokens[0]); return new AtomSpec(modelId, chainId, resNum, 0); } }