/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-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.function;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.visitor.CalcResult;
import org.geotools.feature.visitor.UniqueVisitor;
import org.geotools.util.NullProgressListener;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
/**
* Clone of EqualIntervalFunction for unique values
*
* @author Cory Horner
* @source $URL$
*/
public class UniqueIntervalFunction extends ClassificationFunction {
public UniqueIntervalFunction() {
setName("UniqueInterval");
}
private Object calculate(FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection) {
try {
int classNum = getClasses();
//use a visitor to grab the unique values
UniqueVisitor uniqueVisit = new UniqueVisitor(getExpression());
if (progress == null) progress = new NullProgressListener();
featureCollection.accepts(uniqueVisit, progress);
if (progress.isCanceled()) return null;
CalcResult calcResult = uniqueVisit.getResult();
if (calcResult == null) return null;
List result = calcResult.toList();
//sort the results and put them in an array
Collections.sort(result, new Comparator() {
public int compare(Object o1, Object o2) {
if (o1 == null) {
if (o2 == null) {
return 0; //equal
}
return -1; //less than
} else if (o2 == null) {
return 1;
}
if (o1 instanceof String && o2 instanceof String) {
return ((String) o1).compareTo((String) o2);
}
return 0;
}
});
Object[] results = result.toArray();
//put the results into their respective slots/bins/buckets
Set[] values;
if (classNum < results.length) { //put more than one item in each class
//resize values array
values = new Set[classNum];
//calculate number of items to put in each of the larger bins
int binPop = new Double(Math.ceil((double) results.length / classNum)).intValue();
//determine index of bin where the next bin has one less item
int lastBigBin = results.length % classNum;
if (lastBigBin == 0) lastBigBin = classNum;
else lastBigBin--;
int itemIndex = 0;
//for each bin
for (int binIndex = 0; binIndex < classNum; binIndex++) {
HashSet val = new HashSet();
//add the items
for (int binItem = 0; binItem < binPop; binItem++)
val.add(results[itemIndex++]);
if (lastBigBin == binIndex)
binPop--; // decrease the number of items in a bin for the
// next iteration
//store the bin
values[binIndex] = val;
}
} else {
if (classNum > results.length) {
classNum = results.length; //chop off a few classes
}
//resize values array
values = new Set[classNum];
//assign straight-across (1 item per class)
for (int i = 0; i < classNum; i++) {
HashSet val = new HashSet();
val.add(results[i]);
values[i] = val;
}
}
//save the result (list), finally
return new ExplicitClassifier(values);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "UniqueIntervalFunction calculate failed", e);
return null;
}
}
public Object evaluate(Object feature) {
if (!(feature instanceof FeatureCollection)) {
return null;
}
return calculate((FeatureCollection<SimpleFeatureType, SimpleFeature>) feature);
}
public int getArgCount() {
return 2;
}
}