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.io.Serializable; 025 026/** 027 * A 'fuzzy' location a-la Embl fuzzy locations. 028 * <p> 029 * Fuzzy locations have propreties that indicate that they may start before min 030 * and end after max. However, this in no way affects how they interact with 031 * other locations. 032 * </p> 033 * 034 * @author Matthew Pocock 035 * @author Thomas Down 036 * @author Greg Cox 037 */ 038public class FuzzyLocation 039extends AbstractRangeLocation 040implements Serializable { 041 /** 042 * Always use the `inner' values. 043 */ 044 045 public final static RangeResolver RESOLVE_INNER; 046 047 /** 048 * Use the `outer' values, unless they are unbounded in which case the 049 * `inner' values are used. 050 */ 051 052 public final static RangeResolver RESOLVE_OUTER; 053 054 /** 055 * Use the arithmetic mean of the `inner' and `outer' values, unless the 056 * outer value is unbounded. 057 */ 058 059 public final static RangeResolver RESOLVE_AVERAGE; 060 061 static { 062 RESOLVE_INNER = new InnerRangeResolver(); 063 RESOLVE_OUTER = new OuterRangeResolver(); 064 RESOLVE_AVERAGE = new AverageRangeResolver(); 065 } 066 067 private int outerMin; 068 private int innerMin; 069 private int innerMax; 070 private int outerMax; 071 private boolean mIsMinFuzzy; 072 private boolean mIsMaxFuzzy; 073 private RangeResolver resolver; 074 075 /** 076 * Create a new FuzzyLocation with endpoints (outerMin.innerMin) and (innerMax.outerMax). 077 * 078 * @param outerMin the lower bound on the location's min value. 079 * Integer.MIN_VALUE indicates unbounded. 080 * @param outerMax the upper bound on the location's max value. 081 * Integer.MAX_VALUE indicates unbounded. 082 * @param innerMin the upper bound on the location's min value. 083 * @param innerMax the lower bound on the location's max value. 084 * @param resolver a RangeResolver object which defines the policy used to calculate 085 * the location's min and max properties. 086 */ 087 088 public FuzzyLocation( 089 int outerMin, int outerMax, 090 int innerMin, int innerMax, 091 RangeResolver resolver 092 ) { 093 boolean isMinFuzzy = false; 094 boolean isMaxFuzzy = false; 095 if (outerMin != innerMin) 096 { 097 isMinFuzzy = true; 098 } 099 if (outerMax != innerMax) 100 { 101 isMaxFuzzy = true; 102 } 103 this.initializeVariables(outerMin, outerMax, innerMin, innerMax, isMinFuzzy, isMaxFuzzy, resolver); 104 } 105 106 /** 107 * Create a new FuzzyLocation with endpoints (outerMin.innerMin) and 108 * (innerMax.outerMax). This constructor allows you to explicitly mark an 109 * endpoint as fuzzy, even if there is no other information about it. For 110 * example, a valid swissprot location "?5 10" would be a fuzzy location 5 111 * to 10 where the min is fuzzy and the max is not. 112 * <p> 113 * Note that it is not logical to specify inner and outer values that 114 * clearly denote fuzzy boundaries and the set the <code>isMinFuzzy</code> or 115 * <code>isMaxFuzzy</code> value to false. This object makes 116 * no specific check of your logic so be careful. 117 * 118 * @param outerMin the lower bound on the location's min value. 119 * Integer.MIN_VALUE indicates unbounded. 120 * @param outerMax the upper bound on the location's max value. 121 * Integer.MAX_VALUE indicates unbounded. 122 * @param innerMin the upper bound on the location's min value. 123 * @param innerMax the lower bound on the location's max value. 124 * @param isMinFuzzy Explictly state if the minimum is fuzzy 125 * @param isMaxFuzzy Explictly state if the maximum is fuzzy 126 * @param resolver a RangeResolver object which defines the policy used to 127 * calculate the location's min and max properties. 128 */ 129 130 public FuzzyLocation(int outerMin, int outerMax, 131 int innerMin, int innerMax, 132 boolean isMinFuzzy, boolean isMaxFuzzy, 133 RangeResolver resolver) 134 { 135 this.initializeVariables(outerMin, outerMax, innerMin, innerMax, isMinFuzzy, isMaxFuzzy, resolver); 136 } 137 138 public Location translate(int dist) { 139 return new FuzzyLocation( 140 outerMin + dist, 141 outerMax + dist, 142 innerMin + dist, 143 innerMax + dist, 144 resolver 145 ); 146 } 147 148 /** 149 * Retrieve the Location that this decorates. 150 * 151 * @return the Location instance that stores all of the Location interface 152 * data 153 */ 154 155 public RangeResolver getResolver() { 156 return resolver; 157 } 158 159 public int getOuterMin() { 160 return outerMin; 161 } 162 163 164 public int getOuterMax() { 165 return outerMax; 166 } 167 168 public int getInnerMin() { 169 return innerMin; 170 } 171 172 173 public int getInnerMax() { 174 return innerMax; 175 } 176 177 public int getMin() { 178 return resolver.resolveMin(this); 179 } 180 181 public int getMax() { 182 return resolver.resolveMax(this); 183 } 184 185 public boolean hasBoundedMin() { 186 return outerMin != Integer.MIN_VALUE; 187 } 188 189 public boolean hasBoundedMax() { 190 return outerMax != Integer.MAX_VALUE; 191 } 192 193 public String toString() 194 { 195 return "[" 196 + (hasBoundedMin() ? Integer.toString(getMin()) : "<" + Integer.toString(getMin())) 197 + ", " 198 + (hasBoundedMax() ? Integer.toString(getMax()) : ">" + Integer.toString(getMax())) 199 + "]"; 200 } 201 202 /** 203 * Determines how a <code>FuzzyLocation</code> should be treated when used 204 * as a normal <code>Location</code>. 205 * 206 * Use one of the implementations of this interface when creating a <code>FuzzyLocation</code> 207 * to specify how the fuzzy (inner/outer) properties are translated into the standard 208 * Location min and max properties. 209 * 210 * It is possible to write custom implementations of this to create <code>FuzzyLocations</code> 211 * with exotic behaviour. 212 */ 213 214 public static interface RangeResolver extends Serializable { 215 /** 216 * Delegate for the getMin() method. 217 * @param loc The Location to resolve 218 * @return the resolved Min 219 */ 220 221 public int resolveMin(FuzzyLocation loc); 222 223 /** 224 * Delegate for the getMax() method. 225 * @param loc The Location to resolve 226 * @return the resolved Max 227 */ 228 229 public int resolveMax(FuzzyLocation loc); 230 } 231 232 private static class InnerRangeResolver implements RangeResolver { 233 public int resolveMin(FuzzyLocation loc) { 234 return loc.getInnerMin(); 235 } 236 237 public int resolveMax(FuzzyLocation loc) { 238 return loc.getInnerMax(); 239 } 240 } 241 242 private static class OuterRangeResolver implements RangeResolver { 243 public int resolveMin(FuzzyLocation loc) { 244 if (loc.hasBoundedMin()) { 245 return loc.getOuterMin(); 246 } else { 247 return loc.getInnerMin(); 248 } 249 } 250 251 public int resolveMax(FuzzyLocation loc) { 252 if (loc.hasBoundedMax()) { 253 return loc.getOuterMax(); 254 } else { 255 return loc.getInnerMax(); 256 } 257 } 258 } 259 260 private static class AverageRangeResolver implements RangeResolver { 261 public int resolveMin(FuzzyLocation loc) { 262 if (loc.hasBoundedMin()) { 263 return (loc.getOuterMin() + loc.getInnerMin()) / 2; 264 } else { 265 return loc.getInnerMin(); 266 } 267 } 268 269 public int resolveMax(FuzzyLocation loc) { 270 if (loc.hasBoundedMax()) { 271 return (loc.getOuterMax() + loc.getInnerMax()) / 2; 272 } else { 273 return loc.getInnerMax(); 274 } 275 } 276 } 277 278 public boolean isMinFuzzy() 279 { 280 return mIsMinFuzzy; 281 } 282 283 public boolean isMaxFuzzy() 284 { 285 return mIsMaxFuzzy; 286 } 287 288 /** 289 * Refactored initialization code from the constructors. 290 * 291 * @param outerMin the lower bound on the location's min value. 292 * Integer.MIN_VALUE indicates unbounded. 293 * @param outerMax the upper bound on the location's max value. 294 * Integer.MAX_VALUE indicates unbounded. 295 * @param innerMin the upper bound on the location's min value. 296 * @param innerMax the lower bound on the location's max value. 297 * @param resolver a RangeResolver object which defines the policy used to calculate 298 * the location's min and max properties. 299 */ 300 protected void initializeVariables(int outerMin, int outerMax, 301 int innerMin, int innerMax, 302 boolean isMinFuzzy, boolean isMaxFuzzy, 303 RangeResolver resolver) 304 { 305 this.outerMin = outerMin; 306 this.outerMax = outerMax; 307 this.innerMin = innerMin; 308 this.innerMax = innerMax; 309 this.resolver = resolver; 310 this.mIsMinFuzzy = isMinFuzzy; 311 this.mIsMaxFuzzy = isMaxFuzzy; 312 } 313}