Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend tiling api to be able to transform raster images #442

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d66f106
Implemented retrieval of tiles for queries with other crs than the so…
dstenger Oct 17, 2014
3946280
Added tests for TileLayer
dstenger Oct 17, 2014
384cd70
Fixed GeoTIFFTileDataLevel by correcting order of min and max values …
dstenger Oct 20, 2014
efb8b99
Created GeotoolsRasterTransformer with no functionality
dstenger Oct 20, 2014
72b63e1
Extended Java2DTileRenderer to transform image and bounding box to qu…
dstenger Oct 20, 2014
4e38c76
Implemented geotools raster transformer
dstenger Oct 20, 2014
0f8a93f
Adjusted Java2DTileRenderer to use the GeotoolsRasterTransformer
dstenger Oct 20, 2014
3952cf1
Fixed GeoTIFFTileDataLevel to work with transformation
dstenger Oct 20, 2014
208df68
Refactoring of Java2DTileRenderer
dstenger Oct 20, 2014
db2c494
Added nullcheck to Java2DTileRenderer
dstenger Oct 22, 2014
0b55878
Refactoring of epsg code retrieval
dstenger Oct 24, 2014
16cf5de
Fixed bug causing exception if first tile of tile iterator is null
dstenger Oct 24, 2014
1c92d4a
Added tests for Java2DTileRenderer
dstenger Oct 24, 2014
74b2d45
Added mockito to deegree-core-rendering-2d
dstenger Oct 24, 2014
540c06a
Added javadoc
dstenger Oct 27, 2014
b1753f7
Moved dependency version of geotools to parent pom
dstenger Oct 27, 2014
0286437
Updated javadoc of TileRenderer
dstenger Oct 27, 2014
53d9105
Introduced image transformer interface
dstenger Oct 27, 2014
2317d87
Image transformer is now passed by constructor injection to Java2DTil…
dstenger Oct 27, 2014
5be685f
Removed all geotools dependencies
dstenger Oct 27, 2014
f79955d
added test to ensure tranformation is executed and min/max points of …
Oct 29, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.deegree.geometry;

import org.deegree.cs.coordinatesystems.ICRS;
import org.deegree.cs.exceptions.TransformationException;
import org.deegree.cs.exceptions.UnknownCRSException;
import org.deegree.cs.persistence.CRSManager;
import org.deegree.geometry.standard.DefaultEnvelope;
import org.deegree.geometry.standard.primitive.DefaultPoint;
import org.junit.Test;

import static org.junit.Assert.assertTrue;

