001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/io/oraclegeoraster/GeoRasterReader.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 and 009 grit GmbH 010 http://www.grit.de 011 012 This library is free software; you can redistribute it and/or modify it under 013 the terms of the GNU Lesser General Public License as published by the Free 014 Software Foundation; either version 2.1 of the License, or (at your option) 015 any later version. 016 This library is distributed in the hope that it will be useful, but WITHOUT 017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 018 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 019 details. 020 You should have received a copy of the GNU Lesser General Public License 021 along with this library; if not, write to the Free Software Foundation, Inc., 022 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 023 024 Contact information: 025 026 lat/lon GmbH 027 Aennchenstr. 19, 53177 Bonn 028 Germany 029 http://lat-lon.de/ 030 031 Department of Geography, University of Bonn 032 Prof. Dr. Klaus Greve 033 Postfach 1147, 53001 Bonn 034 Germany 035 http://www.geographie.uni-bonn.de/deegree/ 036 037 e-mail: info@deegree.org 038 ----------------------------------------------------------------------------*/ 039 package org.deegree.io.oraclegeoraster; 040 041 import java.awt.Graphics2D; 042 import java.awt.Image; 043 import java.awt.image.BufferedImage; 044 import java.awt.image.RenderedImage; 045 import java.io.IOException; 046 import java.lang.reflect.Method; 047 import java.sql.Connection; 048 import java.sql.PreparedStatement; 049 import java.sql.ResultSet; 050 import java.sql.SQLException; 051 import java.sql.Statement; 052 import java.util.Properties; 053 054 import oracle.spatial.georaster.GeoRasterException; 055 import oracle.spatial.georaster.JGeoRaster; 056 import oracle.spatial.georaster.JGeoRasterMeta; 057 import oracle.sql.STRUCT; 058 059 import org.deegree.framework.log.ILogger; 060 import org.deegree.framework.log.LoggerFactory; 061 import org.deegree.framework.util.StringTools; 062 import org.deegree.graphics.transformation.GeoTransform; 063 import org.deegree.graphics.transformation.WorldToScreenTransform; 064 import org.deegree.io.DBConnectionPool; 065 import org.deegree.io.JDBCConnection; 066 import org.deegree.model.spatialschema.Envelope; 067 import org.deegree.ogcwebservices.InvalidParameterValueException; 068 069 /** 070 * @version $Revision: 21672 $ 071 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 072 * @author <a href="mailto:reichhelm@grit.de">Stephan Reichhelm</a> 073 * @author <a href="mailto:lipski@grit.de">Eryk Lipski</a> 074 * @author last edited by: $Author: apoth $ 075 * 076 * Currently only tested on Oracle 10gR2. 077 * 078 * @version 1.0. $Revision: 21672 $, $Date: 2009-12-29 09:44:20 +0100 (Di, 29 Dez 2009) $ 079 * 080 * @since 2.0 081 */ 082 public class GeoRasterReader { 083 084 private static final ILogger LOG = LoggerFactory.getLogger( GeoRasterReader.class ); 085 086 /** 087 * 088 * @param grDesc 089 * @param envelope 090 * requested envelope 091 * @param width 092 * @param height 093 * @return rendered image 094 * @throws SQLException 095 * @throws IOException 096 * @throws GeoRasterException 097 * @throws Exception 098 */ 099 public static RenderedImage exportRaster( GeoRasterDescription grDesc, Envelope envelope, float width, float height ) 100 throws SQLException, IOException, GeoRasterException, Exception { 101 102 DBConnectionPool pool = DBConnectionPool.getInstance(); 103 JDBCConnection jdbc = grDesc.getJdbcConnection(); 104 Connection con = pool.acquireConnection( jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 105 106 RenderedImage ri = exportRaster( con, envelope, grDesc.getRdtTable(), grDesc.getTable(), grDesc.getColumn(), 107 grDesc.getIdentification(), grDesc.getLevel(), width, height ); 108 109 pool.releaseConnection( con, jdbc.getDriver(), jdbc.getURL(), jdbc.getUser(), jdbc.getPassword() ); 110 111 return ri; 112 } 113 114 /** 115 * 116 * @param connection 117 * connection to Oracle database 118 * @param envelope 119 * requested area 120 * @param rasterRDT 121 * name of the RDT-table 122 * @param rasterTable 123 * name of the table containing a geo raster column 124 * @param geoRasterCol 125 * name of the geoRaster column 126 * @param identification 127 * SQL where clause that identifies the raster of interest 128 * @param level 129 * requested resolution level 130 * @param width 131 * @param height 132 * @return rendered image 133 * @throws SQLException 134 * @throws IOException 135 * @throws GeoRasterException 136 * @throws Exception 137 */ 138 public static RenderedImage exportRaster( Connection connection, Envelope envelope, String rasterRDT, 139 String rasterTable, String geoRasterCol, String identification, 140 int level, float width, float height ) 141 throws Exception { 142 RenderedImage img = null; 143 try { 144 145 int rasterID = readRasterID( connection, identification, rasterTable, geoRasterCol ); 146 147 STRUCT struct = readGeoRasterMetadata( connection, rasterRDT, rasterTable, geoRasterCol, rasterID ); 148 149 int major = connection.getMetaData().getDriverMajorVersion(); 150 int minor = connection.getMetaData().getDriverMinorVersion(); 151 152 JGeoRaster jGeoRaster = null; 153 if ( major == 10 && minor == 1 ) { 154 // synthax for Oracle 10g R1 155 Class<?>[] clzz = new Class[] { STRUCT.class }; 156 Method method = JGeoRaster.class.getMethod( "load", clzz ); 157 jGeoRaster = (JGeoRaster) method.invoke( null, new Object[] { struct } ); 158 jGeoRaster = JGeoRaster.load( struct ); 159 } else if ( major == 10 && minor == 2 ) { 160 // synthax for Oracle 10g R2 161 Class<?>[] clzz = new Class[] { STRUCT.class, Connection.class, boolean.class }; 162 Method method = JGeoRaster.class.getMethod( "load", clzz ); 163 Object[] params = new Object[] { struct, connection, false }; 164 jGeoRaster = (JGeoRaster) method.invoke( null, params ); 165 } else { 166 String s = StringTools.concat( 250, "Oracle driver ", major, ".", minor, 167 " currently not supported for using Georaster functionality. (use 10.1 or 10.2)" ); 168 throw new InvalidParameterValueException( s ); 169 } 170 jGeoRaster.setViewerUse( true ); 171 Properties props = jGeoRaster.getProperties(); 172 173 int maxWidth = Integer.parseInt( props.getProperty( "rasterInfo/dimensionSize_column" ) ); 174 int maxHeight = Integer.parseInt( props.getProperty( "rasterInfo/dimensionSize_row" ) ); 175 176 JGeoRasterMeta metaObj = jGeoRaster.getMetadataObject(); 177 178 // retieve meta-information how row/cells are referenced 179 String metaTyp = "CC"; 180 String metaTxt = jGeoRaster.getMetadataString(); 181 if ( metaTxt != null 182 && metaTxt.indexOf( "<modelCoordinateLocation>UPPERLEFT</modelCoordinateLocation>" ) != -1 ) 183 metaTyp = "UL"; 184 185 double xMin = metaObj.getX( 0, 0 ); 186 double xMax = metaObj.getX( maxWidth - 1, maxHeight - 1 ); 187 double sc = Math.pow( 2, level ); 188 double yMin = metaObj.getY( 0, 0 ); 189 double yMax = metaObj.getY( maxWidth - 1, maxHeight - 1 ); 190 191 double xDiffPx = Math.abs( ( metaObj.getX( 1, 1 ) - xMin ) / 2 ); 192 double yDiffPx = Math.abs( ( metaObj.getY( 1, 1 ) - yMin ) / 2 ); 193 194 // LOG.logDebug(StringTools.concat(350, "georaster-extend ", 195 // xMin, " ", yMin, " - ", xMax, " ", yMax, " typ: ", metaTyp )); 196 197 /* 198 * Difference between UL and CC handling 199 * 200 * CC: Extend BBOX from middle-middel-pixel values to outer extend (default) (A -> B) 201 * 202 * B-----* *-----B |\ | | /| | \ | . | / | | A | . | A | | | . | | | | | | *-----* *-----* ... ... *-----* 203 * *-----* | | | | | | . | | | A | . | A | | / | . | \ | |/ | | \| B-----* *-----B 204 * 205 * UL: Extend BBOX from upper-left-pixel values to outer extend (C=A=B; A->B) 206 * 207 * C-----* A->->-B | | | | | | . | | | | . | | | | . | | | | | | *-----* *-----* ... ... A-----* A-----* | | 208 * |\ | v | . | \ | | | . | \ | v | . | \ | | | | \| B-----A *-----B 209 */ 210 if ( "UL".equals( metaTyp ) ) { 211 // koordinatenreferenzierung oben-links 212 yMax -= ( yDiffPx + yDiffPx ); 213 xMax += ( xDiffPx + xDiffPx ); 214 } else { 215 // koordinatenreferenzierung center-center 216 xMin -= xDiffPx; 217 yMin += yDiffPx; 218 xMax += xDiffPx; 219 yMax -= yDiffPx; 220 } 221 222 WorldToScreenTransform wld2ora = new WorldToScreenTransform( xMin, yMin, xMax, yMax, 0, 0, maxWidth - 1, 223 maxHeight - 1 ); 224 225 int xMinCell = (int) Math.round( wld2ora.getDestX( envelope.getMin().getX() ) / sc ); 226 int xMaxCell = (int) Math.round( wld2ora.getDestX( envelope.getMax().getX() ) / sc ); 227 int yMaxCell = (int) Math.round( wld2ora.getDestY( envelope.getMin().getY() ) / sc ); 228 int yMinCell = (int) Math.round( wld2ora.getDestY( envelope.getMax().getY() ) / sc ); 229 230 if ( LOG.isDebug() ) { 231 LOG.logDebug( StringTools.concat( 400, "req-env: ", envelope.getMin().getX(), " ", 232 envelope.getMin().getY(), " - ", envelope.getMax().getX(), " ", 233 envelope.getMax().getY(), " lvl: ", level, " typ: ", metaTyp, 234 " row/cell-env: ", xMinCell, " ", yMinCell, " - ", xMaxCell, " ", 235 yMaxCell, " dx/y: ", xDiffPx, "/", yDiffPx ) ); 236 } 237 238 // TODO: grit: testen und entfernen 239 // if ( xMinCell < 0 ) 240 // xMinCell = 0; 241 // if ( yMinCell < 0 ) 242 // yMinCell = 0; 243 // if ( xMaxCell < 0 ) 244 // xMaxCell = 0; 245 // if ( yMaxCell < 0 ) 246 // yMaxCell = 0; 247 248 img = jGeoRaster.getRasterImage( connection, level, xMinCell, yMinCell, xMaxCell, yMaxCell ); 249 250 /* 251 * rearange returned image in new image with size of request 252 */ 253 if ( img != null ) { 254 /* 255 * 1) calculate result bbox in nativ/georaster-level resulution (m/px from oracle georaster) 2) convert 256 * to outer bbox 3) calculate result resulution (m/px from result) 4) convert from outer bbox to bbox in 257 * result resulution (middle px) 5) calculate position on result-image (px-box) 6) draw (maybe streched) 258 * returned image inside the px-box 259 */ 260 261 // 1a) returned cell values 262 int rcMinX = ( xMinCell < 0 ) ? 0 : xMinCell; 263 int rcMinY = ( yMinCell < 0 ) ? 0 : yMinCell; 264 int rcMaxX = rcMinX + ( img.getWidth() - 1 ); 265 int rcMaxY = rcMinY + ( img.getHeight() - 1 ); 266 267 // 1b) cell values to world 268 double rwMinX = metaObj.getX( (int) ( rcMinX * sc ), (int) ( rcMinY * sc ) ); 269 double rwMinY = metaObj.getY( (int) ( rcMinX * sc ), (int) ( rcMinY * sc ) ); 270 double rwMaxX = metaObj.getX( (int) ( rcMaxX * sc ), (int) ( rcMaxY * sc ) ); 271 double rwMaxY = metaObj.getY( (int) ( rcMaxX * sc ), (int) ( rcMaxY * sc ) ); 272 273 // 2) convert to edges (see UL/CC handling above) 274 if ( "UL".equals( metaTyp ) ) { 275 rwMaxY -= ( yDiffPx + yDiffPx ); 276 rwMaxX += ( xDiffPx + xDiffPx ); 277 } else { 278 rwMinX -= xDiffPx; 279 rwMinY += yDiffPx; 280 rwMaxX += xDiffPx; 281 rwMaxY -= yDiffPx; 282 } 283 284 // 3) calculate result resulution (m/px) 285 double resDiffX = envelope.getWidth() / (double) width / 2.0d; 286 double resDiffY = envelope.getHeight() / (double) height / 2.0d; 287 288 // 4) convert outer bbox to middle of pixel values 289 rwMinX -= resDiffX; 290 rwMinY += resDiffY; 291 rwMaxX += resDiffX; 292 rwMaxY -= resDiffY; 293 294 GeoTransform wld2scr = new WorldToScreenTransform( envelope.getMin().getX(), envelope.getMin().getY(), 295 envelope.getMax().getX(), envelope.getMax().getY(), 296 0, 0, width - 1, height - 1 ); 297 298 // 5) calculate pixel position of returned fragment 299 int scMinX = (int) Math.round( wld2scr.getDestX( rwMinX ) ); 300 int scMinY = (int) Math.round( wld2scr.getDestY( rwMinY ) ); 301 int scMaxX = (int) Math.round( wld2scr.getDestX( rwMaxX ) ); 302 int scMaxY = (int) Math.round( wld2scr.getDestY( rwMaxY ) ); 303 304 int scWidth = ( scMaxX - scMinX ) + 1; 305 int scHeight = ( scMaxY - scMinY ) + 1; 306 307 // 6) draw returned image into result image 308 BufferedImage bimg = new BufferedImage( Math.round( width ), Math.round( height ), 309 BufferedImage.TYPE_INT_ARGB ); 310 Graphics2D bg = bimg.createGraphics(); 311 312 bg.drawImage( (Image) img, scMinX, scMinY, scWidth, scHeight, null ); 313 bg.dispose(); 314 img = bimg; 315 } 316 317 } catch ( SQLException e1 ) { 318 String s = StringTools.concat( 1000, e1.getMessage(), " ", rasterTable, "; ", rasterRDT, "; ", 319 geoRasterCol, "; ", identification, "; level: ", level ); 320 LOG.logError( s, e1 ); 321 322 throw new RuntimeException( s ); 323 } catch ( Exception e ) { 324 LOG.logError( "error reading georaster", e ); 325 throw new RuntimeException( e ); 326 } 327 return img; 328 } 329 330 /** 331 * 332 * @param connection 333 * @param rasterRDT 334 * @param rasterTable 335 * @param geoRasterCol 336 * @param rasterID 337 * @return 338 * @throws SQLException 339 */ 340 private static STRUCT readGeoRasterMetadata( Connection connection, String rasterRDT, String rasterTable, 341 String geoRasterCol, int rasterID ) 342 throws SQLException { 343 PreparedStatement ps = connection.prepareStatement( "select " + geoRasterCol + " from " + rasterTable 344 + " a where a." + geoRasterCol + ".rasterid = " + rasterID 345 + " and a." + geoRasterCol + ".rasterdatatable = '" 346 + rasterRDT.toUpperCase() + "'" ); 347 ResultSet resultset = ps.executeQuery(); 348 if ( !resultset.next() ) { 349 throw new SQLException( "No GeoRaster object exists at rasterid = " + rasterID + ", RDT = " + rasterRDT ); 350 } 351 352 STRUCT struct = (STRUCT) resultset.getObject( geoRasterCol.toUpperCase() ); 353 resultset.close(); 354 return struct; 355 } 356 357 /** 358 * returns the rasterID of the requested GeoRaster 359 * 360 * @param connection 361 * @param identification 362 * @param sql 363 * @return 364 * @throws SQLException 365 * @throws GeoRasterException 366 */ 367 private static int readRasterID( Connection connection, String identification, String rasterTable, 368 String geoRasterCol ) 369 throws SQLException, GeoRasterException { 370 String sql = "SELECT a." + geoRasterCol + ".rasterid FROM " + rasterTable + " a where " + identification; 371 Statement stmt = connection.createStatement(); 372 ResultSet rs = stmt.executeQuery( sql ); 373 if ( !rs.next() ) { 374 throw new GeoRasterException( "Georaster with identification = " + identification + " not found!" ); 375 } 376 int rasterID = rs.getInt( 1 ); 377 stmt.close(); 378 rs.close(); 379 return rasterID; 380 } 381 }