/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2014, 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.process.spatialstatistics.styler;
import java.awt.Color;
import java.util.Arrays;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.brewer.color.BrewerPalette;
import org.geotools.brewer.color.ColorBrewer;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.filter.function.RangedClassifier;
import org.geotools.process.spatialstatistics.core.FeatureTypes;
import org.geotools.process.spatialstatistics.core.FeatureTypes.SimpleShapeType;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.Mark;
import org.geotools.styling.Rule;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.Symbolizer;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
/**
* GraduatedColorStyleBuilder
*
* @author Minpa Lee, MangoSystem
*
* @source $URL$
*/
public class GraduatedColorStyleBuilder extends AbstractFeatureStyleBuilder {
protected static final Logger LOGGER = Logging.getLogger(GraduatedColorStyleBuilder.class);
String normalProperty;
public void setNormalProperty(String normalProperty) {
this.normalProperty = normalProperty;
}
public String getNormalProperty() {
return normalProperty;
}
// Diverging: PuOr, BrBG, PRGn, PiYG, RdBu, RdGy, RdYlBu, Spectral, RdYlGn
// Qualitative: Set1, Pastel1, Set2, Pastel2, Dark2, Set3, Paired, Accents,
// Sequential: YlGn, YlGnBu, GnBu, BuGn, PuBuGn, PuBu, BuPu, RdPu, PuRd, OrRd, YlOrRd, YlOrBr,
// Purples, Blues, Greens, Oranges, Reds, Grays,
public Style createStyle(SimpleFeatureCollection inputFeatures, String propertyName,
String methodName, int numClasses, String brewerPaletteName, boolean reverse) {
numClasses = numClasses < 3 ? 3 : numClasses;
if (numClasses > 12) {
numClasses = numClasses > 12 ? 12 : numClasses;
LOGGER.log(Level.WARNING, "maximum numClasses cannot exceed 12!");
}
// get classifier
RangedClassifier classifier = null;
if (normalProperty == null || normalProperty.isEmpty()) {
classifier = getClassifier(inputFeatures, propertyName, methodName, numClasses);
} else {
classifier = getClassifier(inputFeatures, propertyName, normalProperty, methodName,
numClasses);
}
double[] classBreaks = getClassBreaks(classifier);
if (brewerPaletteName == null || brewerPaletteName.isEmpty()) {
brewerPaletteName = "OrRd"; // default
}
ColorBrewer brewer = ColorBrewer.instance();
BrewerPalette brewerPalette = brewer.getPalette(brewerPaletteName);
Color[] colors = brewerPalette.getColors(classBreaks.length - 1);
if (reverse) {
Collections.reverse(Arrays.asList(colors));
}
return createStyle(inputFeatures.getSchema(), propertyName, classBreaks, colors);
}
public Style createStyle(SimpleFeatureCollection inputFeatures, String propertyName,
String methodName, int numClasses, String brewerPaletteName) {
return createStyle(inputFeatures, propertyName, methodName, numClasses, brewerPaletteName,
false);
}
public Style createStyle(SimpleFeatureType inputFeatureType, String propertyName,
double[] classBreaks, Color[] colors) {
if (classBreaks.length - 1 != colors.length) {
LOGGER.log(Level.FINE, "classBreaks's length dose not equal colors's length");
return null;
}
GeometryDescriptor geomDesc = inputFeatureType.getGeometryDescriptor();
String geometryPropertyName = geomDesc.getLocalName();
SimpleShapeType shapeType = FeatureTypes
.getSimpleShapeType(geomDesc.getType().getBinding());
FeatureTypeStyle fts = sf.createFeatureTypeStyle();
PropertyName property = ff.property(propertyName);
for (int k = 0, length = classBreaks.length - 2; k <= length; k++) {
Expression color = ff.literal(colors[k]);
Expression lowerClass = ff.literal(classBreaks[k]);
Expression upperClass = ff.literal(classBreaks[k + 1]);
Symbolizer symbolizer = null;
switch (shapeType) {
case POINT:
Mark mark = sf.getCircleMark();
Stroke markStroke = sf.createStroke(ff.literal(Color.WHITE),
ff.literal(outlineWidth), ff.literal(outlineOpacity));
mark.setStroke(markStroke);
mark.setFill(sf.createFill(color, ff.literal(fillOpacity)));
Graphic graphic = sf.createDefaultGraphic();
graphic.graphicalSymbols().clear();
graphic.graphicalSymbols().add(mark);
graphic.setSize(ff.literal(markerSize));
symbolizer = sf.createPointSymbolizer(graphic, geometryPropertyName);
break;
case LINESTRING:
Stroke lineStroke = sf.createStroke(color, ff.literal(lineWidth),
ff.literal(lineOpacity));
symbolizer = sf.createLineSymbolizer(lineStroke, geometryPropertyName);
break;
case POLYGON:
Stroke outlineStroke = sf.createStroke(ff.literal(outlineColor),
ff.literal(outlineWidth), ff.literal(outlineOpacity));
Fill fill = sf.createFill(color, ff.literal(fillOpacity));
symbolizer = sf.createPolygonSymbolizer(outlineStroke, fill, geometryPropertyName);
break;
}
Filter lower = ff.greaterOrEqual(property, lowerClass);
Filter upper = k == length ? ff.lessOrEqual(property, upperClass) : ff.less(property,
upperClass);
Rule rule = sf.createRule();
rule.setName(classBreaks[k] + " - " + classBreaks[k + 1]);
rule.setFilter(ff.and(lower, upper));
rule.symbolizers().add(symbolizer);
fts.rules().add(rule);
}
Style style = sf.createStyle();
style.featureTypeStyles().add(fts);
return style;
}
}