/* * GeoTools - The Open Source Java GIS Tookit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This file is hereby placed into the Public Domain. This means anyone is * free to do whatever they wish with this file. Use it well and enjoy! */ package org.geotools.demo.filter.function; import java.io.File; import java.net.URL; import org.geotools.data.FeatureSource; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.factory.CommonFactoryFinder; import org.geotools.map.DefaultMapContext; import org.geotools.map.MapContext; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.Fill; import org.geotools.styling.PolygonSymbolizer; import org.geotools.styling.Rule; import org.geotools.styling.SLDParser; import org.geotools.styling.Stroke; import org.geotools.styling.Style; import org.geotools.styling.StyleFactory; import org.geotools.swing.ExceptionMonitor; import org.geotools.swing.JMapFrame; import org.opengis.feature.type.FeatureType; import org.opengis.filter.FilterFactory; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Function; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * Demonstrates using a custom written filter function to dynamically set * the fill and outline color of polygon features based on the value of a * specified feature attribute. Here we use the countries shapefile and * the log of population size as the value to base color on. * * @author Michael Bedward * * @source $URL$ */ public class DynamicFillColor { private static final float SATURATION = 0.8f; private static final float BRIGHTNESS = 0.8f; private FilterFactory filterFactory; private StyleFactory styleFactory; /** * Construtor - just initializes our factory objects */ public DynamicFillColor() { filterFactory = CommonFactoryFinder.getFilterFactory(null); styleFactory = CommonFactoryFinder.getStyleFactory(null); } /** * Creates a new Style object for polygon features in which the fill * and outline stroke colors will be based on the specified feature * attribute (a numeric field). * * @param attrName the name of the feature attribute to use as the * value field * * @param minValue the minimum expected feature value * * @param maxValue the maximum expected feature value * * @param logValues if true, calculations will use the log of feature * value (in this case min and max value parameters should be on * the log scale); if false feature values are used directly * * @return a new Style object containing the dynamic color function */ public Style createColorRampStyle(String attrName, float minValue, float maxValue, boolean logValues) { Style style = styleFactory.createStyle(); Expression valueExpr = null; if (logValues) { /* * Here we use one of GeoTools provided maths functions which * will calculate log values */ valueExpr = filterFactory.function("log", filterFactory.property(attrName)); } else { /* * Here we specify the feature attribute which will be used * directly */ valueExpr = filterFactory.property(attrName); } /* * Create a new function object and set it as the basis for Fill * and Stroke colors */ // ColorRampFunction fn = new ColorRampFunction(valueExpr, minValue, maxValue, 0.8f, 0.8f); Function colorRampFn = filterFactory.function("colorramp", valueExpr, filterFactory.literal(minValue), filterFactory.literal(maxValue), filterFactory.literal(SATURATION), filterFactory.literal(BRIGHTNESS)); Fill fill = styleFactory.createFill(colorRampFn); Stroke stroke = styleFactory.createStroke(colorRampFn, filterFactory.literal(1.0)); PolygonSymbolizer symbolizer = styleFactory.createPolygonSymbolizer(stroke, fill, "the_geom"); /* * Package up our dynamic symbolizer created above in the hierarchy * of rule, feature type style, style */ Rule rule = styleFactory.createRule(); rule.symbolizers().add(symbolizer); FeatureTypeStyle fts = styleFactory.createFeatureTypeStyle(new Rule[]{rule}); style.featureTypeStyles().add(fts); return style; } /** * An alternative approach... * Read the style from the SLD document provided with the countries shapefile. * Refer to this document to see how the function is specified in SLD-ese * * @param url shapefile URL * * @return the style */ private Style createFromSLD(URL url) { String path = url.getPath(); int dot = path.lastIndexOf('.'); File sld = new File(path.substring(0, dot) + ".sld"); Style style = null; try { SLDParser stylereader = new SLDParser(styleFactory, sld.toURI().toURL()); Style[] styles = stylereader.readXML(); return styles[0]; } catch (Exception e) { ExceptionMonitor.show(null, e, "Problem creating style"); } return null; } /** * Main method, runs a demo displaying the countries shapefile with fill * and outline colors based on population data * * @param args ignored * * @throws java.lang.Exception */ public static void main(String[] args) throws Exception { DynamicFillColor me = new DynamicFillColor(); me.demo(); } /** * * @throws java.lang.Exception */ private void demo() throws Exception { URL url = DynamicFillColor.class.getResource("/data/shapefiles/countries.shp"); ShapefileDataStore shapefile = new ShapefileDataStore(url); /* * Get the feature source and coordinate reference system * from the shapefile */ String typeName = shapefile.getTypeNames()[0]; FeatureSource featureSource = shapefile.getFeatureSource(typeName); FeatureType schema = featureSource.getSchema(); CoordinateReferenceSystem crs = schema.getCoordinateReferenceSystem(); Style style = null; /* * Create the dynamic fill Style using the POP_CNTRY attribute * and specifying that we want to use log values (5 and 22 are * approximate limits of the population data on the log scale) */ style = createColorRampStyle("POP_CNTRY", 5, 22, true); /* * Alternatively, comment out the line above and uncomment the line * below to read the style from a SLD file associated with the countries * shapefile (see the SLD doc for how the function is used) */ // style = createFromSLD(url); /* * Create our map and dispaly it */ MapContext map = new DefaultMapContext(crs); map.addLayer(featureSource, style); JMapFrame.showMap(map); } }