Raster to vector conversion - Java proof-of-concept attached

19 messages Options
Embed this post
Permalink
Ferdinando Villa-4

Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
Hi,

I remember a discussion a few weeks ago about the need for  
vectorization of rasters in geotools. Andrea Aime pointed to some  
JGrass code (port of Grass' r.to.vect) and people offered to test the  
algorithm for Geotools.

I also need this badly, so I gave it a try and made a  
geotools-compatible class, which tests satisfactorily so far. The code  
is self-contained (in a geotools environment) and contains a main()  
with some minimal testing code. It can be made a lot smarter, but it  
works ok as a proof of concept. If anyone wants to see it, it can be  
found on our fisheye server:

http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/integratedmodelling/geospace/gis/Vectorizer.java

I'm also going to start work on a rasterizer - which is likely to be  
dumb, as I'm definitely not the spatial algorithm guru, but after 12  
years in the USA I have no shame left and I'll post what I come up  
with anyway :) Suggestions for algorithms or pointers to existing code  
are of course welcome.

Cheers,
ferdinando


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
mbedward

Re: Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
On Mon, Mar 31, 2008 at 1:23 AM, Ferdinando Villa
<[hidden email]> wrote:
>  I also need this badly, so I gave it a try and made a
>  geotools-compatible class, which tests satisfactorily so far. The code
>  is self-contained (in a geotools environment) and contains a main()
>  with some minimal testing code. It can be made a lot smarter, but it
>  works ok as a proof of concept. If anyone wants to see it, it can be
>  found on our fisheye server:
>
>  http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/integratedmodelling/geospace/gis/Vectorizer.java

This is great - thankyou Ferdinando !  I was the one offering to do
something about this a few weeks ago but got a bit stuck / distracted
/ insert other feeble excuses :)

>  after 12 years in the USA I have no shame left

*chuckle*

Michael

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Andrea Antonello

Re: Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
In reply to this post by Ferdinando Villa-4
>  I remember a discussion a few weeks ago about the need for
>  vectorization of rasters in geotools. Andrea Aime pointed to some
>  JGrass code (port of Grass' r.to.vect) and people offered to test the
>  algorithm for Geotools.

Aime wrote the original algo in GRASS, I started the port to java :)

>  I also need this badly, so I gave it a try and made a
>  geotools-compatible class, which tests satisfactorily so far. The code
>  is self-contained (in a geotools environment) and contains a main()
>  with some minimal testing code. It can be made a lot smarter, but it
>  works ok as a proof of concept. If anyone wants to see it, it can be
>  found on our fisheye server:
>
>  http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/integratedmodelling/geospace/gis/Vectorizer.java

That is really great. Looking forward to use the enhanced version as
thei geotools version comes to udig :)

>  I'm also going to start work on a rasterizer - which is likely to be
>  dumb, as I'm definitely not the spatial algorithm guru, but after 12
>  years in the USA I have no shame left and I'll post what I come up
>  with anyway :) Suggestions for algorithms or pointers to existing code
>  are of course welcome.

I think I can supply you a starting point on this implemented through
the scan line algorythm. Not the most performant, but the quickest to
implement: http://jgrasstechtips.blogspot.com/2008/01/how-to-rasterize-polygon-in-jgrass.html

Implementation is here, method rasterizePolygonGeometry:
https://dev.cocos.bz/plugins/scmsvn/viewcvs.php/jgrass3.0/trunk/eu.hydrologis.jgrass.libs/src/eu/hydrologis/jgrass/libs/utils/JGrassUtilities.java?rev=1353&root=jgrass&view=markup

Hope this helps,
Andrea


>
>  Cheers,
>  ferdinando
>
>
>  -------------------------------------------------------------------------
>  Check out the new SourceForge.net Marketplace.
>  It's the best place to buy or sell services for
>  just about anything Open Source.
>  http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
>  _______________________________________________
>  Geotools-gt2-users mailing list
>  [hidden email]
>  https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
>

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
aaime-2

Re: Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
andrea antonello ha scritto:
>>  I remember a discussion a few weeks ago about the need for
>>  vectorization of rasters in geotools. Andrea Aime pointed to some
>>  JGrass code (port of Grass' r.to.vect) and people offered to test the
>>  algorithm for Geotools.
>
> Aime wrote the original algo in GRASS, I started the port to java :)

In fact I just fixed some bugs in that module, someone
else wrote it (can't remember who).
Cheers
Andrea

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Ferdinando Villa-4

Re: Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
Grazie Andrea for pointing to the rasterization algorithm - what I was
playing with was very different, a recursive bisection thing that was lots
of fun to write but likely 100 times less efficient ;-) I'll give this a
spin this week and will post my results. I need both algorithms to work
reliably for well-behaved cases in a couple of months, so that's my
timeline. If at some point anyone decides to take them up for integration in
geotools, let me know so I can use the geotools version and stop playing
with them in my own codebase. Again, I'm all but a GIS guru so my choices
will need careful review.

I'll make sure to mention at least the known authors/contributors in the
credits - if it comes from the original Grass the root authors were probably
either Jim Westervelt or Mike Shapiro. Both old friends - I'll look at the
grass source and if it's still unclear, I'll shoot them an email.

Cheers,
ferdinando

-----Original Message-----
From: [hidden email]
[mailto:[hidden email]] On Behalf Of
Andrea Aime
Sent: Monday, March 31, 2008 4:43 AM
To: andrea antonello
Cc: Ferdinando Villa; [hidden email]
Subject: Re: [Geotools-gt2-users] Raster to vector conversion - Java
proof-of-concept attached

andrea antonello ha scritto:
>>  I remember a discussion a few weeks ago about the need for
>>  vectorization of rasters in geotools. Andrea Aime pointed to some
>>  JGrass code (port of Grass' r.to.vect) and people offered to test the
>>  algorithm for Geotools.
>
> Aime wrote the original algo in GRASS, I started the port to java :)

In fact I just fixed some bugs in that module, someone
else wrote it (can't remember who).
Cheers
Andrea

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Andrea Antonello

Re: Raster to vector conversion - Java proof-of-concept attached

Reply Threaded More More options
Print post
Permalink
In reply to this post by aaime-2
On Mon, Mar 31, 2008 at 2:50 PM, Ferdinando Villa
<[hidden email]> wrote:

> Grazie Andrea for pointing to the rasterization algorithm - what I was
>  playing with was very different, a recursive bisection thing that was lots
>  of fun to write but likely 100 times less efficient ;-) I'll give this a
>  spin this week and will post my results. I need both algorithms to work
>  reliably for well-behaved cases in a couple of months, so that's my
>  timeline. If at some point anyone decides to take them up for integration in
>  geotools, let me know so I can use the geotools version and stop playing
>  with them in my own codebase. Again, I'm all but a GIS guru so my choices
>  will need careful review.
>
>  I'll make sure to mention at least the known authors/contributors in the
>  credits - if it comes from the original Grass the root authors were probably
>  either Jim Westervelt or Mike Shapiro. Both old friends - I'll look at the
>  grass source and if it's still unclear, I'll shoot them an email.

Doesn't seem, paste from the r.to.vect C code:
 * MODULE:       r.to.vect
 *
 * AUTHOR(S):    Bill Brown, Mike Baba, Jean Ezell and Andrew Heekin,
 *               David Satnik, Andrea Aime, Radim Blazek


Ciao
Andrea


>
>  Cheers,
>  ferdinando
>
>
>
>  -----Original Message-----
>  From: [hidden email]
>  [mailto:[hidden email]] On Behalf Of
>  Andrea Aime
>  Sent: Monday, March 31, 2008 4:43 AM
>  To: andrea antonello
>  Cc: Ferdinando Villa; [hidden email]
>  Subject: Re: [Geotools-gt2-users] Raster to vector conversion - Java
>  proof-of-concept attached
>
>  andrea antonello ha scritto:
>  >>  I remember a discussion a few weeks ago about the need for
>  >>  vectorization of rasters in geotools. Andrea Aime pointed to some
>  >>  JGrass code (port of Grass' r.to.vect) and people offered to test the
>  >>  algorithm for Geotools.
>  >
>  > Aime wrote the original algo in GRASS, I started the port to java :)
>
>  In fact I just fixed some bugs in that module, someone
>  else wrote it (can't remember who).
>  Cheers
>  Andrea
>
>
>
> -------------------------------------------------------------------------
>  Check out the new SourceForge.net Marketplace.
>  It's the best place to buy or sell services for
>  just about anything Open Source.
>  http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
>  _______________________________________________
>  Geotools-gt2-users mailing list
>  [hidden email]
>  https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
>
>

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Steve.Ansari

Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by Andrea Antonello
Some javascript/style in this post has been disabled (why?)
Hello all,

I've worked a little on rasterizing based on Java 2D using Graphics & BufferedImage classes.  Initially my need was just to handle Polygon objects, so I have little testing with other Geometry types although they should work (I've tested with LineString and MultiPolygon).  I've had good performance with this so far ( > 10,000 polygons / sec )

I'm attaching the necessary classes (FeatureRasterizer is the only one that really matters!).  Note that this is written using Geotools 2.0 (legacy app) and some changes will need to be made to upgrade to 2.3+ .  I appreciate any feedback and improvements!  I'm hoping to try with JOGL at some point for even greater performance.


Thanks,
Steve







I think I can supply you a starting point on this implemented through
the scan line algorythm. Not the most performant, but the quickest to
implement: http://jgrasstechtips.blogspot.com/2008/01/how-to-rasterize-polygon-in-jgrass.html

Implementation is here, method rasterizePolygonGeometry:
https://dev.cocos.bz/plugins/scmsvn/viewcvs.php/jgrass3.0/trunk/eu.hydrologis.jgrass.libs/src/eu/hydrologis/jgrass/libs/utils/JGrassUtilities.java?rev=1353&root=jgrass&view=markup

Hope this helps,
Andrea



-- 
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4022 

package steve.test;

import gov.noaa.ncdc.ndit.export.raster.FeatureRasterizer;
import gov.noaa.ncdc.ndit.export.raster.FeatureRasterizerException;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.NoSuchElementException;

import javax.swing.JFrame;

import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.gc.GridCoverage;

import com.sun.media.jai.widget.DisplayJAI;

public class TestFeatureRasterizer {

   
    public static void main(String[] args) {
        try {
            testRasterizer();
           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
   
    public static void testRasterizer() throws IOException, NoSuchElementException, IllegalAttributeException, FeatureRasterizerException {
       
       
        URL url = new File("H:\\ESRI\\usa\\counties.shp").toURI().toURL();
        ShapefileDataStore ds = new ShapefileDataStore(url);
        FeatureSource fs = ds.getFeatureSource("counties");

       
        FeatureRasterizer rasterizer = new FeatureRasterizer(800, 800, -999.0f);
        rasterizer.setAttName("POP2001");

//        Envelope env = fs.getBounds();
//        Rectangle2D.Double bounds = new Rectangle2D.Double(env.getMinX(), env.getMinY(), env.getWidth(), env.getHeight());
        Rectangle2D.Double bounds = new Rectangle2D.Double(-120.0, 20.0, 40.0, 20.0);
       
        rasterizer.setBounds(bounds);
       
       
       
        FeatureReader fr = fs.getFeatures().reader();
        while (fr.hasNext()) {
            rasterizer.addFeature(fr.next());
        }
        rasterizer.close();
       
       
        GridCoverage gc = new GridCoverage("TEST1", rasterizer.getWritableRaster(), new org.geotools.pt.Envelope(bounds));
        DisplayJAI display = new DisplayJAI(gc.getRenderedImage());
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame.getContentPane().add(display);
        frame.pack();
        frame.setVisible(true);
       
       
       
       
        FeatureCollection fc = fs.getFeatures().collection();
        rasterizer.rasterize(fc, "POP2002");
       
        GridCoverage gc2 = new GridCoverage("TEST1", rasterizer.getWritableRaster(), new org.geotools.pt.Envelope(bounds));
        DisplayJAI display2 = new DisplayJAI(gc2.getRenderedImage());
        JFrame frame2 = new JFrame();
        frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame2.getContentPane().add(display2);
        frame2.pack();
        frame2.setVisible(true);


    }
}

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.export.raster;

import gov.noaa.ncdc.ndit.decoders.StreamingProcess;
import gov.noaa.ncdc.ndit.event.GeneralProgressEvent;
import gov.noaa.ncdc.ndit.event.GeneralProgressListener;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.util.Vector;

import javax.media.jai.RasterFactory;

import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;

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
 * @created    March 20, 2008
 */
public class FeatureRasterizer implements StreamingProcess {




    private int height;
    private int width;
    private double noDataValue;
    private WritableRaster raster = null;  
    private BufferedImage bimage = null;
    private Graphics2D graphics = null;




    private java.awt.geom.Rectangle2D.Double bounds;
    private double cellsize;
    private double minAttValue = 999999999;
    private double maxAttValue = -999999999;


    // Declare these as global
    private int[] coordGridX = new int[3500];
    private int[] coordGridY = new int[3500];
    private float value;

    private boolean emptyGrid = false;




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



    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 = false;



    // The list of event listeners.
    private Vector<GeneralProgressListener> listeners = new Vector<GeneralProgressListener>();







    /**
     *Constructor for the FeatureRasterizer object
     *
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer() {
        this(800, 800, -999.0f);
    }


    /**
     * Constructor for the FeatureRasterizer object - will use default 800x800 raster
     *
     * @param  noData                         No Data value for raster
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer(float noData) {
        this(800, 800, noData);
    }


    /**
     * Constructor for the FeatureRasterizer object.  No Data value defaults to -999.0
     *
     * @param  height                         Height of raster (number of grid cells)
     * @param  width                          Width of raster (number of grid cells)
     */
    public FeatureRasterizer(int height, int width) {
        this(height, width, -999.0f);
    }

    /**
     * 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);
        bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        bimage.setAccelerationPriority(1.0f);

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//      System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
        graphics = bimage.createGraphics();
        graphics.setPaintMode();
        graphics.setComposite(AlphaComposite.Src);


    }

    /**
     *  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 FeatureRasterizerException {

        // calculate variable resolution bounds that fit around feature collection

        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);
       
        System.out.println("BOUNDS: "+bounds);
        System.out.println("FCBNDS: "+fc.getBounds());

       
        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  FeatureRasterizerException  An error when rasterizing the data
     */
    public void rasterize(FeatureCollection fc, java.awt.geom.Rectangle2D.Double bounds, String attributeName)
    throws FeatureRasterizerException {



        this.attributeName = attributeName;
       



        // Check if we need to change the underlying raster
        if (resetRaster) {
            raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT,
                    width, height, 1, null);

            bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            bimage.setAccelerationPriority(1.0f);
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//          System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
            graphics = bimage.createGraphics();
            graphics.setPaintMode();
            graphics.setComposite(AlphaComposite.Src);


            resetRaster = false;

            System.out.println("---------------- RESETING FeatureRasterizer WritableRaster OBJECT -------------------- ");
        }
        // initialize raster to NoData value
        clearRaster();





        GeneralProgressEvent event = new GeneralProgressEvent(this);

        // Start
        // --------------
        for (int i = 0; i < listeners.size(); i++) {
            event.setProgress(0);
            listeners.get(i).started(event);
        }









        setBounds(bounds);

        // TODO - change method calls to account for a switch to control if rasterizer should work if vis bounds > feature bounds


        // All the data should start in the lower left corner.  Don't export what we don't need.
        double ratio = bounds.height / bounds.width;
        int ncols;
        int nrows;
        if (ratio < 1) {
            // wider than tall
            nrows = (int) (ratio * height);
            ncols = width;
        }
        else {
            nrows = height;
            ncols = (int) (height / ratio);
        }

        System.out.println("1 --- WIDTH: " + ncols + "   HEIGHT: " + nrows);

        FeatureIterator fci = fc.features();
        Feature feature;
        int size = fc.size();
        int cnt = 0;


        while (fci.hasNext()) {

            // Progress
            // --------------
            for (int n = 0; n < listeners.size(); n++) {
                event.setProgress( (int)( ( ((double)++cnt) / size ) * 100.0) );
                listeners.get(n).progress(event);
            }

            feature = fci.next();

            addFeature(feature);

        }
        close();



        // End
        // --------------
        for (int i = 0; i < listeners.size(); i++) {
            event.setProgress(0);
            listeners.get(i).ended(event);
        }



    }


    /**
     * 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(Feature feature) {


//      System.out.println("rasterizer - processing feature: "+feature);
        try {

            value = Float.parseFloat(feature.getAttribute(attributeName).toString());              

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

        } catch (Exception e) {        
            e.printStackTrace();        
            System.err.println("THE FEATURE COULD NOT BE RASTERIZED BASED ON THE '"+attributeName+
                    "' ATTRIBUTE VALUE OF '"+feature.getAttribute(attributeName).toString()+"'");        
            return;        
        }




        int rgbVal = floatBitsToInt(value);

        graphics.setColor(new Color(rgbVal, true));

        // Extract polygon and rasterize!
        Geometry geometry = feature.getDefaultGeometry();
        if (geometry.intersects(extentGeometry)) {

            if (geometry.getClass().equals(MultiPolygon.class)) {
                MultiPolygon mp = (MultiPolygon)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiLineString.class)) {
                MultiLineString mp = (MultiLineString)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiPoint.class)) {
                MultiPoint mp = (MultiPoint)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else {
                drawGeometry(geometry);
            }
        }


    }

    /**
     * Implementation the StreamingProcess interface - this copies values from BufferedImage RGB to WritableRaster of floats.
     */
    public void close() {
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                double val = Float.intBitsToFloat(bimage.getRGB(i, j));
                raster.setSample(i, j, 0, val);
            }
        }
    }
















    private void drawGeometry(Geometry geometry) {

        Coordinate[] coords = geometry.getCoordinates();


        // 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)
        for (int n = 0; n < coords.length; n++) {
            coordGridX[n] = (int) (((coords[n].x - bounds.x) / xInterval));
            coordGridY[n] = (int) (((coords[n].y - bounds.y) / 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.drawPolyline(coordGridX, coordGridY, coords.length);
        }

    }























    /**
     *  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;
    }


    /**
     *  Gets the bounds attribute of the FeatureRasterizer object
     *
     * @return    The bounds value
     */
    public java.awt.geom.Rectangle2D.Double getBounds() {
        return bounds;
    }

    /**
     *  Sets the bounds for the Rasterizer
     *
     * @return    The bounds value
     */
    public void setBounds(java.awt.geom.Rectangle2D.Double bounds) {
        this.bounds = bounds;

        xInterval = bounds.width / (double) width;
        yInterval = bounds.height / (double) height;

        System.out.println("xInterval: " + xInterval + "  yInterval: " + yInterval);

        if (xInterval > yInterval) {
            yInterval = xInterval;
        }
        if (yInterval > xInterval) {
            xInterval = yInterval;
        }

        cellsize = yInterval;

        // Clip geometries to the provided bounds      
        // Create extent geometry  
        Envelope env = new Envelope(
                bounds.getX(),
                bounds.getX() + bounds.getWidth(),
                bounds.getY(),
                bounds.getY() + bounds.getHeight()
        );
        extentGeometry = geoFactory.toGeometry(env);

    }






    /**
     *  Sets the entire raster to NoData
     */
    public void clearRaster() {

//      System.out.println("CLEARING RASTER");      
        minAttValue = 999999999;
        maxAttValue = -999999999;

        // initialize raster to NoData value
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                raster.setSample(i, j, 0, noDataValue);
                bimage.setRGB(i, j, floatBitsToInt((float)noDataValue));
            }
        }
    }














    /**
     *  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;
    }










    /**
     *  Gets the cellsize attribute of the FeatureRasterizer object
     *
     * @return    The cellsize value
     */
    public double getCellsize() {
        return cellsize;
    }


    public double getNoDataValue() {
        return noDataValue;
    }

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


    public int getHeight() {
        return height;
    }

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


    public int getWidth() {
        return width;
    }

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



    public double getMinAttValue() {
        return minAttValue;
    }

    public double getMaxAttValue() {
        return maxAttValue;
    }


















    /**
     * Adds a GeneralProgressListener to the list.
     *
     * @param  listener  The feature to be added to the GeneralProgressListener attribute
     */
    public void addGeneralProgressListener(GeneralProgressListener listener) {
        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }


    /**
     * Removes a GeneralProgressListener from the list.
     *
     * @param  listener   GeneralProgressListener to remove.
     */
    public void removeGeneralProgressListener(GeneralProgressListener listener) {
        listeners.remove(listener);
    }





    private static int floatBitsToInt(float f) {
        ByteBuffer conv = ByteBuffer.allocate(4);
        conv.putFloat(0, f);
        return conv.getInt(0);
    }


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













}


/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.export.raster;

public class FeatureRasterizerException extends Exception {
   
    /**
     * Constructor with message argument.
     *
     * @param message Reason for the exception being thrown
     */
    public FeatureRasterizerException(String message) {
        super(message);
    }
   
 }

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.decoders;

import org.geotools.feature.Feature;

/**
 *  Interface that defines the necessary "addFeature" method that receives a single
 *  Feature and does some process on it.  The 'close' method is only used when I/O
 *  is present such as writing a Shapefile.
 *
 * @author    steve.ansari
 */
public interface StreamingProcess {

   /**
    *  Receives a feature and does a process on it.  It is up to the LiteProcess
    *  implementor to decide what to do with this feature.  This could be to
    *  export it to shapefile, rasterize it, etc...
    *
    * @param  feature                   The feature to be added to the Feature attribute
    * @exception  StreamingProcessException  Description of the Exception
    */
   public void addFeature(Feature feature) throws StreamingProcessException;


   /**
    * Only used when I/O is present such as writing a Shapefile (in ExportShapefileLite).
    *
    * @exception  StreamingProcessException  Description of the Exception
    */
   public void close() throws StreamingProcessException;

}


package gov.noaa.ncdc.ndit.decoders;

public class StreamingProcessException extends Exception {
   
    /**
     * Constructor with message argument.
     *
     * @param message Reason for the exception being thrown
     */
    public StreamingProcessException(String message) {
        super(message);
    }
   
 }

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.event;

import java.util.*;

/**
 * A data transfer listener receives data transfer events and performs
 * some appripriate action in response.  Data transfer events are used
 * to signal the details of a data transfer, such as starting,
 * transfer progress, and ending.
 */
public interface GeneralProgressListener
  extends EventListener {

  ////////////////////////////////////////////////////////////

  /** Responds to a starting. */
  public void started(GeneralProgressEvent event);


  ////////////////////////////////////////////////////////////

  /** Responds to an ending. */
  public void ended(GeneralProgressEvent event);

  ////////////////////////////////////////////////////////////

  /** Responds to an progress. */
  public void progress(GeneralProgressEvent event);

  ////////////////////////////////////////////////////////////


} // NexradExportListener class

////////////////////////////////////////////////////////////////////////

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.event;

// Imports
// -------
import java.util.*;
import java.net.URL;
import java.io.File;

/**

 */
public class GeneralProgressEvent extends EventObject {

     
  private int progress;
     
  ////////////////////////////////////////////////////////////

  /** Create a new event. */
  public GeneralProgressEvent (Object source) {
 
    super (source);

  } // NexradExportEvent

  ////////////////////////////////////////////////////////////
 
 
 
  public void setProgress(int progress) {
     this.progress = progress;
  }
 
  public int getProgress() {
     return progress;
  }
 
 

} // NexradExportEvent class

////////////////////////////////////////////////////////////////////////

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Ferdinando Villa-4

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)

Hi Steve,

 

Thanks so much for contributing this – it’s going to save me a lot of work! I’ll do some testing and modernize where needed (although I don’t see any deprecated geotools methods used in FeatureRasterizer.java) and let the list know.

 

 

Thanks again,

ferdinando

 

---

Ferdinando Villa, Ph.D.

Associate Research Professor, Ecoinformatics Collaboratory, Gund Institute for Ecological Economics, UVM

http://ecoinformatics.uvm.edu

 

 

From: Steve Ansari [mailto:[hidden email]]
Sent: Monday, March 31, 2008 11:23 AM
To: Ferdinando Villa
Cc: [hidden email]
Subject: Vector to Raster conversion

 

Hello all,
 
I've worked a little on rasterizing based on Java 2D using Graphics & BufferedImage classes.  Initially my need was just to handle Polygon objects, so I have little testing with other Geometry types although they should work (I've tested with LineString and MultiPolygon).  I've had good performance with this so far ( > 10,000 polygons / sec )
 
I'm attaching the necessary classes (FeatureRasterizer is the only one that really matters!).  Note that this is written using Geotools 2.0 (legacy app) and some changes will need to be made to upgrade to 2.3+ .  I appreciate any feedback and improvements!  I'm hoping to try with JOGL at some point for even greater performance.
 
 
Thanks,
Steve
 
 
 
 
 
 
 
I think I can supply you a starting point on this implemented through
the scan line algorythm. Not the most performant, but the quickest to
implement: http://jgrasstechtips.blogspot.com/2008/01/how-to-rasterize-polygon-in-jgrass.html
 
Implementation is here, method rasterizePolygonGeometry:
https://dev.cocos.bz/plugins/scmsvn/viewcvs.php/jgrass3.0/trunk/eu.hydrologis.jgrass.libs/src/eu/hydrologis/jgrass/libs/utils/JGrassUtilities.java?rev=1353&root=jgrass&view=markup
 
Hope this helps,
Andrea





-- 
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4022 

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Jody Garnett

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Hey guys; we are setting up a "Process" module in geotools (see this
weeks IRC). After you do your "testing and modernize" do you want to
send it our way? It woudl be great to have examples of different kinds
of processes to make sure the API works out okay.
Jody

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Steve.Ansari

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Sure thing!  At some point I'll be upgrading it for Geotools 2.4+ for
use in some other projects.  I'll be sure to pass it along at that point.
Steve

Jody Garnett said the following on 4/1/2008 3:28 PM:
> Hey guys; we are setting up a "Process" module in geotools (see this
> weeks IRC). After you do your "testing and modernize" do you want to
> send it our way? It woudl be great to have examples of different kinds
> of processes to make sure the API works out okay.
> Jody


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Ferdinando Villa-4

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by Jody Garnett
Actually Steve's code works beautifully and does not seem to require much
modernization! I haven't tested it with a subsampled envelope yet, but it
spits out 4000x2000 rasters from big shapefiles in seconds. I only commented
out some (not all) debug printouts and added a function to produce a
GridCoverage2D directly:

    public GridCoverage2D rasterize(String name, FeatureCollection fc,
String attributeName, ReferencedEnvelope env)

you can pass null as the envelope and it will use the boundaries of the
feature collection. I also internalized the FeatureRasterizerException so
the code is now self-contained as long as geotools is in the classpath. It
does not use any deprecated API - that's the extent of my modernization
capabilities :)

If I find bugs along the way I'll try to fix them - progress can be followed
at
http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/int
egratedmodelling/geospace/gis/FeatureRasterizer.java.

Bottom line: Thanks Steve!

Cheers,
ferdinando


-----Original Message-----
From: Jody Garnett [mailto:[hidden email]]
Sent: Tuesday, April 01, 2008 3:28 PM
To: Ferdinando Villa
Cc: 'Steve Ansari'; [hidden email]
Subject: Re: [Geotools-gt2-users] Vector to Raster conversion

Hey guys; we are setting up a "Process" module in geotools (see this
weeks IRC). After you do your "testing and modernize" do you want to
send it our way? It woudl be great to have examples of different kinds
of processes to make sure the API works out okay.
Jody


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users

FeatureRasterizer.java (18K) Download Attachment
Steve.Ansari

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by Jody Garnett
Some javascript/style in this post has been disabled (why?)
Thanks Ferdinando!  It looks great.

Steve


Ferdinando Villa said the following on 4/1/2008 4:18 PM:
Actually Steve's code works beautifully and does not seem to require much
modernization! I haven't tested it with a subsampled envelope yet, but it
spits out 4000x2000 rasters from big shapefiles in seconds. I only commented
out some (not all) debug printouts and added a function to produce a
GridCoverage2D directly:

    public GridCoverage2D rasterize(String name, FeatureCollection fc,
String attributeName, ReferencedEnvelope env)

you can pass null as the envelope and it will use the boundaries of the
feature collection. I also internalized the FeatureRasterizerException so
the code is now self-contained as long as geotools is in the classpath. It
does not use any deprecated API - that's the extent of my modernization
capabilities :)

If I find bugs along the way I'll try to fix them - progress can be followed
at
http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/int
egratedmodelling/geospace/gis/FeatureRasterizer.java.

Bottom line: Thanks Steve!

Cheers,
ferdinando


-----Original Message-----
From: Jody Garnett [[hidden email]] 
Sent: Tuesday, April 01, 2008 3:28 PM
To: Ferdinando Villa
Cc: 'Steve Ansari'; [hidden email]
Subject: Re: [Geotools-gt2-users] Vector to Raster conversion

Hey guys; we are setting up a "Process" module in geotools (see this 
weeks IRC). After you do your "testing and modernize" do you want to 
send it our way? It woudl be great to have examples of different kinds 
of processes to make sure the API works out okay.
Jody
  

------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

_______________________________________________ Geotools-gt2-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users

-- 
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4022 

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Steve.Ansari

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)
Hello all,

I received a question about the rasterization code (Features to Grid Coverage) and upgraded the code to Geotools 2.5.2.  I've attached the main class (FeatureRasterizer.java) and a test class (TestFeatureRasterizer.java). 

Here are the geotools jars needed to run this:
geoapi-2.2-M1.jar
 gt-api-2.5.2.jar
 gt-coverage-2.5.2.jar
 gt-epsg-wkt-2.5.2.jar
 gt-main-2.5.2.jar
 gt-metadata-2.5.2.jar
 gt-referencing-2.5.2.jar
 gt-render-2.5.2.jar
 gt-shapefile-2.5.2.jar
 jai_codec-1.1.3.jar
 jai_imageio-1.1.jar
jsr-275-1.0-beta-2.jar
 jts-1.9.jar
vecmath-1.3.1.jar

Steve

Steve Ansari said the following on 4/1/2008 4:46 PM:
Thanks Ferdinando!  It looks great.

Steve


Ferdinando Villa said the following on 4/1/2008 4:18 PM:
Actually Steve's code works beautifully and does not seem to require much
modernization! I haven't tested it with a subsampled envelope yet, but it
spits out 4000x2000 rasters from big shapefiles in seconds. I only commented
out some (not all) debug printouts and added a function to produce a
GridCoverage2D directly:

    public GridCoverage2D rasterize(String name, FeatureCollection fc,
String attributeName, ReferencedEnvelope env)

you can pass null as the envelope and it will use the boundaries of the
feature collection. I also internalized the FeatureRasterizerException so
the code is now self-contained as long as geotools is in the classpath. It
does not use any deprecated API - that's the extent of my modernization
capabilities :)

If I find bugs along the way I'll try to fix them - progress can be followed
at
http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/int
egratedmodelling/geospace/gis/FeatureRasterizer.java.

Bottom line: Thanks Steve!

Cheers,
ferdinando


-----Original Message-----
From: Jody Garnett [[hidden email]] 
Sent: Tuesday, April 01, 2008 3:28 PM
To: Ferdinando Villa
Cc: 'Steve Ansari'; [hidden email]
Subject: Re: [Geotools-gt2-users] Vector to Raster conversion

Hey guys; we are setting up a "Process" module in geotools (see this 
weeks IRC). After you do your "testing and modernize" do you want to 
send it our way? It woudl be great to have examples of different kinds 
of processes to make sure the API works out okay.
Jody
  

------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

_______________________________________________ Geotools-gt2-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users

-- 
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4022 

-- 
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4328

package gov.noaa.ncdc.geotools;

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;

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.ReferencedEnvelope;
import org.opengis.feature.Feature;

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
 * @author Ferdinando Villa
 * @created    March 20, 2008
 */
public class FeatureRasterizer {

    public class FeatureRasterizerException extends Exception {
           
        /**
         * Constructor with message argument.
         *
         * @param message Reason for the exception being thrown
         */
        public FeatureRasterizerException(String message) {
            super(message);
        }      
     }

    private int height;
    private int width;
    private double noDataValue;
    private WritableRaster raster = null;  
    private BufferedImage bimage = null;
    private Graphics2D graphics = null;

    private java.awt.geom.Rectangle2D.Double bounds;
    private double cellsize;
    private double minAttValue = 999999999;
    private double maxAttValue = -999999999;

    // Declare these as global
    private int[] coordGridX = new int[3500];
    private int[] coordGridY = new int[3500];
    private float value;

    private boolean emptyGrid = false;

    private Geometry extentGeometry;
    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 = false;

    /**
     *Constructor for the FeatureRasterizer object
     *
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer() {
        this(800, 800, -999.0f);
    }

    /**
     * Constructor for the FeatureRasterizer object - will use default 800x800 raster
     *
     * @param  noData                         No Data value for raster
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer(float noData) {
        this(800, 800, noData);
    }

    /**
     * Constructor for the FeatureRasterizer object.  No Data value defaults to -999.0
     *
     * @param  height                         Height of raster (number of grid cells)
     * @param  width                          Width of raster (number of grid cells)
     */
    public FeatureRasterizer(int height, int width) {
        this(height, width, -999.0f);
    }

    /**
     * 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);
        bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        bimage.setAccelerationPriority(1.0f);

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//      System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
        graphics = bimage.createGraphics();
        graphics.setPaintMode();
        graphics.setComposite(AlphaComposite.Src);


    }
   
    public GridCoverage2D rasterize(String name, FeatureCollection fc, String attributeName, ReferencedEnvelope env) throws FeatureRasterizerException {
       
        if (raster == null) {
       
            WritableRaster raster =
                RasterFactory.createBandedRaster(
                    DataBuffer.TYPE_FLOAT,
                    this.width,
                    this.height,
                    1,
                    null);
       
            setWritableRaster(raster);
        }

        clearRaster();
       
        if (env == null) {
                   
            rasterize(fc, 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, box, attributeName);
        }
       
        GridCoverage2D coverage =
            rasterFactory.create(name, raster, env);
       
        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 FeatureRasterizerException {

        // calculate variable resolution bounds that fit around feature collection

        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);
       
        System.out.println("BOUNDS: "+bounds);
        System.out.println("FCBNDS: "+fc.getBounds());

       
        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  FeatureRasterizerException  An error when rasterizing the data
     */
    public void rasterize(FeatureCollection fc, java.awt.geom.Rectangle2D.Double bounds, String attributeName)
        throws FeatureRasterizerException {

        this.attributeName = attributeName;
       
        // Check if we need to change the underlying raster
        if (resetRaster) {
            raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT,
                    width, height, 1, null);

            bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            bimage.setAccelerationPriority(1.0f);
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//          System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
            graphics = bimage.createGraphics();
            graphics.setPaintMode();
            graphics.setComposite(AlphaComposite.Src);


            resetRaster = false;

            //System.out.println("---------------- RESETING FeatureRasterizer WritableRaster OBJECT -------------------- ");
        }
        // initialize raster to NoData value
        clearRaster();
        setBounds(bounds);

        // TODO - change method calls to account for a switch to control if rasterizer should work if vis bounds > feature bounds


        // All the data should start in the lower left corner.  Don't export what we don't need.
        double ratio = bounds.height / bounds.width;
        int ncols;
        int nrows;
        if (ratio < 1) {
            // wider than tall
            nrows = (int) (ratio * height);
            ncols = width;
        }
        else {
            nrows = height;
            ncols = (int) (height / ratio);
        }

        //System.out.println("1 --- WIDTH: " + ncols + "   HEIGHT: " + nrows);

        FeatureIterator fci = fc.features();
        Feature feature;

        while (fci.hasNext()) {


            feature = fci.next();

            addFeature(feature);

        }
        close();
    }

    /**
     * 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(Feature feature) {

        //System.out.println("rasterizer - processing feature: "+ attributeName + " -- " + feature);
       
        try {

            value = Float.parseFloat(feature.getProperty(attributeName).getValue().toString());              

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

        } catch (Exception e) {        
            e.printStackTrace();            
            System.err.println("THE FEATURE COULD NOT BE RASTERIZED BASED ON THE '"+attributeName+
                    "' ATTRIBUTE VALUE OF '"+feature.getProperty(attributeName).getValue().toString()+"'");          
            return;        
        }

        int rgbVal = floatBitsToInt(value);

        graphics.setColor(new Color(rgbVal, true));

        // Extract polygon and rasterize!
        Geometry geometry = (Geometry)feature.getDefaultGeometryProperty().getValue();
        if (geometry.intersects(extentGeometry)) {

            if (geometry.getClass().equals(MultiPolygon.class)) {
                MultiPolygon mp = (MultiPolygon)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiLineString.class)) {
                MultiLineString mp = (MultiLineString)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiPoint.class)) {
                MultiPoint mp = (MultiPoint)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else {
                drawGeometry(geometry);
            }
        }
    }

    /**
     * Implementation the StreamingProcess interface - this copies values from BufferedImage RGB to WritableRaster of floats.
     */
    public void close() {
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                double val = Float.intBitsToFloat(bimage.getRGB(i, j));
                raster.setSample(i, j, 0, val);
            }
        }
    }

    private void drawGeometry(Geometry geometry) {

        Coordinate[] coords = geometry.getCoordinates();

        // 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)
        for (int n = 0; n < coords.length; n++) {
            coordGridX[n] = (int) (((coords[n].x - bounds.x) / xInterval));
            coordGridY[n] = (int) (((coords[n].y - bounds.y) / 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.drawPolyline(coordGridX, coordGridY, coords.length);
        }
    }

    /**
     *  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;
    }

    /**
     *  Gets the bounds attribute of the FeatureRasterizer object
     *
     * @return    The bounds value
     */
    public java.awt.geom.Rectangle2D.Double getBounds() {
        return bounds;
    }

    /**
     *  Sets the bounds for the Rasterizer
     *
     * @return    The bounds value
     */
    public void setBounds(java.awt.geom.Rectangle2D.Double bounds) {
        this.bounds = bounds;

        xInterval = bounds.width / (double) width;
        yInterval = bounds.height / (double) height;

        System.out.println("xInterval: " + xInterval + "  yInterval: " + yInterval);

        if (xInterval > yInterval) {
            yInterval = xInterval;
        }
        if (yInterval > xInterval) {
            xInterval = yInterval;
        }

        cellsize = yInterval;

        // Clip geometries to the provided bounds      
        // Create extent geometry  
        Envelope env = new Envelope(
                bounds.getX(),
                bounds.getX() + bounds.getWidth(),
                bounds.getY(),
                bounds.getY() + bounds.getHeight()
        );
        extentGeometry = geoFactory.toGeometry(env);
    }

    /**
     *  Sets the entire raster to NoData
     */
    public void clearRaster() {

//      System.out.println("CLEARING RASTER");      
        minAttValue = 999999999;
        maxAttValue = -999999999;

        // initialize raster to NoData value
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                raster.setSample(i, j, 0, noDataValue);
                bimage.setRGB(i, j, floatBitsToInt((float)noDataValue));
            }
        }
    }

    /**
     *  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;
    }

    /**
     *  Gets the cellsize attribute of the FeatureRasterizer object
     *
     * @return    The cellsize value
     */
    public double getCellsize() {
        return cellsize;
    }


    public double getNoDataValue() {
        return noDataValue;
    }

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

    public int getHeight() {
        return height;
    }

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

    public int getWidth() {
        return width;
    }

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

    public double getMinAttValue() {
        return minAttValue;
    }

    public double getMaxAttValue() {
        return maxAttValue;
    }

    private static int floatBitsToInt(float f) {
        ByteBuffer conv = ByteBuffer.allocate(4);
        conv.putFloat(0, f);
        return conv.getInt(0);
    }

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

}



package gov.noaa.ncdc.geotools;

import gov.noaa.ncdc.geotools.FeatureRasterizerSteve.FeatureRasterizerException;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.NoSuchElementException;

import javax.swing.JFrame;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;

import com.sun.media.jai.widget.DisplayJAI;

public class TestFeatureRasterizer {

   
    public static void main(String[] args) {
        try {
            testRasterizer();
           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
   
    public static void testRasterizer() throws IOException, NoSuchElementException, FeatureRasterizerException, MismatchedDimensionException, NoSuchAuthorityCodeException, FactoryException {
       
       
        URL url = new File("H:\\ESRI\\usa\\counties.shp").toURI().toURL();
        ShapefileDataStore ds = new ShapefileDataStore(url);
        FeatureSource fs = ds.getFeatureSource("counties");

       
        FeatureRasterizerSteve rasterizer = new FeatureRasterizerSteve(800, 800, -999.0f);
        rasterizer.setAttName("POP2000");

//        Envelope env = fs.getBounds();
//        Rectangle2D.Double bounds = new Rectangle2D.Double(env.getMinX(), env.getMinY(), env.getWidth(), env.getHeight());
        Rectangle2D.Double bounds = new Rectangle2D.Double(-120.0, 20.0, 40.0, 20.0);
       
        rasterizer.setBounds(bounds);
       
       
       
        FeatureIterator fi = fs.getFeatures().features();
        while (fi.hasNext()) {
            rasterizer.addFeature(fi.next());
        }
        rasterizer.close();
       
       
        GridCoverageFactory gcFactory = new GridCoverageFactory();
        GridCoverage2D gc = gcFactory.create("TEST1", rasterizer.getWritableRaster(),
                new ReferencedEnvelope(bounds.getMinX(), bounds.getMaxX(), bounds.getMinY(), bounds.getMaxY(),
                        CRS.decode("EPSG:4326")));
        DisplayJAI display = new DisplayJAI(gc.getRenderedImage());
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame.getContentPane().add(display);
        frame.pack();
        frame.setVisible(true);
       
       
       
       
        FeatureCollection fc = fs.getFeatures();
        System.out.println("POP2001 feature collection size: "+fc.size());
        rasterizer.rasterize(fc, "POP2001");
       
        GridCoverage2D gc2 = gcFactory.create("TEST1", rasterizer.getWritableRaster(),
                new ReferencedEnvelope(bounds.getMinX(), bounds.getMaxX(), bounds.getMinY(), bounds.getMaxY(),
                CRS.decode("EPSG:4326")));
        DisplayJAI display2 = new DisplayJAI(gc2.getRenderedImage());
        JFrame frame2 = new JFrame();
        frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame2.getContentPane().add(display2);
        frame2.pack();
        frame2.setVisible(true);


    }
}

------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
mbedward

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Many thanks for this update Steve, I'll be using your code in the near future :)

Michael


2009/1/21 Steve Ansari <[hidden email]>:
> Hello all,
>
> I received a question about the rasterization code (Features to Grid
> Coverage) and upgraded the code to Geotools 2.5.2.  I've attached the main
> class (FeatureRasterizer.java) and a test class
> (TestFeatureRasterizer.java).
>

------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
jorgearevalo

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by Steve.Ansari
Hello

I think I'm the one who made the question :-). Many thanks for the help. I'm sure it will be really, really useful. I'll inform

Regards
Jorge

Steve.Ansari wrote:
Hello all,

I received a question about the rasterization code (Features to Grid
Coverage) and upgraded the code to Geotools 2.5.2.  I've attached the
main class (FeatureRasterizer.java) and a test class
(TestFeatureRasterizer.java).

Here are the geotools jars needed to run this:

geoapi-2.2-M1.jar
 gt-api-2.5.2.jar
 gt-coverage-2.5.2.jar
 gt-epsg-wkt-2.5.2.jar
 gt-main-2.5.2.jar
 gt-metadata-2.5.2.jar
 gt-referencing-2.5.2.jar
 gt-render-2.5.2.jar
 gt-shapefile-2.5.2.jar
 jai_codec-1.1.3.jar
 jai_imageio-1.1.jar
jsr-275-1.0-beta-2.jar
 jts-1.9.jar
vecmath-1.3.1.jar


Steve

Steve Ansari said the following on 4/1/2008 4:46 PM:
> Thanks Ferdinando!  It looks great.
>
> Steve
>
>
> Ferdinando Villa said the following on 4/1/2008 4:18 PM:
>> Actually Steve's code works beautifully and does not seem to require much
>> modernization! I haven't tested it with a subsampled envelope yet, but it
>> spits out 4000x2000 rasters from big shapefiles in seconds. I only commented
>> out some (not all) debug printouts and added a function to produce a
>> GridCoverage2D directly:
>>
>>     public GridCoverage2D rasterize(String name, FeatureCollection fc,
>> String attributeName, ReferencedEnvelope env)
>>
>> you can pass null as the envelope and it will use the boundaries of the
>> feature collection. I also internalized the FeatureRasterizerException so
>> the code is now self-contained as long as geotools is in the classpath. It
>> does not use any deprecated API - that's the extent of my modernization
>> capabilities :)
>>
>> If I find bugs along the way I'll try to fix them - progress can be followed
>> at
>> http://ecoinformatics.uvm.edu/crucible/browse/ThinklabGeospacePlugin/org/int
>> egratedmodelling/geospace/gis/FeatureRasterizer.java.
>>
>> Bottom line: Thanks Steve!
>>
>> Cheers,
>> ferdinando
>>
>>
>> -----Original Message-----
>> From: Jody Garnett [mailto:jgarnett@refractions.net]
>> Sent: Tuesday, April 01, 2008 3:28 PM
>> To: Ferdinando Villa
>> Cc: 'Steve Ansari'; geotools-gt2-users@lists.sourceforge.net
>> Subject: Re: [Geotools-gt2-users] Vector to Raster conversion
>>
>> Hey guys; we are setting up a "Process" module in geotools (see this
>> weeks IRC). After you do your "testing and modernize" do you want to
>> send it our way? It woudl be great to have examples of different kinds
>> of processes to make sure the API works out okay.
>> Jody
>>  
>> ------------------------------------------------------------------------
>>
>> -------------------------------------------------------------------------
>> Check out the new SourceForge.net Marketplace.
>> It's the best place to buy or sell services for
>> just about anything Open Source.
>> http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Geotools-gt2-users mailing list
>> Geotools-gt2-users@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
>>  
>
> --
> Steve Ansari
> Physical Scientist
> NOAA's National Climatic Data Center
> Veach-Baley Federal Building
> 151 Patton Avenue
> Asheville, NC 28801
> Ph: 828-271-4611
> Fax: 828-271-4022

--
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4328


package gov.noaa.ncdc.geotools;

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;

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.ReferencedEnvelope;
import org.opengis.feature.Feature;

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
 * @author Ferdinando Villa
 * @created    March 20, 2008
 */
public class FeatureRasterizer {

    public class FeatureRasterizerException extends Exception {
           
        /**
         * Constructor with message argument.
         *
         * @param message Reason for the exception being thrown
         */
        public FeatureRasterizerException(String message) {
            super(message);
        }      
     }

    private int height;
    private int width;
    private double noDataValue;
    private WritableRaster raster = null;  
    private BufferedImage bimage = null;
    private Graphics2D graphics = null;

    private java.awt.geom.Rectangle2D.Double bounds;
    private double cellsize;
    private double minAttValue = 999999999;
    private double maxAttValue = -999999999;

    // Declare these as global
    private int[] coordGridX = new int[3500];
    private int[] coordGridY = new int[3500];
    private float value;

    private boolean emptyGrid = false;

    private Geometry extentGeometry;
    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 = false;

    /**
     *Constructor for the FeatureRasterizer object
     *
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer() {
        this(800, 800, -999.0f);
    }

    /**
     * Constructor for the FeatureRasterizer object - will use default 800x800 raster
     *
     * @param  noData                         No Data value for raster
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer(float noData) {
        this(800, 800, noData);
    }

    /**
     * Constructor for the FeatureRasterizer object.  No Data value defaults to -999.0
     *
     * @param  height                         Height of raster (number of grid cells)
     * @param  width                          Width of raster (number of grid cells)
     */
    public FeatureRasterizer(int height, int width) {
        this(height, width, -999.0f);
    }

    /**
     * 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);
        bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        bimage.setAccelerationPriority(1.0f);

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//      System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
        graphics = bimage.createGraphics();
        graphics.setPaintMode();
        graphics.setComposite(AlphaComposite.Src);


    }
   
    public GridCoverage2D rasterize(String name, FeatureCollection fc, String attributeName, ReferencedEnvelope env) throws FeatureRasterizerException {
       
        if (raster == null) {
       
            WritableRaster raster =
                RasterFactory.createBandedRaster(
                    DataBuffer.TYPE_FLOAT,
                    this.width,
                    this.height,
                    1,
                    null);
       
            setWritableRaster(raster);
        }

        clearRaster();
       
        if (env == null) {
                   
            rasterize(fc, 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, box, attributeName);
        }
       
        GridCoverage2D coverage =
            rasterFactory.create(name, raster, env);
       
        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 FeatureRasterizerException {

        // calculate variable resolution bounds that fit around feature collection

        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);
       
        System.out.println("BOUNDS: "+bounds);
        System.out.println("FCBNDS: "+fc.getBounds());

       
        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  FeatureRasterizerException  An error when rasterizing the data
     */
    public void rasterize(FeatureCollection fc, java.awt.geom.Rectangle2D.Double bounds, String attributeName)
        throws FeatureRasterizerException {

        this.attributeName = attributeName;
       
        // Check if we need to change the underlying raster
        if (resetRaster) {
            raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT,
                    width, height, 1, null);

            bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            bimage.setAccelerationPriority(1.0f);
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//          System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
            graphics = bimage.createGraphics();
            graphics.setPaintMode();
            graphics.setComposite(AlphaComposite.Src);


            resetRaster = false;

            //System.out.println("---------------- RESETING FeatureRasterizer WritableRaster OBJECT -------------------- ");
        }
        // initialize raster to NoData value
        clearRaster();
        setBounds(bounds);

        // TODO - change method calls to account for a switch to control if rasterizer should work if vis bounds > feature bounds


        // All the data should start in the lower left corner.  Don't export what we don't need.
        double ratio = bounds.height / bounds.width;
        int ncols;
        int nrows;
        if (ratio < 1) {
            // wider than tall
            nrows = (int) (ratio * height);
            ncols = width;
        }
        else {
            nrows = height;
            ncols = (int) (height / ratio);
        }

        //System.out.println("1 --- WIDTH: " + ncols + "   HEIGHT: " + nrows);

        FeatureIterator fci = fc.features();
        Feature feature;

        while (fci.hasNext()) {


            feature = fci.next();

            addFeature(feature);

        }
        close();
    }

    /**
     * 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(Feature feature) {

        //System.out.println("rasterizer - processing feature: "+ attributeName + " -- " + feature);
       
        try {

            value = Float.parseFloat(feature.getProperty(attributeName).getValue().toString());              

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

        } catch (Exception e) {        
            e.printStackTrace();            
            System.err.println("THE FEATURE COULD NOT BE RASTERIZED BASED ON THE '"+attributeName+
                    "' ATTRIBUTE VALUE OF '"+feature.getProperty(attributeName).getValue().toString()+"'");          
            return;        
        }

        int rgbVal = floatBitsToInt(value);

        graphics.setColor(new Color(rgbVal, true));

        // Extract polygon and rasterize!
        Geometry geometry = (Geometry)feature.getDefaultGeometryProperty().getValue();
        if (geometry.intersects(extentGeometry)) {

            if (geometry.getClass().equals(MultiPolygon.class)) {
                MultiPolygon mp = (MultiPolygon)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiLineString.class)) {
                MultiLineString mp = (MultiLineString)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiPoint.class)) {
                MultiPoint mp = (MultiPoint)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else {
                drawGeometry(geometry);
            }
        }
    }

    /**
     * Implementation the StreamingProcess interface - this copies values from BufferedImage RGB to WritableRaster of floats.
     */
    public void close() {
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                double val = Float.intBitsToFloat(bimage.getRGB(i, j));
                raster.setSample(i, j, 0, val);
            }
        }
    }

    private void drawGeometry(Geometry geometry) {

        Coordinate[] coords = geometry.getCoordinates();

        // 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)
        for (int n = 0; n < coords.length; n++) {
            coordGridX[n] = (int) (((coords[n].x - bounds.x) / xInterval));
            coordGridY[n] = (int) (((coords[n].y - bounds.y) / 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.drawPolyline(coordGridX, coordGridY, coords.length);
        }
    }

    /**
     *  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;
    }

    /**
     *  Gets the bounds attribute of the FeatureRasterizer object
     *
     * @return    The bounds value
     */
    public java.awt.geom.Rectangle2D.Double getBounds() {
        return bounds;
    }

    /**
     *  Sets the bounds for the Rasterizer
     *
     * @return    The bounds value
     */
    public void setBounds(java.awt.geom.Rectangle2D.Double bounds) {
        this.bounds = bounds;

        xInterval = bounds.width / (double) width;
        yInterval = bounds.height / (double) height;

        System.out.println("xInterval: " + xInterval + "  yInterval: " + yInterval);

        if (xInterval > yInterval) {
            yInterval = xInterval;
        }
        if (yInterval > xInterval) {
            xInterval = yInterval;
        }

        cellsize = yInterval;

        // Clip geometries to the provided bounds      
        // Create extent geometry  
        Envelope env = new Envelope(
                bounds.getX(),
                bounds.getX() + bounds.getWidth(),
                bounds.getY(),
                bounds.getY() + bounds.getHeight()
        );
        extentGeometry = geoFactory.toGeometry(env);
    }

    /**
     *  Sets the entire raster to NoData
     */
    public void clearRaster() {

//      System.out.println("CLEARING RASTER");      
        minAttValue = 999999999;
        maxAttValue = -999999999;

        // initialize raster to NoData value
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                raster.setSample(i, j, 0, noDataValue);
                bimage.setRGB(i, j, floatBitsToInt((float)noDataValue));
            }
        }
    }

    /**
     *  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;
    }

    /**
     *  Gets the cellsize attribute of the FeatureRasterizer object
     *
     * @return    The cellsize value
     */
    public double getCellsize() {
        return cellsize;
    }


    public double getNoDataValue() {
        return noDataValue;
    }

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

    public int getHeight() {
        return height;
    }

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

    public int getWidth() {
        return width;
    }

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

    public double getMinAttValue() {
        return minAttValue;
    }

    public double getMaxAttValue() {
        return maxAttValue;
    }

    private static int floatBitsToInt(float f) {
        ByteBuffer conv = ByteBuffer.allocate(4);
        conv.putFloat(0, f);
        return conv.getInt(0);
    }

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

}



package gov.noaa.ncdc.geotools;

import gov.noaa.ncdc.geotools.FeatureRasterizerSteve.FeatureRasterizerException;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.NoSuchElementException;

import javax.swing.JFrame;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;

import com.sun.media.jai.widget.DisplayJAI;

public class TestFeatureRasterizer {

   
    public static void main(String[] args) {
        try {
            testRasterizer();
           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
   
    public static void testRasterizer() throws IOException, NoSuchElementException, FeatureRasterizerException, MismatchedDimensionException, NoSuchAuthorityCodeException, FactoryException {
       
       
        URL url = new File("H:\\ESRI\\usa\\counties.shp").toURI().toURL();
        ShapefileDataStore ds = new ShapefileDataStore(url);
        FeatureSource fs = ds.getFeatureSource("counties");

       
        FeatureRasterizerSteve rasterizer = new FeatureRasterizerSteve(800, 800, -999.0f);
        rasterizer.setAttName("POP2000");

//        Envelope env = fs.getBounds();
//        Rectangle2D.Double bounds = new Rectangle2D.Double(env.getMinX(), env.getMinY(), env.getWidth(), env.getHeight());
        Rectangle2D.Double bounds = new Rectangle2D.Double(-120.0, 20.0, 40.0, 20.0);
       
        rasterizer.setBounds(bounds);
       
       
       
        FeatureIterator fi = fs.getFeatures().features();
        while (fi.hasNext()) {
            rasterizer.addFeature(fi.next());
        }
        rasterizer.close();
       
       
        GridCoverageFactory gcFactory = new GridCoverageFactory();
        GridCoverage2D gc = gcFactory.create("TEST1", rasterizer.getWritableRaster(),
                new ReferencedEnvelope(bounds.getMinX(), bounds.getMaxX(), bounds.getMinY(), bounds.getMaxY(),
                        CRS.decode("EPSG:4326")));
        DisplayJAI display = new DisplayJAI(gc.getRenderedImage());
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame.getContentPane().add(display);
        frame.pack();
        frame.setVisible(true);
       
       
       
       
        FeatureCollection fc = fs.getFeatures();
        System.out.println("POP2001 feature collection size: "+fc.size());
        rasterizer.rasterize(fc, "POP2001");
       
        GridCoverage2D gc2 = gcFactory.create("TEST1", rasterizer.getWritableRaster(),
                new ReferencedEnvelope(bounds.getMinX(), bounds.getMaxX(), bounds.getMinY(), bounds.getMaxY(),
                CRS.decode("EPSG:4326")));
        DisplayJAI display2 = new DisplayJAI(gc2.getRenderedImage());
        JFrame frame2 = new JFrame();
        frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame2.getContentPane().add(display2);
        frame2.pack();
        frame2.setVisible(true);


    }
}

------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Geotools-gt2-users mailing list
Geotools-gt2-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Agossa

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by Steve.Ansari
Hello ,
I am using  FeatureRasterizer of Steve Ansari . It is great! Thanks. I have a little problem. I always get a little displacement between the result of the rasterizing and the original Feature on displaying. (See attachment). how can I avoid that?
Thank you.

FeatureCollection fc=....;

GridCoverage2D cov = ...;
//I want to get the same image dimensions ratio as the ones of cov
                RenderedImage dest = cov.getRenderedImage();
               
               
                int width = dest.getWidth();

                int height = dest.getHeight();

//1200 pixels wide
                height=(int)( Math.floor(1200.0 * ((double)height)
                                / (double)width));
               

                width=1200;
               
               
                FeatureRasterizer fr = new FeatureRasterizer(height,width, -999f);


                Envelope env = cov.getEnvelope();

                GridCoverage2D result= null;
                try {
                        result = fr.rasterize("Selection", fc, "ID",
                                        new ReferencedEnvelope(env));
                } catch (FeatureRasterizer.FeatureRasterizerException e) {
                       
                        e.printStackTrace();
                }
                raster.png
               




Steve.Ansari wrote:
Hello all,

I've worked a little on rasterizing based on Java 2D using Graphics & BufferedImage classes.  Initially my need was just to handle Polygon objects, so I have little testing with other Geometry types although they should work (I've tested with LineString and MultiPolygon).  I've had good performance with this so far ( > 10,000 polygons / sec )

I'm attaching the necessary classes (FeatureRasterizer is the only one that really matters!).  Note that this is written using Geotools 2.0 (legacy app) and some changes will need to be made to upgrade to 2.3+ .  I appreciate any feedback and improvements!  I'm hoping to try with JOGL at some point for even greater performance.


Thanks,
Steve







/I think I can supply you a starting point on this implemented through
the scan line algorythm. Not the most performant, but the quickest to
implement: http://jgrasstechtips.blogspot.com/2008/01/how-to-rasterize-polygon-in-jgrass.html

Implementation is here, method rasterizePolygonGeometry:
https://dev.cocos.bz/plugins/scmsvn/viewcvs.php/jgrass3.0/trunk/eu.hydrologis.jgrass.libs/src/eu/hydrologis/jgrass/libs/utils/JGrassUtilities.java?rev=1353&root=jgrass&view=markup

Hope this helps,
Andrea/




--
Steve Ansari
Physical Scientist
NOAA's National Climatic Data Center
Veach-Baley Federal Building
151 Patton Avenue
Asheville, NC 28801
Ph: 828-271-4611
Fax: 828-271-4022


package steve.test;

import gov.noaa.ncdc.ndit.export.raster.FeatureRasterizer;
import gov.noaa.ncdc.ndit.export.raster.FeatureRasterizerException;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.NoSuchElementException;

import javax.swing.JFrame;

import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.gc.GridCoverage;

import com.sun.media.jai.widget.DisplayJAI;

public class TestFeatureRasterizer {

   
    public static void main(String[] args) {
        try {
            testRasterizer();
           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
   
    public static void testRasterizer() throws IOException, NoSuchElementException, IllegalAttributeException, FeatureRasterizerException {
       
       
        URL url = new File("H:\\ESRI\\usa\\counties.shp").toURI().toURL();
        ShapefileDataStore ds = new ShapefileDataStore(url);
        FeatureSource fs = ds.getFeatureSource("counties");

       
        FeatureRasterizer rasterizer = new FeatureRasterizer(800, 800, -999.0f);
        rasterizer.setAttName("POP2001");

//        Envelope env = fs.getBounds();
//        Rectangle2D.Double bounds = new Rectangle2D.Double(env.getMinX(), env.getMinY(), env.getWidth(), env.getHeight());
        Rectangle2D.Double bounds = new Rectangle2D.Double(-120.0, 20.0, 40.0, 20.0);
       
        rasterizer.setBounds(bounds);
       
       
       
        FeatureReader fr = fs.getFeatures().reader();
        while (fr.hasNext()) {
            rasterizer.addFeature(fr.next());
        }
        rasterizer.close();
       
       
        GridCoverage gc = new GridCoverage("TEST1", rasterizer.getWritableRaster(), new org.geotools.pt.Envelope(bounds));
        DisplayJAI display = new DisplayJAI(gc.getRenderedImage());
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame.getContentPane().add(display);
        frame.pack();
        frame.setVisible(true);
       
       
       
       
        FeatureCollection fc = fs.getFeatures().collection();
        rasterizer.rasterize(fc, "POP2002");
       
        GridCoverage gc2 = new GridCoverage("TEST1", rasterizer.getWritableRaster(), new org.geotools.pt.Envelope(bounds));
        DisplayJAI display2 = new DisplayJAI(gc2.getRenderedImage());
        JFrame frame2 = new JFrame();
        frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        frame2.getContentPane().add(display2);
        frame2.pack();
        frame2.setVisible(true);


    }
}

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.export.raster;

import gov.noaa.ncdc.ndit.decoders.StreamingProcess;
import gov.noaa.ncdc.ndit.event.GeneralProgressEvent;
import gov.noaa.ncdc.ndit.event.GeneralProgressListener;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.util.Vector;

import javax.media.jai.RasterFactory;

import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;

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
 * @created    March 20, 2008
 */
public class FeatureRasterizer implements StreamingProcess {




    private int height;
    private int width;
    private double noDataValue;
    private WritableRaster raster = null;  
    private BufferedImage bimage = null;
    private Graphics2D graphics = null;




    private java.awt.geom.Rectangle2D.Double bounds;
    private double cellsize;
    private double minAttValue = 999999999;
    private double maxAttValue = -999999999;


    // Declare these as global
    private int[] coordGridX = new int[3500];
    private int[] coordGridY = new int[3500];
    private float value;

    private boolean emptyGrid = false;




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



    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 = false;



    // The list of event listeners.
    private Vector<GeneralProgressListener> listeners = new Vector<GeneralProgressListener>();







    /**
     *Constructor for the FeatureRasterizer object
     *
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer() {
        this(800, 800, -999.0f);
    }


    /**
     * Constructor for the FeatureRasterizer object - will use default 800x800 raster
     *
     * @param  noData                         No Data value for raster
     * @exception  FeatureRasterizerException  Description of the Exception
     */
    public FeatureRasterizer(float noData) {
        this(800, 800, noData);
    }


    /**
     * Constructor for the FeatureRasterizer object.  No Data value defaults to -999.0
     *
     * @param  height                         Height of raster (number of grid cells)
     * @param  width                          Width of raster (number of grid cells)
     */
    public FeatureRasterizer(int height, int width) {
        this(height, width, -999.0f);
    }

    /**
     * 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);
        bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        bimage.setAccelerationPriority(1.0f);

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//      System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
        graphics = bimage.createGraphics();
        graphics.setPaintMode();
        graphics.setComposite(AlphaComposite.Src);


    }

    /**
     *  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 FeatureRasterizerException {

        // calculate variable resolution bounds that fit around feature collection

        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);
       
        System.out.println("BOUNDS: "+bounds);
        System.out.println("FCBNDS: "+fc.getBounds());

       
        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  FeatureRasterizerException  An error when rasterizing the data

     */
    public void rasterize(FeatureCollection fc, java.awt.geom.Rectangle2D.Double bounds, String attributeName)
    throws FeatureRasterizerException {



        this.attributeName = attributeName;
       



        // Check if we need to change the underlying raster
        if (resetRaster) {
            raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT,
                    width, height, 1, null);

            bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            bimage.setAccelerationPriority(1.0f);
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//          System.out.println("IMAGE ACCELERATED? "+bimage.getCapabilities(ge.getDefaultScreenDevice().getDefaultConfiguration()).isAccelerated());
            graphics = bimage.createGraphics();
            graphics.setPaintMode();
            graphics.setComposite(AlphaComposite.Src);


            resetRaster = false;

            System.out.println("---------------- RESETING FeatureRasterizer WritableRaster OBJECT -------------------- ");
        }
        // initialize raster to NoData value
        clearRaster();





        GeneralProgressEvent event = new GeneralProgressEvent(this);

        // Start
        // --------------
        for (int i = 0; i < listeners.size(); i++) {
            event.setProgress(0);
            listeners.get(i).started(event);
        }









        setBounds(bounds);

        // TODO - change method calls to account for a switch to control if rasterizer should work if vis bounds > feature bounds


        // All the data should start in the lower left corner.  Don't export what we don't need.
        double ratio = bounds.height / bounds.width;
        int ncols;
        int nrows;
        if (ratio < 1) {
            // wider than tall
            nrows = (int) (ratio * height);
            ncols = width;
        }
        else {
            nrows = height;
            ncols = (int) (height / ratio);
        }

        System.out.println("1 --- WIDTH: " + ncols + "   HEIGHT: " + nrows);

        FeatureIterator fci = fc.features();
        Feature feature;
        int size = fc.size();
        int cnt = 0;


        while (fci.hasNext()) {

            // Progress
            // --------------
            for (int n = 0; n < listeners.size(); n++) {
                event.setProgress( (int)( ( ((double)++cnt) / size ) * 100.0) );
                listeners.get(n).progress(event);
            }

            feature = fci.next();

            addFeature(feature);

        }
        close();



        // End
        // --------------
        for (int i = 0; i < listeners.size(); i++) {
            event.setProgress(0);
            listeners.get(i).ended(event);
        }



    }


    /**
     * 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(Feature feature) {


//      System.out.println("rasterizer - processing feature: "+feature);
        try {

            value = Float.parseFloat(feature.getAttribute(attributeName).toString());              

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

        } catch (Exception e) {        
            e.printStackTrace();        
            System.err.println("THE FEATURE COULD NOT BE RASTERIZED BASED ON THE '"+attributeName+
                    "' ATTRIBUTE VALUE OF '"+feature.getAttribute(attributeName).toString()+"'");        
            return;        
        }




        int rgbVal = floatBitsToInt(value);

        graphics.setColor(new Color(rgbVal, true));

        // Extract polygon and rasterize!
        Geometry geometry = feature.getDefaultGeometry();
        if (geometry.intersects(extentGeometry)) {

            if (geometry.getClass().equals(MultiPolygon.class)) {
                MultiPolygon mp = (MultiPolygon)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiLineString.class)) {
                MultiLineString mp = (MultiLineString)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else if (geometry.getClass().equals(MultiPoint.class)) {
                MultiPoint mp = (MultiPoint)geometry;
                for (int n=0; n<mp.getNumGeometries(); n++) {
                    drawGeometry(mp.getGeometryN(n));
                }
            }
            else {
                drawGeometry(geometry);
            }
        }


    }

    /**
     * Implementation the StreamingProcess interface - this copies values from BufferedImage RGB to WritableRaster of floats.
     */
    public void close() {
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                double val = Float.intBitsToFloat(bimage.getRGB(i, j));
                raster.setSample(i, j, 0, val);
            }
        }
    }
















    private void drawGeometry(Geometry geometry) {

        Coordinate[] coords = geometry.getCoordinates();


        // 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)
        for (int n = 0; n < coords.length; n++) {
            coordGridX[n] = (int) (((coords[n].x - bounds.x) / xInterval));
            coordGridY[n] = (int) (((coords[n].y - bounds.y) / 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.drawPolyline(coordGridX, coordGridY, coords.length);
        }

    }























    /**
     *  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;
    }


    /**
     *  Gets the bounds attribute of the FeatureRasterizer object
     *
     * @return    The bounds value
     */
    public java.awt.geom.Rectangle2D.Double getBounds() {
        return bounds;
    }

    /**
     *  Sets the bounds for the Rasterizer
     *
     * @return    The bounds value
     */
    public void setBounds(java.awt.geom.Rectangle2D.Double bounds) {
        this.bounds = bounds;

        xInterval = bounds.width / (double) width;
        yInterval = bounds.height / (double) height;

        System.out.println("xInterval: " + xInterval + "  yInterval: " + yInterval);

        if (xInterval > yInterval) {
            yInterval = xInterval;
        }
        if (yInterval > xInterval) {
            xInterval = yInterval;
        }

        cellsize = yInterval;

        // Clip geometries to the provided bounds      
        // Create extent geometry  
        Envelope env = new Envelope(
                bounds.getX(),
                bounds.getX() + bounds.getWidth(),
                bounds.getY(),
                bounds.getY() + bounds.getHeight()
        );
        extentGeometry = geoFactory.toGeometry(env);

    }






    /**
     *  Sets the entire raster to NoData
     */
    public void clearRaster() {

//      System.out.println("CLEARING RASTER");      
        minAttValue = 999999999;
        maxAttValue = -999999999;

        // initialize raster to NoData value
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                raster.setSample(i, j, 0, noDataValue);
                bimage.setRGB(i, j, floatBitsToInt((float)noDataValue));
            }
        }
    }














    /**
     *  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;
    }










    /**
     *  Gets the cellsize attribute of the FeatureRasterizer object
     *
     * @return    The cellsize value
     */
    public double getCellsize() {
        return cellsize;
    }


    public double getNoDataValue() {
        return noDataValue;
    }

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


    public int getHeight() {
        return height;
    }

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


    public int getWidth() {
        return width;
    }

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



    public double getMinAttValue() {
        return minAttValue;
    }

    public double getMaxAttValue() {
        return maxAttValue;
    }


















    /**
     * Adds a GeneralProgressListener to the list.
     *
     * @param  listener  The feature to be added to the GeneralProgressListener attribute
     */
    public void addGeneralProgressListener(GeneralProgressListener listener) {
        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }


    /**
     * Removes a GeneralProgressListener from the list.
     *
     * @param  listener   GeneralProgressListener to remove.
     */
    public void removeGeneralProgressListener(GeneralProgressListener listener) {
        listeners.remove(listener);
    }





    private static int floatBitsToInt(float f) {
        ByteBuffer conv = ByteBuffer.allocate(4);
        conv.putFloat(0, f);
        return conv.getInt(0);
    }


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













}


/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.export.raster;

public class FeatureRasterizerException extends Exception {
   
    /**
     * Constructor with message argument.
     *
     * @param message Reason for the exception being thrown
     */
    public FeatureRasterizerException(String message) {
        super(message);
    }
   
 }

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.decoders;

import org.geotools.feature.Feature;

/**
 *  Interface that defines the necessary "addFeature" method that receives a single
 *  Feature and does some process on it.  The 'close' method is only used when I/O
 *  is present such as writing a Shapefile.
 *
 * @author    steve.ansari
 */
public interface StreamingProcess {

   /**
    *  Receives a feature and does a process on it.  It is up to the LiteProcess
    *  implementor to decide what to do with this feature.  This could be to
    *  export it to shapefile, rasterize it, etc...
    *
    * @param  feature                   The feature to be added to the Feature attribute
    * @exception  StreamingProcessException  Description of the Exception
    */
   public void addFeature(Feature feature) throws StreamingProcessException;


   /**
    * Only used when I/O is present such as writing a Shapefile (in ExportShapefileLite).
    *
    * @exception  StreamingProcessException  Description of the Exception
    */
   public void close() throws StreamingProcessException;

}


package gov.noaa.ncdc.ndit.decoders;

public class StreamingProcessException extends Exception {
   
    /**
     * Constructor with message argument.
     *
     * @param message Reason for the exception being thrown
     */
    public StreamingProcessException(String message) {
        super(message);
    }
   
 }

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.event;

import java.util.*;

/**
 * A data transfer listener receives data transfer events and performs
 * some appripriate action in response.  Data transfer events are used
 * to signal the details of a data transfer, such as starting,
 * transfer progress, and ending.
 */
public interface GeneralProgressListener
  extends EventListener {

  ////////////////////////////////////////////////////////////

  /** Responds to a starting. */
  public void started(GeneralProgressEvent event);


  ////////////////////////////////////////////////////////////

  /** Responds to an ending. */
  public void ended(GeneralProgressEvent event);

  ////////////////////////////////////////////////////////////

  /** Responds to an progress. */
  public void progress(GeneralProgressEvent event);

  ////////////////////////////////////////////////////////////


} // NexradExportListener class

////////////////////////////////////////////////////////////////////////

/**
 * NOAA's National Climatic Data Center
 * NOAA/NESDIS/NCDC
 * 151 Patton Ave, Asheville, NC  28801
 *
 * THIS SOFTWARE AND ITS DOCUMENTATION ARE CONSIDERED TO BE IN THE
 * PUBLIC DOMAIN AND THUS ARE AVAILABLE FOR UNRESTRICTED PUBLIC USE.  
 * THEY ARE FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS
 * INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY,
 * EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND
 * DOCUMENTATION FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1)
 * FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE
 * TECHNICAL SUPPORT TO USERS.
 */

package gov.noaa.ncdc.ndit.event;

// Imports
// -------
import java.util.*;
import java.net.URL;
import java.io.File;

/**

 */
public class GeneralProgressEvent extends EventObject {

     
  private int progress;
     
  ////////////////////////////////////////////////////////////

  /** Create a new event. */
  public GeneralProgressEvent (Object source) {
 
    super (source);

  } // NexradExportEvent

  ////////////////////////////////////////////////////////////
 
 
 
  public void setProgress(int progress) {
     this.progress = progress;
  }
 
  public int getProgress() {
     return progress;
  }
 
 

} // NexradExportEvent class

////////////////////////////////////////////////////////////////////////

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Geotools-gt2-users mailing list
Geotools-gt2-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
mbedward

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Hello,

Steve's raster to vector code is now included in the gt-process module
in GeoTools version 2.6. Parts of the code were rewritten while
porting it to GeoTools so, if possible, could you try switching to
that version and see if you still get the same registration error ?

You will need to include the gt-process jar in your project. The
easiest way to use do the conversion is to use the static
RasterToVectorProcess.process method.  Here is the method header:

    /**
     * A static helper method that can be called directy to run the process.
     * <p>
     * The process interface is useful for advertising functionality to
     * dynamic applications, but for 'hands on' coding this method is much more
     * convenient than working via {@linkplain
org.geotools.process.Process#execute }.
     *
     * @param cov the input coverage
     * @param band the index of the band to be vectorized
     * @param bounds bounds of the area (in world coordinates) to
vectorize; if {@code null}
     *            the whole coverage
     * @param outsideValues a collection of one or more values which
represent 'outside' or no data
     * @param progress an optional ProgressListener (may be null)
     *
     * @return a FeatureCollection containing simple polygon features
     *
     */
    public static FeatureCollection<SimpleFeatureType,SimpleFeature> process(
            GridCoverage2D cov,
            int band,
            Envelope2D bounds,
            Collection<Double> outsideValues,
            ProgressListener progress) throws ProcessException {

If you are using maven as your build tool you can simple add
gt-process as a dependency to your project.

You will need to swap over to one of the GeoTools 2.6 releases: the
most recent being 2.6-M3.

Please try it and let me know how it works for you.

Michael

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
Agossa

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
Hello Michael
Thanks for your answer. I am rather talking about the FeatureCollection to Raster conversion using the FeatureRasterizer class. Switching to Geotools 2.6 will give me so much to do. I am using Geotools 2.4.
Agossa.

mbedward wrote:
Hello,

Steve's raster to vector code is now included in the gt-process module
in GeoTools version 2.6. Parts of the code were rewritten while
porting it to GeoTools so, if possible, could you try switching to
that version and see if you still get the same registration error ?

You will need to include the gt-process jar in your project. The
easiest way to use do the conversion is to use the static
RasterToVectorProcess.process method.  Here is the method header:

    /**
     * A static helper method that can be called directy to run the process.
     * <p>
     * The process interface is useful for advertising functionality to
     * dynamic applications, but for 'hands on' coding this method is much more
     * convenient than working via {@linkplain
org.geotools.process.Process#execute }.
     *
     * @param cov the input coverage
     * @param band the index of the band to be vectorized
     * @param bounds bounds of the area (in world coordinates) to
vectorize; if {@code null}
     *            the whole coverage
     * @param outsideValues a collection of one or more values which
represent 'outside' or no data
     * @param progress an optional ProgressListener (may be null)
     *
     * @return a FeatureCollection containing simple polygon features
     *
     */
    public static FeatureCollection<SimpleFeatureType,SimpleFeature> process(
            GridCoverage2D cov,
            int band,
            Envelope2D bounds,
            Collection<Double> outsideValues,
            ProgressListener progress) throws ProcessException {

If you are using maven as your build tool you can simple add
gt-process as a dependency to your project.

You will need to swap over to one of the GeoTools 2.6 releases: the
most recent being 2.6-M3.

Please try it and let me know how it works for you.

Michael

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Geotools-gt2-users mailing list
Geotools-gt2-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users
mbedward

Re: Vector to Raster conversion

Reply Threaded More More options
Print post
Permalink
In reply to this post by mbedward
Yes - sorry about that last post where I referred you to the
RasterToVectorProcess class - my brain was in reverse :-(

The class you want is, of course, VectorToRasterProcess and its static
helper method: process.

Here is an example...

FeatureCollection<SimpleFeatureType, SimpleFeature> features = ...

// name of the feature attribute from which raster cell values will be taken
String valueAttr = ...

// bounds of the output grid coverage in world coords
ReferencedEnvelope bounds = ...

// dimensions of the output grid coverage (cols, rows)
Dimension gridDim = ...

// name of the output grid coverage
String covName = ...

GridCoverage2D cov = VectorToRasterProcess.process(features,
valueAttr, gridDim, bounds, covName, null);

I'm afraid I can only really help you with GeoTools 2.6 - sorry about that.

Michael

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Geotools-gt2-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users