001 //$$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wpvs/configuration/WPVSConfiguration.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 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 037 package org.deegree.ogcwebservices.wpvs.configuration; 038 039 import java.awt.GraphicsConfigTemplate; 040 import java.awt.GraphicsConfiguration; 041 import java.awt.GraphicsDevice; 042 import java.awt.GraphicsEnvironment; 043 import java.awt.image.BufferedImage; 044 import java.io.File; 045 import java.io.IOException; 046 import java.io.StringReader; 047 import java.util.ArrayList; 048 import java.util.Arrays; 049 import java.util.HashMap; 050 import java.util.List; 051 import java.util.Map; 052 import java.util.Set; 053 import java.util.Vector; 054 055 import javax.imageio.ImageIO; 056 import javax.media.j3d.Canvas3D; 057 import javax.media.j3d.GraphicsConfigTemplate3D; 058 import javax.media.j3d.View; 059 import javax.vecmath.Point3d; 060 061 import org.deegree.datatypes.Code; 062 import org.deegree.datatypes.QualifiedName; 063 import org.deegree.framework.log.ILogger; 064 import org.deegree.framework.log.LoggerFactory; 065 import org.deegree.framework.util.CharsetUtils; 066 import org.deegree.framework.util.IDGenerator; 067 import org.deegree.framework.xml.XMLTools; 068 import org.deegree.i18n.Messages; 069 import org.deegree.model.coverage.grid.ImageGridCoverage; 070 import org.deegree.model.crs.CRSTransformationException; 071 import org.deegree.model.crs.CoordinateSystem; 072 import org.deegree.model.crs.GeoTransformer; 073 import org.deegree.model.crs.UnknownCRSException; 074 import org.deegree.model.feature.FeatureCollection; 075 import org.deegree.model.filterencoding.ComplexFilter; 076 import org.deegree.model.filterencoding.FeatureFilter; 077 import org.deegree.model.filterencoding.FeatureId; 078 import org.deegree.model.filterencoding.Filter; 079 import org.deegree.model.spatialschema.Envelope; 080 import org.deegree.model.spatialschema.GMLGeometryAdapter; 081 import org.deegree.model.spatialschema.Position; 082 import org.deegree.ogcbase.PropertyPath; 083 import org.deegree.ogcwebservices.OGCWebServiceException; 084 import org.deegree.ogcwebservices.getcapabilities.Contents; 085 import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata; 086 import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification; 087 import org.deegree.ogcwebservices.getcapabilities.ServiceProvider; 088 import org.deegree.ogcwebservices.wcs.WCSException; 089 import org.deegree.ogcwebservices.wcs.WCService; 090 import org.deegree.ogcwebservices.wcs.getcoverage.DomainSubset; 091 import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage; 092 import org.deegree.ogcwebservices.wcs.getcoverage.Output; 093 import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage; 094 import org.deegree.ogcwebservices.wcs.getcoverage.SpatialSubset; 095 import org.deegree.ogcwebservices.wfs.WFService; 096 import org.deegree.ogcwebservices.wfs.operation.FeatureResult; 097 import org.deegree.ogcwebservices.wfs.operation.GetFeature; 098 import org.deegree.ogcwebservices.wpvs.capabilities.Dataset; 099 import org.deegree.ogcwebservices.wpvs.capabilities.ElevationModel; 100 import org.deegree.ogcwebservices.wpvs.capabilities.WPVSCapabilities; 101 import org.deegree.ogcwebservices.wpvs.j3d.PointsToPointListFactory; 102 import org.deegree.processing.raster.converter.Image2RawData; 103 import org.w3c.dom.Document; 104 105 /** 106 * This class represents a <code>WPVSConfiguration</code> object. 107 * 108 * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> 109 * @author last edited by: $Author: rbezema $ 110 * 111 * $Revision: 20603 $, $Date: 2009-11-05 16:26:23 +0100 (Do, 05 Nov 2009) $ 112 * 113 */ 114 public class WPVSConfiguration extends WPVSCapabilities { 115 116 private static ILogger LOG = LoggerFactory.getLogger( WPVSConfiguration.class ); 117 118 /** 119 * 120 */ 121 private static final long serialVersionUID = 3699085834869705611L; 122 123 private WPVSDeegreeParams deegreeParams; 124 125 private double smallestMinimalScaleDenomiator; 126 127 // set if the configured datasets were searched. 128 private static boolean searchedForElevModel = false; 129 130 // pool for the canvasses 131 private static List<Canvas3D> canvasPool = new ArrayList<Canvas3D>(); 132 133 private static Vector<Canvas3D> inUseCanvases = new Vector<Canvas3D>(); 134 135 // just some strings for getting the gpu-properties 136 private final static String tusm = "textureUnitStateMax"; 137 138 private final static String twm = "textureWidthMax"; 139 140 /** 141 * Is set to the maximum number of texture units accessable to the wpvs. 142 */ 143 public static int availableTextureUnitStates = 1; 144 145 /** 146 * Is set to the maximum size of a texture supported by the canvas3d. 147 */ 148 public static int texture2DMaxSize = 1024; 149 150 /** 151 * The size of a wfs/wms/wcs request if larger as the available texture size it will be the texture size (read from 152 * the gpu). 153 */ 154 public static int MAX_REQUEST_SIZE; 155 156 /** 157 * The elevation model to check for the height above the terrain. 158 */ 159 public static AbstractDataSource largestElevModel = null; 160 161 // holding the z values with heightMap[y][x] 162 private static float[][] heightMap; 163 164 // scale mapping the width of the configured bbox to the width of the heightmap 165 private static double scaleMapWidth; 166 167 // scale mapping the height of the configured bbox to the height of the heightmap 168 private static double scaleMapHeight; 169 170 // actual width of the heightMap == heightmap[0].length 171 private static int mapWidth; 172 173 // actual height of the heightMap == heightmap.length 174 private static int mapHeight; 175 176 // the found minimalHeight for the terrain or the configuredMinTerrainHeight. 177 private static double globalMinimalHeight; 178 179 // the configured bbox of the top dataset. 180 private static Envelope configuredBBox; 181 182 static { 183 canvasPool.add( createOffscreenCanvas3D() ); 184 } 185 186 /** 187 * @param version 188 * the Version of this wpvs 189 * @param updateSequence 190 * optional needed for clients who want to do caching (ogc-spec) 191 * @param serviceIdentification 192 * @param serviceProvider 193 * @param operationsMetadata 194 * @param contents 195 * @param dataset 196 * @param wpvsParams 197 * deegree specific parameters. 198 * @param smallestMinimalScaleDenomiator 199 * of all datasources, it is needed to calculate the smallest resolutionstripe possible. 200 */ 201 public WPVSConfiguration( String version, String updateSequence, ServiceIdentification serviceIdentification, 202 ServiceProvider serviceProvider, OperationsMetadata operationsMetadata, 203 Contents contents, Dataset dataset, WPVSDeegreeParams wpvsParams, 204 double smallestMinimalScaleDenomiator ) { 205 206 super( version, updateSequence, serviceIdentification, serviceProvider, operationsMetadata, contents, dataset ); 207 this.deegreeParams = wpvsParams; 208 // int size = Integer.MAX_VALUE;// deegreeParams.getMaxRequestSize(); 209 int size = deegreeParams.getMaxTextureDimension(); // deegreeParams.getMaxRequestSize(); 210 if ( size == Integer.MAX_VALUE ) { 211 MAX_REQUEST_SIZE = texture2DMaxSize; 212 } else { 213 MAX_REQUEST_SIZE = size; 214 if ( MAX_REQUEST_SIZE > texture2DMaxSize ) { 215 LOG.logWarning( "The specified max request size value (of the deeegree params section) is larger then the possible texture size of your graphics-card, therefore setting it to: " 216 + texture2DMaxSize ); 217 MAX_REQUEST_SIZE = texture2DMaxSize; 218 } 219 } 220 // set the minmalScaleDenominator according to the request-size 221 this.smallestMinimalScaleDenomiator = ( (double) deegreeParams.getMaxViewWidth() ) / MAX_REQUEST_SIZE; 222 LOG.logDebug( "Smallest denomi: " + this.smallestMinimalScaleDenomiator ); 223 if ( Double.isInfinite( smallestMinimalScaleDenomiator ) || smallestMinimalScaleDenomiator < 0 224 || smallestMinimalScaleDenomiator > 1 ) { 225 this.smallestMinimalScaleDenomiator = 1; 226 } 227 228 // create the global height map if it does not exist already 229 if ( !searchedForElevModel && largestElevModel == null ) { 230 synchronized ( canvasPool ) { 231 if ( !searchedForElevModel ) { 232 largestElevModel = findLargestElevModel(); 233 searchedForElevModel = true; 234 if ( largestElevModel != null ) { 235 Dataset topSet = getDataset(); 236 Envelope env = topSet.getWgs84BoundingBox(); 237 CoordinateSystem[] definedCRSs = topSet.getCrs(); 238 CoordinateSystem defaultCRS = null; 239 if ( definedCRSs != null && definedCRSs.length > 0 ) { 240 defaultCRS = definedCRSs[0]; 241 if ( definedCRSs.length > 1 ) { 242 LOG.logInfo( "Using first defined crs: " + defaultCRS 243 + " to convert latlon (wgs84) coordinates to." ); 244 } 245 try { 246 GeoTransformer gt = new GeoTransformer( defaultCRS ); 247 configuredBBox = gt.transform( env, "EPSG:4326" ); 248 } catch ( UnknownCRSException e ) { 249 LOG.logError( e.getMessage(), e ); 250 } catch ( CRSTransformationException e ) { 251 LOG.logError( e.getMessage(), e ); 252 } 253 // check if the admin has configured a minimal dgm resolution, if so the request and 254 // response resolution for the dgm must be set. 255 int requestWidth = MAX_REQUEST_SIZE; 256 int requestHeight = MAX_REQUEST_SIZE; 257 if ( configuredBBox.getWidth() >= configuredBBox.getHeight() ) { 258 requestHeight = (int) Math.floor( ( configuredBBox.getHeight() / configuredBBox.getWidth() ) 259 * MAX_REQUEST_SIZE ); 260 } else { 261 requestWidth = (int) Math.floor( ( configuredBBox.getWidth() / configuredBBox.getHeight() ) 262 * MAX_REQUEST_SIZE ); 263 } 264 LOG.logDebug( "Setting globalHeightmap requestWidth: " + requestWidth ); 265 LOG.logDebug( "Setting globalHeightmap requestHeight: " + requestHeight ); 266 267 // Set the static members for easy global access 268 mapHeight = requestHeight; 269 mapWidth = requestWidth; 270 271 scaleMapWidth = mapWidth / configuredBBox.getWidth(); 272 scaleMapHeight = mapHeight / configuredBBox.getHeight(); 273 274 if ( largestElevModel instanceof LocalWCSDataSource ) { 275 heightMap = invokeWCS( (LocalWCSDataSource) largestElevModel, configuredBBox, 276 requestWidth, requestHeight ); 277 } else if ( largestElevModel instanceof LocalWFSDataSource ) { 278 heightMap = invokeWFS( (LocalWFSDataSource) largestElevModel, configuredBBox, 279 requestWidth, requestHeight ); 280 } 281 282 if ( heightMap.length == 0 ) { 283 LOG.logWarning( "The creation of the global heightmap has failed." ); 284 globalMinimalHeight = getDeegreeParams().getMinimalTerrainHeight(); 285 } else { 286 float max = Float.MIN_VALUE; 287 globalMinimalHeight = Double.MAX_VALUE; 288 for ( int y = 0; y < requestHeight; ++y ) { 289 for ( int x = 0; x < requestWidth; ++x ) { 290 float height = heightMap[y][x]; 291 globalMinimalHeight = Math.min( globalMinimalHeight, height ); 292 max = Math.max( max, height ); 293 } 294 } 295 if ( globalMinimalHeight < getDeegreeParams().getMinimalTerrainHeight() ) { 296 LOG.logDebug( "Setting found globalMinimalHeight: " + globalMinimalHeight 297 + " to configured minmalTerrainHeight of: " 298 + getDeegreeParams().getMinimalTerrainHeight() ); 299 globalMinimalHeight = getDeegreeParams().getMinimalTerrainHeight(); 300 } 301 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 302 BufferedImage img = new BufferedImage( requestWidth, requestHeight, 303 BufferedImage.TYPE_INT_RGB ); 304 LOG.logDebug( "global maximumHeight: " + max ); 305 LOG.logDebug( "global minimalHeight: " + globalMinimalHeight ); 306 307 double scale = ( 1 / ( max - globalMinimalHeight ) ) * 255; 308 for ( int y = 0; y < requestHeight; ++y ) { 309 for ( int x = 0; x < requestWidth; ++x ) { 310 float height = heightMap[y][x]; 311 byte first = (byte) Math.floor( height * scale ); 312 int color = first; 313 color |= ( color << 8 ); 314 color |= ( color << 16 ); 315 316 img.setRGB( x, y, color ); 317 } 318 319 } 320 try { 321 File f = File.createTempFile( "global_heightmap_response", ".png" ); 322 LOG.logDebug( "creating tmpfile for global heightmap with name: " 323 + f.toString() ); 324 f.deleteOnExit(); 325 ImageIO.write( img, "png", f ); 326 } catch ( IOException e ) { 327 LOG.logError( e.getMessage(), e ); 328 } 329 } 330 331 } 332 333 } 334 } 335 } 336 canvasPool.notifyAll(); 337 } 338 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 339 if ( largestElevModel != null ) { 340 LOG.logDebug( "found elev-model: " + largestElevModel ); 341 } 342 } 343 } 344 } 345 346 /** 347 * @param dataSource 348 * @param env 349 * @param requestHeight 350 * @param requestWidth 351 * @return the wfs-feature-points mapped to the heightmap, or an empty map if no features were found. 352 */ 353 private float[][] invokeWFS( LocalWFSDataSource dataSource, Envelope env, int requestWidth, int requestHeight ) { 354 float[][] result = new float[0][0]; 355 WFService service = null; 356 try { 357 service = (WFService) dataSource.getOGCWebService(); 358 } catch ( OGCWebServiceException ogcwe ) { 359 LOG.logError( ogcwe.getMessage() ); 360 // throw new RuntimeException( ogcwe ); 361 } 362 if ( service == null ) { 363 LOG.logError( "No Web Feature Service instance available for creation of the Global height map." ); 364 } else { 365 Object response = null; 366 try { 367 368 // create the GetFeature request. 369 QualifiedName qn = dataSource.getName(); 370 371 StringBuilder sb = new StringBuilder( 5000 ); 372 sb.append( "<?xml version='1.0' encoding='" + CharsetUtils.getSystemCharset() + "'?>" ); 373 sb.append( "<wfs:GetFeature xmlns:wfs='http://www.opengis.net/wfs' " ); 374 sb.append( "xmlns:ogc='http://www.opengis.net/ogc' " ); 375 sb.append( "xmlns:gml='http://www.opengis.net/gml' " ); 376 sb.append( "xmlns:" ).append( qn.getPrefix() ).append( '=' ); 377 sb.append( "'" ).append( qn.getNamespace() ).append( "' " ); 378 379 if ( dataSource.getServiceType() == AbstractDataSource.LOCAL_WFS ) { 380 sb.append( "outputFormat='FEATURECOLLECTION'>" ); 381 } else { 382 sb.append( "outputFormat='text/xml; subtype=gml/3.1.1'>" ); 383 } 384 385 /** 386 * To make things a little clearer compare with this SQL-Statement: SELECT ( !texture )? geoProperty : * 387 * FROM qn.getLocalName() WHERE geoPoperty intersects with resolutionStripe.getSurface() AND 388 * FilterConditions. 389 */ 390 PropertyPath geoProperty = dataSource.getGeometryProperty(); 391 392 // FROM 393 sb.append( "<wfs:Query typeName='" ).append( qn.getPrefix() ).append( ":" ); 394 sb.append( qn.getLocalName() ).append( "'>" ); 395 396 // SELECT 397 StringBuffer sbArea = GMLGeometryAdapter.exportAsEnvelope( env ); 398 399 // WHERE 400 sb.append( "<ogc:Filter>" ); 401 402 // AND 403 Filter filter = dataSource.getFilter(); 404 if ( filter != null ) { 405 if ( filter instanceof ComplexFilter ) { 406 sb.append( "<ogc:And>" ); 407 sb.append( "<ogc:Intersects>" ); 408 sb.append( "<wfs:PropertyName>" ); 409 sb.append( geoProperty.getAsString() ); 410 sb.append( "</wfs:PropertyName>" ); 411 sb.append( sbArea ); 412 sb.append( "</ogc:Intersects>" ); 413 // add filter as defined in the layers datasource description 414 // to the filter expression 415 org.deegree.model.filterencoding.Operation op = ( (ComplexFilter) filter ).getOperation(); 416 sb.append( op.toXML() ).append( "</ogc:And>" ); 417 } else { 418 if ( filter instanceof FeatureFilter ) { 419 ArrayList<FeatureId> featureIds = ( (FeatureFilter) filter ).getFeatureIds(); 420 if ( featureIds.size() != 0 ) 421 sb.append( "<ogc:And>" ); 422 for ( FeatureId fid : featureIds ) { 423 sb.append( fid.toXML() ); 424 } 425 if ( featureIds.size() != 0 ) 426 sb.append( "</ogc:And>" ); 427 } 428 } 429 } else { 430 sb.append( "<ogc:Intersects>" ); 431 sb.append( "<wfs:PropertyName>" ); 432 sb.append( geoProperty.getAsString() ); 433 sb.append( "</wfs:PropertyName>" ); 434 sb.append( sbArea ); 435 sb.append( "</ogc:Intersects>" ); 436 } 437 438 sb.append( "</ogc:Filter></wfs:Query></wfs:GetFeature>" ); 439 440 Document doc = null; 441 try { 442 doc = XMLTools.parse( new StringReader( sb.toString() ) ); 443 } catch ( Exception e ) { 444 LOG.logError( e.getMessage(), e ); 445 // throw new OGCWebServiceException( e.getMessage() ); 446 } 447 if ( doc != null ) { 448 IDGenerator idg = IDGenerator.getInstance(); 449 GetFeature getFeature = GetFeature.create( String.valueOf( idg.generateUniqueID() ), 450 doc.getDocumentElement() ); 451 LOG.logDebug( "WFS request: " + getFeature ); 452 453 // send the request 454 response = service.doService( getFeature ); 455 } 456 } catch ( OGCWebServiceException ogcwse ) { 457 if ( !Thread.currentThread().isInterrupted() ) { 458 LOG.logError( "Exception while performing WFS-GetFeature: ", ogcwse ); 459 } 460 } 461 462 if ( response != null && response instanceof FeatureResult ) { 463 FeatureCollection fc = (FeatureCollection) ( (FeatureResult) response ).getResponse(); 464 if ( fc != null ) { 465 PointsToPointListFactory ptpFac = new PointsToPointListFactory(); 466 List<Point3d> heights = ptpFac.createFromFeatureCollection( fc ); 467 468 // find the min value. 469 float min = Float.MAX_VALUE; 470 for ( Point3d p : heights ) { 471 min = Math.min( min, (float) p.z ); 472 } 473 474 result = new float[requestHeight][requestWidth]; 475 for ( float[] t : result ) { 476 Arrays.fill( t, min ); 477 } 478 479 double scaleX = requestWidth / env.getWidth(); 480 double scaleY = requestHeight / env.getHeight(); 481 for ( Point3d height : heights ) { 482 int x = (int) Math.round( ( height.x - env.getMin().getX() ) * scaleX ); 483 int y = (int) Math.round( requestHeight - ( ( height.y - env.getMin().getY() ) * scaleY ) ); 484 float savedHeight = result[y][x]; 485 if ( Math.abs( savedHeight - min ) > 1E-10 ) { 486 savedHeight += height.z; 487 result[y][x] = savedHeight * 0.5f; 488 } else { 489 result[y][x] = (float) height.z; 490 } 491 } 492 } 493 } else { 494 LOG.logError( "ERROR creating a global heightmap while invoking wfs-datasource : " 495 + dataSource.getName() + " the result was no WFS-response or no FeatureResult instance" ); 496 } 497 } 498 return result; 499 } 500 501 /** 502 * @param pos 503 * the position to get the height value 504 * @return the height value of the given position or the globalMinimalHeight value if the position was outside the 505 * heightmap. 506 */ 507 public static double getHeightForPosition( Point3d pos ) { 508 int posX = (int) Math.floor( ( pos.x - configuredBBox.getMin().getX() ) * scaleMapWidth ); 509 int posY = (int) Math.floor( mapHeight - ( ( pos.y - configuredBBox.getMin().getY() ) * scaleMapHeight ) ); 510 if ( posY < 0 || posY > heightMap.length || posX < 0 || posX > heightMap[0].length ) { 511 LOG.logDebug( "Given position " + pos + " is outside the global height lookup, returning minimal value: " 512 + globalMinimalHeight ); 513 return globalMinimalHeight; 514 } 515 LOG.logDebug( "The looked up value for postion: " + pos + " (mapped to: " + posX + ", " + posY + ") is: " 516 + heightMap[posY][posX] ); 517 return heightMap[posY][posX]; 518 } 519 520 /** 521 * @param dataSource 522 * @param env 523 * @return the heightmap created from the wcs elevation model or an empty array if no such heightmap could be 524 * created. 525 */ 526 private float[][] invokeWCS( LocalWCSDataSource dataSource, Envelope env, int requestWidth, int requestHeight ) { 527 float[][] result = new float[0][0]; 528 WCService service = null; 529 try { 530 service = (WCService) dataSource.getOGCWebService(); 531 } catch ( OGCWebServiceException e1 ) { 532 e1.printStackTrace(); 533 } 534 535 if ( service == null ) { 536 LOG.logError( "No Web Coverage Service instance available for creation of the Global height map." ); 537 } else { 538 539 Object coverageResponse = null; 540 541 try { 542 String crsString = env.getCoordinateSystem().getFormattedString(); 543 Output output = GetCoverage.createOutput( crsString, null, dataSource.getDefaultFormat(), null ); 544 545 // put missing parts in this map: 546 Map<String, String> map = new HashMap<String, String>( 5 ); 547 StringBuffer sb = new StringBuffer( 1000 ); 548 Position p = env.getMin(); 549 sb.append( p.getX() ).append( "," ).append( p.getY() ).append( "," ); 550 p = env.getMax(); 551 sb.append( p.getX() ).append( "," ).append( p.getY() ); 552 map.put( "BBOX", sb.toString() ); 553 554 map.put( "WIDTH", String.valueOf( requestWidth ) ); 555 map.put( "HEIGHT", String.valueOf( requestHeight ) ); 556 557 SpatialSubset sps = GetCoverage.createSpatialSubset( map, crsString ); 558 559 GetCoverage filterCondition = dataSource.getCoverageFilterCondition(); 560 561 Code code = filterCondition.getDomainSubset().getRequestSRS(); 562 DomainSubset domainSubset = new DomainSubset( code, sps, null ); 563 564 IDGenerator idg = IDGenerator.getInstance(); 565 566 GetCoverage getCoverageRequest = new GetCoverage( String.valueOf( idg.generateUniqueID() ), 567 filterCondition.getVersion(), 568 filterCondition.getSourceCoverage(), domainSubset, 569 null, filterCondition.getInterpolationMethod(), 570 output ); 571 LOG.logDebug( "Sending wcs request:" + dataSource.getName() ); 572 coverageResponse = service.doService( getCoverageRequest ); 573 } catch ( WCSException wcse ) { 574 if ( !Thread.currentThread().isInterrupted() ) { 575 LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR", "WCSException", dataSource.getName(), 576 wcse.getMessage() ) ); 577 } 578 } catch ( OGCWebServiceException ogcwse ) { 579 if ( !Thread.currentThread().isInterrupted() ) { 580 LOG.logError( Messages.getMessage( "WPVS_WCS_REQUEST_ERROR", "OGCWebServiceException", 581 dataSource.getName(), ogcwse.getMessage() ) ); 582 } 583 } catch ( Throwable t ) { 584 if ( !Thread.currentThread().isInterrupted() ) { 585 t.printStackTrace(); 586 } 587 } 588 if ( coverageResponse != null && coverageResponse instanceof ResultCoverage ) { 589 590 LOG.logDebug( "\t -> a valid response\n" ); 591 ResultCoverage response = (ResultCoverage) coverageResponse; 592 if ( response.getCoverage() != null && response.getCoverage() instanceof ImageGridCoverage ) { 593 ImageGridCoverage igc = (ImageGridCoverage) response.getCoverage(); 594 BufferedImage image = igc.getAsImage( requestWidth, requestHeight ); 595 // the heightdata is in x and -y coordinates, they must be flipped before using 596 // PlanarImage im2 = JAI.create( "transpose", image, TransposeDescriptor.FLIP_VERTICAL ); 597 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 598 try { 599 File f = File.createTempFile( "global_wcs_dgm_response", ".jpg" ); 600 LOG.logDebug( "creating tmpfile for global wcs elevationmodel response with name: " 601 + f.toString() ); 602 f.deleteOnExit(); 603 ImageIO.write( image, "jpg", f ); 604 } catch ( Exception e ) { 605 LOG.logError( e.getMessage(), e ); 606 } 607 } 608 // BufferedImage heightMap = image.get; 609 Image2RawData i2rd = new Image2RawData( image, 1 ); 610 result = i2rd.parse(); 611 } 612 } else { 613 LOG.logWarning( Messages.getMessage( "WPVS_IVALID_WCS_RESPONSE", dataSource.getName(), 614 "an ImageGridCoverage" ) ); 615 } 616 } 617 return result; 618 } 619 620 /** 621 * @return an elevation datasource with the largest min scale denominator or <code>null</code> if no elevation model 622 * datasource was found. 623 */ 624 private AbstractDataSource findLargestElevModel() { 625 return findLargestElevModel( super.getDataset() ); 626 } 627 628 /** 629 * @param dataset 630 * to look for the elevationmodel datasources. 631 * @return an elevation datasource with the largest min scale denominator or <code>null</code> if no elevation model 632 * datasource was found. 633 */ 634 private AbstractDataSource findLargestElevModel( Dataset dataset ) { 635 Dataset[] children = dataset.getDatasets(); 636 ElevationModel model = dataset.getElevationModel(); 637 AbstractDataSource elevSource = null; 638 if ( model != null ) { 639 AbstractDataSource[] sources = model.getDataSources(); 640 if ( sources != null ) { 641 for ( AbstractDataSource source : sources ) { 642 if ( source != null 643 && ( elevSource == null || source.getMinScaleDenominator() > elevSource.getMinScaleDenominator() ) ) { 644 elevSource = source; 645 } 646 } 647 } 648 } 649 for ( Dataset set : children ) { 650 AbstractDataSource tmpSource = findLargestElevModel( set ); 651 if ( tmpSource != null 652 && ( elevSource == null || tmpSource.getMinScaleDenominator() > elevSource.getMinScaleDenominator() ) ) { 653 elevSource = tmpSource; 654 } 655 } 656 return elevSource; 657 } 658 659 /** 660 * @return an Offscreen canvas3D from a simple pool if it has no view and the renderer is not running. 661 */ 662 public synchronized static Canvas3D getCanvas3D() { 663 LOG.logDebug( "The pool now contains: " + canvasPool.size() + " canvasses" ); 664 LOG.logDebug( "The inuse pool now contains: " + inUseCanvases.size() + " canvasses" ); 665 for ( Canvas3D c : canvasPool ) { 666 if ( !inUseCanvases.contains( c ) ) { 667 if ( c != null ) { 668 View v = c.getView(); 669 LOG.logDebug( "Canvas has view attached: " + v ); 670 if ( v != null ) { 671 LOG.logDebug( "Removing the view from the pooled Canvas3D because it is not in use anymore." ); 672 v.removeAllCanvas3Ds(); 673 } 674 LOG.logDebug( "Using a pooled Canvas3D." ); 675 inUseCanvases.add( c ); 676 return c; 677 } 678 } 679 } 680 LOG.logDebug( "Creating a new Canvas3D, because all canvasses are in use." ); 681 Canvas3D tmp = createOffscreenCanvas3D(); 682 canvasPool.add( tmp ); 683 inUseCanvases.add( tmp ); 684 return tmp; 685 } 686 687 /** 688 * @param canvas 689 * to be released. 690 * @return true if the removal operation was successful, false if the given canvas3D was not in the list of used 691 * canvasses. 692 */ 693 public synchronized static boolean releaseCanvas3D( Canvas3D canvas ) { 694 if ( canvas != null ) { 695 View v = canvas.getView(); 696 if ( v != null ) { 697 LOG.logDebug( "Removing the view from the Canvas3D because it is not used anymore." ); 698 v.removeAllCanvas3Ds(); 699 } 700 if ( inUseCanvases.contains( canvas ) ) { 701 LOG.logDebug( "Removing the given Canvas3D from the list." ); 702 703 return inUseCanvases.remove( canvas ); 704 } 705 LOG.logInfo( "The given canvas3D was not held by the configuration." ); 706 } 707 LOG.logDebug( "The pool now contains: " + canvasPool.size() + " canvasses" ); 708 LOG.logDebug( "The inuse pool now contains: " + inUseCanvases.size() + " canvasses" ); 709 return false; 710 } 711 712 /** 713 * creates and returns a canvas for offscreen rendering 714 * 715 * @return a offscreen Canvas3D on which the the scene will be rendered. 716 */ 717 @SuppressWarnings("unchecked") 718 protected static synchronized Canvas3D createOffscreenCanvas3D() { 719 GraphicsDevice[] gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); 720 GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D(); 721 gc3D.setSceneAntialiasing( GraphicsConfigTemplate.PREFERRED ); 722 gc3D.setDoubleBuffer( GraphicsConfigTemplate.REQUIRED ); 723 724 if ( gd != null && gd.length > 0 ) { 725 GraphicsConfiguration gc = gd[0].getBestConfiguration( gc3D ); 726 if ( gc != null ) { 727 Canvas3D offScreenCanvas3D = new Canvas3D( gc, true ); 728 Map<String, ?> props = offScreenCanvas3D.queryProperties(); 729 if ( props.containsKey( tusm ) ) { 730 Integer tus = (Integer) props.get( tusm ); 731 if ( tus != null ) { 732 availableTextureUnitStates = tus.intValue(); 733 } 734 } 735 736 if ( props.containsKey( twm ) ) { 737 Integer tw = (Integer) props.get( twm ); 738 if ( tw != null ) { 739 texture2DMaxSize = tw.intValue(); 740 } 741 } 742 743 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 744 Set<String> keys = props.keySet(); 745 StringBuilder sb = new StringBuilder( "Canvas3D has following properties:\n" ); 746 for ( String key : keys ) { 747 sb.append( key ).append( " : " ).append( props.get( key ) ).append( "\n" ); 748 } 749 LOG.logDebug( sb.toString() ); 750 } 751 return offScreenCanvas3D; 752 } 753 LOG.logError( "Could not get a GraphicsConfiguration from the graphics environment, cannot create a canvas3d." ); 754 } else { 755 LOG.logError( "Could not get a graphicsdevice to create a canvas3d." ); 756 } 757 return null; 758 } 759 760 /** 761 * @return Returns the deegreeParams. 762 */ 763 public WPVSDeegreeParams getDeegreeParams() { 764 return deegreeParams; 765 } 766 767 /** 768 * @param deegreeParams 769 * The deegreeParams to set. 770 */ 771 public void setDeegreeParams( WPVSDeegreeParams deegreeParams ) { 772 this.deegreeParams = deegreeParams; 773 } 774 775 /** 776 * @return the smallestMinimalScaleDenomiator value. 777 */ 778 public double getSmallestMinimalScaleDenomiator() { 779 return smallestMinimalScaleDenomiator; 780 } 781 }