001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 * Created on Jun 17, 2010 021 * Author: ap3 022 * 023 */ 024 025package org.biojava.nbio.structure; 026 027import java.io.Serializable; 028import java.io.StringWriter; 029 030/** 031 * Everything that is needed to uniquely describe a residue position 032 * 033 * @author Andreas Prlic 034 * 035 */ 036public class ResidueNumber implements Serializable, Comparable<ResidueNumber> 037{ 038 039 private static final long serialVersionUID = 1773011704758536083L; 040 private String chainName; 041 private Character insCode; 042 private Integer seqNum; 043 044 public ResidueNumber() { 045 } 046 047 public ResidueNumber(ResidueNumber o) { 048 this.chainName = o.chainName; 049 this.insCode = o.insCode; 050 this.seqNum = o.seqNum; 051 } 052 053 public ResidueNumber(String chainName, Integer residueNumber, Character insCode) { 054 this.chainName = chainName; 055 this.seqNum = residueNumber; 056 this.insCode = insCode; 057 } 058 059 public String getChainName() 060 { 061 return chainName; 062 } 063 public void setChainName(String chainName) 064 { 065 this.chainName = chainName; 066 } 067 public Character getInsCode() 068 { 069 return insCode; 070 } 071 public void setInsCode(Character insCode) 072 { 073 this.insCode = insCode; 074 } 075 public Integer getSeqNum() 076 { 077 return seqNum; 078 } 079 public void setSeqNum(Integer seqNum) 080 { 081 this.seqNum = seqNum; 082 } 083 084 085 086 087 088 @Override 089 public boolean equals(Object obj) { 090 if (this == obj) 091 return true; 092 if (obj == null) 093 return false; 094 if (getClass() != obj.getClass()) 095 return false; 096 ResidueNumber other = (ResidueNumber) obj; 097 if (chainName == null) { 098 if (other.chainName != null) 099 return false; 100 } else if (!chainName.equals(other.chainName)) 101 return false; 102 if (insCode == null) { 103 if (other.insCode != null) 104 return false; 105 } else if (!insCode.equals(other.insCode)) 106 return false; 107 if (seqNum == null) { 108 if (other.seqNum != null) 109 return false; 110 } else if (!seqNum.equals(other.seqNum)) 111 return false; 112 113 return true; 114 } 115 116 /** 117 * Check if the seqNum and insertion code are equivalent, 118 * ignoring the chain 119 * @param obj 120 * @return 121 */ 122 public boolean equalsPositional(Object obj) { 123 if (this == obj) 124 return true; 125 if (obj == null) 126 return false; 127 if (getClass() != obj.getClass()) 128 return false; 129 ResidueNumber other = (ResidueNumber) obj; 130 if (insCode == null) { 131 if (other.insCode != null) 132 return false; 133 } else if (!insCode.equals(other.insCode)) 134 return false; 135 if (seqNum == null) { 136 if (other.seqNum != null) 137 return false; 138 } else if (!seqNum.equals(other.seqNum)) 139 return false; 140 141 return true; 142 143 } 144 145 @Override 146 public int hashCode() { 147 final int prime = 31; 148 int result = 1; 149 result = prime * result + ((chainName == null) ? 0 : chainName.hashCode()); 150 result = prime * result + ((insCode == null) ? 0 : insCode.hashCode()); 151 result = prime * result + ((seqNum == null) ? 0 : seqNum.hashCode()); 152 return result; 153 } 154 155 /** 156 * @return The residue number and insertion code as a string, eg "74A" 157 * @see java.lang.Object#toString() 158 */ 159 @Override 160 public String toString() { 161 162 StringWriter writer = new StringWriter(); 163 // if ( chainName != null){ 164 // writer.append(chainName); 165 // writer.append(":"); 166 // } 167 writer.append(String.valueOf(seqNum)); 168 if ( insCode != null && ( insCode != ' ')) 169 writer.append(insCode); 170 171 return writer.toString(); 172 } 173 174 /** 175 * @return The chain, number, and insertion code as a string, eg "B 74A" or "A 1 " 176 */ 177 public String toPDB() { 178 String insCodeS ; 179 if ( insCode != null) 180 insCodeS = insCode+""; 181 else insCodeS = " "; 182 return String.format("%s%4d%-2s", chainName, seqNum, insCodeS); 183 } 184 185 186 /** Convert a string representation of a residue number to a residue number object. 187 * The string representation can be a integer followed by a character. 188 * 189 * @param pdb_code 190 * @return a ResidueNumber object, or null if the input was null 191 */ 192 public static ResidueNumber fromString(String pdb_code) { 193 if(pdb_code == null) 194 return null; 195 196 ResidueNumber residueNumber = new ResidueNumber(); 197 Integer resNum = null; 198 String icode = null; 199 200 try { 201 resNum = Integer.parseInt(pdb_code); 202 } catch ( NumberFormatException e){ 203 // there is an insertion code.. 204 205 // Split at any position that's either: 206 // preceded by a digit and followed by a non-digit, or 207 // preceded by a non-digit and followed by a digit. 208 String[] spl = pdb_code.split("(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)"); 209 if ( spl.length == 2){ 210 resNum = Integer.parseInt(spl[0]); 211 icode = spl[1]; 212 } 213 214 } 215 216 residueNumber.setSeqNum(resNum); 217 if ( icode == null) 218 residueNumber.setInsCode(null); 219 else if ( icode.length() > 0) 220 residueNumber.setInsCode(icode.charAt(0)); 221 return residueNumber; 222 } 223 224 225 /** 226 * Compare residue numbers by chain, sequence number, and insertion code 227 */ 228 @Override 229 public int compareTo(ResidueNumber other) { 230 231 // chain id 232 if (chainName != null && other.chainName != null) { 233 if (!chainName.equals(other.chainName)) return chainName.compareTo(other.chainName); 234 } 235 if (chainName != null && other.chainName == null) { 236 return 1; 237 } else if (chainName == null && other.chainName != null) { 238 return -1; 239 } 240 241 return compareToPositional(other); 242 } 243 244 /** 245 * Compare residue numbers by sequence number and insertion code, 246 * ignoring the chain 247 * @param other 248 * @return 249 */ 250 public int compareToPositional(ResidueNumber other) { 251 // sequence number 252 if (seqNum != null && other.seqNum != null) { 253 if (!seqNum.equals(other.seqNum)) return seqNum.compareTo(other.seqNum); 254 } 255 if (seqNum != null && other.seqNum == null) { 256 return 1; 257 } else if (seqNum == null && other.seqNum != null) { 258 return -1; 259 } 260 261 // insertion code 262 if (insCode != null && other.insCode != null) { 263 if (!insCode.equals(other.insCode)) return insCode.compareTo(other.insCode); 264 } 265 if (insCode != null && other.insCode == null) { 266 return 1; 267 } else if (insCode == null && other.insCode != null) { 268 return -1; 269 } 270 271 return 0; 272 } 273 274 public String printFull() { 275 final String chain = chainName==null? "" : chainName; 276 return chain + "_" + toString(); 277 } 278 279}