Package org.locationtech.udig.ui.graphics

Source Code of org.locationtech.udig.ui.graphics.ColorVisitor

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2004, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*
*/
package org.locationtech.udig.ui.graphics;

import java.awt.Color;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.locationtech.udig.internal.ui.UiPlugin;

import org.eclipse.swt.graphics.FontData;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.NameImpl;
import org.geotools.filter.Filters;
import org.geotools.sld.v1_1.SLDConfiguration;
import org.geotools.styling.FeatureTypeConstraint;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Font;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.NamedStyle;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.SLD;
import org.geotools.styling.SLDParser;
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.TextSymbolizer;
import org.geotools.styling.UserLayer;
import org.geotools.xml.Parser;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.expression.Add;
import org.opengis.filter.expression.Divide;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.Multiply;
import org.opengis.filter.expression.NilExpression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.expression.Subtract;
import org.opengis.style.Graphic;
import org.opengis.style.GraphicalSymbol;

/**
* Utility class for working with Geotools SLD objects.
* <p>
* This class assumes a subset of the SLD specification:
* <ul>
* <li>Single Rule - matching Filter.INCLUDE
* <li>Symbolizer lookup by name
* </ul>
* </p>
* <p>
* When you start to branch out to SLD information that contains
* multiple rules you will need to modify this class.
* </p>
* @author Jody Garnett, Refractions Research.
* @since 0.7.0
* @version 1.3.2
*/
public class SLDs extends SLD {
    private static StyleFactory sf = CommonFactoryFinder.getStyleFactory(null);
    private static FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);

    public static final double ALIGN_LEFT = 1.0;
    public static final double ALIGN_CENTER = 0.5;
    public static final double ALIGN_RIGHT = 0.0;
    public static final double ALIGN_BOTTOM = 1.0;
    public static final double ALIGN_MIDDLE = 0.5;
    public static final double ALIGN_TOP = 0.0;

    public static int size( Graphic graphic ) {
        if (graphic == null) {
            return NOTFOUND;
        }
        return Filters.asInt(graphic.getSize());
    }

    public static Color polyFill(PolygonSymbolizer symbolizer) {
        if (symbolizer == null) {
            return null;
        }

        Fill fill = symbolizer.getFill();

        if (fill == null) {
            return null;
        }

        Expression color = fill.getColor();
        return color(color);
    }
    public static Color color(Expression expr) {
        if (expr == null) {
            return null;
        }
        try {
            return expr.evaluate(null, Color.class );
        }
        catch( Throwable t ){
            class ColorVisitor implements ExpressionVisitor {
                Color found;
                public Object visit( Literal expr, Object data ) {
                    if( found != null ) return null;
                    try {
                        Color color = expr.evaluate(expr, Color.class );
                        if( color != null ){
                            found = color;
                        }
                    }
                    catch (Throwable t){
                        // not a color
                    }
                    return data;
                }
                public Object visit( NilExpression arg0, Object data ) {
                    return data;
                }
                public Object visit( Add arg0, Object data ) {
                    return data;
                }
                public Object visit( Divide arg0, Object data ) {
                    return null;
                }
                public Object visit( Function function, Object data ) {
                    for( Expression param : function.getParameters() ){
                        param.accept(this, data );
                    }
                    return data;
                }
                public Object visit( Multiply arg0, Object data ) {
                    return data;
                }
                public Object visit( PropertyName arg0, Object data ) {
                    return data;
                }
                public Object visit( Subtract arg0, Object data ) {
                    return data;
                }
            }
            ColorVisitor search = new ColorVisitor();
            expr.accept(search, null );
           
            return search.found;           
        }
    }
   
    /**
     * Grabs the font from the first TextSymbolizer.
     * <p>
     * If you are using something fun like symbols you
     * will need to do your own thing.
     * </p>
     * @param symbolizer Text symbolizer information.
     * @return FontData[] of the font's fill, or null if unavailable.
     */
    public static FontData[] textFont( TextSymbolizer symbolizer ) {

        Font font = font(symbolizer);
        if (font == null)
            return null;
        // FIXME: font style isn't being set properly here...seems screwy so leaving till later
        // String fontStyle = font[0].getFontStyle().toString();
        // if(fontStyle == null) return null;
        // else if(fontStyle.equalsIgnoreCase("italic"))

        FontData[] tempFD = new FontData[1];
        Expression fontFamilyExpression = font.getFamily().get(0);
        Expression sizeExpression = font.getSize();
        if (sizeExpression == null || fontFamilyExpression == null)
            return null;

        Double size = sizeExpression.evaluate(null, Double.class);

        try {
            String fontFamily = fontFamilyExpression.evaluate(null, String.class);
            tempFD[0] = new FontData(fontFamily, size.intValue(), 1);
        } catch (NullPointerException ignore) {
            return null;
        }
        if (tempFD[0] != null)
            return tempFD;
        return null;
    }

    /**
     * Retrieves all colour names defined in a rule
     * @param rule the rule
     * @return an array of unique colour names
     */
    public static String[] colors( Rule rule ) {
        Set<String> colorSet = new HashSet<String>();

        Color color = null;
        for( Symbolizer sym : rule.symbolizers() ) {
            if (sym instanceof PolygonSymbolizer) {
                PolygonSymbolizer symb = (PolygonSymbolizer) sym;
                color = polyFill(symb);

            } else if (sym instanceof LineSymbolizer) {
                LineSymbolizer symb = (LineSymbolizer) sym;
                color = color(symb);

            } else if (sym instanceof PointSymbolizer) {
                PointSymbolizer symb = (PointSymbolizer) sym;
                color = pointFillWithAlpha(symb);
            }

            if (color != null) {
                colorSet.add(SLD.colorToHex(color));
            }
        }

        if (colorSet.size() > 0) {
            return colorSet.toArray(new String[0]);
        } else {
            return new String[0];
        }
    }

    /**
     * Extracts the fill color with a given opacity from the {@link PointSymbolizer}.
     *
     * @param symbolizer the point symbolizer from which to get the color.
     * @return the {@link Color} with transparency if available. Returns null if no color is available.
     */
    public static Color pointFillWithAlpha( PointSymbolizer symbolizer ) {
        if (symbolizer == null) {
            return null;
        }

        Graphic graphic = symbolizer.getGraphic();
        if (graphic == null) {
            return null;
        }

        for( GraphicalSymbol gs : graphic.graphicalSymbols() ) {
            if ((gs != null) && (gs instanceof Mark)) {
                Mark mark = (Mark) gs;
                Fill fill = mark.getFill();
                if (fill != null) {
                    Color colour = color(fill.getColor());
                    if (colour == null) {
                        return null;
                    }
                    Expression opacity = fill.getOpacity();
                    if (opacity == null)
                        opacity = ff.literal(1.0);
                    float alpha = (float) Filters.asDouble(opacity);
                    colour = new Color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, alpha);
                    if (colour != null) {
                        return colour;
                    }
                }
            }
        }

        return null;
    }

    /**
     * Extracts the stroke color with a given opacity from the {@link PointSymbolizer}.
     *
     * @param symbolizer the point symbolizer from which to get the color.
     * @return the {@link Color} with transparency if available. Returns null if no color is available.
     */
    public static Color pointStrokeColorWithAlpha( PointSymbolizer symbolizer ) {
        if (symbolizer == null) {
            return null;
        }

        Graphic graphic = symbolizer.getGraphic();
        if (graphic == null) {
            return null;
        }

        for( GraphicalSymbol gs : graphic.graphicalSymbols() ) {
            if ((gs != null) && (gs instanceof Mark)) {
                Mark mark = (Mark) gs;
                Stroke stroke = mark.getStroke();
                if (stroke != null) {
                    Color colour = color(stroke);
                    if (colour == null) {
                        return null;
                    }
                    Expression opacity = stroke.getOpacity();
                    if (opacity == null)
                        opacity = ff.literal(1.0);
                    float alpha = (float) Filters.asDouble(opacity);
                    colour = new Color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, alpha);
                    if (colour != null) {
                        return colour;
                    }
                }
            }
        }

        return null;
    }

    public static Font font( TextSymbolizer symbolizer ) {
        if (symbolizer == null)
            return null;
        Font font = symbolizer.getFont();
        return font;
    }

    public static Style getDefaultStyle( StyledLayerDescriptor sld ) {
        Style[] styles = styles(sld);
        for( int i = 0; i < styles.length; i++ ) {
            Style style = styles[i];
            List<FeatureTypeStyle> ftStyles = style.featureTypeStyles();
            genericizeftStyles(ftStyles);
            if (style.isDefault()) {
                return style;
            }
        }
        // no default, so just grab the first one
        return styles[0];
    }

    /**
     * Converts the type name of all FeatureTypeStyles to Feature so that the all apply to any feature type.  This is admittedly dangerous
     * but is extremely useful because it means that the style can be used with any feature type.
     *
     * @param ftStyles
     */
    private static void genericizeftStyles( List<FeatureTypeStyle> ftStyles ) {
        for( FeatureTypeStyle featureTypeStyle : ftStyles ) {
            featureTypeStyle.featureTypeNames().clear();
            featureTypeStyle.featureTypeNames().add(new NameImpl(SLDs.GENERIC_FEATURE_TYPENAME));
        }
    }

    public static boolean isSemanticTypeMatch( FeatureTypeStyle fts, String regex ) {
        String[] identifiers = fts.getSemanticTypeIdentifiers();
        for( int i = 0; i < identifiers.length; i++ ) {
            if (identifiers[i].matches(regex))
                return true;
        }
        return false;
    }

    /**
     * Returns the min scale of the default rule, or 0 if none is set
     */
    public static double minScale( FeatureTypeStyle fts ) {
        if (fts == null || fts.rules().isEmpty()){
            return 0.0;
        }
        Rule r = fts.rules().get(0);
        return r.getMinScaleDenominator();
    }

    /**
     * Returns the max scale of the default rule, or {@linkplain Double#NaN} if none is set
     */
    public static double maxScale( FeatureTypeStyle fts ) {
        if (fts == null || fts.rules().isEmpty()){
            return Double.NaN;
        }
        Rule r = fts.rules().get(0);
        return r.getMaxScaleDenominator();
    }

    /**
     * gets the first FeatureTypeStyle
     */
    public static FeatureTypeStyle getFeatureTypeStyle( Style s ) {
         List<FeatureTypeStyle> fts = s.featureTypeStyles();
        if (!fts.isEmpty()) {
            return fts.get(0);
        }
        return null;
    }

    /**
     * Find the first rule which contains a rastersymbolizer, and return it
     *
     * @param s A style to search in
     * @return a rule, or null if no raster symbolizers are found.
     */
    public static Rule getRasterSymbolizerRule( Style s ) {
        for( FeatureTypeStyle featureTypeStyle : s.featureTypeStyles() ) {
            for( Rule rule : featureTypeStyle.rules()  ) {
                for( Symbolizer symbolizer : rule.getSymbolizers()) {
                    if (symbolizer instanceof RasterSymbolizer) {
                        return rule;
                    }
                }
            }
        }
        return null;
    }

    /**
     * The type name that can be used in an SLD in the featuretypestyle that matches all feature types.
     */
    public static final String GENERIC_FEATURE_TYPENAME = "Feature";

    public static StyledLayerDescriptor parseSLD(File file) throws IOException {
        StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
     // try SLD 1.1 first
        SLDConfiguration config = new SLDConfiguration();
        Reader reader = null;
        try {
            Parser parser = new Parser( config );
            reader = new FileReader(file);
            Object object = parser.parse( reader );
            if( object instanceof StyledLayerDescriptor){
                StyledLayerDescriptor sld = (StyledLayerDescriptor) object;
                return sld;
            }
            else if ( object instanceof NamedStyle ){
                NamedStyle style = (NamedStyle) object;
                StyledLayerDescriptor sld = createDefaultSLD( style );
                return sld;
            }
        }
        catch(Exception ignore){
            // we are ignoring this error and will try the more forgiving option below
            UiPlugin.trace(SLDs.class,"SLD 1.1 configuration failed to parse "+file, ignore);
        }
        finally {
            if( reader != null){
                reader.close();
            }
        }
        // parse it up
        SLDParser parser = new SLDParser(styleFactory);
        try {
            parser.setInput(file);
            StyledLayerDescriptor sld = parser.parseSLD();
            return sld;
        } catch (FileNotFoundException e) {
            return null; // well that is unexpected since f.exists()
        }
    }
   
    public static Style parseStyle(URL url) throws IOException {
        // try SLD 1.1 first
        SLDConfiguration config = new SLDConfiguration();
        InputStream input = null;
        try {
            Parser parser = new Parser( config );
            input = url.openStream();
            Object object = parser.parse( input );
            if( object instanceof StyledLayerDescriptor){
                StyledLayerDescriptor sld = (StyledLayerDescriptor) object;
                Style[] array = SLDs.styles( sld );
                if( array != null && array.length > 0 ){
                    return array[0];
                }
            }
            else if ( object instanceof NamedStyle ){
                NamedStyle style = (NamedStyle) object;
                return style;
            }
        }
        catch(Exception ignore){
            // we are ignoring this error and will try the more forgiving option below
            UiPlugin.trace(SLDs.class,"SLD 1.1 configuration failed to parse "+url, ignore);
        }
        finally {
            if( input != null){
                input.close();
            }
        }
        // The SLD 1.0 parser is far more forgiving
        StyleFactory factory = CommonFactoryFinder.getStyleFactory(GeoTools.getDefaultHints());
        SLDParser styleReader = new SLDParser(factory, url);
        Style style = styleReader.readXML()[0];
        return style;
    }
   
    public static Style praseStyle(File file) throws IOException {
        StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
        // try SLD 1.1 first
        SLDConfiguration config = new SLDConfiguration();
        Reader reader = null;
        try {
            Parser parser = new Parser( config );
            reader = new FileReader(file);
            Object object = parser.parse( reader );
            if( object instanceof StyledLayerDescriptor){
                StyledLayerDescriptor sld = (StyledLayerDescriptor) object;
                Style[] array = SLDs.styles( sld );
                if( array != null && array.length > 0 ){
                    return array[0];
                }
            }
            else if ( object instanceof NamedStyle ){
                NamedStyle style = (NamedStyle) object;
                return style;
            }
        }
        catch(Exception ignore){
            // we are ignoring this error and will try the more forgiving option below
            UiPlugin.trace(SLDs.class,"SLD 1.1 configuration failed to parse "+file, ignore);
        }
        finally {
            if( reader != null){
                reader.close();
            }
        }
       
        // parse it up
        SLDParser parser = new SLDParser(styleFactory);
        try {
            parser.setInput(file);
            Style[] array = parser.readXML();
            if( array != null && array.length > 0 ){
                return array[0];
            }
        } catch (FileNotFoundException e) {
            return null; // well that is unexpected since f.exists()
        }
        return null;
    }
    /**
     * Creates an SLD and UserLayer, and nests the style (SLD-->UserLayer-->Style).
     *
     * @see net.refractions.project.internal.render.SelectionStyleContent#createDefaultStyledLayerDescriptor
     * @param style
     * @return SLD
     */
    public static StyledLayerDescriptor createDefaultSLD(Style style) {
        StyledLayerDescriptor sld = sf.createStyledLayerDescriptor();
        UserLayer layer = sf.createUserLayer();
        //FeatureTypeConstraint ftc = styleFactory.createFeatureTypeConstraint(null, Filter.INCLUDE, null);
        layer.setLayerFeatureConstraints(new FeatureTypeConstraint[] {null});
        sld.addStyledLayer(layer);
        layer.addUserStyle(style);
        return sld;
    }

}
TOP

Related Classes of org.locationtech.udig.ui.graphics.ColorVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.