eu.udig.style.advanced.utils.Utilities.java Source code

Java tutorial

Introduction

Here is the source code for eu.udig.style.advanced.utils.Utilities.java

Source

/*
 * JGrass - Free Open Source Java GIS http://www.jgrass.org 
 * (C) HydroloGIS - www.hydrologis.com 
 *
 * 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 HydroloGIS BSD
 * License v1.0 (http://udig.refractions.net/files/hsd3-v10.html).
 */
package eu.udig.style.advanced.utils;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import net.refractions.udig.style.sld.SLD;
import net.refractions.udig.ui.graphics.SLDs;

import org.apache.commons.io.FilenameUtils;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Spinner;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.filter.function.FilterFunction_offset;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.FeatureTypeConstraint;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Font;
import org.geotools.styling.Graphic;
import org.geotools.styling.LabelPlacement;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.SLDParser;
import org.geotools.styling.SLDTransformer;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
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.styling.visitor.DuplicatingStyleVisitor;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.style.GraphicalSymbol;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

import eu.udig.style.advanced.common.styleattributeclasses.FeatureTypeStyleWrapper;
import eu.udig.style.advanced.common.styleattributeclasses.RuleWrapper;
import eu.udig.style.advanced.common.styleattributeclasses.StyleWrapper;

/**
 * Style related utilities.
 * 
 * @author Andrea Antonello (www.hydrologis.com)
 */
@SuppressWarnings("nls")
public class Utilities {
    public static final String NONE = "- none -";

    public static final String DEFAULT_SIZE = "5";
    public static final String DEFAULT_WIDTH = "1";
    public static final String DEFAULT_ROTATION = "0";
    public static final String DEFAULT_OFFSET = "0";
    public static final String DEFAULT_OPACITY = "1";
    public static final String DEFAULT_COLOR = "#000000";
    public static final String DEFAULT_MINSCALE = "0";
    public static final String DEFAULT_MAXSCALE = "infinity";

    // offset values
    public static final int OFFSET_MAX = 1000;
    public static final int OFFSET_MIN = -1000;
    public static final int OFFSET_STEP = 10;
    // displacement values
    public static final int DISPLACEMENT_MAX = 1000;
    public static final int DISPLACEMENT_MIN = -1000;
    public static final int DISPLACEMENT_STEP = 10;

    public static final String DEFAULT_GROUPNAME = "group ";
    public static final String DEFAULT_STYLENAME = "default style";

    public static final String SLD_EXTENTION = ".sld";

    /**
     * The SLD defined well known mark codes.
     */
    public static final String[] wkMarkDefs = { //
            "", //
            "cross", //
            "circle", //
            "triangle", //
            "X", //
            "star", //
            "arrow", //
            "hatch", //
            "square"//
    };

    /**
     * The SLD defined well known mark names for gui use.
     */
    public static final String[] wkMarkNames = { //
            "", //
            "cross", //
            "circle", //
            "triangle", //
            "X", //
            "star", //
            "arrow", //
            "hatch", //
            "square"//
    };

    public static final String SHAPE_PREFIX = "shape://";

    /**
     * The custom shape mark names as needed by geotools.
     */
    public static final String[] shapeMarkDefs = { //
            "", //
            SHAPE_PREFIX + "vertline", //
            SHAPE_PREFIX + "horline", //
            SHAPE_PREFIX + "slash", //
            SHAPE_PREFIX + "backslash", //
            SHAPE_PREFIX + "times", //
            SHAPE_PREFIX + "dot", //
            SHAPE_PREFIX + "plus" //
    };
    /**
     * The custom shape mark names for gui.
     */
    public static final String[] shapeMarkNames = { //
            "", //
            "vertical lines", //
            "horizontal lines", //
            "diagonal lines", //
            "inverse diagonal lines", //
            "crossed diagonal lines", //
            "dots", //
            "plus" //
    };

    /**
     * A map of names for all the marks.
     */
    public static final BiMap<String, String> markNamesToDef = HashBiMap.create();
    static {

        // well known marks
        markNamesToDef.put(wkMarkNames[0], wkMarkDefs[0]);
        markNamesToDef.put(wkMarkNames[1], wkMarkDefs[1]);
        markNamesToDef.put(wkMarkNames[2], wkMarkDefs[2]);
        markNamesToDef.put(wkMarkNames[3], wkMarkDefs[3]);
        markNamesToDef.put(wkMarkNames[4], wkMarkDefs[4]);
        markNamesToDef.put(wkMarkNames[5], wkMarkDefs[5]);
        markNamesToDef.put(wkMarkNames[6], wkMarkDefs[6]);
        markNamesToDef.put(wkMarkNames[7], wkMarkDefs[7]);
        markNamesToDef.put(wkMarkNames[8], wkMarkDefs[8]);
        // custom shapes
        markNamesToDef.put(shapeMarkNames[1], shapeMarkDefs[1]);
        markNamesToDef.put(shapeMarkNames[2], shapeMarkDefs[2]);
        markNamesToDef.put(shapeMarkNames[3], shapeMarkDefs[3]);
        markNamesToDef.put(shapeMarkNames[4], shapeMarkDefs[4]);
        markNamesToDef.put(shapeMarkNames[5], shapeMarkDefs[5]);
        markNamesToDef.put(shapeMarkNames[6], shapeMarkDefs[6]);
        markNamesToDef.put(shapeMarkNames[7], shapeMarkDefs[7]);
    }

