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

org.integratedmodelling.engine.geospace.coverage.raster.RasterCoverage Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2015:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    This program 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
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.geospace.coverage.raster;

import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;

import javax.media.jai.InterpolationNearest;
import javax.media.jai.RasterFactory;
import javax.media.jai.iterator.RandomIterFactory;

import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.processing.Operations;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.integratedmodelling.api.modelling.IExtent;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IState;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.space.IGridMask;
import org.integratedmodelling.common.utils.Escape;
import org.integratedmodelling.common.utils.MiscUtilities;
import org.integratedmodelling.engine.geospace.coverage.ICoverage;
import org.integratedmodelling.engine.geospace.extents.Area;
import org.integratedmodelling.engine.geospace.extents.Grid;
import org.integratedmodelling.engine.geospace.extents.SpaceExtent;
import org.integratedmodelling.engine.visualization.VisualizationFactory;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabUnsupportedOperationException;
import org.integratedmodelling.exceptions.KlabValidationException;

public class RasterCoverage extends AbstractRasterCoverage {

    static GridCoverageFactory rasterFactory = new GridCoverageFactory();

    public RasterCoverage(IState state) throws KlabException {

        double[] data = VisualizationFactory.get().getStateDataAsNumbers(state);
        IExtent space = state.getSpace();

        if (data == null || space == null || !(space instanceof SpaceExtent)
                || ((SpaceExtent) space).getGrid() == null) {
            throw new KlabValidationException("cannot create a coverage from a non-spatial state");
        }

        buildFromData(state.getObservable().getSemantics().getType().getLocalName(), ((SpaceExtent) space).getGrid(), data);
    }

    public RasterCoverage(IState state, Iterable locators) throws KlabException {

        double[] data = VisualizationFactory.get().getStateDataAsNumbers(state, locators);
        IExtent space = state.getSpace();

        if (data == null || space == null || !(space instanceof SpaceExtent)
                || ((SpaceExtent) space).getGrid() == null) {
            throw new KlabValidationException("cannot create a coverage from a non-spatial state");
        }

        buildFromData(state.getObservable().getSemantics().getType().getLocalName(), ((SpaceExtent) space).getGrid(), data);
    }

    private void buildFromData(String name, Grid extent, Object data) throws KlabException {
        /* 
         * build a coverage 
         * 
         * TODO use a raster of the appropriate type - for now there is apparently a bug in geotools
         * that makes it work only with float.
         * */
        WritableRaster raster = RasterFactory
                .createBandedRaster(DataBuffer.TYPE_FLOAT, extent.getXCells(), extent.getYCells(), 1, null);

        /*
         * TODO raster should be pre-filled with a chosen nodata value
         * TODO use activation layer
         */
        IGridMask act = extent.requireActivationLayer(true);

        if (data instanceof int[]) {
            for (int i = 0; i < extent.getCellCount(); i++) {
                float d = ((int[]) data)[i];
                int[] xy = extent.getXYOffsets(i);
                raster.setSample(xy[0], xy[1], 0, d);
            }
        } else if (data instanceof long[]) {
            for (int i = 0; i < extent.getCellCount(); i++) {
                int[] xy = extent.getXYOffsets(i);
                raster.setSample(xy[0], xy[1], 0, ((long[]) data)[i]);
            }
        } else if (data instanceof float[]) {
            for (int i = 0; i < extent.getCellCount(); i++) {
                int[] xy = extent.getXYOffsets(i);
                raster.setSample(xy[0], xy[1], 0, ((float[]) data)[i]);
            }
        } else if (data instanceof double[]) {
            for (int i = 0; i < extent.getCellCount(); i++) {
                int[] xy = extent.getXYOffsets(i);
                raster.setSample(xy[0], xy[1], 0, (float) ((double[]) data)[i]);
            }
        } else {
            throw new KlabValidationException("cannot create a raster coverage from a "
                    + data.getClass());
        }

        this.coverage = rasterFactory.create(name, raster, extent.getEnvelope());
        this.layerName = name;
        this.dimension = coverage.getSampleDimension(0);
        this.crs = coverage.getCoordinateReferenceSystem2D();
        this.gridGeometry = coverage.getGridGeometry();

        /* no data values */
        noData = dimension.getNoDataValues();

        xCellSize = coverage.getEnvelope2D().getWidth() / getXCells();
        yCellSize = coverage.getEnvelope2D().getHeight() / getYCells();

        this.boundingBox = new ReferencedEnvelope(coverage.getEnvelope2D().getMinX(), coverage
                .getEnvelope2D().getMaxX(), coverage.getEnvelope2D().getMinY(), coverage.getEnvelope2D()
                        .getMaxY(), crs);

    }

