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.filter.function;
017:
018: import java.io.IOException;
019: import java.util.Collections;
020: import java.util.Comparator;
021: import java.util.HashSet;
022: import java.util.List;
023: import java.util.Set;
024: import java.util.logging.Level;
025:
026: import org.geotools.feature.FeatureCollection;
027: import org.geotools.feature.visitor.CalcResult;
028: import org.geotools.feature.visitor.UniqueVisitor;
029: import org.geotools.util.NullProgressListener;
030:
031: /**
032: * Clone of EqualIntervalFunction for unique values
033: *
034: * @author Cory Horner
035: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/filter/function/UniqueIntervalFunction.java $
036: */
037: public class UniqueIntervalFunction extends ClassificationFunction {
038:
039: public UniqueIntervalFunction() {
040: setName("UniqueInterval");
041: }
042:
043: private Object calculate(FeatureCollection featureCollection) {
044: try {
045: int classNum = getClasses();
046: //use a visitor to grab the unique values
047: UniqueVisitor uniqueVisit = new UniqueVisitor(
048: getExpression());
049: if (progress == null)
050: progress = new NullProgressListener();
051: featureCollection.accepts(uniqueVisit, progress);
052: if (progress.isCanceled())
053: return null;
054:
055: CalcResult calcResult = uniqueVisit.getResult();
056: if (calcResult == null)
057: return null;
058: List result = calcResult.toList();
059: //sort the results and put them in an array
060: Collections.sort(result, new Comparator() {
061:
062: public int compare(Object o1, Object o2) {
063: if (o1 == null) {
064: if (o2 == null) {
065: return 0; //equal
066: }
067: return -1; //less than
068: } else if (o2 == null) {
069: return 1;
070: }
071: if (o1 instanceof String && o2 instanceof String) {
072: return ((String) o1).compareTo((String) o2);
073: }
074: return 0;
075: }
076:
077: });
078: Object[] results = result.toArray();
079: //put the results into their respective slots/bins/buckets
080: Set[] values;
081: if (classNum < results.length) { //put more than one item in each class
082: //resize values array
083: values = new Set[classNum];
084: //calculate number of items to put in each of the larger bins
085: int binPop = new Double(Math
086: .ceil((double) results.length / classNum))
087: .intValue();
088: //determine index of bin where the next bin has one less item
089: int lastBigBin = results.length % classNum;
090: if (lastBigBin == 0)
091: lastBigBin = classNum;
092: else
093: lastBigBin--;
094:
095: int itemIndex = 0;
096: //for each bin
097: for (int binIndex = 0; binIndex < classNum; binIndex++) {
098: HashSet val = new HashSet();
099: //add the items
100: for (int binItem = 0; binItem < binPop; binItem++)
101: val.add(results[itemIndex++]);
102: if (lastBigBin == binIndex)
103: binPop--; // decrease the number of items in a bin for the
104: // next iteration
105: //store the bin
106: values[binIndex] = val;
107: }
108: } else {
109: if (classNum > results.length) {
110: classNum = results.length; //chop off a few classes
111: }
112: //resize values array
113: values = new Set[classNum];
114: //assign straight-across (1 item per class)
115: for (int i = 0; i < classNum; i++) {
116: HashSet val = new HashSet();
117: val.add(results[i]);
118: values[i] = val;
119: }
120: }
121: //save the result (list), finally
122: return new ExplicitClassifier(values);
123: } catch (IOException e) {
124: LOGGER.log(Level.SEVERE,
125: "UniqueIntervalFunction calculate failed", e);
126: return null;
127: }
128: }
129:
130: public Object evaluate(Object feature) {
131: if (!(feature instanceof FeatureCollection)) {
132: return null;
133: }
134: return calculate((FeatureCollection) feature);
135: }
136:
137: public int getArgCount() {
138: return 2;
139: }
140: }
|