All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.limetri.client.mapviewer.swing.render.GridCoverage2DRenderer Maven / Gradle / Ivy

/**
 *  Copyright (C) 2008-2013 LimeTri. All rights reserved.
 *
 *  AgroSense is free software: you can redistribute it and/or modify it under
 *  the terms of the GNU General Public License as published by the Free Software
 *  Foundation, either version 3 of the License, or (at your option) any later
 *  version.
 *
 *  There are special exceptions to the terms and conditions of the GPLv3 as it
 *  is applied to this software, see the FLOSS License Exception
 *  .
 *
 *  AgroSense 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with
 *  AgroSense. If not, see .
 */
package eu.limetri.client.mapviewer.swing.render;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;


import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.ViewType;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.expression.ExpressionAbstract;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer;
import org.geotools.styling.ColorMap;
import org.geotools.styling.ColorMapEntry;
import org.geotools.styling.ColorMapEntryImpl;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.StyleFactory;
import org.netbeans.api.visual.model.ObjectState;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import org.openide.util.Exceptions;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;

import eu.limetri.api.grid.Grid;
import eu.limetri.client.mapviewer.api.Palette;
import eu.limetri.client.mapviewer.api.ValueRange;

/**
 * GridCoverage2DRenderer
 *
 *
 * @author Timon Veenstra
 */
public class GridCoverage2DRenderer implements RasterRenderer {

    private static final Color EMPTY_COLOR = new Color(0.0f, 0.0f, 0.0f);
    private static final float OPACITY_HOVER = (float) Palette.ALPHA_HOVER / 255;
    private static final float OPACITY_SELECTED = (float) Palette.ALPHA_SELECTED / 255;
    private static final float OPACITY_NORMAL = (float) Palette.ALPHA_NORMAL / 255;

    /**
     * this gets rid of exception for not using native acceleration
     */
    static {
        System.setProperty("com.sun.media.jai.disableMediaLib", "true");
    }
    private StyleFactory sf = CommonFactoryFinder.getStyleFactory(null);

    @Override
    public void paint(GridCoverage2D raster, Rectangle viewport, Graphics2D graphics, Palette palette, ObjectState state, GeoTranslator translator) {
        // skip painting is raster is empty
        if (raster == null) {
            return;
        }
        
        int numBands = raster.getNumSampleDimensions();
        if (numBands > 1) {
            // can't apply a ColorMap to a multiband coverage (org.geotools.renderer.lite.gridcoverage2d.ColorMapNode:150)
            return;
        }

        try {
            ReferencedEnvelope rasterEnvelope = new ReferencedEnvelope(raster.getEnvelope2D());
            rasterEnvelope = rasterEnvelope.transform(DefaultGeographicCRS.WGS84, true);
            Rectangle bounds = getBounds(rasterEnvelope, viewport, translator);
            GridCoverageRenderer renderer = new GridCoverageRenderer(DefaultGeographicCRS.WGS84, rasterEnvelope, bounds, (AffineTransform) null);
            RasterSymbolizer symbolizer = sf.getDefaultRasterSymbolizer();
            if (state.isHovered() || state.isObjectHovered()) {
                symbolizer.setOpacity(new OpacityExp(OPACITY_HOVER));
            } else if (state.isSelected()) {
                symbolizer.setOpacity(new OpacityExp(OPACITY_SELECTED));
            } else {
                symbolizer.setOpacity(new OpacityExp(OPACITY_NORMAL));
            }
            if (palette instanceof ValueRange) {
                ValueRange range = (ValueRange) palette;
                Number min = (range.getMinValue() == null ? 0 : range.getMinValue());
                Number max = (range.getMaxValue() == null ? 0 : range.getMaxValue());
                ColorMapEntry entry = getEntry(EMPTY_COLOR, Grid.EMPTY_VALUE);
                entry.setOpacity(new OpacityExp(0.0f));
                symbolizer.getColorMap().addColorMapEntry(entry);
                
                if (min.equals(max)) {
                    // add single value
                    Color c = palette.getColorForValue(min);
                    ColorMapEntry singleEntry = getEntry(c, min.doubleValue());
                    symbolizer.getColorMap().addColorMapEntry(singleEntry);
                } else {
                    int nColors = range.getSteps();
                    double step = (max.doubleValue() - min.doubleValue()) / (nColors - 1);
                    for (int s = 0; s < nColors; s++) {
                        Double value = min.doubleValue() + (s * step);
                        Color c = palette.getColorForValue(value); // FIXME: depends on the Palette implementation using Number as the generic type (and not the subclass used by the ValueRange implementation)
                        symbolizer.getColorMap().addColorMapEntry(getEntry(c, value));
                    }
                }

            } else {
                //
                //fallback
                //
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF000000, true), 1));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF8F050C, true), 100));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFFDB0F01, true), 200));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFFE65E00, true), 300));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFFFC9F00, true), 400));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFFFAD007, true), 500));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFFDCF40A, true), 600));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF92FC00, true), 700));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF41C405, true), 800));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF048608, true), 900));
                symbolizer.getColorMap().addColorMapEntry(getEntry(new Color(0xFF044606, true), 1000));
            }
            symbolizer.getColorMap().setType(ColorMap.TYPE_RAMP);

            renderer.paint(graphics, raster.view(ViewType.GEOPHYSICS), symbolizer);
        } catch (FactoryException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformException ex) {
            Exceptions.printStackTrace(ex);
        } catch (NoninvertibleTransformException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    private ColorMapEntry getEntry(Color color, double value) {
        ColorMapEntry entry = new ColorMapEntryImpl();
        entry.setColor(new ColorExp(color));
        entry.setQuantity(new ValueExp(value));
        return entry;
    }

    private class ColorExp extends ExpressionAbstract {

        private final Color color;

        public ColorExp(Color color) {
            this.color = color;
        }

        @Override
        public Object evaluate(Object object) {
            return this.color;
        }

        @Override
        public Object accept(ExpressionVisitor visitor, Object extraData) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }

    private class ValueExp extends ExpressionAbstract {

        private final double value;

        public ValueExp(double value) {
            this.value = value;
        }

        @Override
        public Object evaluate(Object object) {
            return Double.valueOf(this.value);
        }

        @Override
        public Object accept(ExpressionVisitor visitor, Object extraData) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }

    private class OpacityExp extends ExpressionAbstract {

        private final double opacity;

        public OpacityExp(double opacity) {
            assert opacity <= 1.0 && opacity >= 0.0;
            this.opacity = opacity;
        }

        @Override
        public Object evaluate(Object object) {
            return new Double(this.opacity);
        }

        @Override
        public Object accept(ExpressionVisitor visitor, Object extraData) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    
    private Rectangle getBounds(Envelope envelope, Rectangle viewport, GeoTranslator translator) {
        Geometry geometry = JTS.toGeometry(envelope);
        final Point2D upLeft = translator.geoToPixel(viewport, geometry, new Coordinate(envelope.getMinX(), envelope.getMinY()));
        final Point2D downRight = translator.geoToPixel(viewport, geometry, new Coordinate(envelope.getMaxX(), envelope.getMaxY()));
        Rectangle bounds = new Rectangle((int) (upLeft.getX() - viewport.getX()), (int) (upLeft.getY() - viewport.getY()), 0, 0);
        bounds.add((int) (downRight.getX() - viewport.getX()), (int) (downRight.getY() - viewport.getY()));
        return bounds;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy