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