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 <michael.bedw...@gmail.com> 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 > Geotools-devel@lists.sourceforge.net > 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 Geotools-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/geotools-devel