/* * 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.Random; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.transform.TransformerException; import org.geotools.factory.CommonFactoryFinder; import org.geotools.styling.FeatureTypeConstraint; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.Fill; import org.geotools.styling.Rule; import org.geotools.styling.SLD; import org.geotools.styling.SLDTransformer; import org.geotools.styling.Stroke; import org.geotools.styling.Style; import org.geotools.styling.StyleFactory; import org.geotools.styling.StyledLayerDescriptor; import org.geotools.styling.Symbolizer; import org.geotools.styling.UserLayer; import org.geotools.util.logging.Logging; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.PropertyName; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; /** * Style builder for spatial statistics * * @author Minpa Lee, MangoSystem * * @source $URL$ */ public class SSStyleBuilder { protected static final Logger LOGGER = Logging.getLogger(SSStyleBuilder.class); final FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); final StyleFactory sf = CommonFactoryFinder.getStyleFactory(null); static final Color LINE_COLOR = new Color(110, 110, 110); static final float LINE_WIDTH = 0.5f; private float opacity = 1.0f; private Stroke lineStroke; private SimpleFeatureType featureType = null; private String geometryField = null; public float getOpacity() { return opacity; } public void setOpacity(float opacity) { this.opacity = opacity; } public Stroke getLineStroke() { return lineStroke; } public void setLineStroke(Stroke lineStroke) { this.lineStroke = lineStroke; } public SSStyleBuilder(SimpleFeatureType featureType) { this.featureType = featureType; this.geometryField = featureType.getGeometryDescriptor().getLocalName(); this.lineStroke = sf.createStroke(ff.literal(Color.WHITE), ff.literal(LINE_WIDTH)); } public Style getZScoreStdDevStyle(String propertyName) { final String styleName = "Cluster / Outlier Analysis"; final double[] classBreaks = { -2.58, -1.96, -1.65, 1.65, 1.96, 2.58 }; final String[] classDescs = { "< -2.58 Std. Dev.", "-2.58 ~ -1.96 Std. Dev.", "-1.96 ~ -1.65 Std. Dev.", "-1.65 ~ 1.65 Std. Dev.", "1.65 ~ 1.96 Std. Dev.", "1.96 ~ 2.58 Std. Dev.", "> 2.58 Std. Dev." }; final Color[] colorList = { new Color(69, 117, 181), new Color(132, 158, 186), new Color(192, 204, 190), new Color(255, 255, 191), new Color(250, 185, 132), new Color(237, 117, 81), new Color(214, 47, 39) }; return buildStyle(propertyName, styleName, classBreaks, classDescs, colorList); } public Style getZScoreStyle(String propertyName) { final String styleName = "Cluster / Outlier Analysis"; final double[] classBreaks = { -2.0, -1.0, 1.0, 2.0 }; final String[] classDescs = { "< -2.0", "-2.0 ~ -1.0", "-1.0 ~ 1.0", "1.0 ~ 2.0", "> 2.0" }; final Color[] colorList = { new Color(0, 92, 230), new Color(115, 255, 225), new Color(255, 255, 205), new Color(255, 215, 130), new Color(255, 0, 0) }; return buildStyle(propertyName, styleName, classBreaks, classDescs, colorList); } public Style buildStyle(String propertyName, String styleName, double[] classBreaks, String[] classDescs, Color[] colorList) { FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle(); featureTypeStyle.setName(styleName); PropertyName property = ff.property(propertyName); for (int k = 0, length = classBreaks.length - 1; k <= classBreaks.length; k++) { Fill fill = sf.createFill(ff.literal(colorList[k]), ff.literal(opacity)); Symbolizer symbolizer = sf.createPolygonSymbolizer(lineStroke, fill, geometryField); if (classDescs != null && classDescs.length > k) { symbolizer.setName(classDescs[k]); } Filter filter = null; if (k == 0) { filter = ff.less(property, ff.literal(classBreaks[k])); } else if (k >= classBreaks.length) { filter = ff.greater(property, ff.literal(classBreaks[k - 1])); } else { Filter lower = ff.greaterOrEqual(property, ff.literal(classBreaks[k - 1])); Filter upper = k == length ? ff.lessOrEqual(property, ff.literal(classBreaks[k])) : ff.less(property, ff.literal(classBreaks[k])); filter = ff.and(lower, upper); } Rule rule = sf.createRule(); if (classDescs != null && classDescs.length > k) { rule.setName(classDescs[k]); } rule.setFilter(filter); rule.symbolizers().add(symbolizer); featureTypeStyle.rules().add(rule); } Style style = sf.createStyle(); style.featureTypeStyles().add(featureTypeStyle); style.setName(styleName); return style; } public Style getLISAStyle(String propertyName) { final String styleName = "LISA"; final String[] classValues = { "HH", "LH", "LL", "HL", "" }; final String[] classDescs = { "H-H", "L-H", "L-L", "H-L", "None" }; // http://www.w3schools.com/tags/ref_color_tryit.asp // Color.Tomato, Color.LightGoldenrodYellow, Color.CornflowerBlue, Color.Thistle final Color[] colorList = { new Color(255, 99, 71), new Color(250, 250, 210), new Color(100, 149, 237), new Color(216, 191, 216), new Color(225, 225, 225) }; FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle(); featureTypeStyle.setName(styleName); for (int k = 0; k < classValues.length; k++) { Fill fill = sf.createFill(ff.literal(colorList[k]), ff.literal(opacity)); Symbolizer symbolizer = sf.createPolygonSymbolizer(lineStroke, fill, geometryField); symbolizer.setName(classDescs[k]); Rule rule = sf.createRule(); rule.setName(classDescs[k]); rule.setFilter(ff.equal(ff.property(propertyName), ff.literal(classValues[k]), false)); rule.symbolizers().add(symbolizer); featureTypeStyle.rules().add(rule); } Style style = sf.createStyle(); style.featureTypeStyles().add(featureTypeStyle); style.setName(styleName); return style; } public Style getDefaultFeatureStyle() { Style defaultStyle = null; Class<?> origBinding = featureType.getGeometryDescriptor().getType().getBinding(); Random rnd = new Random(); Color randomColor = Color.getHSBColor(rnd.nextFloat(), 1.0f, 1.0f); if (origBinding.isAssignableFrom(Point.class)) { defaultStyle = SLD.createPointStyle("Circle", Color.GRAY, randomColor, 1.0f, 4); } else if (origBinding.isAssignableFrom(MultiPoint.class)) { defaultStyle = SLD.createPointStyle("Circle", Color.GRAY, randomColor, 1.0f, 4); } else if (origBinding.isAssignableFrom(LineString.class)) { defaultStyle = SLD.createLineStyle(randomColor, 1f); } else if (origBinding.isAssignableFrom(MultiLineString.class)) { defaultStyle = SLD.createLineStyle(randomColor, 1f); } else if (origBinding.isAssignableFrom(Polygon.class)) { defaultStyle = SLD.createPolygonStyle(Color.GRAY, randomColor, 0.5f); } else if (origBinding.isAssignableFrom(MultiPolygon.class)) { defaultStyle = SLD.createPolygonStyle(Color.GRAY, randomColor, 0.5f); } return defaultStyle; } public String toXML(Style style) { if (style == null) { return null; } UserLayer layer = sf.createUserLayer(); layer.setLayerFeatureConstraints(new FeatureTypeConstraint[] { null }); layer.setName(featureType.getTypeName()); layer.addUserStyle(style); StyledLayerDescriptor sld = sf.createStyledLayerDescriptor(); sld.addStyledLayer(layer); try { SLDTransformer styleTransform = new SLDTransformer(); return styleTransform.transform(sld); } catch (TransformerException te) { LOGGER.log(Level.FINE, te.getMessage(), te); } return null; } }