org.kalypso.ui.wizards.results.ResultSldHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.ui.wizards.results.ResultSldHelper.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  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; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.ui.wizards.results;

import java.awt.Color;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;

import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.filters.StringInputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.kalypso1d2d.internal.i18n.Messages;
import org.kalypso.kalypsomodel1d2d.conv.results.NodeResultHelper;
import org.kalypso.kalypsomodel1d2d.conv.results.ResultMeta1d2dHelper;
import org.kalypsodeegree.filterencoding.FilterEvaluationException;
import org.kalypsodeegree.graphics.sld.FeatureTypeStyle;
import org.kalypsodeegree.graphics.sld.Fill;
import org.kalypsodeegree.graphics.sld.LineColorMapEntry;
import org.kalypsodeegree.graphics.sld.NamedLayer;
import org.kalypsodeegree.graphics.sld.ParameterValueType;
import org.kalypsodeegree.graphics.sld.PolygonColorMapEntry;
import org.kalypsodeegree.graphics.sld.Rule;
import org.kalypsodeegree.graphics.sld.Stroke;
import org.kalypsodeegree.graphics.sld.Style;
import org.kalypsodeegree.graphics.sld.StyledLayerDescriptor;
import org.kalypsodeegree.graphics.sld.SurfaceLineSymbolizer;
import org.kalypsodeegree.graphics.sld.SurfacePolygonSymbolizer;
import org.kalypsodeegree.graphics.sld.Symbolizer;
import org.kalypsodeegree.graphics.sld.UserStyle;
import org.kalypsodeegree_impl.graphics.sld.LineColorMap;
import org.kalypsodeegree_impl.graphics.sld.LineColorMapEntry_Impl;
import org.kalypsodeegree_impl.graphics.sld.LineColorMap_Impl;
import org.kalypsodeegree_impl.graphics.sld.PolygonColorMap;
import org.kalypsodeegree_impl.graphics.sld.PolygonColorMapEntry_Impl;
import org.kalypsodeegree_impl.graphics.sld.PolygonColorMap_Impl;
import org.kalypsodeegree_impl.graphics.sld.SLDFactory;
import org.kalypsodeegree_impl.graphics.sld.StyleFactory;

/**
 * @author Thomas Jung
 * 
 */
public class ResultSldHelper {

    /**
     * returns the interpolated color of a color map defined by start and end color.
     * 
     * @param currentClass
     *          current class
     * @param numOfClasses
     *          number of all classes in which the colormap is divided.
     */
    public static Color interpolateColor(final Color minColor, final Color maxColor, final int currentClass,
            final int numOfClasses) {
        // interpolate color
        final float[] minhsb = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null);
        final float[] maxhsb = Color.RGBtoHSB(maxColor.getRed(), maxColor.getGreen(), maxColor.getBlue(), null);

        final float minHue = minhsb[0];
        final float maxHue = maxhsb[0];

        final float minSat = minhsb[1];
        final float maxSat = maxhsb[1];

        final float minBri = minhsb[2];
        final float maxBri = maxhsb[2];

        final double Hue = minHue + (currentClass * (maxHue - minHue) / (numOfClasses - 1));
        final double Sat = minSat + (currentClass * (maxSat - minSat) / (numOfClasses - 1));
        final double Bri = minBri + (currentClass * (maxBri - minBri) / (numOfClasses - 1));

        final Color hsbColor = Color.getHSBColor((float) Hue, (float) Sat, (float) Bri);
        final Color rgbColor = new Color(hsbColor.getRed(), hsbColor.getGreen(), hsbColor.getBlue());

