//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcwebservices/wpvs/DefaultGetViewHandler.java,v 1.70 2006/12/04 17:06:44 bezema Exp $ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/exse/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstraße 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.ogcwebservices.wpvs; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.Callable; import javax.imageio.ImageIO; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Node; import javax.media.j3d.OrderedGroup; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import org.deegree.framework.concurrent.ExecutionFinishedEvent; import org.deegree.framework.concurrent.Executor; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.StringTools; import org.deegree.framework.util.TimeTools; import org.deegree.model.crs.CRSFactory; import org.deegree.model.crs.CRSTransformationException; import org.deegree.model.crs.CoordinateSystem; import org.deegree.model.crs.GeoTransformer; import org.deegree.model.crs.IGeoTransformer; import org.deegree.model.crs.UnknownCRSException; import org.deegree.model.spatialschema.Envelope; import org.deegree.model.spatialschema.Surface; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.wpvs.capabilities.Dataset; import org.deegree.ogcwebservices.wpvs.capabilities.ElevationModel; import org.deegree.ogcwebservices.wpvs.configuration.AbstractDataSource; import org.deegree.ogcwebservices.wpvs.configuration.WPVSConfiguration; import org.deegree.ogcwebservices.wpvs.configuration.WPVSDeegreeParams; import org.deegree.ogcwebservices.wpvs.j3d.OffScreenWPVSRenderer; import org.deegree.ogcwebservices.wpvs.j3d.ViewPoint; import org.deegree.ogcwebservices.wpvs.j3d.WPVSScene; import org.deegree.ogcwebservices.wpvs.operation.GetView; import org.deegree.ogcwebservices.wpvs.operation.GetViewResponse; import org.deegree.ogcwebservices.wpvs.util.QuadTreeSplitter; import org.deegree.ogcwebservices.wpvs.util.ResolutionStripe; import org.deegree.ogcwebservices.wpvs.util.StripeFactory; import com.sun.j3d.utils.image.TextureLoader; /** * Default handler for WPVS GetView requests. This Class is the central position where the * {@link GetView} request lands the configured Datasources are gathered and the scene is put * together. * * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> * @author last edited by: $Author: bezema $ * * $Revision: 1.70 $, $Date: 2006/12/04 17:06:44 $ * */ public class DefaultGetViewHandler extends GetViewHandler { static private final ILogger LOG = LoggerFactory.getLogger( DefaultGetViewHandler.class ); private WPVSConfiguration config; private URL backgroundImgURL; private WPVSScene theScene; private OffScreenWPVSRenderer renderer; /** * Constructor for DefaultGetViewHandler. * * @param owner * the service creating this handler */ public DefaultGetViewHandler( WPVService owner ) { super( owner ); this.config = owner.getConfiguration(); } /** * This Method handles a clients GetView request by creating the appropriate (configured) * Datasources, the {@link ResolutionStripe}s, the requeststripes (which are actually * axisalligned Resolutionsripes) and finally putting them all together in a java3d scene. The * creation of the Shape3D Objects (by requesting the ResolutionStripe relevant Datasources) is * done in separate Threads for each ResolutionStripe (which is in conflict with the deegree * styleguides) using the {@link Executor} class. * * @see org.deegree.ogcwebservices.wpvs.GetViewHandler#handleRequest(org.deegree.ogcwebservices.wpvs.operation.GetView) */ @Override public GetViewResponse handleRequest( final GetView request ) throws OGCWebServiceException { // request = req; validateImageSize( request ); CoordinateSystem coordSys = request.getCrs(); List<Dataset> validDatasets = getValidRequestDatasets( request ); if ( validDatasets.size() == 0 ) { throw new OGCWebServiceException( StringTools.concat( 200, "The CRS '", coordSys.getAsString(), "' is not supported by any of the requested Datasets '" ) ); } ElevationModel elevationModel = getValidElevationModel( request.getElevationModel() ); if ( request.getFarClippingPlane() > config.getDeegreeParams().getMaximumFarClippingPlane() ) request.setFarClippingPlane( config.getDeegreeParams().getMaximumFarClippingPlane() ); ViewPoint viewPoint = new ViewPoint( request ); viewPoint.setTerrainDistanceToSeaLevel( getTerrainHeightAboveSeaLevel( viewPoint.getObserverPosition() ) ); ArrayList<ResolutionStripe> resolutionStripes = createRequestBoxes( request, viewPoint, config.getSmallestMinimalScaleDenomiator() ); if ( resolutionStripes.size() == 0 ) { throw new OGCWebServiceException( StringTools.concat( 200, "There were no RequestBoxes found, therefor this WPVS-request is invalid" ) ); } Surface visibleArea = viewPoint.getVisibleArea(); findValidDataSourcesFromDatasets( validDatasets, resolutionStripes, request.getOutputFormat(), visibleArea ); findValidEMDataSourceFromElevationModel( elevationModel, resolutionStripes, visibleArea ); // will also check is background is valid, before doing any hard work this.backgroundImgURL = createBackgroundImageURL( request ); Executor exec = Executor.getInstance(); List<ExecutionFinishedEvent<ResolutionStripe>> resultingBoxes = null; try { resultingBoxes = exec.performSynchronously( new ArrayList<Callable<ResolutionStripe>>( resolutionStripes ) ); } catch ( InterruptedException ie ) { throw new OGCWebServiceException( StringTools.concat( 200, "A Threading-Error occurred while placing your request." ) ); } if ( resultingBoxes != null && resultingBoxes.size() > 0 ) { theScene = createScene( request, viewPoint, resolutionStripes ); renderer = new OffScreenWPVSRenderer( theScene, request.getImageDimension().width, request.getImageDimension().height ); BufferedImage output = renderScene(); return new GetViewResponse( output, request.getOutputFormat() ); } return null; } /** * @param elevationModelName * @return an elevationModell or <tt>null</tt> if no name was given * @throws OGCWebServiceException * if no elevationModel is found for the given elevationmodelname */ private ElevationModel getValidElevationModel( String elevationModelName ) throws OGCWebServiceException { ElevationModel resultEMModel = null; if ( elevationModelName != null ) { resultEMModel = config.findElevationModel( elevationModelName );// dataset.getElevationModel(); if ( resultEMModel == null ) { throw new OGCWebServiceException( StringTools.concat( 150, "ElevationModel '", elevationModelName, "' is not known to the WPVS" ) ); } } return resultEMModel; } /** * Finds the datasets which can handle the requested crs's, and check if they are defined inside * the requested bbox * * @param request * the GetView request * @param coordSys * the name of the requested coordsys * @return an ArrayList containing all the datasets which comply with the requested crs. * @throws OGCWebServiceException */ private ArrayList<Dataset> getValidRequestDatasets( GetView request ) throws OGCWebServiceException { ArrayList<Dataset> resultDatasets = new ArrayList<Dataset>(); Envelope bbox = request.getBoundingBox(); List<String> datasets = request.getDatasets(); CoordinateSystem coordSys = request.getCrs(); // If the BoundingBox request not is try { if ( !"EPSG:4326".equalsIgnoreCase( coordSys.getAsString() ) ) { // transform the bounding box of the request to EPSG:4326/WGS 84 IGeoTransformer gt = new GeoTransformer( CRSFactory.create( "EPSG:4326" ) ); bbox = gt.transform( bbox, coordSys ); } } catch ( CRSTransformationException e ) { LOG.logError( e.getMessage(), e ); throw new OGCWebServiceException( e.getMessage() ); } catch ( UnknownCRSException e ) { LOG.logError( e.getMessage(), e ); throw new OGCWebServiceException( e.getMessage() ); } for ( String dset : datasets ) { Dataset configuredDataset = config.findDataset( dset ); if ( configuredDataset != null ) { CoordinateSystem[] dataSetCRS = configuredDataset.getCrs(); for ( CoordinateSystem crs : dataSetCRS ) { if ( crs.equals( coordSys ) ) { // lookslike compatible crs therefor check if bbox intersect if ( configuredDataset.getWgs84BoundingBox().intersects( bbox ) ) { if ( !resultDatasets.contains( configuredDataset ) ) resultDatasets.add( configuredDataset ); } } } } } return resultDatasets; } /** * Finds the valid datasources in the configured (and allready checked) datasets. * * @param datasets * the datasets which are valid for this request */ private void findValidDataSourcesFromDatasets( List<Dataset> datasets, ArrayList<ResolutionStripe> stripes, String outputFormat, Surface visibleArea ) { double resolution = 0; for ( ResolutionStripe stripe : stripes ) { stripe.setOutputFormat( outputFormat ); resolution = stripe.getMaxResolutionAsScaleDenominator(); for ( int i = 0; i < datasets.size(); ++i ) { Dataset dset = datasets.get( i ); AbstractDataSource[] dataSources = dset.getDataSources(); for ( AbstractDataSource ads : dataSources ) { System.out.println( "AbstractDataSource: " + ads ); if ( resolution >= dset.getMinimumScaleDenominator() && resolution < dset.getMaximumScaleDenominator() && resolution >= ads.getMinScaleDenominator() && resolution < ads.getMaxScaleDenominator() && ( ( ads.getValidArea() != null ) ? ads.getValidArea().intersects( visibleArea ) : true ) ) { if ( ads.getServiceType() == AbstractDataSource.LOCAL_WFS || ads.getServiceType() == AbstractDataSource.REMOTE_WFS ) { stripe.addFeatureCollectionDataSource( ads ); } else if ( ads.getServiceType() == AbstractDataSource.LOCAL_WMS || ads.getServiceType() == AbstractDataSource.REMOTE_WMS || ads.getServiceType() == AbstractDataSource.LOCAL_WCS || ads.getServiceType() == AbstractDataSource.REMOTE_WCS ) { stripe.addTextureDataSource( ads ); } } } } } } /** * @param elevationModel * and it's datasources. */ private void findValidEMDataSourceFromElevationModel( ElevationModel elevationModel, ArrayList<ResolutionStripe> stripes, Surface visibleArea ) { if ( elevationModel != null ) { AbstractDataSource[] emDataSources = elevationModel.getDataSources(); Dataset dataset = elevationModel.getParentDataset(); for ( ResolutionStripe stripe : stripes ) { double resolution = stripe.getMaxResolution(); for ( AbstractDataSource ads : emDataSources ) { if ( resolution >= dataset.getMinimumScaleDenominator() && resolution < dataset.getMaximumScaleDenominator() && resolution >= ads.getMinScaleDenominator() && resolution < ads.getMaxScaleDenominator() && ( ( ads.getValidArea() != null ) ? ads.getValidArea().intersects( visibleArea ) : true ) ) { stripe.setElevationModelDataSource( ads ); } } } } } /** * Extracts from the request and the configuration the URL behind teh name of a given BACKGROUND * * @return the URL, under which the background image is found * @throws OGCWebServiceException * if no URL with the name given by 'BACKGROUND' can be found. */ private URL createBackgroundImageURL( GetView request ) throws OGCWebServiceException { String imageName = request.getVendorSpecificParameter( "BACKGROUND" ); URL imgURL = null; if ( imageName != null ) { imgURL = (URL) config.getDeegreeParams().getBackgroundMap().get( imageName ); if ( imgURL == null ) { throw new OGCWebServiceException( StringTools.concat( 100, "Cannot find any image referenced by parameter BACKGROUND=", imageName ) ); } } return imgURL; } /** * Creates a Java3D Node representing the background. * * @param minAltitude * the minimum altitude of the backgroudn plane * @param viewPoint * the viewersposition * @return a new Node containing a geometry representing the background * @throws IOException */ private Node createBackground( ViewPoint viewPoint, GetView request ) throws OGCWebServiceException { Point3d ftPrint = viewPoint.getFootprint()[0]; Background bg = new Background( new Color3f( request.getBackgroundColor() ) ); Point3d origin = new Point3d( ftPrint.x, ftPrint.y, ftPrint.z ); BoundingSphere bounds = new BoundingSphere( origin, ftPrint.x ); bg.setApplicationBounds( bounds ); try { if ( backgroundImgURL != null ) { BufferedImage buffImg = ImageIO.read( backgroundImgURL ); // scale image to fill the whole bakground BufferedImage tmpImg = new BufferedImage( request.getImageDimension().width, request.getImageDimension().height, buffImg.getType() ); Graphics g = tmpImg.getGraphics(); g.drawImage( buffImg, 0, 0, tmpImg.getWidth() - 1, tmpImg.getHeight() - 1, null ); g.dispose(); ImageComponent2D img = new TextureLoader( tmpImg ).getImage(); bg.setImage( img ); } } catch ( IOException e ) { throw new OGCWebServiceException( StringTools.concat( 100, "Could not create backgoudn image: ", e.getMessage() ) ); } return bg; } /** * Creates the request boxes from the parameters available i teh incoming request. * * @param viewPoint * where the viewer is * @return a new array of surfaces representing the area in which data will be collected */ private ArrayList<ResolutionStripe> createRequestBoxes( GetView request, ViewPoint viewPoint, double smallestMinimalScaleDenominator ) { ArrayList<ResolutionStripe> requestStripes = new ArrayList<ResolutionStripe>(); String splittingMode = request.getVendorSpecificParameter( "SPLITTER" ); StripeFactory stripesFactory = new StripeFactory( viewPoint, smallestMinimalScaleDenominator ); int imageWidth = request.getImageDimension().width; if ( "BBOX".equals( splittingMode ) ) { requestStripes = stripesFactory.createBBoxResolutionStripe( viewPoint.getVisibleArea().getEnvelope(), imageWidth, viewPoint.getPointOfInterest().z ); } else { // Calculate the resolution stripes perpendicular to the viewdirection requestStripes = stripesFactory.createResolutionStripes( request.getImageDimension().width, viewPoint.getPointOfInterest().z, null ); QuadTreeSplitter splittree = new QuadTreeSplitter( requestStripes, request.getImageDimension().width, request.getImageDimension().height, config.getDeegreeParams().isRequestQualityPreferred(), null ); requestStripes = splittree.getRequestQuads( null ); } return requestStripes; } /** * Should return the height of the terrain above the sealevel. TODO just returns a constant * value. * * @param eyePositionX * @param eyePositionY * @param eyePositionZ * @return the height above the terrain */ protected double getTerrainHeightAboveSeaLevel( double eyePositionX, double eyePositionY, double eyePositionZ ) { return getTerrainHeightAboveSeaLevel( new Point3d( eyePositionX, eyePositionY, eyePositionZ ) ); } /** * Should return the height of the terrain above the sealevel. TODO just returns a constant * value. * * @param eyePosition * * @return the height above */ protected double getTerrainHeightAboveSeaLevel( @SuppressWarnings("unused") Point3d eyePosition ) { return 0.0; } /** * Creates a WPVS scene * * @param viewPoint * position of the viewer * @return a new scene * @throws OGCWebServiceException * if the background img cannot be read */ private WPVSScene createScene( GetView request, ViewPoint viewPoint, List<ResolutionStripe> stripes ) throws OGCWebServiceException { BranchGroup scene = new BranchGroup(); for ( ResolutionStripe stripe : stripes ) { scene.addChild( stripe.getJava3DRepresentation() ); } Calendar date = TimeTools.createCalendar( request.getVendorSpecificParameters().get( "DATETIME" ) ); return new WPVSScene( scene, viewPoint, date, null, createBackground( viewPoint, request ) ); } /** * Renders the scene and the resulting image. * * @return a new image representing a screen shot of the scene */ public BufferedImage renderScene() { BufferedImage image = renderer.renderScene(); if ( !config.getDeegreeParams().isWatermarked() ) { paintCopyright( image ); } return image; } /** * prints a copyright note at left side of the map bottom. The copyright note will be extracted * from the WMS capabilities/configuration * * @param image * the image onto which to print the copyright message/image */ private void paintCopyright( BufferedImage image ) { Graphics2D g2 = (Graphics2D) image.getGraphics(); WPVSDeegreeParams dp = config.getDeegreeParams(); String copyright = dp.getCopyright(); if ( config.getDeegreeParams().getCopyrightImage() != null ) { g2.drawImage( config.getDeegreeParams().getCopyrightImage(), 0, image.getHeight() - config.getDeegreeParams().getCopyrightImage().getHeight(), null ); } else if ( copyright != null ) { g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); final int fontSize = 14; final int margin = 5; int imgHeight = image.getHeight(); Font f = new Font( "SANSSERIF", Font.PLAIN, fontSize ); g2.setFont( f ); // draw text shadow g2.setColor( Color.black ); g2.drawString( copyright, margin, imgHeight - margin ); // draw text g2.setColor( Color.white ); g2.drawString( copyright, margin - 1, imgHeight - margin - 1 ); } g2.dispose(); } /** * Checks if the image size is compatible with that given in the configuration * * @throws OGCWebServiceException */ private void validateImageSize( GetView request ) throws OGCWebServiceException { int width = request.getImageDimension().width; int maxWidth = config.getDeegreeParams().getMaxViewWidth(); if ( width > maxWidth ) { throw new OGCWebServiceException( StringTools.concat( 100, "Requested view width exceeds allowed maximum width of ", maxWidth, " pixels." ) ); } int height = request.getImageDimension().height; int maxHeight = config.getDeegreeParams().getMaxViewHeight(); if ( height > maxHeight ) { throw new OGCWebServiceException( StringTools.concat( 100, "Requested view height exceeds allowed maximum height of ", maxHeight, " pixels." ) ); } } /** * @return Returns the generated scene for this request... handy for debugging. */ public WPVSScene getTheScene() { return theScene; } } /*************************************************************************************************** * Changes to this class. What the people have been up to: $Log: DefaultGetViewHandler.java,v $ * Changes to this class. What the people have been up to: Revision 1.70 2006/12/04 17:06:44 bezema * Changes to this class. What the people have been up to: enhanced dgm from wcs support * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.69 2006/11/29 16:00:11 bezema * Changes to this class. What the people have been up to: bug fixes and added features * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.68 2006/11/28 16:55:05 bezema * Changes to this class. What the people have been up to: bbox resolution works plus clean up and javadoc * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.67 2006/11/27 16:11:41 bezema * Changes to this class. What the people have been up to: formatting question * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.66 2006/11/27 15:35:11 bezema * Changes to this class. What the people have been up to: Fixed coordinatesystem stuff system * Changes to this class. What the people have been up to: Changes to this class. What the people * have been up to: Revision 1.65 2006/11/27 11:54:02 bezema Changes to this class. What the people * have been up to: Cleaned up and removed a lot of member variables Changes to this class. What the * people have been up to: Changes to this class. What the people have been up to: Revision 1.63 * 2006/11/23 11:46:14 bezema Changes to this class. What the people have been up to: The initial * version of the new wpvs Changes to this class. What the people have been up to: Revision 1.55 * 2006/07/19 10:17:20 taddei bug fix: texture for rasters was being painted wrongly * * Revision 1.54 2006/07/18 15:12:25 taddei changes in DEM (WCS) geometry * * Revision 1.52 2006/07/05 14:08:04 taddei attempt to put budligns at z = 0; buggy for reasons not * understood Changes to this class. What the people have been up to: Revision 1.51 2006/07/05 * 11:21:27 taddei now sets EM to zero plane (if EM == null); j3D background gets its img scaled * Changes to this class. What the people have been up to: Revision 1.50 2006/07/04 09:01:43 taddei * remove println, use img util for transparency Changes to this class. What the people have been up * to: Revision 1.48 2006/06/30 06:34:36 poth *** empty log message *** Changes to this class. What * the people have been up to: Revision 1.47 2006/06/29 19:11:40 poth performance enhancements * Changes to this class. What the people have been up to: Revision 1.46 2006/06/29 19:05:14 poth * bug fix and performance enhancements Changes to this class. What the people have been up to: * Revision 1.45 2006/06/29 16:50:09 poth *** empty log message *** Changes to this class. What the * people have been up to: Revision 1.44 2006/06/27 09:07:35 taddei renaming of vars, change in * GetView response Changes to this class. What the people have been up to: Revision 1.43 2006/06/20 * 10:16:01 taddei clean up and javadoc Changes to this class. What the people have been up to: * Revision 1.42 2006/06/20 07:38:16 taddei check if bbox and crs are valid Changes to this class. * What the people have been up to: Revision 1.41 2006/05/15 09:53:52 taddei set crs of boxes * Changes to this class. What the people have been up to: Revision 1.40 2006/05/12 13:12:07 taddei * renamed splitter to simple; log debug are partially warn Changes to this class. What the people * have been up to: Revision 1.39 2006/05/10 14:58:19 taddei >>>>>>> 1.55 string comparison w equals * ignore case Changes to this class. What the people have been up to: Revision 1.38 2006/05/03 * 20:09:52 poth Changes to this class. What the people have been up to: *** empty log message *** * Changes to this class. What the people have been up to: Revision 1.37 2006/05/01 20:15:26 poth * *** empty log message *** Changes to this class. What the people have been up to: Changes to this * class. What the people have been up to: Revision 1.36 2006/04/26 12:16:19 taddei Changes to this * class. What the people have been up to: style formatting and max sizes Changes to this class. * What the people have been up to: Revision 1.35 2006/04/07 08:48:24 taddei isValidArea is checking * agains vis are, not with req.envelope * * Revision 1.33 2006/04/06 15:07:59 taddei added support for ValidArea * * Revision 1.32 2006/04/05 09:05:55 taddei added code for computing res of different surfs * * Revision 1.30 2006/03/29 15:06:21 taddei with buildings * * Revision 1.29 2006/03/17 13:33:31 taddei dgm/wcs working; triangulation * * Revision 1.28 2006/03/16 11:34:30 taddei handles dem from coverages; small changes to splitters * (overlapping) * * Revision 1.27 2006/03/13 12:55:29 taddei corrected threaded implementation * * Revision 1.26 2006/03/10 15:51:42 taddei removing unsused objs and clear ops in createScene * * Revision 1.25 2006/03/10 10:31:41 taddei changes regarding cood sys and scale calculation * * Revision 1.24 2006/03/09 15:40:45 taddei fixed bug: counting datasets wrongly * * Revision 1.23 2006/03/09 08:58:52 taddei splitted background code into img and J3D BG * * Revision 1.22 2006/03/07 15:17:58 taddei splitter changes * * Revision 1.21 2006/03/07 08:49:20 taddei changes due to pts list factories * * Revision 1.20 2006/03/06 10:38:13 taddei improved image handling, also watermark * * Revision 1.19 2006/03/02 15:26:08 taddei using now StringTools, also some clean up * * Revision 1.18 2006/03/01 13:08:08 taddei commit of splitter as is, clean-up coming (AOK from AP) * * Revision 1.17 2006/02/24 14:56:27 taddei scale par is aok * * Revision 1.16 2006/02/24 11:42:41 taddei refactoring (background) * * Revision 1.15 2006/02/22 17:12:31 taddei implemented correct drawing order * * Revision 1.14 2006/02/21 14:04:44 taddei javadoc, added better positioning for background * * Revision 1.13 2006/02/21 13:02:05 taddei small improvements * * Revision 1.12 2006/02/21 09:29:06 taddei using flag for paiting transparent texture border * * Revision 1.11 2006/02/17 15:40:12 taddei ** empty log message *** * * Revision 1.10 2006/02/14 15:19:17 taddei added possibility to choose splitter * * Revision 1.9 2006/02/10 16:08:39 taddei no comments (nothing, really) * * Revision 1.8 2006/02/09 15:47:24 taddei bug fixes, refactoring and javadoc * * Revision 1.7 2006/01/30 15:00:08 taddei working local wcs invoker; copyright info is being * printed * * Revision 1.6 2006/01/26 14:40:15 taddei WFS and WMS invokers working * * Revision 1.5 2006/01/18 08:58:13 taddei implementation (WFS) * * Revision 1.3 2005/12/23 11:59:45 taddei removed harcoded stuff * * Revision 1.2 2005/12/21 13:49:01 taddei dummy functions for live testing * * Revision 1.1 2005/12/16 15:19:11 taddei added DeafultViewHandler and the Invokers * * **************************************************************************************************/