001 //$$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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 }