public class GeometryTransformerTest {

@Test
public void transformEnvelopeKeepsMinAndMaxIn25833To4326 () throws UnknownCRSException, TransformationException {
ICRS targetCrs = CRSManager.lookup("EPSG:4326");
GeometryTransformer transformer = new GeometryTransformer(targetCrs);
Envelope srcEnvelope = createEnvelopeInEpsg25833();
Envelope targetEnvelope = transformer.transform(srcEnvelope);
double minx = targetEnvelope.getMin().get0();
double miny = targetEnvelope.getMin().get1();
double maxx = targetEnvelope.getMax().get0();
double maxy = targetEnvelope.getMax().get1();

assertTrue(targetEnvelope.getCoordinateSystem().equals(targetCrs));
assertTrue(minx < maxx);
assertTrue(miny < maxy);
}

@Test
public void transformEnvelopeKeepsMinAndMaxIn4326To25833 () throws UnknownCRSException, TransformationException {
ICRS targetCrs = CRSManager.lookup("EPSG:25833");
GeometryTransformer transformer = new GeometryTransformer(targetCrs);
Envelope srcEnvelope = createEnvelopeInEpsg4326();
Envelope targetEnvelope = transformer.transform(srcEnvelope);
double minx = targetEnvelope.getMin().get0();
double miny = targetEnvelope.getMin().get1();
double maxx = targetEnvelope.getMax().get0();
double maxy = targetEnvelope.getMax().get1();

assertTrue(targetEnvelope.getCoordinateSystem().equals(targetCrs));
assertTrue(minx < maxx);
assertTrue(miny < maxy);
}

private Envelope createEnvelopeInEpsg25833( ) throws UnknownCRSException {
ICRS crs = CRSManager.lookup("EPSG:25833");
double minx = 372988.94024799997;
double miny = 5723566.818151;
double maxx = 382478.052521;
double maxy = 5734058.460988999;
DefaultPoint minPoint = new DefaultPoint( "minPoint", crs, null, new double[] { miny, minx } );
DefaultPoint maxPoint = new DefaultPoint( "maxPoint", crs, null, new double[] { maxy, maxx } );
return new DefaultEnvelope( "newEnvelope", crs, null, minPoint, maxPoint );
}

private Envelope createEnvelopeInEpsg4326( ) throws UnknownCRSException {
ICRS crs = CRSManager.lookup("EPSG:4326");
double minx = 51.64873620668787;
double miny = 13.164151617571893;
double maxx = 51.74509300270947;
double maxy = 13.297706688558224;
DefaultPoint minPoint = new DefaultPoint( "minPoint", crs, null, new double[] { miny, minx } );
DefaultPoint maxPoint = new DefaultPoint( "maxPoint", crs, null, new double[] { maxy, maxx } );
return new DefaultEnvelope( "newEnvelope", crs, null, minPoint, maxPoint );
}

}
7 changes: 6 additions & 1 deletion deegree-core/deegree-core-rendering-2d/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>deegree-core-rendering-2d</artifactId>
<name>deegree-core-rendering-2d</name>
Expand Down Expand Up @@ -55,6 +56,10 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.deegree.rendering.r2d;

import org.deegree.geometry.Envelope;

import java.awt.image.BufferedImage;

