Ciao Michael,
I have spent some time meesing up the WritableGridCoverage2D class you
have put together, I am attaching a small patch for trunk.
Here is some sparse thoughts on it:
- Think about how to avoid creation of a large number of {...@link
DirectPosition2D} and {...@link GridCoordinates2D}
- Merge/Borrow from DeferredPlanarImage
- Allow for making previous {...@link GridCoverage2D} writable in a more
explicit way
- Think about closer integration with JAI-Tools DiskMemImage class
I still have problems with JIRA, so I cannot open up a new JIRA ( I
did not find one already created). I would suggest we open a new JIRA
for this enhancement.
Ciao,
Simone.
-------------------------------------------------------
Ing. Simone Giannecchini
GeoSolutions S.A.S.
Founder - Software Engineer
Via Carignoni 5
55041 Camaiore (LU)
Italy
phone: +39 0584983027
fax: +39 0584983027
mob: +39 333 8128928
http://www.geo-solutions.it
http://geo-solutions.blogspot.com/
http://www.linkedin.com/in/simonegiannecchini
http://twitter.com/simogeo
-------------------------------------------------------
On Tue, May 4, 2010 at 8:11 AM, Michael Bedward
<[email protected]> wrote:
> Hi Jody,
>
> I just committed the class and a little demo on trunk into
> demo/example, in the coverage package.
>
> Michael
>
>
>
> On 4 May 2010 16:09, Jody Garnett wrote:
>> Do you have a link to the class? I am curious ...
>>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Geotools-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/geotools-devel
>
>
Index: src/main/java/org/geotools/demo/coverage/WritableGridCoverage2D.java
===================================================================
--- src/main/java/org/geotools/demo/coverage/WritableGridCoverage2D.java
(revision 35430)
+++ src/main/java/org/geotools/demo/coverage/WritableGridCoverage2D.java
(working copy)
@@ -1,55 +1,138 @@
+/*
+ * GeoTools - The Open Source Java GIS Tookit
+ * http://geotools.org
+ *
+ * (C) 2010, Open Source Geospatial Foundation (OSGeo)
+ *
+ * This file is hereby placed into the Public Domain. This means anyone is
+ * free to do whatever they wish with this file. Use it well and enjoy!
+ */
package org.geotools.demo.coverage;
import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-import javax.media.jai.TiledImage;
+import java.util.Set;
+
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;
+
import org.geotools.coverage.grid.GridCoordinates2D;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.ViewType;
import org.geotools.geometry.DirectPosition2D;
+import org.geotools.renderer.i18n.Errors;
+import org.geotools.util.Utilities;
import org.opengis.coverage.CannotEvaluateException;
+import org.opengis.coverage.grid.GridRange;
+import org.opengis.coverage.grid.InvalidRangeException;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.operation.TransformException;
/**
- *
+ * Draft class for a writable {...@link GridCoverage2D} instance.
+ *
+ * TODO Think about how to avoid creation of a large number of {...@link
DirectPosition2D} and {...@link GridCoordinates2D}
+ * TODO Merge/Borrow from DeferredPlanarImage
+ * TODO Allow for making previous {...@link GridCoverage2D} writable in a more
explicit way
+ *
* @author Michael Bedward
+ * @author Simone Giannecchini, GeoSolutions S.A.S.
*/
-/**
- * @author Michael Bedward
- */
+...@suppresswarnings("deprecation")
public class WritableGridCoverage2D extends GridCoverage2D {
- private GridCoverage2D wrapped;
- private static final int MAX_PENDING_VALUES = 10000;
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7894734946444396087L;
+
+ private GridCoverage2D wrapped;
+
+ /** Default maximum number of cached values waiting to be written
down.**/
+ private static final int DEFAULT_MAX_PENDING_VALUES = 10000;
- private static class PendingValue {
- Object pos;
+ /**
+ * Simple placeholder class for pending values.
+ * @author Michael Bedward
+ * @author Simone Giannecchini, GeoSolutions S.A.S.
+ *
+ * @param <P> positions class
+ * @param <V> value class
+ */
+ private static class PendingValue<P,V> {
+ P pos;
boolean isGeographic;
- Object value;
+ V value;
}
- private List<PendingValue> pendingValues = new ArrayList<PendingValue>();
+ /**
+ * Pending value living in raster space.
+ *
+ * @author Simone Giannecchini, GeoSolutions S.A.S.
+ *
+ */
+ private static class RasterPosition extends
PendingValue<GridCoordinates2D,Number> {
+ }
/**
+ * Pending value living in model space.
+ *
+ * @author Simone Giannecchini, GeoSolutions S.A.S.
+ *
+ */
+ private static class ModelPosition extends
PendingValue<DirectPosition,Number> {
+ }
+
+ private final List<PendingValue<?,?>> pendingValues =
Collections.synchronizedList(new ArrayList<PendingValue<?,?>>());
+
+ private int dataType;
+
+ private final int maxPendingValues;
+
+ /**
* Constructor: wraps the given grid
*
- * @param grid the original grid
+ * @param grid the original {...@link GridCoverage2D}
*/
- public WritableGridCoverage2D(GridCoverage2D grid) {
- super(grid.getName().toString(), grid);
+ public WritableGridCoverage2D(final GridCoverage2D grid) {
+ this(grid,DEFAULT_MAX_PENDING_VALUES);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param grid the original {...@link GridCoverage2D}
+ * @param maxPendingValues the maximum number of values to keep cached in
memory prior to writing down.
+ */
+ public WritableGridCoverage2D(final GridCoverage2D grid, final int
maxPendingValues){
+ super(checkIsWritable(grid).getName().toString(), grid);
this.wrapped = grid;
+
+ final WritableRenderedImage writableImage = (WritableRenderedImage)
image;
+ dataType = writableImage.getSampleModel().getDataType();
+ this.maxPendingValues=maxPendingValues;
}
- @Override
+ /**
+ * Check that the input {...@link GridCoverage2D} is back by an underlying
{...@link WritableRenderedImage}.
+ *
+ * @param grid the input {...@link GridCoverage2D}.
+ * @return the input {...@link GridCoverage2D}.
+ */
+ private static GridCoverage2D checkIsWritable(final GridCoverage2D grid) {
+ Utilities.ensureNonNull("Grid", grid);
+ if(!(grid.getRenderedImage() instanceof WritableRenderedImage))
+ throw new
IllegalArgumentException(Errors.format(org.geotools.resources.i18n.ErrorKeys.ILLEGAL_ARGUMENT_$2,"GridCoverage2D","Not
Writable"));
+ return grid;
+ }
+
+ @Override
public Object evaluate(DirectPosition point) throws
CannotEvaluateException {
flushCache(true);
return super.evaluate(point);
@@ -125,6 +208,12 @@
}
@Override
+ public synchronized Set<ViewType> getViewTypes() {
+ flushCache(true);
+ return super.getViewTypes();
+ }
+
+ @Override
public RenderableImage getRenderableImage(int xAxis, int yAxis) {
flushCache(true);
return super.getRenderableImage(xAxis, yAxis);
@@ -142,11 +231,6 @@
}
@Override
- public void prefetch(Rectangle2D area) {
- // not implemented
- }
-
- @Override
public void show(String title, int xAxis, int yAxis) {
flushCache(true);
super.show(title, xAxis, yAxis);
@@ -163,90 +247,197 @@
flushCache(true);
return super.view(type);
}
-
- public void setValue(DirectPosition worldPos, int value) {
+
+ /**
+ * Set a value in model space.
+ * @param <V> the value type
+ * @param worldPos the model space position
+ * @param value the value to set
+ */
+ public<V extends Number> void setValue(DirectPosition worldPos, V value) {
doSetWorldValue(worldPos, value);
}
-
- public void setValue(DirectPosition worldPos, float value) {
- doSetWorldValue(worldPos, value);
- }
-
- public void setValue(DirectPosition worldPos, double value) {
- doSetWorldValue(worldPos, value);
- }
-
- public void setValue(GridCoordinates2D gridPos, int value) {
+
+ /**
+ * Set a value in raster space.
+ * @param <V> the value type
+ * @param worldPos the raster space position
+ * @param value the value to set
+ */
+ public <V extends Number> void setValue(GridCoordinates2D gridPos, V
value) {
doSetGridValue(gridPos, value);
}
- public void setValue(GridCoordinates2D gridPos, float value) {
- doSetGridValue(gridPos, value);
- }
-
- public void setValue(GridCoordinates2D gridPos, double value) {
- doSetGridValue(gridPos, value);
- }
-
private void doSetWorldValue(DirectPosition pos, Number value) {
- PendingValue pv = new PendingValue();
+ final ModelPosition pv = new ModelPosition();
pv.pos = new DirectPosition2D(pos);
pv.isGeographic = true;
pv.value = value;
- pendingValues.add(pv);
- flushCache(false);
+ synchronized (pendingValues) {
+ pendingValues.add(pv);
+ flushCache(false);
+ }
}
private void doSetGridValue(GridCoordinates2D gridPos, Number value) {
- PendingValue pv = new PendingValue();
- pv.pos = new GridCoordinates2D(gridPos);
+ final RasterPosition pv = new RasterPosition();
+ pv.pos = gridPos.clone();
pv.isGeographic = false;
pv.value = value;
- pendingValues.add(pv);
- flushCache(false);
+ synchronized (pendingValues) {
+ pendingValues.add(pv);
+ flushCache(false);
+ }
}
private void flushCache(boolean force) {
- if (pendingValues.size() >= MAX_PENDING_VALUES || (force &&
pendingValues.size() > 0)) {
+ synchronized (pendingValues) {
+ if (pendingValues.size() >= maxPendingValues || (force &&
pendingValues.size() > 0)) {
- WritableRenderedImage writableImage = null;
- if (super.isDataEditable()) {
- writableImage = (WritableRenderedImage) image;
- } else {
- writableImage = new TiledImage(wrapped.getRenderedImage(),
true);
- }
- WritableRandomIter writeIter =
RandomIterFactory.createWritable(writableImage, null);
- int dataType = writableImage.getSampleModel().getDataType();
-
- GridCoordinates2D gridPos = null;
- for (PendingValue pv : pendingValues) {
- if (pv.isGeographic) {
- try {
- gridPos =
wrapped.getGridGeometry().worldToGrid((DirectPosition) pv.pos);
- } catch (TransformException ex) {
- throw new RuntimeException("Could not transform
location [" +
- pv.pos + "] to grid coords");
+ final WritableRenderedImage writableImage =
(WritableRenderedImage) image;
+ final WritableRandomIter writeIter=
RandomIterFactory.createWritable(writableImage, null);
+ GridCoordinates2D gridPos = null;
+ for (final PendingValue<?,?> pv : pendingValues) {
+ if (pv.isGeographic) {
+ try {
+ gridPos =
wrapped.getGridGeometry().worldToGrid((DirectPosition) pv.pos);
+ } catch (TransformException ex) {
+ throw new RuntimeException("Could not transform
location [" +pv.pos + "] to grid coords");
+ }
+ } else {
+ gridPos = (GridCoordinates2D) pv.pos;
}
- } else {
- gridPos = (GridCoordinates2D) pv.pos;
- }
- switch (dataType) {
- case DataBuffer.TYPE_INT:
- writeIter.setSample(gridPos.x, gridPos.y, 0,
(Integer)pv.value);
- break;
- case DataBuffer.TYPE_FLOAT:
- writeIter.setSample(gridPos.x, gridPos.y, 0,
(Float)pv.value);
- break;
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ writeIter.setSample(gridPos.x, gridPos.y, 0,
(Byte)pv.value);
+ break;
+
+ case DataBuffer.TYPE_SHORT:case
DataBuffer.TYPE_USHORT:
+ writeIter.setSample(gridPos.x, gridPos.y, 0,
(Short)pv.value);
+ break;
+ case DataBuffer.TYPE_INT:
+ writeIter.setSample(gridPos.x, gridPos.y, 0,
(Integer)pv.value);
+ break;
- case DataBuffer.TYPE_DOUBLE:
- writeIter.setSample(gridPos.x, gridPos.y, 0,
(Double)pv.value);
- break;
+ case DataBuffer.TYPE_FLOAT:
+ writeIter.setSample(gridPos.x, gridPos.y, 0,
(Float)pv.value);
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ writeIter.setSample(gridPos.x, gridPos.y, 0,
(Double)pv.value);
+ break;
+ }
}
+
+ pendingValues.clear();
+ writeIter.done();
}
+
+ }
+ }
- pendingValues.clear();
- }
- }
+ @Override
+ public synchronized boolean dispose(boolean force) {
+ flushCache(true);
+ pendingValues.clear();
+ return super.dispose(force);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, boolean[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]?1:0);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, byte[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, double[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, float[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, int[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
+
+ @Override
+ public void setDataBlock(GridRange gridRange, short[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
+
+
+
+ @Override
+ public void setPackedDataBlock(GridRange gridRange, byte[] values)
+ throws InvalidRangeException,
+ ArrayIndexOutOfBoundsException {
+ final int minX =gridRange.getLow(0);
+ final int minY =gridRange.getLow(1);
+ final int maxX =gridRange.getSpan(0)+minX;
+ final int maxY =gridRange.getSpan(1)+minY;
+ for(int x=minX;x<maxX;x++)
+ for(int y=minY;y<maxY;y++)
+ setValue(new GridCoordinates2D(x, y),
values[x+y*gridRange.getSpan(0)]);
+ }
}
Index: src/main/java/org/geotools/demo/coverage/WritableGridDemo.java
===================================================================
--- src/main/java/org/geotools/demo/coverage/WritableGridDemo.java
(revision 35430)
+++ src/main/java/org/geotools/demo/coverage/WritableGridDemo.java
(working copy)
@@ -32,7 +32,7 @@
for (int x = 0; x < WIDTH; x++) {
double dx = (x - centre) / centre;
double d = Math.sqrt(dx*dx + dy2);
- GridCoordinates2D coords = new GridCoordinates2D(x, y);
+ final GridCoordinates2D coords = new GridCoordinates2D(x, y);
writableCov.setValue(coords, (float) Math.sin(8 * Math.PI *
d));
}
}
------------------------------------------------------------------------------
_______________________________________________
Geotools-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-devel