deegree / deegree3

Official deegree repository providing geospatial core libraries, data access and advanced OGC web service implementations
https://www.deegree.org
GNU Lesser General Public License v2.1
146 stars 99 forks source link

GDALTileStore/GDALTileMatrixSet with geotiff: Tiles are mirror-inverted in y-direction #512

Open lgoltz opened 9 years ago

lgoltz commented 9 years ago

In a WMS with GDALTileStore/GDALTileMatrixSet providing a tiff file, each tile is mirror-inverted in y-direction (tested with deegree-3.4-pre16 as well as the current master). The same file looks fine with a GeoTIFFTileStore/GeoTIFFTileMatrixSet as well as GDALLayer referencing the file directly. After some investigations we found that the calculation of the tile envelop differs in GdalTileDataLevel [1] and GeoTIFFTileDataLevel [2](miny and maxy are inverted). We implemented a workaround [3] to fix this, but it requires a coordinate switch in GdalDataset [3]. Other GDAL configurations (e.g. simple GDALLayer referencing the file) are broken now.

[1] https://github.com/deegree/deegree3/blob/master/deegree-datastores/deegree-tilestores/deegree-tilestore-gdal/src/main/java/org/deegree/tile/persistence/gdal/GdalTileDataLevel.java [2] https://github.com/deegree/deegree3/blob/master/deegree-datastores/deegree-tilestores/deegree-tilestore-geotiff/src/main/java/org/deegree/tile/persistence/geotiff/GeoTIFFTileDataLevel.java [3] https://github.com/lat-lon/deegree3/tree/twistedTiles-1111 [4] https://github.com/deegree/deegree3/blob/master/deegree-core/deegree-core-gdal/src/main/java/org/deegree/commons/gdal/GdalDataset.java

stephanr commented 8 years ago

Today i also reproduced the effect of the horizontally flipped tiles when using the tile renderer directly from a customized store.

In my opinion the problem is only partial bound to the creation of the envelope, because i think the Java2DTileRenderer does a wrong calculation for rendering.

Affected Rows in Java2DRenderer:

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 );
try {
  graphics.drawImage( tile.getAsImage(), minx, miny, maxx - minx, maxy - miny, null );
} catch ( TileIOException e ) {

Helper Code to initialize the worldToScreen Trasnformation:

RenderHelper.getWorldToScreenTransform( worldToScreen, envelope, width, height );

RenderHelper.getWorldToScreenTransform

This coded debugged as example gave me the following:

Envelope:
  min: (4468366.481109,5659641.646923),
  max: (4468655.872915,5659836.042355)

minx      -1    
miny     859    
maxx    1280    
maxy      -1

This resulted to a drawing command:

graphics.drawImage( tile.getAsImage(), -1, 859, 1281, -860, null );
Graphics2D.drawImage(Image img, int x, int y, int width, int height,ImageObserver observer)

So Graphics2D / BufferedImage is using an image coordinate system with 0,0 in the upper left and the drawing is defined in the lower left with height negative, so that the image is flipped.

Fixing the rendering is easy, but as an effect all tile stores have to be checked if they create a clean envelope (LL/UR) for rendering.

p.s. prepareing a pull for the rendering would be quite easy for me, but we do not have any tiles stores examples currently in use.