/**
* Interface for image transformers.
*
* @author <a href="mailto:stenger@lat-lon.de">Dirk Stenger</a>
* @author last edited by: $Author: stenger $
*
* @version $Revision: $, $Date: $
*/
public interface ImageTransformer {

/**
* Transforms an image.
*
* @param image
* image to transform, never <code>null</code>
* @param sourceEnvelope
* source envelope of image, never <code>null</code>
* @return transformed image
*/
BufferedImage transform( BufferedImage image, Envelope sourceEnvelope );

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,27 @@ Occam Labs UG (haftungsbeschränkt)
----------------------------------------------------------------------------*/
package org.deegree.rendering.r2d;

import static java.awt.Color.RED;
import static org.slf4j.LoggerFactory.getLogger;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;

import org.deegree.commons.utils.math.MathUtils;
import org.deegree.cs.coordinatesystems.ICRS;
import org.deegree.cs.exceptions.TransformationException;
import org.deegree.cs.exceptions.UnknownCRSException;
import org.deegree.geometry.Envelope;
import org.deegree.geometry.GeometryTransformer;
import org.deegree.tile.Tile;
import org.deegree.tile.TileIOException;
import org.slf4j.Logger;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Iterator;

import static java.awt.Color.RED;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
import static org.slf4j.LoggerFactory.getLogger;

/**
* <code>Java2DTileRenderer</code>
*
Expand All @@ -61,48 +69,193 @@ Occam Labs UG (haftungsbeschränkt)
*
* @version $Revision: 31882 $, $Date: 2011-09-15 02:05:04 +0200 (Thu, 15 Sep 2011) $
*/

public class Java2DTileRenderer implements TileRenderer {

private static final Logger LOG = getLogger( Java2DTileRenderer.class );

private Graphics2D graphics;
private final Graphics2D graphics;

private final int width;

private final int height;

private final Envelope envelope;

private final ImageTransformer imageTransformer;

private AffineTransform worldToScreen = new AffineTransform();

/**
* When transform is called, all tiles are rendered into main graphics.
*
* @param graphics
* main graphics, never <code>null</code>
* @param width
* query width
* @param height
* query height
* @param envelope
* query envelope, never <code>null</code>
* @param imageTransformer
* image transformer to transform image, if source CRS of tiles does not match CRS of query envelope. If
* <code>null</code>, image transformation is not possible.
*/
public Java2DTileRenderer( Graphics2D graphics, int width, int height, Envelope envelope ) {
public Java2DTileRenderer( Graphics2D graphics, int width, int height, Envelope envelope,
ImageTransformer imageTransformer ) {
this.graphics = graphics;
this.width = width;
this.height = height;
this.envelope = envelope;
this.imageTransformer = imageTransformer;
RenderHelper.getWorldToScreenTransform( worldToScreen, envelope, width, height );
}

@Override
public void render( Tile tile ) {
public void render( Iterator<Tile> tiles ) {
BufferedImage image = new BufferedImage( width, height, TYPE_4BYTE_ABGR );
Graphics g = image.getGraphics();
ICRS crsOfTile = renderAllTilesInTileCrs( tiles, g );
renderToMainGraphics( image, crsOfTile );
}

private ICRS renderAllTilesInTileCrs( Iterator<Tile> tiles, Graphics g ) {
ICRS crsOfTile = null;
Tile firstNonNullTile = retrieveFirstNonNullTile( tiles );
if ( firstNonNullTile != null ) {
crsOfTile = firstNonNullTile.getEnvelope().getCoordinateSystem();
AffineTransform worldToScreenTransformInTileCrs = createWorldToScreenTransform( crsOfTile );
renderInTileCrs( firstNonNullTile, g, worldToScreenTransformInTileCrs );
processRestOfTiles( tiles, g, worldToScreenTransformInTileCrs );
}
return crsOfTile;
}

private Tile retrieveFirstNonNullTile( Iterator<Tile> tiles ) {
while ( tiles.hasNext() ) {
Tile tile = tiles.next();
if ( tile != null )
return tile;
}
return null;
}

private void processRestOfTiles( Iterator<Tile> tiles, Graphics g, AffineTransform worldToScreenTransformInTileCrs ) {
while ( tiles.hasNext() ) {
renderInTileCrs( tiles.next(), g, worldToScreenTransformInTileCrs );
}
}

private AffineTransform createWorldToScreenTransform( ICRS sourceCrs ) {
try {
if ( !sourceCrs.equals( envelope.getCoordinateSystem() ) ) {
AffineTransform worldToScreenInTileCrs = new AffineTransform();
Envelope transformedEnvelope = transformQueryEnvelope( sourceCrs );
RenderHelper.getWorldToScreenTransform( worldToScreenInTileCrs, transformedEnvelope, width, height );
return worldToScreenInTileCrs;
}
return worldToScreen;
} catch ( UnknownCRSException e ) {
handleWorldToScreenTransformException( e );
return worldToScreen;
} catch ( TransformationException e ) {
handleWorldToScreenTransformException( e );
return worldToScreen;
}
}

private void renderInTileCrs( Tile tile, Graphics g, AffineTransform worldToScreenInTileCrs ) {
if ( tile == null ) {
LOG.debug( "Not rendering null tile." );
return;
}
BufferedImage image = tile.getAsImage();
drawImage( image, g, worldToScreenInTileCrs, tile.getEnvelope() );
}

private void renderToMainGraphics( BufferedImage image, ICRS sourceCrs ) {
if ( sourceCrs != null && !envelope.getCoordinateSystem().equals( sourceCrs ) ) {
BufferedImage transformedImage = transformImage( image, sourceCrs );
drawImage( transformedImage, graphics, worldToScreen, envelope );
} else {
drawImage( image, graphics, worldToScreen, envelope );
}
}

private BufferedImage transformImage( BufferedImage image, ICRS sourceCrs ) {
try {
checkIfImageTransformationIsPossible();
Envelope sourceEnvelope = transformQueryEnvelope( sourceCrs );
return imageTransformer.transform( image, sourceEnvelope );
} catch ( UnknownCRSException e ) {
handleTransformImageException( e );
return image;
} catch ( TransformationException e ) {
handleTransformImageException( e );
return image;
}
}

private void checkIfImageTransformationIsPossible() {
if ( imageTransformer == null ) {
String msg = "Source tiles do not offer the requested coordinate system and transformation has not been implemented, yet";
LOG.debug( msg );
throw new RasterRenderingException( msg );
}
}

private Envelope transformQueryEnvelope( ICRS targetCrs )
throws UnknownCRSException, TransformationException {
try {
return new GeometryTransformer( targetCrs ).transform( envelope );
} catch ( TransformationException e ) {
LOG.warn( "Could not transform envelope: " + e.getMessage() );
e.printStackTrace();
throw e;
} catch ( UnknownCRSException e ) {
LOG.warn( "Could not transform envelope as CRS is unknown: " + e.getMessage() );
e.printStackTrace();
throw e;
}
}

private void drawImage( BufferedImage image, Graphics g, AffineTransform worldToScreenTransform, Envelope env ) {
int minx, miny, maxx, maxy;
Envelope env = tile.getEnvelope();
Point2D.Double p = (Point2D.Double) worldToScreen.transform( new Point2D.Double( env.getMin().get0(),
env.getMin().get1() ), null );
minx = MathUtils.round( p.x );
miny = MathUtils.round( p.y );
p = (Point2D.Double) worldToScreen.transform( new Point2D.Double( env.getMax().get0(), env.getMax().get1() ),
null );
maxx = MathUtils.round( p.x );
maxy = MathUtils.round( p.y );
Point2D.Double minPoint = (Point2D.Double) worldToScreenTransform.transform( new Point2D.Double(
env.getMin().get0(),
env.getMin().get1() ),
null );
minx = MathUtils.round( minPoint.x );
miny = MathUtils.round( minPoint.y );
Point2D.Double maxPoint = (Point2D.Double) worldToScreenTransform.transform( new Point2D.Double(
env.getMax().get0(),
env.getMax().get1() ),
null );
maxx = MathUtils.round( maxPoint.x );
maxy = MathUtils.round( maxPoint.y );

int minxCorrected = Math.min( minx, maxx );
int minyCorrected = Math.min( miny, maxy );
int maxxCorrected = Math.max( minx, maxx );
int maxyCorrected = Math.max( miny, maxy );

try {
graphics.drawImage( tile.getAsImage(), minx, miny, maxx - minx, maxy - miny, null );
g.drawImage( image, minxCorrected, minyCorrected, maxxCorrected - minxCorrected, maxyCorrected
- minyCorrected, null );
} catch ( TileIOException e ) {
LOG.debug( "Error retrieving tile image: " + e.getMessage() );
graphics.setColor( RED );
graphics.fillRect( minx, miny, maxx - minx, maxy - miny );
LOG.debug( "Error retrieving image: " + e.getMessage() );
g.setColor( RED );
g.fillRect( minx, miny, maxx - minx, maxy - miny );
}
}
}

private void handleWorldToScreenTransformException( Exception e ) {
LOG.warn( "Envelope could not be transformed to source CRS. World-To-Screen-Transformation of query envelope is used! Reason: "
+ e.getMessage() );
}

private void handleTransformImageException( Exception e ) {
LOG.warn( "Envelope could not be transformed to source CRS. Image transformation is canceled! Reason: "
+ e.getMessage() );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Occam Labs UG (haftungsbeschränkt)

import org.deegree.tile.Tile;

import java.util.Iterator;

/**
* <code>TileRenderer</code>
*
Expand All @@ -53,6 +55,12 @@ Occam Labs UG (haftungsbeschränkt)

public interface TileRenderer {

void render( Tile tile );
/**
* Renders all tiles.
*
* @param tiles
* never <code>null</code>
*/
void render( Iterator<Tile> tiles );

}
}
Loading