/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.filter;
import org.opengis.filter.FilterVisitor;
/**
* Defines a 'between' filter (which is a specialized compare filter). A
* between filter is just shorthand for a less-than-or-equal filter ANDed with
* a greater-than-or-equal filter. Arguably, this would be better handled
* using those constructs, but the OGC filter specification creates its own
* object for this, so we do as well. An important note here is that a
* between filter is actually a math filter, so its outer (left and right)
* expressions must be math expressions. This is enforced by the
* FilterAbstract class, which considers a BETWEEN operator to be a math
* filter.
*
* @author Rob Hranac, TOPP
* @source $URL$
* @version $Id$
*
* @task REVISIT: I think AbstractFilter right now does not consider between a
* math filter. ch
*
* @deprecated use {@link org.geotools.filter.IsBetweenImpl}
*/
public class BetweenFilterImpl extends CompareFilterImpl
implements BetweenFilter {
/** The 'middle' value, which must be an attribute expression. */
protected org.opengis.filter.expression.Expression middleValue = null;
protected BetweenFilterImpl(org.opengis.filter.FilterFactory factory) {
super(factory,null,null);
this.filterType = BETWEEN;
}
/**
* Constructor which flags the operator as between.
*
* @throws IllegalFilterException Should never happen.
*/
protected BetweenFilterImpl() throws IllegalFilterException {
super(BETWEEN);
}
/**
* Sets the values to be compared as between the left and right values.
*
* @param middleValue The expression to be compared.
*
* @deprecated use {@link #setExpression(org.opengis.filter.expression.Expression)}
*/
public final void addMiddleValue(Expression middleValue) {
setExpression(middleValue);
}
/**
* Sets the expression or middle value.
*/
public void setExpression(org.opengis.filter.expression.Expression expression) {
this.middleValue = expression;
}
/**
* Gets the middle value of the between.
*
* @return The expression in the middle.
*
* @deprecated use {@link #getExpression()}
*/
public final Expression getMiddleValue() {
return (Expression) getExpression();
}
/**
* Gets the middle value of the between.
*
* @return The expression in the middle.
*/
public org.opengis.filter.expression.Expression getExpression() {
return middleValue;
}
/**
* Returns the left,lower, or first expression.
*/
public org.opengis.filter.expression.Expression getLowerBoundary() {
return getExpression1();
}
/**
* Sets the left,lower, or first expression.
*/
public void setLowerBoundary(org.opengis.filter.expression.Expression lowerBounds) {
setExpression1(lowerBounds);
}
/**
* Returns the right,upper, or second expression.
*/
public org.opengis.filter.expression.Expression getUpperBoundary() {
return getExpression2();
}
/**
* Sets the right,upper, or second expression.
*/
public void setUpperBoundary(org.opengis.filter.expression.Expression upperBounds) {
setExpression2(upperBounds);
}
/**
* Determines whether or not a given feature is 'inside' this filter.
*
* @param feature Specified feature to examine.
*
* @return Flag confirming whether or not this feature is inside the
* filter.
*/
public boolean evaluate(Object feature) {
if (middleValue == null) {
return false;
} else {
/*Object leftObj = leftValue.getValue(feature);
Object rightObj = rightValue.getValue(feature);
Object middleObj = middleValue.getValue(feature);
//if (leftObj instanceof Number &&
//middleObj instanceof Number &&
//rightObj instanceof Number) {
double left = ((Number) leftObj).doubleValue();
double right = ((Number) rightObj).doubleValue();
double mid = ((Number) middleObj).doubleValue();
return (left <= mid) && (right >= mid);
*/
Object middleObj = eval(middleValue, feature);
//evaluate the between wrt the class of the middle object
Object leftObj = eval(expression1, feature, middleObj.getClass());
Object rightObj = eval(expression2, feature, middleObj.getClass());
if (leftObj instanceof Number &&
middleObj instanceof Number &&
rightObj instanceof Number) {
double left = ((Number) leftObj).doubleValue();
double right = ((Number) rightObj).doubleValue();
double mid = ((Number) middleObj).doubleValue();
return (left <= mid) && (right >= mid);
//instanceof Comparator? And same object type?
//this may miss variations on similar classes that actually
//could be compared, but I think AttributeType parsing may
//have helped us out before we get here.
} else if (leftObj.getClass() == middleObj.getClass() &&
rightObj.getClass() == middleObj.getClass() &&
//I don't think we need to check all for comparator
//if they are all the same class?
leftObj instanceof Comparable) {
return (((Comparable)leftObj).compareTo(middleObj) <= 0 &&
((Comparable)middleObj).compareTo(rightObj) <= 0);
} else {
String mesg = "Supplied between values are either not " +
"compatible or not supported for comparison: " + leftObj +
" <= " + middleObj + " <= " + rightObj;
throw new IllegalArgumentException(mesg);
}
}
}
/**
* Returns a string representation of this filter.
*
* @return String representation of the between filter.
*/
public String toString() {
return "[ " + expression1.toString() + " < " + middleValue.toString()
+ " < " + expression2.toString() + " ]";
}
/**
* Returns true if the passed in object is the same as this filter. Checks
* to make sure the filter types are the same as well as all three of the
* values.
*
* @param oFilter the filter to test for eqaulity.
*
* @return True if the objects are equal.
*/
public boolean equals(Object oFilter) {
if (oFilter.getClass() == this.getClass()) {
BetweenFilterImpl bFilter = (BetweenFilterImpl) oFilter;
return ((bFilter.getFilterType() == this.filterType)
&& bFilter.getLeftValue().equals(this.expression1)
&& bFilter.getMiddleValue().equals(this.middleValue)
&& bFilter.getRightValue().equals(this.expression2));
} else {
return false;
}
}
/**
* Override of hashCode method.
*
* @return a code to hash this filter by.
*/
public int hashCode() {
int result = 17;
result = (37 * result)
+ ((expression1 == null) ? 0 : expression1.hashCode());
result = (37 * result)
+ ((middleValue == null) ? 0 : middleValue.hashCode());
result = (37 * result)
+ ((expression2 == null) ? 0 : expression2.hashCode());
return result;
}
/**
* Used by FilterVisitors to perform some action on this filter instance.
* Typicaly used by Filter decoders, but may also be used by any thing
* which needs infomration from filter structure. Implementations should
* always call: visitor.visit(this); It is importatant that this is not
* left to a parent class unless the parents API is identical.
*
* @param visitor The visitor which requires access to this filter, the
* method must call visitor.visit(this);
*/
public Object accept(FilterVisitor visitor, Object extraData) {
return visitor.visit(this,extraData);
}
}