001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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: 20437 $ 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: 20437 $, $Date: 2009-10-29 09:49:03 +0100 (Do, 29. Okt 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 level 092 * requested level (resolution) 093 * @return 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 * connnection 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 georaster col 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 * @return 131 * @throws SQLException 132 * @throws IOException 133 * @throws GeoRasterException 134 * @throws Exception 135 */ 136 public static RenderedImage exportRaster( Connection connection, Envelope envelope, String rasterRDT, 137 String rasterTable, String geoRasterCol, String identification, 138 int level, float width, float height ) 139 throws Exception { 140 RenderedImage img = null; 141 try { 142 143 int rasterID = readRasterID( connection, identification, rasterTable, geoRasterCol ); 144 145 STRUCT struct = readGeoRasterMetadata( connection, rasterRDT, rasterTable, geoRasterCol, rasterID ); 146 147 int major = connection.getMetaData().getDriverMajorVersion(); 148 int minor = connection.getMetaData().getDriverMinorVersion(); 149 150 JGeoRaster jGeoRaster = null; 151 if ( major == 10 && minor == 1 ) { 152 // synthax for Oracle 10g R1 153 Class<?>[] clzz = new Class[] { STRUCT.class }; 154 Method method = JGeoRaster.class.getMethod( "load", clzz ); 155 jGeoRaster = (JGeoRaster) method.invoke( null, new Object[] { struct } ); 156 jGeoRaster = JGeoRaster.load( struct ); 157 } else if ( major == 10 && minor == 2 ) { 158 // synthax for Oracle 10g R2 159 Class<?>[] clzz = new Class[] { STRUCT.class, Connection.class, boolean.class }; 160 Method method = JGeoRaster.class.getMethod( "load", clzz ); 161 Object[] params = new Object[] { struct, connection, false }; 162 jGeoRaster = (JGeoRaster) method.invoke( null, params ); 163 } else { 164 String s = StringTools.concat( 250, "Oracle driver ", major, ".", minor, 165 " currently not supported for using Georaster functionality. (use 10.1 or 10.2)" ); 166 throw new InvalidParameterValueException( s ); 167 } 168 jGeoRaster.setViewerUse( true ); 169 Properties props = jGeoRaster.getProperties(); 170 171 int maxWidth = Integer.parseInt( props.getProperty( "rasterInfo/dimensionSize_column" ) ); 172 int maxHeight = Integer.parseInt( props.getProperty( "rasterInfo/dimensionSize_row" ) ); 173 174 JGeoRasterMeta metaObj = jGeoRaster.getMetadataObject(); 175 176 // retieve meta-information how row/cells are referenced 177 String metaTyp = "CC"; 178 String metaTxt = jGeoRaster.getMetadataString(); 179 if ( metaTxt != null 180 && metaTxt.indexOf( "<modelCoordinateLocation>UPPERLEFT</modelCoordinateLocation>" ) != -1 ) 181 metaTyp = "UL"; 182 183 double xMin = metaObj.getX( 0, 0 ); 184 double xMax = metaObj.getX( maxWidth - 1, maxHeight - 1 ); 185 double sc = Math.pow( 2, level ); 186 double yMin = metaObj.getY( 0, 0 ); 187 double yMax = metaObj.getY( maxWidth - 1, maxHeight - 1 ); 188 189 double xDiffPx = Math.abs( ( metaObj.getX( 1, 1 ) - xMin ) / 2 ); 190 double yDiffPx = Math.abs( ( metaObj.getY( 1, 1 ) - yMin ) / 2 ); 191 192 // LOG.logDebug(StringTools.concat(350, "georaster-extend ", 193 // xMin, " ", yMin, " - ", xMax, " ", yMax, " typ: ", metaTyp )); 194 195 /* 196 * Difference between UL and CC handling 197 * 198 * CC: Extend BBOX from middle-middel-pixel values to outer extend (default) (A -> B) 199 * 200 * B-----* *-----B |\ | | /| | \ | . | / | | A | . | A | | | . | | | | | | *-----* *-----* ... ... *-----* 201 * *-----* | | | | | | . | | | A | . | A | | / | . | \ | |/ | | \| B-----* *-----B 202 * 203 * UL: Extend BBOX from upper-left-pixel values to outer extend (C=A=B; A->B) 204 * 205 * C-----* A->->-B | | | | | | . | | | | . | | | | . | | | | | | *-----* *-----* ... ... A-----* A-----* | | 206 * |\ | v | . | \ | | | . | \ | v | . | \ | | | | \| B-----A *-----B 207 */ 208 if ( "UL".equals( metaTyp ) ) { 209 // koordinatenreferenzierung oben-links 210 yMax -= ( yDiffPx + yDiffPx ); 211 xMax += ( xDiffPx + xDiffPx ); 212 } else { 213 // koordinatenreferenzierung center-center 214 xMin -= xDiffPx; 215 yMin += yDiffPx; 216 xMax += xDiffPx; 217 yMax -= yDiffPx; 218 } 219 220 WorldToScreenTransform wld2ora = new WorldToScreenTransform( xMin, yMin, xMax, yMax, 0, 0, maxWidth - 1, 221 maxHeight - 1 ); 222 223 int xMinCell = (int) Math.round( wld2ora.getDestX( envelope.getMin().getX() ) / sc ); 224 int xMaxCell = (int) Math.round( wld2ora.getDestX( envelope.getMax().getX() ) / sc ); 225 int yMaxCell = (int) Math.round( wld2ora.getDestY( envelope.getMin().getY() ) / sc ); 226 int yMinCell = (int) Math.round( wld2ora.getDestY( envelope.getMax().getY() ) / sc ); 227 228 if ( LOG.isDebug() ) { 229 LOG.logDebug( StringTools.concat( 400, "req-env: ", envelope.getMin().getX(), " ", 230 envelope.getMin().getY(), " - ", envelope.getMax().getX(), " ", 231 envelope.getMax().getY(), " lvl: ", level, " typ: ", metaTyp, 232 " row/cell-env: ", xMinCell, " ", yMinCell, " - ", xMaxCell, " ", 233 yMaxCell, " dx/y: ", xDiffPx, "/", yDiffPx ) ); 234 } 235 236 // TODO: grit: testen und entfernen 237 // if ( xMinCell < 0 ) 238 // xMinCell = 0; 239 // if ( yMinCell < 0 ) 240 // yMinCell = 0; 241 // if ( xMaxCell < 0 ) 242 // xMaxCell = 0; 243 // if ( yMaxCell < 0 ) 244 // yMaxCell = 0; 245 246 img = jGeoRaster.getRasterImage( connection, level, xMinCell, yMinCell, xMaxCell, yMaxCell ); 247 248 /* 249 * rearange returned image in new image with size of request 250 */ 251 if ( img != null ) { 252 /* 253 * 1) calculate result bbox in nativ/georaster-level resulution (m/px from oracle georaster) 2) convert 254 * to outer bbox 3) calculate result resulution (m/px from result) 4) convert from outer bbox to bbox in 255 * result resulution (middle px) 5) calculate position on result-image (px-box) 6) draw (maybe streched) 256 * returned image inside the px-box 257 */ 258 259 // 1a) returned cell values 260 int rcMinX = ( xMinCell < 0 ) ? 0 : xMinCell; 261 int rcMinY = ( yMinCell < 0 ) ? 0 : yMinCell; 262 int rcMaxX = rcMinX + ( img.getWidth() - 1 ); 263 int rcMaxY = rcMinY + ( img.getHeight() - 1 ); 264 265 // 1b) cell values to world 266 double rwMinX = metaObj.getX( (int) ( rcMinX * sc ), (int) ( rcMinY * sc ) ); 267 double rwMinY = metaObj.getY( (int) ( rcMinX * sc ), (int) ( rcMinY * sc ) ); 268 double rwMaxX = metaObj.getX( (int) ( rcMaxX * sc ), (int) ( rcMaxY * sc ) ); 269 double rwMaxY = metaObj.getY( (int) ( rcMaxX * sc ), (int) ( rcMaxY * sc ) ); 270 271 // 2) convert to edges (see UL/CC handling above) 272 if ( "UL".equals( metaTyp ) ) { 273 rwMaxY -= ( yDiffPx + yDiffPx ); 274 rwMaxX += ( xDiffPx + xDiffPx ); 275 } else { 276 rwMinX -= xDiffPx; 277 rwMinY += yDiffPx; 278 rwMaxX += xDiffPx; 279 rwMaxY -= yDiffPx; 280 } 281 282 // 3) calculate result resulution (m/px) 283 double resDiffX = envelope.getWidth() / (double) width / 2.0d; 284 double resDiffY = envelope.getHeight() / (double) height / 2.0d; 285 286 // 4) convert outer bbox to middle of pixel values 287 rwMinX -= resDiffX; 288 rwMinY += resDiffY; 289 rwMaxX += resDiffX; 290 rwMaxY -= resDiffY; 291 292 GeoTransform wld2scr = new WorldToScreenTransform( envelope.getMin().getX(), envelope.getMin().getY(), 293 envelope.getMax().getX(), envelope.getMax().getY(), 294 0, 0, width - 1, height - 1 ); 295 296 // 5) calculate pixel position of returned fragment 297 int scMinX = (int) Math.round( wld2scr.getDestX( rwMinX ) ); 298 int scMinY = (int) Math.round( wld2scr.getDestY( rwMinY ) ); 299 int scMaxX = (int) Math.round( wld2scr.getDestX( rwMaxX ) ); 300 int scMaxY = (int) Math.round( wld2scr.getDestY( rwMaxY ) ); 301 302 int scWidth = ( scMaxX - scMinX ) + 1; 303 int scHeight = ( scMaxY - scMinY ) + 1; 304 305 // 6) draw returned image into result image 306 BufferedImage bimg = new BufferedImage( Math.round( width ), Math.round( height ), 307 BufferedImage.TYPE_INT_ARGB ); 308 Graphics2D bg = bimg.createGraphics(); 309 310 bg.drawImage( (Image) img, scMinX, scMinY, scWidth, scHeight, null ); 311 bg.dispose(); 312 img = bimg; 313 } 314 315 } catch ( SQLException e1 ) { 316 String s = StringTools.concat( 1000, e1.getMessage(), " ", rasterTable, "; ", rasterRDT, "; ", 317 geoRasterCol, "; ", identification, "; level: ", level ); 318 LOG.logError( s, e1 ); 319 320 throw new RuntimeException( s ); 321 } catch ( Exception e ) { 322 LOG.logError( "error reading georaster", e ); 323 throw new RuntimeException( e ); 324 } 325 return img; 326 } 327 328 /** 329 * 330 * @param connection 331 * @param rasterRDT 332 * @param rasterTable 333 * @param geoRasterCol 334 * @param rasterID 335 * @return 336 * @throws SQLException 337 */ 338 private static STRUCT readGeoRasterMetadata( Connection connection, String rasterRDT, String rasterTable, 339 String geoRasterCol, int rasterID ) 340 throws SQLException { 341 PreparedStatement ps = connection.prepareStatement( "select " + geoRasterCol + " from " + rasterTable 342 + " a where a." + geoRasterCol + ".rasterid = " + rasterID 343 + " and a." + geoRasterCol + ".rasterdatatable = '" 344 + rasterRDT.toUpperCase() + "'" ); 345 ResultSet resultset = ps.executeQuery(); 346 if ( !resultset.next() ) { 347 throw new SQLException( "No GeoRaster object exists at rasterid = " + rasterID + ", RDT = " + rasterRDT ); 348 } 349 350 STRUCT struct = (STRUCT) resultset.getObject( geoRasterCol.toUpperCase() ); 351 resultset.close(); 352 return struct; 353 } 354 355 /** 356 * returns the rasterID of the requested GeoRaster 357 * 358 * @param connection 359 * @param identification 360 * @param sql 361 * @return 362 * @throws SQLException 363 * @throws GeoRasterException 364 */ 365 private static int readRasterID( Connection connection, String identification, String rasterTable, 366 String geoRasterCol ) 367 throws SQLException, GeoRasterException { 368 String sql = "SELECT a." + geoRasterCol + ".rasterid FROM " + rasterTable + " a where " + identification; 369 Statement stmt = connection.createStatement(); 370 ResultSet rs = stmt.executeQuery( sql ); 371 if ( !rs.next() ) { 372 throw new GeoRasterException( "Georaster with identification = " + identification + " not found!" ); 373 } 374 int rasterID = rs.getInt( 1 ); 375 stmt.close(); 376 rs.close(); 377 return rasterID; 378 } 379 }