3 * Copyright (c) 2006 The Regents of the University of California.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions, and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 * 3. Redistributions must acknowledge that this software was
16 * originally developed by the UCSF Computer Graphics Laboratory
17 * under support by the NIH National Center for Research Resources,
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package ext.edu.ucsf.rbvi.strucviz2;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
40 import org.slf4j.LoggerFactory;
43 * This class provides the implementation for the ChimeraResidue, object
49 public class ChimeraResidue implements ChimeraStructuralObject, Comparable<ChimeraResidue> {
52 public static final int SINGLE_LETTER = 0; // Display residues as a single
54 public static final int THREE_LETTER = 1; // Display residues as three letters
55 public static final int FULL_NAME = 2; // Display full residue names
57 private String type; // Residue type
58 private String index; // Residue index
59 private String chainId; // ChainID for this residue
60 private int modelNumber; // model number for this residue
61 private int subModelNumber; // sub-model number for this residue
62 protected int residueNumber;
63 protected String insertionCode;
64 private ChimeraModel chimeraModel; // ChimeraModel the residue is part of
65 private Object userData; // user data to associate with this residue
66 // public static HashMap<String, String> aaNames = null; // a map of amino acid
68 private static int displayType = THREE_LETTER; // the current display type
69 private boolean selected = false; // the selection state
72 * Constructor to create a new ChimeraResidue
77 * the index of the residue
79 * the model number this residue is part of
81 public ChimeraResidue(String type, String index, int modelNumber) {
82 this(type, index, modelNumber, 0);
86 * Constructor to create a new ChimeraResidue
91 * the index of the residue
93 * the model number this residue is part of
94 * @param subModelNumber
95 * the sub-model number this residue is part of
97 public ChimeraResidue(String type, String index, int modelNumber, int subModelNumber) {
100 this.modelNumber = modelNumber;
101 this.subModelNumber = subModelNumber;
102 splitInsertionCode(this.index);
103 // if (aaNames == null) {
109 * Constructor to create a new ChimeraResidue from an input line
111 * @param chimeraInputLine
112 * a Chimera residue description
114 // invoked when listing (selected) residues: listr spec #0; lists level residue
115 // Line: residue id #0:37.A type MET
116 public ChimeraResidue(String chimeraInputLine) {
118 String[] split1 = chimeraInputLine.split(":");
120 // First half has model number -- get the number
121 int numberOffset = split1[0].indexOf('#');
122 String model = split1[0].substring(numberOffset + 1);
123 int decimalOffset = model.indexOf('.'); // Do we have a sub-model?
125 this.subModelNumber = 0;
126 if (decimalOffset > 0) {
127 this.subModelNumber = Integer.parseInt(model.substring(decimalOffset + 1));
128 this.modelNumber = Integer.parseInt(model.substring(0, decimalOffset));
130 this.modelNumber = Integer.parseInt(model);
132 } catch (Exception e) {
133 LoggerFactory.getLogger(ChimeraResidue.class)
134 .error("Unexpected return from Chimera: " + model);
135 this.modelNumber = -1;
138 // Second half has residue info: index & type
139 String[] rTokens = split1[1].split(" ");
140 this.type = rTokens[2];
142 String[] iTokens = rTokens[0].split("\\.");
143 if (iTokens.length > 0) {
144 this.index = iTokens[0];
146 // Careful, might or might not have a chainID
147 if (iTokens.length > 1)
148 this.chainId = iTokens[1];
152 this.index = rTokens[0];
154 splitInsertionCode(this.index);
158 * Set the selected state for this residue
161 * the selection state to set
163 public void setSelected(boolean selected) {
164 this.selected = selected;
168 * Return the selected state of this residue
170 * @return the selected state
172 public boolean isSelected() {
177 * Return an array made up of this residue (required for ChimeraStructuralObject interface
179 * @return a List with this residue as its sole member
181 public List<ChimeraStructuralObject> getChildren() {
182 List<ChimeraStructuralObject> v = new ArrayList<ChimeraStructuralObject>();
188 * Return the string representation of this residue as follows: "<i>residue_name</i> <i>index</i>"
189 * where <i>residue_name</i> could be either the single letter, three letter, or full name
190 * representation of the amino acid.
192 * @return the string representation
194 public String displayName() {
199 * Return the string representation of this residue as follows: "<i>residue_name</i> <i>index</i>"
200 * where <i>residue_name</i> could be either the single letter, three letter, or full name
201 * representation of the amino acid.
203 * @return the string representation
205 public String toString() {
206 if (displayType == FULL_NAME) {
207 return (ChimUtils.toFullName(type) + " " + index);
208 } else if (displayType == SINGLE_LETTER) {
209 return (ChimUtils.toSingleLetter(type) + " " + index);
210 } else if (displayType == THREE_LETTER) {
211 return (ChimUtils.toThreeLetter(type) + " " + index);
213 return (type + " " + index);
218 * Return the Chimera specification for this Residue
220 * @return Chimera specification
222 public String toSpec() {
223 if (!chainId.equals("_"))
224 return ("#" + modelNumber + ":" + index + "." + chainId);
226 return ("#" + modelNumber + ":" + index + ".");
230 * Get the index of this residue
232 * @return residue index
234 public String getIndex() {
239 * Get the chainID for this residue
241 * @return String value of the chainId
243 public String getChainId() {
248 * Get the type for this residue
250 * @return residue type
252 public String getType() {
257 * Get the model number for this residue
259 * @return the model number
261 public int getModelNumber() {
262 return this.modelNumber;
266 * Get the sub-model number for this residue
268 * @return the sub-model number
270 public int getSubModelNumber() {
271 return this.subModelNumber;
275 * Get the model this residue is part of
277 * @return the ChimeraModel
279 public ChimeraModel getChimeraModel() {
280 return this.chimeraModel;
284 * Set the model this residue is part of
286 * @param chimeraModel
287 * the ChimeraModel this model is part of
289 public void setChimeraModel(ChimeraModel chimeraModel) {
290 this.chimeraModel = chimeraModel;
294 * Get the user data for this residue
298 public Object getUserData() {
303 * Set the user data for this Residue
306 * the user data to associate with this residue
308 public void setUserData(Object data) {
309 this.userData = data;
312 public int compareTo(ChimeraResidue c2) {
313 if (residueNumber < c2.residueNumber)
315 else if (residueNumber == c2.residueNumber) {
316 if (insertionCode == null && c2.insertionCode == null)
318 else if (insertionCode == null)
320 else if (c2.insertionCode == null)
322 return (insertionCode.compareTo(c2.insertionCode));
327 public void splitInsertionCode(String residue) {
328 // OK, split the index into number and insertion code
329 Pattern p = Pattern.compile("(\\d*)([A-Z]?)");
330 Matcher m = p.matcher(residue);
332 this.residueNumber = Integer.parseInt(m.group(1));
333 if (m.groupCount() > 1)
334 this.insertionCode = m.group(2);
336 this.insertionCode = null;
340 /**********************************************
342 *********************************************/
345 * Initialize the residue names
347 // private static void initNames() {
348 // // Create our residue name table
349 // aaNames = new HashMap<String, String>();
350 // aaNames.put("ALA", "A Ala Alanine N[C@@H](C)C(O)=O");
351 // aaNames.put("ARG", "R Arg Arginine N[C@@H](CCCNC(N)=N)C(O)=O");
352 // aaNames.put("ASN", "N Asn Asparagine N[C@@H](CC(N)=O)C(O)=O");
353 // aaNames.put("ASP", "D Asp Aspartic_acid N[C@@H](CC(O)=O)C(O)=O");
354 // aaNames.put("CYS", "C Cys Cysteine N[C@@H](CS)C(O)=O");
355 // aaNames.put("GLN", "Q Gln Glutamine N[C@H](C(O)=O)CCC(N)=O");
356 // aaNames.put("GLU", "E Glu Glumatic_acid N[C@H](C(O)=O)CCC(O)=O");
357 // aaNames.put("GLY", "G Gly Glycine NCC(O)=O");
358 // aaNames.put("HIS", "H His Histidine N[C@@H](CC1=CN=CN1)C(O)=O");
359 // aaNames.put("ILE", "I Ile Isoleucine N[C@]([C@H](C)CC)([H])C(O)=O");
360 // aaNames.put("LEU", "L Leu Leucine N[C@](CC(C)C)([H])C(O)=O");
361 // aaNames.put("LYS", "K Lys Lysine N[C@](CCCCN)([H])C(O)=O");
362 // aaNames.put("DLY", "K Dly D-Lysine NCCCC[C@@H](N)C(O)=O");
363 // aaNames.put("MET", "M Met Methionine N[C@](CCSC)([H])C(O)=O");
364 // aaNames.put("PHE", "F Phe Phenylalanine N[C@](CC1=CC=CC=C1)([H])C(O)=O");
365 // aaNames.put("PRO", "P Pro Proline OC([C@@]1([H])NCCC1)=O");
366 // aaNames.put("SER", "S Ser Serine OC[C@](C(O)=O)([H])N");
367 // aaNames.put("THR", "T Thr Threonine O[C@H](C)[C@](C(O)=O)([H])N");
368 // aaNames.put("TRP", "W Trp Tryptophan N[C@@]([H])(CC1=CN([H])C2=C1C=CC=C2)C(O)=O");
369 // aaNames.put("TYR", "Y Tyr Tyrosine N[C@@](C(O)=O)([H])CC1=CC=C(O)C=C1");
370 // aaNames.put("VAL", "V Val Valine N[C@@](C(O)=O)([H])C(C)C");
371 // aaNames.put("ASX", "B Asx Aspartic_acid_or_Asparagine");
372 // aaNames.put("GLX", "Z Glx Glutamine_or_Glutamic_acid");
373 // aaNames.put("XAA", "X Xaa Any_or_unknown_amino_acid");
374 // aaNames.put("HOH", "HOH HOH Water [H]O[H]");
378 * Set the display type.
383 public static void setDisplayType(int type) {
387 public static int getDisplayType() {
391 public boolean hasSelectedChildren() {