        return rgbColor;
    }

    public static double interpolate(final double min, final double max, final int currentClass,
            final int numOfClasses) {
        return min + (currentClass * (max - min) / (numOfClasses - 1));
    }

    public static IStatus processStyle(final IFile styleFile, final IFolder sldFolder, final String type,
            final BigDecimal minValue, final BigDecimal maxValue) {
        /* Read sld from template */

        // better, get the sld from resource folder
        final URL resource = ResultSldHelper.class.getResource("resources/myDefault" + type + ".sld"); //$NON-NLS-1$ //$NON-NLS-2$
        try {
            final StyledLayerDescriptor sld = SLDFactory.createSLD(resource);

            if (NodeResultHelper.LINE_TYPE.equals(type) || NodeResultHelper.POLYGON_TYPE.equals(type)) {
                //resolve the problem with initial creation of style files in case with min equals max
                BigDecimal lMax = maxValue;
                if (minValue.equals(maxValue)) {
                    lMax = maxValue.add(new BigDecimal(1));
                }
                processTinStyle(type, minValue, lMax, sld);
                /* Write SLD back to file */
                if (sld != null) {
                    final String sldXML = sld.exportAsXML();
                    final String sldXMLwithHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + sldXML; //$NON-NLS-1$
                    styleFile.create(new StringInputStream(sldXMLwithHeader, "UTF-8"), false, //$NON-NLS-1$
                            new NullProgressMonitor());
                }
            } else if (NodeResultHelper.NODE_TYPE.equals(type)) {
                // we creating more styles for nodes to give the possibility for representation of different types of node
                // results
                createDefaultNodeStyles(sldFolder, maxValue, resource, type);
                // String sldXMLwithHeader = processVectorStyle( maxValue, resource, type ); styleFile,
                // styleFile.create( new StringInputStream( sldXMLwithHeader ), false, new NullProgressMonitor() );
            }
        } catch (final Exception e) {
            e.printStackTrace();
            return StatusUtilities.statusFromThrowable(e,
                    Messages.getString("org.kalypso.ui.wizards.results.ResultSldHelper.0")); //$NON-NLS-1$
        }
        return Status.OK_STATUS;

    }

    private static void createDefaultNodeStyles(final IFolder sldFolder, final BigDecimal maxValue,
            final URL resource, final String type) {
        for (int i = 0; i < NodeResultHelper.NodeStyleTypes.length; i++) {
            final String sldFileName = ResultMeta1d2dHelper.getDefaultStyleFileName(type,
                    NodeResultHelper.NodeStyleTypes[i]);
            final IFile styleFile = sldFolder.getFile(sldFileName);
            String sldXMLwithHeader = processVectorStyle(maxValue, resource, NodeResultHelper.NodeStyleTypes[i]);
            try {
                styleFile.create(new StringInputStream(sldXMLwithHeader), false, new NullProgressMonitor());
            } catch (Exception e) {
                //do not replace existing style files
            }
        }
    }

    private static void processTinStyle(final String type, final BigDecimal minValue, final BigDecimal maxValue,
            final StyledLayerDescriptor sld) {
        final String layerName = "tin" + type + "Style"; //$NON-NLS-1$ //$NON-NLS-2$
        final String featureTypeStyleName = "tinFeatureTypeStyle"; //$NON-NLS-1$
        final String ruleName = "tinRule"; //$NON-NLS-1$

        final NamedLayer namedLayer = sld.getNamedLayer("tinStyles"); //$NON-NLS-1$
        if (namedLayer == null)
            return;

        final Style style = namedLayer.getStyle(layerName);
        if (style instanceof UserStyle) {
            final UserStyle userStyle = (UserStyle) style;
            final FeatureTypeStyle featureTypeStyle = userStyle.getFeatureTypeStyle(featureTypeStyleName);
            if (featureTypeStyle == null)
                return;
            final Rule rule = featureTypeStyle.getRule(ruleName);
            if (rule == null)
                return;
            final Symbolizer[] symbolizers = rule.getSymbolizers();

            // get the first symbolizer
            final Symbolizer symbolizer = symbolizers[0];

            try {
                if (symbolizer instanceof SurfaceLineSymbolizer) {
                    configureLineSymbolizer((SurfaceLineSymbolizer) symbolizer, minValue, maxValue);
                } else if (symbolizer instanceof SurfacePolygonSymbolizer) {
                    configurePolygonSymbolizer((SurfacePolygonSymbolizer) symbolizer, minValue, maxValue);
                }
            } catch (final FilterEvaluationException e) {
                e.printStackTrace();
            } catch (final Exception e) {
                e.printStackTrace();
            }

        }
    }

    private static void configurePolygonSymbolizer(final SurfacePolygonSymbolizer symbolizer,
            final BigDecimal minValue, final BigDecimal maxValue) throws FilterEvaluationException {
        final PolygonColorMap templateColorMap = symbolizer.getColorMap();
        final PolygonColorMap newColorMap = new PolygonColorMap_Impl();

        // retrieve stuff from template-entries
        final PolygonColorMapEntry fromEntry = templateColorMap.findEntry("from", null); //$NON-NLS-1$
        final PolygonColorMapEntry toEntry = templateColorMap.findEntry("to", null); //$NON-NLS-1$

        // Fill
        final Color fromPolygonColor = fromEntry.getFill().getFill(null);
        final Color toPolygonColor = toEntry.getFill().getFill(null);
        final double polygonOpacity = fromEntry.getFill().getOpacity(null);

        // Stroke
        final Color fromLineColor = fromEntry.getStroke().getStroke(null);
        final Color toLineColor = toEntry.getStroke().getStroke(null);
        final double lineOpacity = fromEntry.getStroke().getOpacity(null);

        // step width
        final double stepWidth = fromEntry.getTo(null);

        // scale of the step width
        final BigDecimal setScale = new BigDecimal(fromEntry.getFrom(null)).setScale(0, BigDecimal.ROUND_FLOOR);
        final int stepWidthScale = setScale.intValue();

        // get rounded values below min and above max (rounded by first decimal)
        // as a first try we will generate isareas by using class steps of 0.1
        // later, the classes will be created by using user defined class steps.
        // for that we fill an array of calculated (later user defined values) from max to min
        final BigDecimal minDecimal = minValue.setScale(1, BigDecimal.ROUND_FLOOR);
        final BigDecimal maxDecimal = maxValue.setScale(1, BigDecimal.ROUND_CEILING);

        final BigDecimal polygonStepWidth = new BigDecimal(stepWidth).setScale(stepWidthScale,
                BigDecimal.ROUND_FLOOR);
        int numOfClasses = (maxDecimal.subtract(minDecimal).divide(polygonStepWidth)).intValue();
        // set to provide more them 1 or 0 classes. in such cases the color map will not be created, that results error.  
        if (numOfClasses < 2) {
            numOfClasses = (maxDecimal.subtract(minDecimal).divide(polygonStepWidth.divide(new BigDecimal(4))))
                    .intValue();
        }
        for (int currentClass = 0; currentClass < numOfClasses; currentClass++) {
            final double fromValue = minDecimal.doubleValue() + currentClass * polygonStepWidth.doubleValue();
            final double toValue = minDecimal.doubleValue() + (currentClass + 1) * polygonStepWidth.doubleValue();

            // Stroke
            Color lineColor;
            if (fromLineColor == toLineColor)
                lineColor = fromLineColor;
            else
                lineColor = interpolateColor(fromLineColor, toLineColor, currentClass, numOfClasses);

            // Fill
            final Color polygonColor = interpolateColor(fromPolygonColor, toPolygonColor, currentClass,
                    numOfClasses);
            lineColor = polygonColor;

            final Stroke stroke = StyleFactory.createStroke(lineColor, lineOpacity, 1);

            final Fill fill = StyleFactory.createFill(polygonColor, polygonOpacity);

            final ParameterValueType label = StyleFactory.createParameterValueType("Isoflche " + currentClass); //$NON-NLS-1$
            final ParameterValueType from = StyleFactory.createParameterValueType(fromValue);
            final ParameterValueType to = StyleFactory.createParameterValueType(toValue);

            final PolygonColorMapEntry colorMapEntry = new PolygonColorMapEntry_Impl(fill, stroke, label, from, to);
            newColorMap.addColorMapClass(colorMapEntry);
        }

        symbolizer.setColorMap(newColorMap);
    }

    /**
     * sets the parameters for the colormap of an isoline
     */
    private static void configureLineSymbolizer(final SurfaceLineSymbolizer symbolizer, final BigDecimal minValue,
            final BigDecimal maxValue) throws FilterEvaluationException {
        final LineColorMap templateColorMap = symbolizer.getColorMap();
        final LineColorMap newColorMap = new LineColorMap_Impl();

        // retrieve stuff from template-entries
        final LineColorMapEntry fromEntry = templateColorMap.findEntry("from", null); //$NON-NLS-1$
        final LineColorMapEntry toEntry = templateColorMap.findEntry("to", null); //$NON-NLS-1$
        final LineColorMapEntry fatEntry = templateColorMap.findEntry("fat", null); //$NON-NLS-1$

        final Color fromColor = fromEntry.getStroke().getStroke(null);
        final Color toColor = toEntry.getStroke().getStroke(null);
        final double opacity = fromEntry.getStroke().getOpacity(null);

        final double normalWidth = fromEntry.getStroke().getWidth(null);
        final double fatWidth = fatEntry.getStroke().getWidth(null);

        // defines which isolines are drawn with a fat line
        final double fatValue = fatEntry.getQuantity(null);
        // TODO: get setep / scale from quantity
        // get rounded values below min and above max (rounded by first decimal)
        // as a first try we will generate isolines using class steps of 0.1
        // later, the classes will be done by using user defined class steps.
        // for that we fill an array of calculated (later user defined values) from max to min
        final BigDecimal minDecimal = minValue.setScale(1, BigDecimal.ROUND_FLOOR);
        final BigDecimal maxDecimal = maxValue.setScale(1, BigDecimal.ROUND_CEILING);

        final BigDecimal stepWidth = new BigDecimal(0.1).setScale(1, BigDecimal.ROUND_HALF_UP);
        final int numOfClasses = (maxDecimal.subtract(minDecimal).divide(stepWidth)).intValue() + 1;

        for (int currentClass = 0; currentClass < numOfClasses; currentClass++) {
            final double currentValue = minDecimal.doubleValue() + currentClass * stepWidth.doubleValue();

            Color lineColor;
            if (fromColor == toColor)
                lineColor = fromColor;
            else
                lineColor = interpolateColor(fromColor, toColor, currentClass, numOfClasses);

            final double strokeWidth;
            if (currentValue % fatValue == 0)
                strokeWidth = fatWidth;
            else
                strokeWidth = normalWidth;

            final Stroke stroke = StyleFactory.createStroke(lineColor, strokeWidth, opacity);

            final ParameterValueType label = StyleFactory.createParameterValueType("Isolinie " + currentClass); //$NON-NLS-1$
            final ParameterValueType quantity = StyleFactory.createParameterValueType(currentValue);

            final LineColorMapEntry colorMapEntry = new LineColorMapEntry_Impl(stroke, label, quantity);
            newColorMap.addColorMapClass(colorMapEntry);
        }

        symbolizer.setColorMap(newColorMap);
    }

    private static String processVectorStyle(final BigDecimal maxValue, final URL url, final String type) {
        InputStream is = null;
        try {
            if (NodeResultHelper.VELO_TYPE.equals(type) || NodeResultHelper.WAVE_DIRECTION_TYPE.equals(type)) {
                is = new BufferedInputStream(url.openStream());
            } else {
                final URL extUrl = ResultSldHelper.class.getResource("resources/myDefaultNodeExt.sld"); //$NON-NLS-1$
                is = new BufferedInputStream(extUrl.openStream());
            }
            String fileString = IOUtils.toString(is, "UTF-8"); //$NON-NLS-1$
            is.close();

            // we assume, that the mean distance of mesh nodes is about 30 m, so that the vectors are expanded by an factor
            // which delivers vector lengths of 30 m as maximum.
            BigDecimal factorValue;
            if (maxValue != null && maxValue.doubleValue() > 0)
                factorValue = new BigDecimal(30 / maxValue.doubleValue()).setScale(0, BigDecimal.ROUND_CEILING);
            else
                factorValue = new BigDecimal(100).setScale(0, BigDecimal.ROUND_CEILING);

            String factor = factorValue.toString();
            if (NodeResultHelper.VELO_TYPE.equals(type)) {
                return fileString.replaceAll(NodeResultHelper.VECTORFACTOR, factor)
                        .replaceAll(NodeResultHelper.SIZE_NORM_NODE_FUNC, "velocityNorm"); //$NON-NLS-1$
            } else if (NodeResultHelper.WAVE_DIRECTION_TYPE.equals(type)) {
                return fileString.replaceAll(NodeResultHelper.VECTORFACTOR, factor)
                        .replaceAll(NodeResultHelper.SIZE_NORM_NODE_FUNC, "wavehsig") //$NON-NLS-1$
                        .replaceAll("velocityRotation", type.toLowerCase()); //$NON-NLS-1$ 
            } else {
                if (factorValue.doubleValue() > 30) {
                    factor = "10"; //$NON-NLS-1$ 
                }
                return fileString.replaceAll(NodeResultHelper.VECTORFACTOR, factor)
                        .replaceAll(NodeResultHelper.NODESTYLE_TEMPLATE, type.toLowerCase());
            }

        } catch (final IOException e) {
            e.printStackTrace();

        } finally {
            IOUtils.closeQuietly(is);
        }
        return null;

    }

    public static boolean allDefaultNodeStylesExist(final IFolder sldFolder) {
        for (int i = 0; i < NodeResultHelper.NodeStyleTypes.length; i++) {
            final String sldFileName = ResultMeta1d2dHelper.getDefaultStyleFileName(NodeResultHelper.NODE_TYPE,
                    NodeResultHelper.NodeStyleTypes[i]);
            final IFile styleFile = sldFolder.getFile(sldFileName);
            if (!styleFile.exists())
                return false;

        }
        return true;
    }

}