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 */ 021 022package org.biojava.bio.symbol; 023 024import java.util.AbstractList; 025import java.util.Collections; 026import java.util.Iterator; 027 028import org.biojava.bio.BioError; 029 030/** 031 * <code>FuzzyPointLocation</code> represents two types of EMBL-style 032 * partially-defined locations. These are the '(123.567)' type, which 033 * represent a single residue somewhere between these coordinates and 034 * the '<123' or '>123' type, which represent an unbounded location, 035 * not including the residue at that coordinate. 036 * 037 * @author <a href="mailto:kdj@sanger.ac.uk">Keith James</a> 038 * @author Greg Cox 039 */ 040public class FuzzyPointLocation extends AbstractLocation 041{ 042 // Use the minimum value 043 public final static PointResolver RESOLVE_MIN; 044 045 // Use the maximum value 046 public final static PointResolver RESOLVE_MAX; 047 048 // Use the arithmetic mean of the two values, unless they are 049 // unbounded, in which case Integer.MIN_VALUE or Integer.MAX_VALUE 050 // is returned 051 public final static PointResolver RESOLVE_AVERAGE; 052 053 static 054 { 055 RESOLVE_MIN = new MinPointResolver(); 056 RESOLVE_MAX = new MaxPointResolver(); 057 RESOLVE_AVERAGE = new AveragePointResolver(); 058 } 059 060 private int min; 061 private int max; 062 private PointResolver resolver; 063 064 /** 065 * Creates a new <code>FuzzyPointLocation</code> object. If the minimum 066 * value is equal to the maximum value, it is interperted as a swissprot 067 * point location such as "?24". If the minimum is Integer.MIN_VALUE and 068 * the maximum is Integer.MAX_VALUE, it is interperted as a swissprot 069 * location like '?'. 070 * 071 * @param min an <code>int</code> value for the minimum boundary 072 * of the location, Integer.MIN_VALUE if unbounded. 073 * @param max an <code>int</code> value for the minimum boundary 074 * of the location, Integer.MAX_VALUE if unbounded. 075 * @param resolver a <code>PointResolver</code> which defines the 076 * policy used to calculate the location's min and max 077 * properties. 078 */ 079 public FuzzyPointLocation(int min, int max, PointResolver resolver) 080 { 081 this.min = min; 082 this.max = max; 083 this.resolver = resolver; 084 } 085 086 public PointResolver getResolver() 087 { 088 return resolver; 089 } 090 091 public int getMin() 092 { 093 return min; 094 } 095 096 public int getMax() 097 { 098 return max; 099 } 100 101 public boolean hasBoundedMin() 102 { 103 return min != Integer.MIN_VALUE; 104 } 105 106 public boolean hasBoundedMax() 107 { 108 return max != Integer.MAX_VALUE; 109 } 110 111 public boolean overlaps(Location loc) 112 { 113 return loc.contains(this); 114 } 115 116 public boolean contains(Location loc) 117 { 118 // If the location is unbounded, it is not certain that it 119 // contains any other specific location 120 return (hasBoundedMin() && hasBoundedMax()) && 121 (resolver.resolve(this) == loc.getMin()) && 122 (resolver.resolve(this) == loc.getMax()); 123 } 124 125 public boolean contains(int point) 126 { 127 // If the location is unbounded, it is not certain that it 128 // contains any other specific coordinate 129 return (hasBoundedMin() && hasBoundedMax()) && 130 resolver.resolve(this) == point; 131 } 132 133 public boolean equals(Location loc) 134 { 135 return this.contains(loc) && loc.contains(this); 136 } 137 138 public int hashCode() 139 { 140 return getMin(); 141 } 142 143 public Location intersection(Location loc) 144 { 145 return loc.contains(this) 146 ? this 147 : Location.empty; 148 } 149 150 151 public SymbolList symbols(SymbolList slist) 152 { 153 final Symbol sym = slist.symbolAt(resolver.resolve(this)); 154 try 155 { 156 return new SimpleSymbolList(slist.getAlphabet(), new AbstractList() 157 { 158 public Object get(int index) 159 throws IndexOutOfBoundsException 160 { 161 if (index == 0) 162 { 163 return sym; 164 } 165 166 throw new IndexOutOfBoundsException("Index " + index + " greater than 0"); 167 } 168 169 public int size() 170 { 171 return 1; 172 } 173 }); 174 } 175 catch (IllegalSymbolException ise) 176 { 177 throw new BioError(ise); 178 } 179 } 180 181 public boolean isContiguous() 182 { 183 return true; 184 } 185 186 public Iterator blockIterator() 187 { 188 return Collections.singleton(this).iterator(); 189 } 190 191 public Location translate(int dist) 192 { 193 if (dist == 0) 194 return this; 195 196 return new FuzzyPointLocation(this.min + dist, 197 this.max + dist, 198 this.resolver); 199 } 200 201 public String toString() 202 { 203 if (hasBoundedMin() && hasBoundedMax()) 204 { 205 if (getMin() == getMax()) 206 { 207 return("?" + getMin()); 208 } 209 else 210 { 211 return "[" 212 + Integer.toString(getMin()) 213 + "." 214 + Integer.toString(getMax()); 215 } 216 } 217 else if (hasBoundedMin()) 218 { 219 return "[>" 220 + Integer.toString(getMin()) 221 + "]"; 222 } 223 else if (hasBoundedMax()) 224 { 225 return "[<" 226 + Integer.toString(getMax()) 227 + "]"; 228 } 229 else 230 { 231 return "?"; 232 } 233 } 234 235 236 /** 237 * Determines how a <code>FuzzyPointLocation</code> should be treated when used 238 * as a normal <code>Location</code>. 239 * 240 * Use one of the implementations of this interface when creating a <code>FuzzyPointLocation</code> 241 * to specify how the fuzzy (inner/outer) properties are translated into the standard 242 * Location min and max properties. 243 * 244 * It is possible to write custom implementations of this to create <code>FuzzyLocations</code> 245 * with exotic behaviour. 246 */ 247 248 public static interface PointResolver 249 { 250 /** 251 * Return the actual point that the specified location should claim to 252 * occupy. 253 */ 254 255 public int resolve(FuzzyPointLocation loc); 256 } 257 258 private static class MinPointResolver implements PointResolver 259 { 260 public int resolve(FuzzyPointLocation loc) 261 { 262 if (loc.hasBoundedMin()) 263 return loc.getMin(); 264 else 265 return Integer.MIN_VALUE; 266 } 267 } 268 269 private static class MaxPointResolver implements PointResolver 270 { 271 public int resolve(FuzzyPointLocation loc) 272 { 273 if (loc.hasBoundedMax()) 274 return loc.getMax(); 275 else 276 return Integer.MAX_VALUE; 277 } 278 } 279 280 private static class AveragePointResolver implements PointResolver 281 { 282 public int resolve(FuzzyPointLocation loc) 283 { 284 // Range of form: (123.567) 285 if (loc.hasBoundedMin() && loc.hasBoundedMax()) 286 { 287 return (loc.getMin() + loc.getMax()) / 2; 288 } 289 // Swissprot range ? 290 else if((loc.hasBoundedMin() == false) && 291 (loc.hasBoundedMax() == false)) 292 { 293 return 0; 294 } 295 // Range of form: <123 or >123 296 else 297 { 298 return loc.hasBoundedMin() ? Integer.MAX_VALUE : Integer.MIN_VALUE; 299 } 300 } 301 } 302}