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

org.integratedmodelling.engine.geospace.gis.FeatureRasterizer 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.gis;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashMap;

import javax.media.jai.RasterFactory;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.integratedmodelling.api.modelling.IClassifyingObserver;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.monitoring.Messages;
import org.integratedmodelling.api.space.IGrid;
import org.integratedmodelling.api.space.IGridMask;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.utils.NameGenerator;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.extents.Grid;
import org.integratedmodelling.engine.geospace.literals.ShapeValue;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

/**
 * Rasterize features onto a WritableRaster object using Java 2D Graphics/BufferedImage.
 *
 * @author steve.ansari, NOAA (original code)
 * @author Ferdinando Villa (extensive modifications)
 * @created March 20, 2008
 */
public class FeatureRasterizer {

    private int                       height;
    private int                       width;
    private float                     noDataValue    = Float.NaN;
    private WritableRaster            raster         = null;
    private BufferedImage             bimage         = null;
    private Graphics2D                graphics       = null;

    private double                    minAttValue    = 999999999;
    private double                    maxAttValue    = -999999999;

    private int[]                     coordGridX     = new int[3500];
    private int[]                     coordGridY     = new int[3500];
    private float                     value          = 0.0f;
    private boolean                   emptyGrid      = false;

    private GeometryFactory           geoFactory     = new GeometryFactory();
    private String                    attributeName  = "value";

    public static GridCoverageFactory rasterFactory  = new GridCoverageFactory();

    private double                    xInterval;
    private double                    yInterval;

    // Any change in height, width or no_data values will cause
    // the raster to 'reset' at the next call to .rasterize(...)
    private boolean                   resetRaster    = true;
    private AttributeDescriptor       attributeDescriptor;

    /*
     * if this is not null, we have rasterized a string attribute, and the map defines the
     * values encountered and the corresponding short integer in the resulting coverage.
     */
    private HashMap  classification = null;
    private String                    valueDefault;

    private Geometry                  hullShape      = null;
    private IGrid                      extent;

    IMonitor                          monitor;
    private boolean                   attributeAlertDone;

    /**
     * Constructor for the FeatureRasterizer object
     */
    public FeatureRasterizer() {
        this(800, 800, Float.NaN);
    }

    /**
     * Returns values of the rasterized attribute that correspond to consecutive numeric
     * IDs, ranging from 1 to the number of classes (inclusive), in the raster.
     * 
     * @return classification
     */
    public String[] getClassification() {

        if (classification == null)
            return null;

        String[] ret = new String[classification.size()];

        for (String s : classification.keySet()) {
            ret[classification.get(s) - 1] = s;
        }

        return ret;
    }

    /**
     * Constructor for the FeatureRasterizer object
     *
     * @param height
     *            Height of raster (number of grid cells)
     * @param width
     *            Width of raster (number of grid cells)
     * @param noData
     *            No Data value for raster
     */
    public FeatureRasterizer(int height, int width, float noData) {
        this.height = height;
        this.width = width;
        this.noDataValue = noData;

        raster = /*
                  * RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT, width, height,
                  * 1, null)
                  */null;
        bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        bimage.setAccelerationPriority(1.0f);

        // GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        graphics = bimage.createGraphics();
        graphics.setPaintMode();
        graphics.setComposite(AlphaComposite.Src);
    }

    /**
     * Call this one when you need to analyze the attribute for rasterization and behave
     * accordingly.
     * 
     * @param extent
     * 
     * @param noData
     * @param attributeDescriptor
     * @param monitor
     */
    public FeatureRasterizer(IGrid extent, float noData, AttributeDescriptor attributeDescriptor,
            IMonitor monitor) {
        this(extent.getYCells(), extent.getXCells(), noData);
        this.attributeDescriptor = attributeDescriptor;
        this.extent = extent;
        this.monitor = monitor;
    }

    public GridCoverage2D rasterize(String name, FeatureCollection fc, String attributeName, IObserver observer, ReferencedEnvelope env)
            throws KlabException {

        if (raster == null) {

            WritableRaster raster = RasterFactory
                    .createBandedRaster(getRasterType(observer), this.width, this.height, 1, null);

            setWritableRaster(raster);
        }

        clearRaster(null);

        if (env == null) {

            rasterize(fc, extent, attributeName);

            /*
             * Use full envelope from feature collection TODO check if we need to use a
             * buffer like in Steve's code above
             */
            env = fc.getBounds();

        } else {

            // /*
            // * TODO check if we need to use a buffer like in Steve's code above
            // */
            // java.awt.geom.Rectangle2D.Double box =
            // new java.awt.geom.Rectangle2D.Double(
            // env.getMinX(),
            // env.getMinY(),
            // env.getWidth(),
            // env.getHeight());

            rasterize(fc, extent, attributeName);
        }

        GridCoverage2D coverage = rasterFactory.create(name, raster, env);

        return coverage;
    }

    private int getRasterType(IObserver observer) {

        int ret = DataBuffer.TYPE_FLOAT;

        if (observer instanceof IClassifyingObserver) {

            if (classification == null) {
                classification = new HashMap();
            }

        } /*
           * else if (attributeDescriptor != null) {
           * 
           * if ( !(attributeDescriptor.getType() instanceof NumericAttributeType)) { if
           * (classification == null) { classification = new HashMap(); }
           * } }
           */

        return ret;
    }

    /**
     * Rasterize a single shape. It is assumed that the grid and the shape agree with each
     * other, and that the axes don't need swapping.
     * 
     * @param shape
     * @param value
     * @return rasterized coverage
     * @throws KlabException
     * 
     */
    public GridCoverage2D rasterize(ShapeValue shape, int value) throws KlabException {

        if (raster == null) {

            WritableRaster raster = RasterFactory
                    .createBandedRaster(DataBuffer.TYPE_SHORT, this.width, this.height, 1, null);

            setWritableRaster(raster);
        }

        clearRaster(extent);

        setBounds(extent, false);
        this.value = value;
        checkReset(DataBuffer.TYPE_SHORT);
        addShape(shape, false);
        close();

        GridCoverage2D coverage = rasterFactory
                .create(NameGenerator.newName("mask"), raster, ((Grid)extent).getEnvelope());

        return coverage;
    }

    /**
     * Rasterize a collection of shapes. It is assumed that the grid and the shape agree with each
     * other, and that the axes don't need swapping.
     * 
     * @param shape
     * @param value
     * @return rasterized coverage
     * @throws KlabException
     * 
     */
    public GridCoverage2D rasterize(Collection shapes, int value) throws KlabException {

        if (raster == null) {

            WritableRaster raster = RasterFactory
                    .createBandedRaster(DataBuffer.TYPE_SHORT, this.width, this.height, 1, null);

            setWritableRaster(raster);
        }

        clearRaster(extent);

        setBounds(extent, false);
        this.value = value;
        checkReset(DataBuffer.TYPE_SHORT);
        for (ShapeValue shape : shapes) {
            addShape(shape, false);
        }
        close();

        GridCoverage2D coverage = rasterFactory
                .create(NameGenerator.newName("mask"), raster, ((Grid)extent).getEnvelope());

        return coverage;
    }
    
    private void checkReset(int type) {

        if (resetRaster) {
            raster = RasterFactory.createBandedRaster(type, width, height, 1, null);

            bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            bimage.setAccelerationPriority(1.0f);
            graphics = bimage.createGraphics();
            graphics.setPaintMode();
            graphics.setComposite(AlphaComposite.Src);
            resetRaster = false;
        }
    }

    public GridCoverage2D rasterize(String name, FeatureIterator fc, String attributeName, IObserver observer, String valueDefault, ReferencedEnvelope dataEnvelope, boolean swapAxis)
            throws KlabException {

        /**
         * 1. pass the DATA envelope that the data will come in; 2. swapAxis is IMPOSSIBLE
         * to understand: from WFS it should always be true for 4326. For files, I have no
         * idea. Maybe the datasources should pass it as a parameter.
         * 
         * 
         */
        if (raster == null) {

            WritableRaster raster = RasterFactory
                    .createBandedRaster(getRasterType(observer), this.width, this.height, 1, null);

            setWritableRaster(raster);
        }
        if (dataEnvelope == null) {
            throw new KlabValidationException("rasterizer: data envelope must be passed");
        }

        /*
         * TODO check if we need to use a buffer like in Steve's code above
         */
        // java.awt.geom.Rectangle2D.Double box =
        // new java.awt.geom.Rectangle2D.Double(
        // dataEnvelope.getMinX(),
        // dataEnvelope.getMinY(),
        // dataEnvelope.getWidth(),
        // dataEnvelope.getHeight());

        rasterize(fc, extent, attributeName, observer, valueDefault, dataEnvelope, swapAxis, monitor);

        GridCoverage2D coverage = rasterFactory.create(name, raster, dataEnvelope);

        if (KLAB.CONFIG.isDebug()) {
            coverage.show();
        }

        return coverage;
    }

    // /**
    // * Gets the raster attribute of the FeatureRasterizer object
    // * Processes data from the FeatureCollection and approximates onto a Raster Grid.
    // *
    // * @param fc Feature Collection with features to rasterize.
    // * @param attributeName Name of attribute from feature collection to provide as the
    // cell value.
    // * @exception FeatureRasterizerException An error when rasterizing the data
    // */
    // public void rasterize(FeatureCollection fc,
    // String attributeName)
    // throws ThinklabException {
    //
    // double edgeBuffer = 0.001;
    // double x = fc.getBounds().getMinX() - edgeBuffer;
    // double y = fc.getBounds().getMinY() - edgeBuffer;
    // double width = fc.getBounds().getWidth() + edgeBuffer * 2;
    // double height = fc.getBounds().getHeight() + edgeBuffer * 2;
    // java.awt.geom.Rectangle2D.Double bounds = new java.awt.geom.Rectangle2D.Double(x,
    // y, width, height);
    // rasterize(fc, bounds, attributeName);
    // }

    /**
     * Gets the raster attribute of the FeatureRasterizer object Processes data from the
     * FeatureCollection and approximates onto a Raster Grid.
     *
     * @param fc
     *            Description of the Parameter
     * @param bounds
     *            Description of the Parameter
     * @param attributeName
     *            Name of attribute from feature collection to provide as the cell value.
     * @exception KlabException
     *                An error when rasterizing the data
     */
    public void rasterize(FeatureCollection fc, IGrid bounds, String attributeName)
            throws KlabException {

        this.attributeName = attributeName;
        checkReset(DataBuffer.TYPE_FLOAT);
        clearRaster(null);
        setBounds(bounds, false);
        FeatureIterator fci = fc.features();
        SimpleFeature feature;

        while (fci.hasNext()) {

            feature = fci.next();
            addFeature(feature, null, false);
        }

        close();
    }

    /**
     * Gets the raster attribute of the FeatureRasterizer object Processes data from the
     * FeatureCollection and approximates onto a Raster Grid.
     *
     * @param fc
     *            Description of the Parameter
     * @param bounds
     *            Description of the Parameter
     * @param attributeName
     *            Name of attribute from feature collection to provide as the cell value.
     * @param observer
     * @param valueDefault
     * @param dataEnvelope
     * @param swapAxis
     * @exception KlabException
     *                An error when rasterizing the data
     */
    public void rasterize(FeatureIterator fc, IGrid bounds, String attributeName, IObserver observer, String valueDefault, ReferencedEnvelope dataEnvelope, boolean swapAxis, IMonitor monitor)
            throws KlabException {

        this.attributeName = attributeName;
        this.valueDefault = valueDefault;

        checkReset(getRasterType(observer));

        if (attributeName == null) {
            // no attribute means use 1.0 for presence of feature
            value = 1.0f;
            noDataValue = 0.0f;
        }

        // initialize raster to NoData value
        clearRaster(bounds);
        setBounds(bounds, swapAxis);

        SimpleFeature feature;
        int n = 0;
        while (fc.hasNext()) {
            try {
                feature = fc.next();
                addFeature(feature, dataEnvelope, swapAxis);
                n++;
            } catch (Exception e) {
                // timeouts are easy to get into here, we don't want them to kill the
                // rasterization
                KLAB.warn("problem reading feature #" + n + ": " + e.getMessage());
            }
            // log when we have to rasterize lots of features, so we know we should take
            // action otherwise
            if (n > 0 && (n % 5000) == 0) {
                if (monitor != null) {
                    monitor.info("rasterized " + n
                            + "-th feature. Consider providing pre-rasterized data", Messages.INFOCLASS_MODEL);
                }
                KLAB.info("rasterized " + n + "-th feature... that's a lot to rasterize");
            }
        }

        close();

        if (monitor != null) {
            monitor.info("rasterized " + n + " features", Messages.INFOCLASS_MODEL);
        }
        KLAB.info("rasterized " + n + " features");

    }

    public void addShape(ShapeValue shape, boolean swapAxis) {

        try {
            shape = shape.transform(Geospace.get().getDefaultCRS());
        } catch (KlabException e) {
            return;
        }

        int rgbVal = floatBitsToInt(value);
        graphics.setColor(new Color(rgbVal, true));
        Geometry geometry = shape.getGeometry();

        if (geometry.intersects(((Grid)extent).getBoundary())) {

            if (geometry.getClass().equals(MultiPolygon.class) || geometry.getClass().equals(Polygon.class)) {

                for (int i = 0; i < geometry.getNumGeometries(); i++) {
                    Polygon poly = (Polygon) geometry.getGeometryN(i);
                    LinearRing lr = geoFactory.createLinearRing(poly.getExteriorRing().getCoordinates());
                    Polygon part = geoFactory.createPolygon(lr, null);
                    drawGeometry(part, false, swapAxis);
                    for (int j = 0; j < poly.getNumInteriorRing(); j++) {
                        lr = geoFactory.createLinearRing(poly.getInteriorRingN(j).getCoordinates());
                        part = geoFactory.createPolygon(lr, null);
                        drawGeometry(part, true, swapAxis);
                    }
                }
            } else if (geometry.getClass().equals(MultiLineString.class)) {
                MultiLineString mp = (MultiLineString) geometry;
                for (int n = 0; n < mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n), false, swapAxis);
                }
            } else if (geometry.getClass().equals(MultiPoint.class)) {
                MultiPoint mp = (MultiPoint) geometry;
                for (int n = 0; n < mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n), false, swapAxis);
                }
            } else {
                drawGeometry(geometry, false, swapAxis);
            }
        }

    }

    /**
     * Implementation the StreamingProcess interface. Rasterize a single feature and
     * update current WriteableRaster using the current settings.
     * 
     * @param feature
     *            The feature to rasterize and add to current WritableRaster
     */
    public void addFeature(SimpleFeature feature, ReferencedEnvelope dataEnvelope, boolean swapAxis) {

        try {

            // if (this.attributeTable == null) {

            if (attributeName != null) {

                Object attr = feature.getAttribute(attributeName);
                if (attr == null) {
                    // good old case sensitivity craziness.
                    attr = feature.getAttribute(attributeName.toLowerCase());
                }
                if (attr == null) {
                    // more of it
                    attr = feature.getAttribute(attributeName.toUpperCase());
                }
                if (attr == null) {
                    if (this.valueDefault != null) {
                        attr = this.valueDefault;
                    } else {
                        /*
                         * alert that the attribute is not available (once). Need the
                         * monitor to be passed.
                         */
                        if (!this.attributeAlertDone) {
                            this.attributeAlertDone = true;
                            if (monitor != null) {
                                monitor.error("rasterization attribute " + attributeName + " not found");
                            }
                        }
                        return;
                    }
                }

                if (classification != null) {
                    value = getClassifiedValue(attr.toString());
                } else {
                    try {
                        value = Float.parseFloat(attr.toString());
                    } catch (Throwable e) {
                        // OK, definitely not a number, so let's encode strings and
                        // we deal with that externally.
                        classification = new HashMap();
                        value = getClassifiedValue(attr.toString());
                    }
                }
            }

            if (value > maxAttValue) {
                maxAttValue = value;
            }
            if (value < minAttValue) {
                minAttValue = value;
            }

            // } else {
            //
            // // TODO account for value being used as key into a hash. If so, the value
            // may be null or empty,
            // // and nodata should be left undisturbed with no error (warning maybe).
            // // value =
            // Float.parseFloat(attributeTable.getIndexedValue(feature.getAttribute(attributeName),
            // attributeHandle));
            // // attributeTable.getIndexedValue(feature.getAttribute(attributeName),
            // attributeHandle)
            // }
        } catch (Exception e) {
            e.printStackTrace();
            KLAB
                    .error("THE FEATURE COULD NOT BE RASTERIZED BASED ON THE '" + attributeName
                            + "' ATTRIBUTE VALUE OF '" + feature.getAttribute(attributeName).toString()
                            + "'");
            return;
        }

        // Extract polygon and rasterize
        Geometry geometry = (Geometry) feature.getDefaultGeometry();
        if (dataEnvelope != null) {
            try {
                geometry = JTS.transform(geometry, CRS
                        .findMathTransform(dataEnvelope.getCoordinateReferenceSystem(), ((Grid)extent).getCRS()));
            } catch (Exception e) {
                return;
            }
        }

        if (geometry.getClass().equals(MultiPolygon.class) || geometry.getClass().equals(Polygon.class)) {

            for (int i = 0; i < geometry.getNumGeometries(); i++) {
                Polygon poly = (Polygon) geometry.getGeometryN(i);
                LinearRing lr = geoFactory.createLinearRing(poly.getExteriorRing().getCoordinates());
                Polygon part = geoFactory.createPolygon(lr, null);
                drawGeometry(part, false, swapAxis);
                for (int j = 0; j < poly.getNumInteriorRing(); j++) {
                    lr = geoFactory.createLinearRing(poly.getInteriorRingN(j).getCoordinates());
                    part = geoFactory.createPolygon(lr, null);
                    drawGeometry(part, true, swapAxis);
                }
            }
        } else if (geometry.getClass().equals(MultiLineString.class)) {
            MultiLineString mp = (MultiLineString) geometry;
            for (int n = 0; n < mp.getNumGeometries(); n++) {
                drawGeometry(mp.getGeometryN(n), false, swapAxis);
            }
        } else if (geometry.getClass().equals(MultiPoint.class)) {
            MultiPoint mp = (MultiPoint) geometry;
            for (int n = 0; n < mp.getNumGeometries(); n++) {
                drawGeometry(mp.getGeometryN(n), false, swapAxis);
            }
        } else {
            drawGeometry(geometry, false, swapAxis);
        }
        // }
    }

    private float getClassifiedValue(String string) {

        Integer ret = classification.get(string);
        if (ret == null) {
            ret = classification.size() + 1;
            classification.put(string, ret);
        }

        return ret;
    }

    /**
     * this copies values from BufferedImage RGB to WritableRaster of floats or integers.
     * 
     * @throws KlabException
     */
    public void close() throws KlabException {

        IGridMask mask = null;
        if (extent != null && hullShape != null) {

            mask = ThinklabRasterizer.createMask(new ShapeValue(hullShape
                    .buffer(Math.max(((Grid)extent).getEWExtent(), ((Grid)extent).getNSExtent())), ((Grid)extent).getCRS()), extent);
        }

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {

                float fval = Float.NaN;
                if (mask == null || mask.isActive(i, j)) {
                    fval = Float.intBitsToFloat(bimage.getRGB(i, j));
                }
                raster.setSample(i, j, 0, fval);
            }
        }
    }

    private void drawGeometry(Geometry geometry, boolean hole, boolean swapAxis) {

        Coordinate[] coords = geometry.getCoordinates();

        int rgbVal = floatBitsToInt(hole ? Float.NaN : value);
        graphics.setColor(new Color(rgbVal, true));

        // enlarge if needed
        if (coords.length > coordGridX.length) {
            coordGridX = new int[coords.length];
            coordGridY = new int[coords.length];
        }

        // Clear Array
        for (int i = 0; i < coords.length; i++) {
            coordGridX[i] = -1;
        }
        for (int i = 0; i < coords.length; i++) {
            coordGridY[i] = -1;
        }

        // Go through coordinate array in order received (clockwise)
        // if (swapAxis) {
        // for (int n = 0; n < coords.length; n++) {
        // coordGridX[n] = (int) (((coords[n].y - extent.getWest()) / xInterval));
        // coordGridY[n] = (int) (((coords[n].x - extent.getSouth()) / yInterval));
        // coordGridY[n] = bimage.getHeight() - coordGridY[n];
        // }
        // } else {
        for (int n = 0; n < coords.length; n++) {
            coordGridX[n] = (int) (((coords[n].x - ((Grid)extent).getWest()) / xInterval));
            coordGridY[n] = (int) (((coords[n].y - ((Grid)extent).getSouth()) / yInterval));
            coordGridY[n] = bimage.getHeight() - coordGridY[n];
        }
        // }

        if (geometry.getClass().equals(Polygon.class)) {
            graphics.fillPolygon(coordGridX, coordGridY, coords.length);
        } else if (geometry.getClass().equals(LinearRing.class)) {
            graphics.drawPolyline(coordGridX, coordGridY, coords.length);
        } else if (geometry.getClass().equals(LineString.class)) {
            graphics.drawPolyline(coordGridX, coordGridY, coords.length);
        } else if (geometry.getClass().equals(Point.class)) {
            graphics.drawLine(coordGridX[0], coordGridY[0], coordGridX[0], coordGridY[0]);
        }
    }

    /**
     * Gets the emptyGrid attribute of the FeatureRasterizer object
     *
     * @return The emptyGrid value
     */
    public boolean isEmptyGrid() {
        return emptyGrid;
    }

    /**
     * Gets the writableRaster attribute of the FeatureRasterizer object
     *
     * @return The writableRaster value
     */
    public WritableRaster getWritableRaster() {
        return raster;
    }

    /**
     * Sets the writableRaster attribute of the FeatureRasterizer object
     *
     * @param raster
     *            The new writableRaster value
     */
    public void setWritableRaster(WritableRaster raster) {
        this.raster = raster;
    }

    public Geometry setBounds(IGrid grid, boolean swapAxis) {

        xInterval = ((Grid)grid).getEWExtent() / width;
        yInterval = ((Grid)grid).getNSExtent() / height;

        Envelope env = swapAxis
                ? new Envelope(((Grid)grid).getSouth(), ((Grid)grid).getNorth(), ((Grid)grid).getWest(), ((Grid)grid).getEast())
                : new Envelope(((Grid)grid).getWest(), ((Grid)grid).getEast(), ((Grid)grid).getSouth(), ((Grid)grid).getNorth());

        return geoFactory.toGeometry(env);
    }

    /**
     * Sets the entire raster to NoData
     * 
     * @param bounds
     */
    public void clearRaster(IGrid bounds) {

        minAttValue = 999999999;
        maxAttValue = -999999999;

        // initialize raster to NoData value inside covered area, NaN outside
        for (int i = 0; i < bounds.getXCells(); i++) {
            for (int j = 0; j < bounds.getYCells(); j++) {

                boolean inRegion = true;
                float clear = inRegion ? noDataValue : Float.NaN;
                raster.setSample(i, j, 0, clear);
                bimage.setRGB(i, j, floatBitsToInt(clear));
            }
        }

        /*
         * reset collection of coordinates or geometry to compute convex hull for
         * activation
         */
        this.hullShape = null;
    }

    /**
     * Get the current attribute to use as the grid cell values.
     */
    public String getAttName() {
        return attributeName;
    }

    /**
     * Sets the current attribute to use as the grid cell values.
     */
    public void setAttName(String attName) {
        this.attributeName = attName;
    }

    public float getNoDataValue() {
        return noDataValue;
    }

    public void setNoDataValue(float noData) {
        if (noData != noDataValue) {
            resetRaster = true;
        }
        this.noDataValue = noData;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        if (this.height != height) {
            resetRaster = true;
        }
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        if (this.width != width) {
            resetRaster = true;
        }
        this.width = width;
    }

    public double getMinAttValue() {
        return minAttValue;
    }

    public double getMaxAttValue() {
        return maxAttValue;
    }

    private int floatBitsToInt(float f) {

        ByteBuffer conv = ByteBuffer.allocate(4);
        conv.putFloat(0, f);
        return conv.getInt(0);
    }

    @Override
    public String toString() {
        return "FEATURE RASTERIZER: WIDTH=" + width + " , HEIGHT=" + height + " , NODATA=" + noDataValue;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy