/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojava.bio.symbol; import java.io.Serializable; /** * A 'fuzzy' location a-la Embl fuzzy locations. *

* Fuzzy locations have propreties that indicate that they may start before min * and end after max. However, this in no way affects how they interact with * other locations. *

* * @author Matthew Pocock * @author Thomas Down * @author Greg Cox */ public class FuzzyLocation extends AbstractRangeLocation implements Serializable { /** * Always use the `inner' values. */ public final static RangeResolver RESOLVE_INNER; /** * Use the `outer' values, unless they are unbounded in which case the * `inner' values are used. */ public final static RangeResolver RESOLVE_OUTER; /** * Use the arithmetic mean of the `inner' and `outer' values, unless the * outer value is unbounded. */ public final static RangeResolver RESOLVE_AVERAGE; static { RESOLVE_INNER = new InnerRangeResolver(); RESOLVE_OUTER = new OuterRangeResolver(); RESOLVE_AVERAGE = new AverageRangeResolver(); } private int outerMin; private int innerMin; private int innerMax; private int outerMax; private boolean mIsMinFuzzy; private boolean mIsMaxFuzzy; private RangeResolver resolver; /** * Create a new FuzzyLocation with endpoints (outerMin.innerMin) and (innerMax.outerMax). * * @param outerMin the lower bound on the location's min value. * Integer.MIN_VALUE indicates unbounded. * @param outerMax the upper bound on the location's max value. * Integer.MAX_VALUE indicates unbounded. * @param innerMin the upper bound on the location's min value. * @param innerMax the lower bound on the location's max value. * @param resolver a RangeResolver object which defines the policy used to calculate * the location's min and max properties. */ public FuzzyLocation( int outerMin, int outerMax, int innerMin, int innerMax, RangeResolver resolver ) { boolean isMinFuzzy = false; boolean isMaxFuzzy = false; if (outerMin != innerMin) { isMinFuzzy = true; } if (outerMax != innerMax) { isMaxFuzzy = true; } this.initializeVariables(outerMin, outerMax, innerMin, innerMax, isMinFuzzy, isMaxFuzzy, resolver); } /** * Create a new FuzzyLocation with endpoints (outerMin.innerMin) and * (innerMax.outerMax). This constructor allows you to explicitly mark an * endpoint as fuzzy, even if there is no other information about it. For * example, a valid swissprot location "?5 10" would be a fuzzy location 5 * to 10 where the min is fuzzy and the max is not. *

* Note that it is not logical to specify inner and outer values that * clearly denote fuzzy boundaries and the set the isMinFuzzy or * isMaxFuzzy value to false. This object makes * no specific check of your logic so be careful. * * @param outerMin the lower bound on the location's min value. * Integer.MIN_VALUE indicates unbounded. * @param outerMax the upper bound on the location's max value. * Integer.MAX_VALUE indicates unbounded. * @param innerMin the upper bound on the location's min value. * @param innerMax the lower bound on the location's max value. * @param isMinFuzzy Explictly state if the minimum is fuzzy * @param isMaxFuzzy Explictly state if the maximum is fuzzy * @param resolver a RangeResolver object which defines the policy used to * calculate the location's min and max properties. */ public FuzzyLocation(int outerMin, int outerMax, int innerMin, int innerMax, boolean isMinFuzzy, boolean isMaxFuzzy, RangeResolver resolver) { this.initializeVariables(outerMin, outerMax, innerMin, innerMax, isMinFuzzy, isMaxFuzzy, resolver); } public Location translate(int dist) { return new FuzzyLocation( outerMin + dist, outerMax + dist, innerMin + dist, innerMax + dist, resolver ); } /** * Retrieve the Location that this decorates. * * @return the Location instance that stores all of the Location interface * data */ public RangeResolver getResolver() { return resolver; } public int getOuterMin() { return outerMin; } public int getOuterMax() { return outerMax; } public int getInnerMin() { return innerMin; } public int getInnerMax() { return innerMax; } public int getMin() { return resolver.resolveMin(this); } public int getMax() { return resolver.resolveMax(this); } public boolean hasBoundedMin() { return outerMin != Integer.MIN_VALUE; } public boolean hasBoundedMax() { return outerMax != Integer.MAX_VALUE; } public String toString() { return "[" + (hasBoundedMin() ? Integer.toString(getMin()) : "<" + Integer.toString(getMin())) + ", " + (hasBoundedMax() ? Integer.toString(getMax()) : ">" + Integer.toString(getMax())) + "]"; } /** * Determines how a FuzzyLocation should be treated when used * as a normal Location. * * Use one of the implementations of this interface when creating a FuzzyLocation * to specify how the fuzzy (inner/outer) properties are translated into the standard * Location min and max properties. * * It is possible to write custom implementations of this to create FuzzyLocations * with exotic behaviour. */ public static interface RangeResolver extends Serializable { /** * Delegate for the getMin() method. * @param loc The Location to resolve * @return the resolved Min */ public int resolveMin(FuzzyLocation loc); /** * Delegate for the getMax() method. * @param loc The Location to resolve * @return the resolved Max */ public int resolveMax(FuzzyLocation loc); } private static class InnerRangeResolver implements RangeResolver { public int resolveMin(FuzzyLocation loc) { return loc.getInnerMin(); } public int resolveMax(FuzzyLocation loc) { return loc.getInnerMax(); } } private static class OuterRangeResolver implements RangeResolver { public int resolveMin(FuzzyLocation loc) { if (loc.hasBoundedMin()) { return loc.getOuterMin(); } else { return loc.getInnerMin(); } } public int resolveMax(FuzzyLocation loc) { if (loc.hasBoundedMax()) { return loc.getOuterMax(); } else { return loc.getInnerMax(); } } } private static class AverageRangeResolver implements RangeResolver { public int resolveMin(FuzzyLocation loc) { if (loc.hasBoundedMin()) { return (loc.getOuterMin() + loc.getInnerMin()) / 2; } else { return loc.getInnerMin(); } } public int resolveMax(FuzzyLocation loc) { if (loc.hasBoundedMax()) { return (loc.getOuterMax() + loc.getInnerMax()) / 2; } else { return loc.getInnerMax(); } } } public boolean isMinFuzzy() { return mIsMinFuzzy; } public boolean isMaxFuzzy() { return mIsMaxFuzzy; } /** * Refactored initialization code from the constructors. * * @param outerMin the lower bound on the location's min value. * Integer.MIN_VALUE indicates unbounded. * @param outerMax the upper bound on the location's max value. * Integer.MAX_VALUE indicates unbounded. * @param innerMin the upper bound on the location's min value. * @param innerMax the lower bound on the location's max value. * @param resolver a RangeResolver object which defines the policy used to calculate * the location's min and max properties. */ protected void initializeVariables(int outerMin, int outerMax, int innerMin, int innerMax, boolean isMinFuzzy, boolean isMaxFuzzy, RangeResolver resolver) { this.outerMin = outerMin; this.outerMax = outerMax; this.innerMin = innerMin; this.innerMax = innerMax; this.resolver = resolver; this.mIsMinFuzzy = isMinFuzzy; this.mIsMaxFuzzy = isMaxFuzzy; } }