001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.feature.visitor;
017:
018: import org.geotools.factory.CommonFactoryFinder;
019: import org.geotools.feature.Feature;
020: import org.geotools.feature.FeatureType;
021: import org.geotools.filter.IllegalFilterException;
022: import org.opengis.filter.FilterFactory;
023: import org.opengis.filter.expression.Expression;
024:
025: /**
026: * Calculates the maximum value of an attribute.
027: *
028: * @author Cory Horner, Refractions Research Inc.
029: *
030: * @since 2.2.M2
031: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/visitor/MaxVisitor.java $
032: */
033: public class MaxVisitor implements FeatureCalc {
034: private Expression expr;
035: Comparable maxvalue;
036: Comparable curvalue;
037: boolean visited = false;
038: int countNull = 0;
039: int countNaN = 0;
040:
041: public MaxVisitor(String attributeTypeName) {
042: FilterFactory factory = CommonFactoryFinder
043: .getFilterFactory(null);
044: expr = factory.property(attributeTypeName);
045: }
046:
047: public MaxVisitor(int attributeTypeIndex, FeatureType type)
048: throws IllegalFilterException {
049: FilterFactory factory = CommonFactoryFinder
050: .getFilterFactory(null);
051: expr = factory.property(type.getAttributeType(
052: attributeTypeIndex).getName());
053: }
054:
055: public MaxVisitor(String attrName, FeatureType type)
056: throws IllegalFilterException {
057: FilterFactory factory = CommonFactoryFinder
058: .getFilterFactory(null);
059: expr = factory.property(type.getAttributeType(attrName)
060: .getName());
061: }
062:
063: public MaxVisitor(Expression expr) throws IllegalFilterException {
064: this .expr = expr;
065: }
066:
067: /**
068: * Visitor function, which looks at each feature and finds the maximum.
069: *
070: * @param feature the feature to be visited
071: */
072: public void visit(Feature feature) {
073: Object attribValue = expr.evaluate(feature);
074:
075: if (attribValue == null) {
076: countNull++; //increment the null count, but don't store its value
077: return;
078: }
079:
080: if (attribValue instanceof Double) {
081: double doubleVal = ((Double) attribValue).doubleValue();
082: if (Double.isNaN(doubleVal) || Double.isInfinite(doubleVal)) {
083: countNaN++; //increment the NaN count, but don't store NaN as the max
084: return;
085: }
086: }
087:
088: curvalue = (Comparable) attribValue;
089:
090: if ((!visited) || (curvalue.compareTo(maxvalue) > 0)) {
091: maxvalue = curvalue;
092: visited = true;
093: }
094:
095: // throw new IllegalStateException("Expression is not comparable!");
096: }
097:
098: /**
099: * Get the max value.
100: *
101: * @return Max value
102: *
103: * @throws IllegalStateException DOCUMENT ME!
104: */
105: public Comparable getMax() {
106: if (!visited) {
107: throw new IllegalStateException(
108: "Must visit before max value is ready!");
109: }
110:
111: return maxvalue;
112: }
113:
114: /**
115: * @return the number of features which returned a NaN
116: */
117: public int getNaNCount() {
118: return countNaN;
119: }
120:
121: /**
122: * @return the number of features which returned a null
123: */
124: public int getNullCount() {
125: return countNull;
126: }
127:
128: public void reset() {
129: /**
130: * Reset the count and current maximum
131: */
132: this .visited = false;
133: this .maxvalue = new Integer(Integer.MIN_VALUE);
134: this .countNaN = 0;
135: this .countNull = 0;
136: }
137:
138: public Expression getExpression() {
139: return expr;
140: }
141:
142: public CalcResult getResult() {
143: if (!visited) {
144: throw new IllegalStateException(
145: "Must visit before max value is ready!");
146: }
147:
148: return new MaxResult(maxvalue);
149: }
150:
151: /**
152: * Overwrites the result stored by the visitor. This should only be used by
153: * optimizations which will tell the visitor the answer rather than
154: * visiting all features.
155: *
156: * <p></p>
157: * For 'max', the value stored is of type 'Comparable'.
158: *
159: * @param result
160: */
161: public void setValue(Object result) {
162: visited = true;
163: maxvalue = (Comparable) result;
164: }
165:
166: public static class MaxResult extends AbstractCalcResult {
167: private Comparable maxValue;
168:
169: public MaxResult(Comparable newMaxValue) {
170: maxValue = newMaxValue;
171: }
172:
173: public Object getValue() {
174: Comparable max = (Comparable) maxValue;
175:
176: return max;
177: }
178:
179: public boolean isCompatible(CalcResult targetResults) {
180: //list each calculation result which can merge with this type of result
181: if (targetResults instanceof MaxResult) {
182: return true;
183: }
184:
185: return false;
186: }
187:
188: public CalcResult merge(CalcResult resultsToAdd) {
189: if (!isCompatible(resultsToAdd)) {
190: throw new IllegalArgumentException(
191: "Parameter is not a compatible type");
192: }
193:
194: if (resultsToAdd instanceof MaxResult) {
195: //take the smaller of the 2 values
196: Comparable toAdd = (Comparable) resultsToAdd.getValue();
197: Comparable newMax = maxValue;
198:
199: if (newMax.getClass() != toAdd.getClass()) { //2 different data types, therefore convert
200: Class bestClass = CalcUtil.bestClass(new Object[] {
201: toAdd, newMax });
202: if (bestClass != toAdd.getClass())
203: toAdd = (Comparable) CalcUtil.convert(toAdd,
204: bestClass);
205: if (bestClass != newMax.getClass())
206: newMax = (Comparable) CalcUtil.convert(newMax,
207: bestClass);
208: }
209: if (newMax.compareTo(toAdd) < 0) {
210: newMax = toAdd;
211: }
212:
213: return new MaxResult(newMax);
214: } else {
215: throw new IllegalArgumentException(
216: "The CalcResults claim to be compatible, but the appropriate merge method has not been implemented.");
217: }
218: }
219: }
220: }
|