    /**
     * Getter for an array of all available marks.
     * 
     * @return all mark names (for gui use).
     */
    public static String[] getAllMarksArray() {
        Set<String> keySet = markNamesToDef.keySet();
        return (String[]) keySet.toArray(new String[keySet.size()]);
    }

    /**
     * The SLD names of the line cap definitions.
     */
    public static final String[] lineCapNames = { //
            "", //
            "butt", //
            "round", //
            "square" //
    };

    /**
     * The SLD names of the line join definitions.
     */
    public static final String[] verticalPlacementNames = { //
            "bevel", //
            "miter", //
            "round" //
    };

    /**
     * The SLD names of the line join definitions.
     */
    public static final String[] lineJoinNames = { //
            "", //
            "bevel", //
            "miter", //
            "round" //
    };

    /**
     * The default {@link StyleFactory} to use.
     */
    public static StyleFactory sf = CommonFactoryFinder.getStyleFactory(GeoTools.getDefaultHints());

    /**
     * The default {@link FilterFactory} to use.
     */
    public static FilterFactory ff = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());

    /**
     * The default {@link StyleBuilder} to use.
     */
    public static StyleBuilder sb = new StyleBuilder(sf, ff);

    /** 
     * Utility class for working with Images, Features and Styles 
     */
    private static Drawing d = Drawing.create();

    /**
     * Parse a file and extract the {@link StyledLayerDescriptor}.
     * 
     * @param file the sld file to parse.
     * @return the styled layer descriptor.
     * @throws IOException
     */
    public static StyledLayerDescriptor readStyle(File file) throws IOException {
        SLDParser stylereader = new SLDParser(sf, file);
        StyledLayerDescriptor sld = stylereader.parseSLD();
        return sld;
    }

    /**
     * Creates an image from a set of {@link RuleWrapper}s.
     * 
     * @param ruleWrapperList the list of rule wrappers.
     * @param width the image width.
     * @param height the image height.
     * @param type the geometry type.
     * @return the new created {@link BufferedImage}.
     */
    public static BufferedImage rulesWrapperToImage(List<RuleWrapper> ruleWrappers, int width, int height,
            SLD type) {
        switch (type) {
        case POINT:
            return Utilities.pointRulesWrapperToImage(ruleWrappers, width, height);
        case LINE:
            return Utilities.lineRulesWrapperToImage(ruleWrappers, width, height);
        case POLYGON:
            return Utilities.polygonRulesWrapperToImage(ruleWrappers, width, height);
        default:
            return null;
        }
    }

    /**
     * Creates an image from a {@link RuleWrapper}.
     * 
     * @param ruleWrapper the rule wrapper.
     * @param width the image width.
     * @param height the image height.
     * @param type the geometry type.
     * @return the new created {@link BufferedImage}.
     */
    public static BufferedImage rulesWrapperToImage(RuleWrapper ruleWrapper, int width, int height, SLD type) {
        switch (type) {
        case POINT:
            return Utilities.pointRuleWrapperToImage(ruleWrapper, width, height);
        case LINE:
            return Utilities.lineRuleWrapperToImage(ruleWrapper, width, height);
        case POLYGON:
            return Utilities.polygonRuleWrapperToImage(ruleWrapper, width, height);
        default:
            return null;
        }
    }

    /**
     * Creates an image from a set of {@link RuleWrapper}s.
     * 
     * @param ruleWrapperList the list of rule wrappers.
     * @param width the image width.
     * @param height the image height.
     * @return the new created {@link BufferedImage}.
     */
    public static BufferedImage pointRulesWrapperToImage(final List<RuleWrapper> ruleWrapperList, int width,
            int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        for (RuleWrapper ruleWrapper : ruleWrapperList) {
            BufferedImage tmpImage = Utilities.pointRuleWrapperToImage(ruleWrapper, width, height);
            g2d.drawImage(tmpImage, 0, 0, null);
        }
        g2d.dispose();
        return image;
    }

    /**
     * Creates an {@link Image} for the given {@link RuleWrapper}.
     * 
     * @param ruleWrapper the rule for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage pointRuleWrapperToImage(RuleWrapper ruleWrapper, int width, int height) {
        return pointRuleToImage(ruleWrapper.getRule(), width, height);
    }

    /**
     * Creates an {@link Image} for the given rule.
     * 
     * @param rule the rule for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage pointRuleToImage(final Rule rule, int width, int height) {
        DuplicatingStyleVisitor copyStyle = new DuplicatingStyleVisitor();
        rule.accept(copyStyle);
        Rule newRule = (Rule) copyStyle.getCopy();

        int pointSize = 0;
        Stroke stroke = null;
        Symbolizer[] symbolizers = newRule.getSymbolizers();
        if (symbolizers.length > 0) {
            Symbolizer symbolizer = newRule.getSymbolizers()[0];
            if (symbolizer instanceof PointSymbolizer) {
                PointSymbolizer pointSymbolizer = (PointSymbolizer) symbolizer;
                pointSize = SLDs.pointSize(pointSymbolizer);
                stroke = SLDs.stroke(pointSymbolizer);
            }
        }
        int strokeSize = 0;
        if (stroke != null) {
            strokeSize = SLDs.width(stroke);
            if (strokeSize < 0) {
                strokeSize = 1;
                stroke.setWidth(ff.literal(strokeSize));
            }
        }
        pointSize = pointSize + 2 * strokeSize;
        if (pointSize <= 0) {
            pointSize = width;
        }

        // pointSize = width;
        BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        BufferedImage pointImage = new BufferedImage(pointSize, pointSize, BufferedImage.TYPE_INT_ARGB);
        Point point = d.point(pointSize / 2, pointSize / 2);
        d.drawDirect(pointImage, d.feature(point), newRule);
        Graphics2D g2d = finalImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        if (pointSize > width || pointSize > height) {
            g2d.drawImage(pointImage, 0, 0, width, height, 0, 0, pointSize, pointSize, null);
        } else {
            int x = width / 2 - pointSize / 2;
            int y = height / 2 - pointSize / 2;
            g2d.drawImage(pointImage, x, y, null);
        }
        g2d.dispose();

        return finalImage;
    }

    /**
     * Creates an image from a set of {@link RuleWrapper}s.
     * 
     * @param rulesWrapperList the list of rules wrapper.
     * @param width the image width.
     * @param height the image height.
     * @return the new created {@link BufferedImage}.
     */
    public static BufferedImage polygonRulesWrapperToImage(final List<RuleWrapper> rulesWrapperList, int width,
            int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        for (RuleWrapper rule : rulesWrapperList) {
            BufferedImage tmpImage = Utilities.polygonRuleWrapperToImage(rule, width, height);
            g2d.drawImage(tmpImage, 0, 0, null);
        }
        g2d.dispose();
        return image;
    }

    /**
     * Creates an {@link Image} for the given ruleWrapper.
     * 
     * @param ruleWrapper the rule wrapper for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage polygonRuleWrapperToImage(final RuleWrapper ruleWrapper, int width, int height) {
        return polygonRuleToImage(ruleWrapper.getRule(), width, height);
    }

    /**
     * Creates an {@link Image} for the given rule.
     * 
     * @param rule the rule for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage polygonRuleToImage(final Rule rule, int width, int height) {
        DuplicatingStyleVisitor copyStyle = new DuplicatingStyleVisitor();
        rule.accept(copyStyle);
        Rule newRule = (Rule) copyStyle.getCopy();

        Stroke stroke = null;
        Symbolizer[] symbolizers = newRule.getSymbolizers();
        if (symbolizers.length > 0) {
            Symbolizer symbolizer = symbolizers[0];
            if (symbolizer instanceof PolygonSymbolizer) {
                PolygonSymbolizer polygonSymbolizer = (PolygonSymbolizer) symbolizer;
                stroke = SLDs.stroke(polygonSymbolizer);
            }
        }
        int strokeSize = 0;
        if (stroke != null) {
            strokeSize = SLDs.width(stroke);
            if (strokeSize < 0) {
                strokeSize = 0;
                stroke.setWidth(ff.literal(strokeSize));
            }
        }

        // pointSize = width;
        BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        // Polygon polygon = d.polygon(new int[]{40,30, 60,70, 30,130, 130,130, 130,30});

        int[] xy = new int[] { (int) (height * 0.15), (int) (width * 0.20), (int) (height * 0.4),
                (int) (width * 0.3), (int) (height * 0.85), (int) (width * 0.15), (int) (height * 0.85),
                (int) (width * 0.85), (int) (height * 0.15), (int) (width * 0.85) };
        Polygon polygon = d.polygon(xy);
        d.drawDirect(finalImage, d.feature(polygon), newRule);
        Graphics2D g2d = finalImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawImage(finalImage, 0, 0, null);
        g2d.dispose();

        return finalImage;
    }

    /**
     * Creates an image from a set of {@link RuleWrapper}s.
     * 
     * @param rulesWrapperList the list of rules wrapper.
     * @param width the image width.
     * @param height the image height.
     * @return the new created {@link BufferedImage}.
     */
    public static BufferedImage lineRulesWrapperToImage(final List<RuleWrapper> rulesWrapperList, int width,
            int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        for (RuleWrapper rule : rulesWrapperList) {
            BufferedImage tmpImage = Utilities.lineRuleWrapperToImage(rule, width, height);
            g2d.drawImage(tmpImage, 0, 0, null);
        }
        g2d.dispose();
        return image;
    }

    /**
     * Creates an {@link Image} for the given ruleWrapper.
     * 
     * @param ruleWrapper the rule wrapper for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage lineRuleWrapperToImage(RuleWrapper ruleWrapper, int width, int height) {
        return lineRuleToImage(ruleWrapper.getRule(), width, height);
    }

    /**
     * Creates an {@link Image} for the given rule.
     * 
     * @param rule the rule for which to create the image.
     * @param width the image width.
     * @param height the image height.
     * @return the generated image.
     */
    public static BufferedImage lineRuleToImage(final Rule rule, int width, int height) {
        DuplicatingStyleVisitor copyStyle = new DuplicatingStyleVisitor();
        rule.accept(copyStyle);
        Rule newRule = (Rule) copyStyle.getCopy();

        Stroke stroke = null;
        Symbolizer[] symbolizers = newRule.getSymbolizers();
        if (symbolizers.length > 0) {
            Symbolizer symbolizer = newRule.getSymbolizers()[0];
            if (symbolizer instanceof LineSymbolizer) {
                LineSymbolizer lineSymbolizer = (LineSymbolizer) symbolizer;
                stroke = SLDs.stroke(lineSymbolizer);
            }
        }

        int strokeSize = 0;
        if (stroke != null) {
            strokeSize = SLDs.width(stroke);
            if (strokeSize < 0) {
                strokeSize = 0;
                stroke.setWidth(ff.literal(strokeSize));
            }
        }

        // pointSize = width;
        BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        // Polygon polygon = d.polygon(new int[]{40,30, 60,70, 30,130, 130,130, 130,30});

        int[] xy = new int[] { (int) (height * 0.15), (int) (width * 0.85), (int) (height * 0.35),
                (int) (width * 0.15), (int) (height * 0.75), (int) (width * 0.85), (int) (height * 0.85),
                (int) (width * 0.15) };
        LineString line = d.line(xy);
        d.drawDirect(finalImage, d.feature(line), newRule);
        Graphics2D g2d = finalImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawImage(finalImage, 0, 0, null);
        g2d.dispose();

        return finalImage;
    }

    /**
     * Collect all {@link ExternalGraphic}s from the given {@link Rule}.
     * 
     * @param rule the rule to check.
     * @return the extracted {@link ExternalGraphic}s.
     */
    public static List<ExternalGraphic> externalGraphicsFromRule(Rule rule) {
        List<ExternalGraphic> gList = new ArrayList<ExternalGraphic>();
        List<Symbolizer> symbolizers = rule.symbolizers();
        if (symbolizers.size() != 0) {
            for (Symbolizer symbolizer : symbolizers) {
                Graphic[] graphics = new Graphic[2];
                if (symbolizer instanceof PointSymbolizer) {
                    PointSymbolizer pointSymbolizer = (PointSymbolizer) symbolizer;
                    graphics[0] = pointSymbolizer.getGraphic();
                } else if (symbolizer instanceof LineSymbolizer) {
                    LineSymbolizer lineSymbolizer = (LineSymbolizer) symbolizer;
                    Stroke stroke = lineSymbolizer.getStroke();
                    graphics[0] = stroke.getGraphicStroke();
                } else if (symbolizer instanceof PolygonSymbolizer) {
                    PolygonSymbolizer polygonSymbolizer = (PolygonSymbolizer) symbolizer;
                    Stroke stroke = polygonSymbolizer.getStroke();
                    if (stroke != null)
                        graphics[0] = stroke.getGraphicStroke();
                    Fill fill = polygonSymbolizer.getFill();
                    if (fill != null)
                        graphics[1] = fill.getGraphicFill();
                }
                for (int i = 0; i < graphics.length; i++) {
                    if (graphics[i] != null) {
                        for (GraphicalSymbol gs : graphics[i].graphicalSymbols()) {
                            if ((gs != null) && (gs instanceof ExternalGraphic)) {
                                ExternalGraphic externalGraphic = (ExternalGraphic) gs;
                                gList.add(externalGraphic);
                            }
                        }
                    }
                }
            }
            return gList;
        }
        return Collections.emptyList();
    }

    /**
     * Collect all {@link ExternalGraphic}s from the given {@link Graphic}.
     * 
     * @param graphic the graphic to check.
     * @return the extracted {@link ExternalGraphic}s.
     */
    public static List<ExternalGraphic> externalGraphicsFromGraphic(Graphic graphic) {
        List<ExternalGraphic> gList = new ArrayList<ExternalGraphic>();
        for (GraphicalSymbol gs : graphic.graphicalSymbols()) {
            if ((gs != null) && (gs instanceof ExternalGraphic)) {
                ExternalGraphic externalGraphic = (ExternalGraphic) gs;
                gList.add(externalGraphic);
            }
        }
        return gList;
    }

    /**
     * Creates a default {@link Style} for a point.
     * 
     * @return the default style.
     */
    public static Style createDefaultPointStyle() {

        FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle();
        featureTypeStyle.rules().add(createDefaultPointRule());

        Style style = sf.createStyle();
        style.featureTypeStyles().add(featureTypeStyle);

        return style;
    }

    /**
     * Creates a default {@link Rule} for a point.
     * 
     * @return the default rule.
     */
    public static Rule createDefaultPointRule() {
        Graphic graphic = sf.createDefaultGraphic();
        Mark circleMark = sf.getCircleMark();
        circleMark.setFill(sf.createFill(ff.literal(Color.red)));
        circleMark.setStroke(sf.createStroke(ff.literal(Color.BLACK), ff.literal(DEFAULT_WIDTH)));
        graphic.graphicalSymbols().clear();
        graphic.graphicalSymbols().add(circleMark);
        graphic.setSize(ff.literal(DEFAULT_SIZE));

        PointSymbolizer pointSymbolizer = sf.createPointSymbolizer();
        Rule rule = sf.createRule();
        rule.setName("New rule");
        rule.symbolizers().add(pointSymbolizer);

        pointSymbolizer.setGraphic(graphic);
        return rule;
    }

    /**
     * Creates a default {@link Style} for a polygon.
     * 
     * @return the default style.
     */
    public static Style createDefaultPolygonStyle() {
        FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle();
        featureTypeStyle.rules().add(createDefaultPolygonRule());

        Style style = sf.createStyle();
        style.featureTypeStyles().add(featureTypeStyle);

        return style;
    }

    /**
     * Creates a default {@link Rule} for a polygon.
     * 
     * @return the default rule.
     */
    public static Rule createDefaultPolygonRule() {
        PolygonSymbolizer polygonSymbolizer = sf.createPolygonSymbolizer();
        polygonSymbolizer.setFill(sf.createFill(ff.literal(Color.red)));
        polygonSymbolizer.setStroke(sf.createStroke(ff.literal(Color.BLACK), ff.literal(DEFAULT_WIDTH)));

        Rule rule = sf.createRule();
        rule.setName("New rule");
        rule.symbolizers().add(polygonSymbolizer);

        return rule;
    }

    /**
     * Creates a default {@link Style} for a line.
     * 
     * @return the default style.
     */
    public static Style createDefaultLineStyle() {
        FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle();
        featureTypeStyle.rules().add(createDefaultLineRule());

        Style style = sf.createStyle();
        style.featureTypeStyles().add(featureTypeStyle);

        return style;
    }

    /**
     * Creates a default {@link Rule} for a line.
     * 
     * @return the default rule.
     */
    public static Rule createDefaultLineRule() {
        LineSymbolizer lineSymbolizer = sf.createLineSymbolizer();
        lineSymbolizer.setStroke(sf.createStroke(ff.literal(Color.BLACK), ff.literal(1)));

        Rule rule = sf.createRule();
        rule.setName("New rule");
        rule.symbolizers().add(lineSymbolizer);

        return rule;
    }

    /**
     * Creates a default {@link TextSymbolizer} for a given type.
     * 
     * @return the default symbolizer.
     */
    public static TextSymbolizer createDefaultTextSymbolizer(SLD type) {
        LabelPlacement labelPlacement = null;

        switch (type) {
        case POINT:
        case POLYGON:
            labelPlacement = sf.createPointPlacement(sf.createAnchorPoint(ff.literal(0.0), ff.literal(0.0)),
                    sf.createDisplacement(ff.literal(0.0), ff.literal(0.0)), ff.literal(0.0));
            break;
        case LINE:
            labelPlacement = sf.createLinePlacement(ff.literal(10.0));
            break;

        default:
            throw new IllegalArgumentException();
        }

        Font font = sb.createFont("Arial", false, false, 12); //$NON-NLS-1$
        TextSymbolizer textSymbolizer = sf.createTextSymbolizer(sf.createFill(ff.literal(DEFAULT_COLOR)),
                new Font[] { font }, null, ff.literal("dummy"), labelPlacement, null);

        return textSymbolizer;
    }

    /**
     * Creates a default {@link TextSymbolizer} for a point.
     * 
     * @return the default symbolizer.
     */
    public static Symbolizer createDefaultGeometrySymbolizer(SLD type) {
        Symbolizer symbolizer = null;
        switch (type) {
        case POINT:
            Rule defaultPointRule = createDefaultPointRule();
            symbolizer = defaultPointRule.getSymbolizers()[0];
            break;
        case POLYGON:
            Rule defaultPolygonRule = createDefaultPolygonRule();
            symbolizer = defaultPolygonRule.getSymbolizers()[0];
            break;
        case LINE:
            Rule defaultLineRule = createDefaultLineRule();
            symbolizer = defaultLineRule.getSymbolizers()[0];
            break;

        default:
            throw new IllegalArgumentException();
        }

        return symbolizer;
    }

    /**
     * Get the {@link PointSymbolizer} from the given rule.
     * 
     * @param rule the rule to check for symbolizers.
     * @return the first symbolizer found.
     */
    public static PointSymbolizer pointSymbolizerFromRule(Rule rule) {
        List<Symbolizer> symbolizers = rule.symbolizers();
        PointSymbolizer pointSymbolizer = null;
        for (Symbolizer symbolizer : symbolizers) {
            if (symbolizer instanceof PointSymbolizer) {
                pointSymbolizer = (PointSymbolizer) symbolizer;
                break;
            }
        }
        if (pointSymbolizer == null) {
            throw new IllegalArgumentException();
        }
        return pointSymbolizer;
    }

    /**
     * Get the {@link PolygonSymbolizer} from the given rule.
     * 
     * @param rule the rule to check for symbolizers.
     * @return the first symbolizer found.
     */
    public static PolygonSymbolizer polygonSymbolizerFromRule(Rule rule) {
        List<Symbolizer> symbolizers = rule.symbolizers();
        PolygonSymbolizer polygonSymbolizer = null;
        for (Symbolizer symbolizer : symbolizers) {
            if (symbolizer instanceof PolygonSymbolizer) {
                polygonSymbolizer = (PolygonSymbolizer) symbolizer;
                break;
            }
        }
        if (polygonSymbolizer == null) {
            throw new IllegalArgumentException();
        }
        return polygonSymbolizer;
    }

    /**
     * Get the {@link LineSymbolizer} from the given rule.
     * 
     * @param rule the rule to check for symbolizers.
     * @return the first symbolizer found.
     */
    public static LineSymbolizer lineSymbolizerFromRule(Rule rule) {
        List<Symbolizer> symbolizers = rule.symbolizers();
        LineSymbolizer lineSymbolizer = null;
        for (Symbolizer symbolizer : symbolizers) {
            if (symbolizer instanceof LineSymbolizer) {
                lineSymbolizer = (LineSymbolizer) symbolizer;
                break;
            }
        }
        if (lineSymbolizer == null) {
            throw new IllegalArgumentException();
        }
        return lineSymbolizer;
    }

    /**
     * Change the mark shape in a rule.
     * 
     * @param rule the rule of which the mark has to be changed.
     * @param wellKnownMarkName the name of the new mark.
     */
    public static void substituteMark(Rule rule, String wellKnownMarkName) {
        PointSymbolizer pointSymbolizer = Utilities.pointSymbolizerFromRule(rule);
        Mark oldMark = SLDs.mark(pointSymbolizer);

        Graphic graphic = SLDs.graphic(pointSymbolizer);
        graphic.graphicalSymbols().clear();

        Mark mark = Utilities.sf.createMark();
        mark.setWellKnownName(Utilities.ff.literal(wellKnownMarkName));
        if (oldMark != null) {
            mark.setFill(oldMark.getFill());
            mark.setStroke(oldMark.getStroke());
        }
        graphic.graphicalSymbols().add(mark);
    }

    /**
     * Change the external graphic in a rule.
     * 
     * @param rule the rule of which the external graphic has to be changed.
     * @param path the path of the image.
     */
    public static void substituteExternalGraphics(Rule rule, URL externalGraphicsUrl) {
        String urlString = externalGraphicsUrl.toString();
        String format = "";
        if (urlString.toLowerCase().endsWith(".png")) {
            format = "image/png";
        } else if (urlString.toLowerCase().endsWith(".jpg")) {
            format = "image/jpg";
        } else if (urlString.toLowerCase().endsWith(".svg")) {
            format = "image/svg+xml";
        } else {
            urlString = "";
            try {
                externalGraphicsUrl = new URL("file:");
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        PointSymbolizer pointSymbolizer = Utilities.pointSymbolizerFromRule(rule);
        Graphic graphic = SLDs.graphic(pointSymbolizer);
        graphic.graphicalSymbols().clear();
        ExternalGraphic exGraphic = sf.createExternalGraphic(externalGraphicsUrl, format);

        graphic.graphicalSymbols().add(exGraphic);
    }

    public static String getFormat(String path) {
        String format = "";
        if (path.toLowerCase().endsWith(".png")) {
            format = "image/png";
        } else if (path.toLowerCase().endsWith(".jpg")) {
            format = "image/jpg";
        } else if (path.toLowerCase().endsWith(".gif")) {
            format = "image/gif";
        } else if (path.toLowerCase().endsWith(".svg")) {
            format = "image/svg+xml";
        }
        return format;
    }

    /**
     * Get the format of an {@link ExternalGraphic} from its path or name.
     * 
     * @param name the path or file name to test against.
     * @return teh format definition.
     */
    public static String getExternalGraphicFormat(String name) {
        String format = "";
        if (name.toLowerCase().endsWith(".png")) {
            format = "image/png";
        } else if (name.toLowerCase().endsWith(".jpg")) {
            format = "image/jpg";
        } else if (name.toLowerCase().endsWith(".gif")) {
            format = "image/gif";
        } else if (name.toLowerCase().endsWith(".svg")) {
            format = "image/svg+xml";
        } else {
            return null;
        }

        return format;
    }

    /**
     * Changes the size of a mark inside a rule.
     * 
     * @param rule the {@link Rule}.
     * @param newSize the new size.
     */
    public static void changeMarkSize(Rule rule, int newSize) {
        PointSymbolizer pointSymbolizer = Utilities.pointSymbolizerFromRule(rule);
        Graphic graphic = SLDs.graphic(pointSymbolizer);
        graphic.setSize(ff.literal(newSize));
        // Mark oldMark = SLDs.mark(pointSymbolizer);
        // oldMark.setSize(ff.literal(newSize));
        // Graphic graphic = SLDs.graphic(pointSymbolizer);
    }

    /**
     * Changes the rotation value inside a rule.
     * 
     * @param rule the {@link Rule}.
     * @param newRotation the new rotation value in degrees.
     */
    public static void changeRotation(Rule rule, int newRotation) {
        PointSymbolizer pointSymbolizer = Utilities.pointSymbolizerFromRule(rule);
        Graphic graphic = SLDs.graphic(pointSymbolizer);
        graphic.setRotation(ff.literal(newRotation));
        // Mark oldMark = SLDs.mark(pointSymbolizer);
        // oldMark.setSize(ff.literal(newRotation));
    }

    /**
     * Get the offset from a {@link Symbolizer}.
     * 
     * @param symbolizer the symbolizer.
     * @return the offset.
     */
    @SuppressWarnings("rawtypes")
    public static Point2D getOffset(Symbolizer symbolizer) {
        Expression geometry = symbolizer.getGeometry();
        if (geometry != null) {
            if (geometry instanceof FilterFunction_offset) {
                FilterFunction_offset offsetFunction = (FilterFunction_offset) geometry;
                List parameters = offsetFunction.getParameters();
                Expression xOffsetExpr = (Expression) parameters.get(1);
                Expression yOffsetExpr = (Expression) parameters.get(2);
                Double xOffsetDouble = xOffsetExpr.evaluate(null, Double.class);
                Double yOffsetDouble = yOffsetExpr.evaluate(null, Double.class);
                if (xOffsetDouble != null && yOffsetDouble != null) {
                    Point2D.Double point = new Point2D.Double(xOffsetDouble, yOffsetDouble);
                    return point;
                }
            }
        }
        return null;
    }

    /**
     * Sets the offset in a symbolizer.
     * 
     * @param symbolizer the symbolizer.
     * @param text the text representing the offsets in the CSV form.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void setOffset(Symbolizer symbolizer, String text) {
        if (text.indexOf(',') == -1) {
            return;
        }
        String[] split = text.split(",");
        if (split.length != 2) {
            return;
        }
        double xOffset = Double.parseDouble(split[0]);
        double yOffset = Double.parseDouble(split[1]);

        Expression geometry = symbolizer.getGeometry();
        if (geometry != null) {
            if (geometry instanceof FilterFunction_offset) {
                FilterFunction_offset offsetFunction = (FilterFunction_offset) geometry;
                List parameters = offsetFunction.getParameters();
                parameters.set(1, ff.literal(xOffset));
                parameters.set(2, ff.literal(yOffset));
            }
        } else {
            Function function = ff.function("offset", ff.property("the_geom"), ff.literal(xOffset),
                    ff.literal(yOffset));
            symbolizer.setGeometry(function);
        }
    }

    /**
     * Checks if the list of {@link Rule}s supplied contains one with the supplied name.
     * 
     * <p>If the rule is contained it adds an index to the name.
     * 
     * @param rulesWrapper the list of rules to check.
     * @param ruleName the name of the rule to find.
     * @return the new name of the rule.
     */
    public static String checkSameNameRule(List<RuleWrapper> rulesWrapper, String ruleName) {
        int index = 1;
        String name = ruleName.trim();
        for (int i = 0; i < rulesWrapper.size(); i++) {
            RuleWrapper ruleWrapper = rulesWrapper.get(i);
            String tmpName = ruleWrapper.getName();
            if (tmpName == null) {
                continue;
            }

            tmpName = tmpName.trim();
            if (tmpName.equals(name)) {
                // name exists, change the name of the entering
                if (name.endsWith(")")) {
                    name = name.trim().replaceFirst("\\([0-9]+\\)$", "(" + (index++) + ")");
                } else {
                    name = name + " (" + (index++) + ")";
                }
                // start again
                i = 0;
            }
            if (index == 1000) {
                // something odd is going on
                throw new RuntimeException();
            }
        }
        return name;
    }

    /**
     * Checks if the list of {@link FeatureTypeStyleWrapper}s supplied contains one with the supplied name.
     * 
     * <p>If the rule is contained it adds an index to the name.
     * 
     * @param ftsWrapperList the list of featureTypeStyles to check.
     * @param ftsName the name of the featureTypeStyle to find.
     * @return the new name of the featureTypeStyle.
     */
    public static String checkSameNameFeatureTypeStyle(List<FeatureTypeStyleWrapper> ftsWrapperList,
            String ftsName) {
        int index = 1;
        String name = ftsName.trim();
        for (int i = 0; i < ftsWrapperList.size(); i++) {
            FeatureTypeStyleWrapper ftsWrapper = ftsWrapperList.get(i);
            String tmpName = ftsWrapper.getName();
            if (tmpName == null) {
                continue;
            }

            tmpName = tmpName.trim();
            if (tmpName.equals(name)) {
                // name exists, change the name of the entering
                if (name.endsWith(")")) {
                    name = name.trim().replaceFirst("\\([0-9]+\\)$", "(" + (index++) + ")");
                } else {
                    name = name + " (" + (index++) + ")";
                }
                // start again
                i = 0;
            }
            if (index == 1000) {
                // something odd is going on
                throw new RuntimeException();
            }
        }
        return name;
    }

    /**
     * Checks if the list of {@link StyleWrapper}s supplied contains one with the supplied name.
     * 
     * <p>If the style is contained it adds an index to the name.
     * 
     * @param styles the list of style wrappers to check.
     * @param styleName the name of the style to find.
     * @return the new name of the style.
     */
    public static String checkSameNameStyle(List<StyleWrapper> styles, String styleName) {
        int index = 1;
        String name = styleName.trim();
        for (int i = 0; i < styles.size(); i++) {
            StyleWrapper styleWrapper = styles.get(i);
            String tmpName = styleWrapper.getName();
            if (tmpName == null) {
                continue;
            }

            tmpName = tmpName.trim();
            if (tmpName.equals(name)) {
                // name exists, change the name of the entering
                if (name.endsWith(")")) {
                    name = name.trim().replaceFirst("\\([0-9]+\\)$", "(" + (index++) + ")");
                } else {
                    name = name + " (" + (index++) + ")";
                }
                // start again
                i = 0;
            }
            if (index == 1000) {
                // something odd is going on
                throw new RuntimeException();
            }
        }
        return name;
    }

    /**
     * Converts a list of {@link Rule}s to a {@link Style} with the given name.
     * 
     * @param rules the list of rules.
     * @param name the name of the new style.
     * @param oneFeaturetypestylePerRule switch to create a {@link FeatureTypeStyle} per {@link Rule}. 
     * @return the new style created.
     */
    public static Style rulesToStyle(List<Rule> rules, String name, boolean oneFeaturetypestylePerRule) {
        Style namedStyle = Utilities.sf.createStyle();
        if (!oneFeaturetypestylePerRule) {
            FeatureTypeStyle featureTypeStyle = Utilities.sf.createFeatureTypeStyle();
            List<Rule> currentRules = featureTypeStyle.rules();
            for (int i = 0; i < rules.size(); i++) {
                Rule rule = rules.get(i);
                currentRules.add(rule);
            }
            namedStyle.featureTypeStyles().add(featureTypeStyle);
        } else {
            for (int i = 0; i < rules.size(); i++) {
                FeatureTypeStyle featureTypeStyle = Utilities.sf.createFeatureTypeStyle();
                Rule rule = rules.get(i);
                featureTypeStyle.rules().add(rule);
                namedStyle.featureTypeStyles().add(featureTypeStyle);
            }
        }
        namedStyle.setName(name);
        return namedStyle;
    }

    /**
     * Converts a style to its string representation to be written to file.
     * 
     * @param style the style to convert.
     * @return the style string.
     * @throws Exception
     */
    public static String styleToString(Style style) throws Exception {
        StyledLayerDescriptor sld = sf.createStyledLayerDescriptor();
        UserLayer layer = sf.createUserLayer();
        layer.setLayerFeatureConstraints(new FeatureTypeConstraint[] { null });
        sld.addStyledLayer(layer);
        layer.addUserStyle(style);

        SLDTransformer aTransformer = new SLDTransformer();
        aTransformer.setIndentation(4);
        String xml = aTransformer.transform(sld);
        return xml;
    }

    /**
     * Generates a style based on a graphic.
     * 
     * @param graphicsPath the graphic.
     * @return the generated style.
     * @throws IOException
     */
    public static StyleWrapper createStyleFromGraphic(File graphicsPath) throws IOException {
        String name = graphicsPath.getName();
        ExternalGraphic exGraphic = null;
        if (name.toLowerCase().endsWith(".png")) {
            exGraphic = sf.createExternalGraphic(graphicsPath.toURI().toURL(), "image/png");
        } else if (name.toLowerCase().endsWith(".svg")) {
            exGraphic = sf.createExternalGraphic(graphicsPath.toURI().toURL(), "image/svg+xml");
        } else if (name.toLowerCase().endsWith(".sld")) {
            StyledLayerDescriptor sld = readStyle(graphicsPath);
            Style style = SLDs.getDefaultStyle(sld);
            return new StyleWrapper(style);
        }

        if (exGraphic == null) {
            throw new IOException("Style could not be created!");
        }

        Graphic gr = sf.createDefaultGraphic();
        gr.graphicalSymbols().clear();
        gr.graphicalSymbols().add(exGraphic);
        Expression size = ff.literal(20);
        gr.setSize(size);

        Rule rule = sf.createRule();
        PointSymbolizer pointSymbolizer = sf.createPointSymbolizer(gr, null);
        rule.symbolizers().add(pointSymbolizer);

        FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle();
        featureTypeStyle.rules().add(rule);

        Style namedStyle = sf.createStyle();
        namedStyle.featureTypeStyles().add(featureTypeStyle);
        namedStyle.setName(FilenameUtils.removeExtension(name));

        return new StyleWrapper(namedStyle);
    }

    /**
     * Returns a dash array from a dash string.
     * 
     * @param dashStr the dash string definition. 
     * @return the dash array or null if the definition can't be parsed.
     */
    public static float[] getDash(String dashStr) {
        if (dashStr == null) {
            return null;
        }
        String[] dashSplit = dashStr.split(","); //$NON-NLS-1$
        int size = dashSplit.length;
        float[] dash = new float[size];
        try {
            for (int i = 0; i < dash.length; i++) {
                dash[i] = Float.parseFloat(dashSplit[i].trim());
            }
            return dash;
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * Converts teh array to string.
     * 
     * @param dashArray the dash array.
     * @return the converted string.
     */
    public static String getDashString(float[] dashArray) {
        StringBuilder sb = null;
        for (float f : dashArray) {
            if (sb == null) {
                sb = new StringBuilder(String.valueOf(f));
            } else {
                sb.append(",");
                sb.append(String.valueOf(f));
            }
        }
        return sb.toString();
    }

    /**
     * Checks if a string is a number (currently Double, Float, Integer).
     * 
     * @param value the string to check. 
     * @param adaptee the class to check against. If null, the more permissive {@link Double} will be used.
     * @return the number or null, if the parsing fails.
     */
    @SuppressWarnings("unchecked")
    public static <T extends Number> T isNumber(String value, Class<T> adaptee) {
        if (value == null) {
            return null;
        }
        if (adaptee == null) {
            adaptee = (Class<T>) Double.class;
        }
        if (adaptee.isAssignableFrom(Double.class)) {
            try {
                Double parsed = Double.parseDouble(value);
                return adaptee.cast(parsed);
            } catch (Exception e) {
                return null;
            }
        } else if (adaptee.isAssignableFrom(Float.class)) {
            try {
                Float parsed = Float.parseFloat(value);
                return adaptee.cast(parsed);
            } catch (Exception e) {
                return null;
            }
        } else if (adaptee.isAssignableFrom(Integer.class)) {
            try {
                Integer parsed = Integer.parseInt(value);
                return adaptee.cast(parsed);
            } catch (Exception e) {
                // still try the double
                Double number = isNumber(value, Double.class);
                if (number != null) {
                    return adaptee.cast(number.intValue());
                }
                return null;
            }
        } else {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Get the double value from a spinner that has digits.
     * 
     * @param spinner the spinner to get the value from.
     * @return the selected value.
     */
    public static double getDoubleSpinnerSelection(Spinner spinner) {
        int selection = spinner.getSelection();
        int digits = spinner.getDigits();
        double value = selection / Math.pow(10, digits);
        return value;
    }

    /**
     * Convert a sld line join definition to the java awt value. 
     * 
     * @param sldJoin the sld join string.
     * @return the awt value.
     */
    public static int sld2awtJoin(String sldJoin) {
        if (sldJoin.equals(lineJoinNames[1])) {
            return BasicStroke.JOIN_BEVEL;
        } else if (sldJoin.equals("") || sldJoin.equals(lineJoinNames[2])) {
            return BasicStroke.JOIN_MITER;
        } else if (sldJoin.equals(lineJoinNames[3])) {
            return BasicStroke.JOIN_ROUND;
        } else {
            throw new IllegalArgumentException("unsupported line join");
        }
    }

    /**
     * Convert a sld line cap definition to the java awt value. 
     * 
     * @param sldCap the sld cap string.
     * @return the awt value.
     */
    public static int sld2awtCap(String sldCap) {
        if (sldCap.equals("") || sldCap.equals(lineCapNames[1])) {
            return BasicStroke.CAP_BUTT;
        } else if (sldCap.equals(lineCapNames[2])) {
            return BasicStroke.CAP_ROUND;
        } else if (sldCap.equals(lineCapNames[3])) {
            return BasicStroke.CAP_SQUARE;
        } else {
            throw new IllegalArgumentException("unsupported line cap");
        }
    }

}