    /**
     * Produce a new raster coverage from a cell extent and a vector of values that follow the
     * activation model in the extent. Used after external transformation of spatial data.
     * @throws KlabException 
     */
    public RasterCoverage(String name, Grid extent, Object data) throws KlabException {
        buildFromData(name, extent, data);
    }

    /**
     * The resampling constructor. Will do its best to produce a new coverage that matches 
     * a new extent from a different one. Be careful with this one.
     * 
     * TODO it should take an interpolation option as a parameter.
     * FIXME the affine transform for the cropping does weird things and tilts the image on its
     * side. Plus, reprojection doesn't retain values. Until I figure it out, stick to WCS please.
     * 
     * @param cov
     * @param extent
     * @throws KlabException
     */
    public RasterCoverage(RasterCoverage cov, Grid extent) throws KlabException {

        this.sourceURL = cov.sourceURL;
        this.dimension = cov.dimension;
        this.boundingBox = extent.getEnvelope();
        this.xCellSize = boundingBox.getWidth() / extent.getXCells();
        this.yCellSize = boundingBox.getHeight() / extent.getYCells();
        this.crs = extent.getCRS();

        // here's the geometry we want and the crs for the derived coverage
        this.gridGeometry = new GridGeometry2D(extent.getGridRange(), extent.getEnvelope());

        /*
         * subset first
         */
        this.coverage = (GridCoverage2D) Operations.DEFAULT
                .resample(cov.coverage, extent.getEnvelope(), new InterpolationNearest());
        /*
         * then resample
         */
        this.coverage = (GridCoverage2D) Operations.DEFAULT
                .resample(this.coverage, this.crs, this.gridGeometry, new InterpolationNearest());

        // this.coverage.show();

    }

    public RasterCoverage(String sourceURL, GridCoverage2D coverage, GridSampleDimension dimension,
            boolean isSingleBand) {

        this.sourceURL = sourceURL;

        /* add band fragment ONLY if there is more than one band */
        if (!isSingleBand) {
            this.sourceURL += "#" + Escape.forURL(dimension.toString());
        }

        this.coverage = coverage;
        this.dimension = dimension;
        this.crs = coverage.getCoordinateReferenceSystem2D();
        this.gridGeometry = coverage.getGridGeometry();

        /* no data values */
        noData = dimension.getNoDataValues();

        /* TODO see if we have to add the band info */
        this.layerName = MiscUtilities.getURLBaseName(sourceURL).toLowerCase();

        xCellSize = coverage.getEnvelope2D().getWidth() / getXCells();
        yCellSize = coverage.getEnvelope2D().getHeight() / getYCells();

        this.boundingBox = new ReferencedEnvelope(coverage.getEnvelope2D().getMinX(), coverage
                .getEnvelope2D().getMaxX(), coverage.getEnvelope2D().getMinY(), coverage.getEnvelope2D()
                        .getMaxY(), crs);
    }

    public RasterCoverage(String name, GridCoverage2D raster) {

        this.coverage = raster;
        this.layerName = name;
        this.dimension = raster.getSampleDimension(0);

        // this.dimension = dimension;
        this.crs = coverage.getCoordinateReferenceSystem2D();
        this.gridGeometry = coverage.getGridGeometry();

        /* no data values */
        noData = dimension.getNoDataValues();

        xCellSize = coverage.getEnvelope2D().getWidth() / getXCells();
        yCellSize = coverage.getEnvelope2D().getHeight() / getYCells();

        this.boundingBox = new ReferencedEnvelope(coverage.getEnvelope2D().getMinX(), coverage
                .getEnvelope2D().getMaxX(), coverage.getEnvelope2D().getMinY(), coverage.getEnvelope2D()
                        .getMaxY(), crs);

        // coverage.show();
    }

    // @Override
    public void loadData() throws KlabException {

        if (_loaded)
            return;

        /*
         * get rid of old image if we had one
         */
        if (image != null) {
            image = null;
        }

        image = coverage.getRenderedImage();
        itera = RandomIterFactory.create(image, null);

        _loaded = true;
    }

    @Override
    public ICoverage requireMatch(Area extent, IObserver observer, IMonitor monitor, boolean allowClassChange)
            throws KlabException {

        // System.out.println("Coverage " + getLayerName() + " requested to match " + extent);

        if (!(extent instanceof Grid)) {
            throw new KlabUnsupportedOperationException("cannot yet match a raster coverage to a non-raster extent");
        }

        Grid cext = (Grid) extent;

        if (matchesExtent(cext)) {
            return this;
        }

        /* 
         * This constructor clones our metadata into a new coverage and
         * resamples our coverage into another that reflects our extent. 
         */
        RasterCoverage ret = new RasterCoverage(this, cext);
        ret.setClassMappings(classMappings);
        return ret;
    }

    public void setClassMappings(String[] classification) {
        classMappings = classification;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy