Hi,
this week I've tried to make some of the processes in gt-process
run in GeoServer, as they presented some decent variety in input
and outputs. I succeded with some of them and found out a few
issues in the processes that the attached patch fixes.
The patch however does not contain only fixes but also some changes
in the parameters.
The problem I've found working on these processes is that they tend
to have a large variety of input and output types, which makes it
harder to deal with them from the p.o.v. of a fully automated
client such as GeoServer is.
In general, to allow a client to describe and handle all the inputs
and output of the processes there has to be some agreement on what
data types are supported and how to handle multiplicity.
For example, the VectorToRaster has a java.awt.Dimension parameter.
I don't believe it's something that should be part of the interface
of a process interested in being used by a automated system, as
it uses a rendering related class, and the same information can
be easily expressed by using two doubles instead (which is the
change I did in the patch).
It would be nice to have a short list of types that it's safe to
use in the in/out of a process that wants to be supported by
an automated client (which could also be uDig, maybe with a generic
GUI builder that uses the information in the input/output map
to build the GUI to configure and run a process).
What I have in mind so far are all the primitive wrappers, dates,
strings, feature collection, grid coverage 2d, and referenced
envelopes. Do you think the short list should contain something else?
Another general question that came to mind was if processes should
operate against feature collections or against feature sources.
The issue with using collections is that it's harder to query them,
in that light, removing the subcollection methods from the
FeatureCollection would make coding efficient processes quite hard.
Think of a process that needs to perform a vector overlay between
two polygon layers, you scan one layer and look for polygons
in the other layer that intersect it, in that case it's important
to be able to rely on query methods.
So moving forward I see two options:
- the processes stop using feature collection and start using
FeatureSource instead
- the processes use collection but we keep the sub-collection
query methods in the collection interface
I was thinking more or less the same about coverages, instead of
using GridCoverage2D we could trade coverage readers.
However for coverages in theory we're playing with a set of
JAI operations that get chained so, always in theory, trading
coverage should be effective and more familiar to the programmer.
Opinions?
Cheers
Andrea
diff --git a/modules/unsupported/process/pom.xml b/modules/unsupported/process/pom.xml
index 6e08994..9a1d432 100644
--- a/modules/unsupported/process/pom.xml
+++ b/modules/unsupported/process/pom.xml
@@ -110,6 +110,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.geotools</groupId>
+ <artifactId>gt-cql</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>javax.media</groupId>
<artifactId>jai_core</artifactId>
<!-- The version number is specified in the parent POM. -->
diff --git a/modules/unsupported/process/src/main/java/org/geotools/process/feature/AbstractFeatureCollectionProcessFactory.java b/modules/unsupported/process/src/main/java/org/geotools/process/feature/AbstractFeatureCollectionProcessFactory.java
index 9525135..6021c07 100644
--- a/modules/unsupported/process/src/main/java/org/geotools/process/feature/AbstractFeatureCollectionProcessFactory.java
+++ b/modules/unsupported/process/src/main/java/org/geotools/process/feature/AbstractFeatureCollectionProcessFactory.java
@@ -17,6 +17,7 @@
package org.geotools.process.feature;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import org.geotools.data.Parameter;
@@ -52,7 +53,7 @@ public abstract class AbstractFeatureCollectionProcessFactory extends SingleProc
* Adds the {...@link #FEATURES} parameter and then delegates to {...@link #addParameters(Map)}.
*/
public final Map<String, Parameter<?>> getParameterInfo() {
- HashMap<String,Parameter<?>> parameterInfo = new HashMap<String, Parameter<?>>();
+ HashMap<String,Parameter<?>> parameterInfo = new LinkedHashMap<String, Parameter<?>>();
parameterInfo.put( FEATURES.key, FEATURES );
addParameters( parameterInfo );
return parameterInfo;
diff --git a/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorFactory.java b/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorFactory.java
index a7e6df1..7cb99b0 100644
--- a/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorFactory.java
+++ b/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorFactory.java
@@ -60,7 +60,8 @@ public class RasterToVectorFactory extends SingleProcessFactory {
/** Index of the band with data to vectorize */
public static final Parameter<Integer> BAND = new Parameter<Integer>(
- "band", Integer.class, Text.text("Band"), Text.text("Index of band to vectorize"));
+ "band", Integer.class, Text.text("Band"), Text.text("Index of band to vectorize"),
+ false, 0, 1, 1, null);
/**
* Bounds (in world coordinates) ot the area to vectorize; if {...@code null}
@@ -68,7 +69,7 @@ public class RasterToVectorFactory extends SingleProcessFactory {
*/
public static final Parameter<Envelope> BOUNDS = new Parameter<Envelope>(
"bounds", Envelope.class, Text.text("Bounds"),
- Text.text("Bounds of the area to vectorize"));
+ Text.text("Bounds of the area to vectorize"), false, 0, 1, null, null);
/**
* The code(s) representing NODATA or outside the regions to be vectorized.
@@ -76,7 +77,7 @@ public class RasterToVectorFactory extends SingleProcessFactory {
public static final Parameter<Collection> OUTSIDE = new Parameter<Collection>(
"nodata", Collection.class, Text.text("Outside values"),
Text.text("Collection of Double values representing NODATA or outside"),
- true, 1, -1, null, null);
+ false, 0, -1, null, null);
/**
* Whether inside edges (those separating regions with non-outside values)
@@ -87,7 +88,7 @@ public class RasterToVectorFactory extends SingleProcessFactory {
public static final Parameter<Boolean> INSIDE_EDGES = new Parameter<Boolean>(
"inside", Boolean.class, Text.text("Inside edges"),
Text.text("Whether to vectorize inside edges (those separating " +
- "regions with non-outside values"));
+ "regions with non-outside values"), false, 0, 1, Boolean.FALSE, null);
private static final Map<String, Parameter<?>> parameterInfo = new TreeMap<String, Parameter<?>>();
diff --git a/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorProcess.java b/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorProcess.java
index dbe8b2b..8e19bda 100644
--- a/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorProcess.java
+++ b/modules/unsupported/process/src/main/java/org/geotools/process/raster/RasterToVectorProcess.java
@@ -22,6 +22,7 @@ import java.awt.geom.Point2D;
import java.awt.image.RenderedImage;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -251,8 +252,11 @@ public class RasterToVectorProcess extends AbstractProcess {
Envelope bounds = (Envelope) input.get(RasterToVectorFactory.BOUNDS.key);
- Collection<Double> outsideValues = (Collection<Double>)input.get(
+ Collection<Double> outsideValues = (Collection<Double>) input.get(
RasterToVectorFactory.OUTSIDE.key);
+ if(outsideValues == null) {
+ outsideValues = Collections.emptyList();
+ }
boolean insideEdges = true;
o = input.get(RasterToVectorFactory.INSIDE_EDGES.key);
diff --git a/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterFactory.java b/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterFactory.java
index 819a6da..e8694be 100644
--- a/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterFactory.java
+++ b/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterFactory.java
@@ -25,9 +25,8 @@
package org.geotools.process.raster;
-import java.awt.Dimension;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import org.geotools.coverage.grid.GridCoverage2D;
@@ -52,11 +51,19 @@ public class VectorToRasterFactory extends AbstractFeatureCollectionProcessFacto
/**
* Output grid dimensions expressed (in cells).
*/
- static final Parameter<Dimension> GRID_DIM = new Parameter<Dimension>(
- "dim",
- Dimension.class,
- Text.text("Dim"),
- Text.text("Dimensions of the output grid in cells"),
+ static final Parameter<Integer> RASTER_WIDTH = new Parameter<Integer>(
+ "rasterWidth",
+ Integer.class,
+ Text.text("Width"),
+ Text.text("Number of cells in a raster row"),
+ true, // this parameter is mandatory
+ 1, 1, null, null);
+
+ static final Parameter<Integer> RASTER_HEIGHT = new Parameter<Integer>(
+ "rasterHeight",
+ Integer.class,
+ Text.text("Height"),
+ Text.text("Number of cells in a raster column"),
true, // this parameter is mandatory
1, 1, null, null);
@@ -70,19 +77,18 @@ public class VectorToRasterFactory extends AbstractFeatureCollectionProcessFacto
Text.text("Title"),
Text.text("An optional title for the output grid"),
false, // this parameter is optional
- 1, 1, null, null);
+ 0, 1, "raster", null);
/**
* The source of values for cells in the output grid coverage.
* This is either the name ({...@code String}) of a numeric feature property
- * or an {...@code org.opengis.filter.expression.Expression} that can be
- * evaluated to a numeric value.
+ * or a CQL expression that can be evaluated to a numeric value.
* <p>
* This parameter is mandatory.
*/
- static final Parameter<Object> ATTRIBUTE = new Parameter<Object>(
+ static final Parameter<String> ATTRIBUTE = new Parameter<String>(
"attribute",
- Object.class,
+ String.class,
Text.text("Attribute"),
Text.text("The feature attribute to use for raster cell values"),
true, // this parameter is mandatory
@@ -99,7 +105,7 @@ public class VectorToRasterFactory extends AbstractFeatureCollectionProcessFacto
Text.text("Bounds"),
Text.text("Bounds of the area to rasterize"),
false, // this parameter is optional
- 1, 1, null, null);
+ 0, 1, null, null);
/**
* The result of the operation is a FeatureCollection.
@@ -110,16 +116,18 @@ public class VectorToRasterFactory extends AbstractFeatureCollectionProcessFacto
"result", GridCoverage2D.class, Text.text("Result"), Text
.text("Rasterized features"));
- static final Map<String,Parameter<?>> resultInfo = new HashMap<String, Parameter<?>>();
+ static final Map<String,Parameter<?>> resultInfo = new LinkedHashMap<String, Parameter<?>>();
static {
- resultInfo.put( ATTRIBUTE.key, ATTRIBUTE );
- resultInfo.put( GRID_DIM.key, GRID_DIM );
resultInfo.put( RESULT.key, RESULT );
}
@Override
protected void addParameters(Map<String, Parameter<?>> parameters) {
parameters.put(BOUNDS.key, BOUNDS);
+ parameters.put( ATTRIBUTE.key, ATTRIBUTE );
+ parameters.put( RASTER_WIDTH.key, RASTER_WIDTH );
+ parameters.put( RASTER_HEIGHT.key, RASTER_HEIGHT );
+ parameters.put( TITLE.key, TITLE);
}
public InternationalString getTitle() {
diff --git a/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterProcess.java b/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterProcess.java
index ef06c31..e42c23a 100644
--- a/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterProcess.java
+++ b/modules/unsupported/process/src/main/java/org/geotools/process/raster/VectorToRasterProcess.java
@@ -30,7 +30,10 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
@@ -47,6 +50,8 @@ import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.filter.text.cql2.CQLException;
+import org.geotools.filter.text.ecql.ECQL;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.process.feature.AbstractFeatureCollectionProcess;
import org.geotools.process.feature.AbstractFeatureCollectionProcessFactory;
@@ -191,13 +196,24 @@ public class VectorToRasterProcess extends AbstractFeatureCollectionProcess {
SimpleFeatureCollection features = (SimpleFeatureCollection)
input.get(AbstractFeatureCollectionProcessFactory.FEATURES.key);
- Object attribute = input.get(VectorToRasterFactory.ATTRIBUTE.key);
+ String attributeStr = (String) input.get(VectorToRasterFactory.ATTRIBUTE.key);
+ Expression attribute = null;
+ try {
+ attribute = ECQL.toExpression(attributeStr);
+ } catch(CQLException e) {
+ throw new VectorToRasterException(e);
+ }
- Dimension gridDim = (Dimension) input.get(VectorToRasterFactory.GRID_DIM.key);
+ int w = (Integer) input.get(VectorToRasterFactory.RASTER_WIDTH.key);
+ int h = (Integer) input.get(VectorToRasterFactory.RASTER_HEIGHT.key);
+ Dimension gridDim = new Dimension(w, h);
ReferencedEnvelope env = (ReferencedEnvelope) input.get(VectorToRasterFactory.BOUNDS.key);
String title = (String) input.get(VectorToRasterFactory.TITLE.key);
+ if(title == null) {
+ title = "raster";
+ }
GridCoverage2D cov = convert(features, attribute, gridDim, env, title, monitor);
@@ -480,7 +496,8 @@ public class VectorToRasterProcess extends AbstractFeatureCollectionProcess {
DataBuffer.TYPE_INT, image.getWidth(), image.getHeight(), 1);
TiledImage destImage = new TiledImage(0, 0, image.getWidth(), image.getHeight(),
- 0, 0, sm, null);
+ 0, 0, sm, new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ false, false, Transparency.OPAQUE, DataBuffer.TYPE_INT));
for (int yt = 0; yt < numYTiles; yt++) {
for (int xt = 0; xt < numXTiles; xt++) {
@@ -509,7 +526,9 @@ public class VectorToRasterProcess extends AbstractFeatureCollectionProcess {
int numYTiles = image.getNumYTiles();
SampleModel sm = RasterFactory.createPixelInterleavedSampleModel(DataBuffer.TYPE_FLOAT, image.getWidth(), image.getHeight(), 1);
- TiledImage destImage = new TiledImage(0, 0, image.getWidth(), image.getHeight(), 0, 0, sm, null);
+ TiledImage destImage = new TiledImage(0, 0, image.getWidth(), image.getHeight(), 0, 0, sm,
+ new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ false, false, Transparency.OPAQUE, DataBuffer.TYPE_FLOAT));
for (int yt = 0; yt < numYTiles; yt++) {
for (int xt = 0; xt < numXTiles; xt++) {
------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
lucky parental unit. See the prize list and enter to win:
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Geotools-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-devel