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 }