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 }