osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/agglite/AGGLiteRasterizerTileSource.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00020 #include <osgEarthFeatures/FeatureTileSource>
00021 #include <osgEarthFeatures/ResampleFilter>
00022 #include <osgEarthFeatures/TransformFilter>
00023 #include <osgEarthFeatures/BufferFilter>
00024 #include <osgEarthSymbology/Style>
00025 //TODO: replace this with ImageRasterizer
00026 #include <osgEarthSymbology/AGG.h>
00027 #include <osgEarth/Registry>
00028 #include <osgEarth/FileUtils>
00029 
00030 #include <osg/Notify>
00031 #include <osgDB/FileNameUtils>
00032 #include <osgDB/FileUtils>
00033 #include <osgDB/Registry>
00034 #include <osgDB/ReadFile>
00035 #include <osgDB/WriteFile>
00036 
00037 #include "AGGLiteOptions"
00038 //#include "agg.h"
00039 
00040 #include <sstream>
00041 #include <OpenThreads/Mutex>
00042 #include <OpenThreads/ScopedLock>
00043 
00044 #define LC "[AGGLite] "
00045 
00046 using namespace osgEarth;
00047 using namespace osgEarth::Features;
00048 using namespace osgEarth::Symbology;
00049 using namespace osgEarth::Drivers;
00050 using namespace OpenThreads;
00051 
00052 /********************************************************************/
00053 
00054 class AGGLiteRasterizerTileSource : public FeatureTileSource
00055 {
00056 public:
00057     AGGLiteRasterizerTileSource( const TileSourceOptions& options ) : FeatureTileSource( options ),
00058         _options( options )
00059     {
00060         //nop
00061     }
00062 
00063     struct BuildData : public osg::Referenced {
00064         BuildData() : _pass(0) { }
00065         int _pass;
00066     };
00067 
00068     //override
00069     osg::Referenced* createBuildData()
00070     {
00071         return new BuildData();
00072     }
00073 
00074     //override
00075     bool preProcess(osg::Image* image, osg::Referenced* buildData)
00076     {
00077         agg::rendering_buffer rbuf( image->data(), image->s(), image->t(), image->s()*4 );
00078         agg::renderer<agg::span_abgr32> ren(rbuf);
00079         ren.clear(agg::rgba8(0,0,0,0));
00080         //ren.clear(agg::rgba8(255,255,255,0));
00081         return true;
00082     }
00083 
00084     //override
00085     bool renderFeaturesForStyle(
00086         const Style&       style,
00087         const FeatureList& inFeatures,
00088         osg::Referenced*   buildData,
00089         const GeoExtent&   imageExtent,
00090         osg::Image*        image )
00091     {
00092         // local copy of the features that we can process
00093         FeatureList features = inFeatures;
00094 
00095         BuildData* bd = static_cast<BuildData*>( buildData );
00096 
00097         // A processing context to use with the filters:
00098         FilterContext context;
00099         context.profile() = getFeatureSource()->getFeatureProfile();
00100 
00101         const LineSymbol* masterLine = style.getSymbol<LineSymbol>();
00102         const PolygonSymbol* masterPoly = style.getSymbol<PolygonSymbol>();
00103 
00104         //bool embeddedStyles = getFeatureSource()->hasEmbeddedStyles();
00105 
00106         // if only a line symbol exists, and there are polygons in the mix, draw them
00107         // as outlines (line rings).
00108         //OE_INFO << LC << "Line Symbol = " << (masterLine == 0L ? "null" : masterLine->getConfig().toString()) << std::endl;
00109         //OE_INFO << LC << "Poly SYmbol = " << (masterPoly == 0L ? "null" : masterPoly->getConfig().toString()) << std::endl;
00110 
00111         //bool convertPolysToRings = poly == 0L && line != 0L;
00112         //if ( convertPolysToRings )
00113         //    OE_INFO << LC << "No PolygonSymbol; will draw polygons to rings" << std::endl;
00114 
00115         // initialize:
00116         double xmin = imageExtent.xMin();
00117         double ymin = imageExtent.yMin();
00118         //double s = (double)image->s();
00119         //double t = (double)image->t();
00120         double xf = (double)image->s() / imageExtent.width();
00121         double yf = (double)image->t() / imageExtent.height();
00122 
00123         // strictly speaking we should iterate over the features and buffer each one that's a line,
00124         // rather then checking for the existence of a LineSymbol.
00125         FeatureList linesToBuffer;
00126         for(FeatureList::iterator i = features.begin(); i != features.end(); i++)
00127         {
00128             Feature* feature = i->get();
00129             Geometry* geom = feature->getGeometry();
00130 
00131             if ( geom )
00132             {
00133                 // check for an embedded style:
00134                 const LineSymbol* line = feature->style().isSet() ? 
00135                     feature->style()->getSymbol<LineSymbol>() : masterLine;
00136 
00137                 const PolygonSymbol* poly =
00138                     feature->style().isSet() ? feature->style()->getSymbol<PolygonSymbol>() : masterPoly;
00139 
00140                 // if we have polygons but only a LineSymbol, draw the poly as a line.
00141                 if ( geom->getComponentType() == Geometry::TYPE_POLYGON )
00142                 {
00143                     if ( !poly && line )
00144                     {
00145                         Feature* outline = new Feature( *feature );
00146                         geom = geom->cloneAs( Geometry::TYPE_RING );
00147                         outline->setGeometry( geom );
00148                         *i = outline;
00149                         feature = outline;
00150                     }
00151                     //TODO: fix to enable outlined polys. doesn't work, not sure why -gw
00152                     //else if ( poly && line )
00153                     //{
00154                     //    Feature* outline = new Feature();
00155                     //    geom = geom->cloneAs( Geometry::TYPE_LINESTRING );
00156                     //    outline->setGeometry( geom );
00157                     //    features.push_back( outline );
00158                     //}
00159                 }
00160 
00161                 bool needsBuffering =
00162                     geom->getComponentType() == Geometry::TYPE_LINESTRING || 
00163                     geom->getComponentType() == Geometry::TYPE_RING;
00164 
00165                 if ( needsBuffering )
00166                 {
00167                     linesToBuffer.push_back( feature );
00168                 }
00169             }
00170         }
00171 
00172         if ( linesToBuffer.size() > 0 )
00173         {
00174             //We are buffering in the features native extent, so we need to use the transform extent to get the proper "resolution" for the image
00175             GeoExtent transformedExtent = imageExtent.transform(context.profile()->getSRS());
00176 
00177             double trans_xf = (double)image->s() / transformedExtent.width();
00178             double trans_yf = (double)image->t() / transformedExtent.height();
00179 
00180             // resolution of the image (pixel extents):
00181             double xres = 1.0/trans_xf;
00182             double yres = 1.0/trans_yf;
00183 
00184             // downsample the line data so that it is no higher resolution than to image to which
00185             // we intend to rasterize it. If you don't do this, you run the risk of the buffer 
00186             // operation taking forever on very high-res input data.
00187             if ( _options.optimizeLineSampling() == true )
00188             {
00189                 ResampleFilter resample;
00190                 resample.minLength() = osg::minimum( xres, yres );
00191                 context = resample.push( linesToBuffer, context );
00192             }
00193 
00194             // now run the buffer operation on all lines:
00195             BufferFilter buffer;
00196             float lineWidth = 0.5;
00197             if ( masterLine )
00198             {
00199                 buffer.capStyle() = masterLine->stroke()->lineCap().value();
00200 
00201                 if ( masterLine->stroke()->width().isSet() )
00202                     lineWidth = masterLine->stroke()->width().value();
00203             }
00204 
00205             // "relative line size" means that the line width is expressed in (approx) pixels
00206             // rather than in map units
00207             if ( _options.relativeLineSize() == true )
00208                 buffer.distance() = xres * lineWidth;
00209             else
00210                 buffer.distance() = lineWidth;
00211 
00212             buffer.push( linesToBuffer, context );
00213         }
00214 
00215         // First, transform the features into the map's SRS:
00216         TransformFilter xform( imageExtent.getSRS() );
00217         xform.setLocalizeCoordinates( false );
00218         context = xform.push( features, context );
00219 
00220         // set up the AGG renderer:
00221         agg::rendering_buffer rbuf( image->data(), image->s(), image->t(), image->s()*4 );
00222 
00223         // Create the renderer and the rasterizer
00224         agg::renderer<agg::span_abgr32> ren(rbuf);
00225         agg::rasterizer ras;
00226 
00227         // Setup the rasterizer
00228         ras.gamma(1.3);
00229         ras.filling_rule(agg::fill_even_odd);
00230 
00231         GeoExtent cropExtent = GeoExtent(imageExtent);
00232         cropExtent.scale(1.1, 1.1);
00233 
00234         osg::ref_ptr<Symbology::Polygon> cropPoly = new Symbology::Polygon( 4 );
00235         cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMin(), 0 ));
00236         cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMin(), 0 ));
00237         cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMax(), 0 ));
00238         cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMax(), 0 ));
00239 
00240         double lineWidth = 1.0;
00241         if ( masterLine )
00242             lineWidth = (double)masterLine->stroke()->width().value();
00243 
00244         osg::Vec4 color = osg::Vec4(1, 1, 1, 1);
00245         if ( masterLine )
00246             color = masterLine->stroke()->color();
00247 
00248         // render the features
00249         for(FeatureList::iterator i = features.begin(); i != features.end(); i++)
00250         {
00251             Feature* feature = i->get();
00252             //bool first = bd->_pass == 0 && i == features.begin();
00253 
00254             Geometry* geometry = feature->getGeometry();
00255 
00256             osg::ref_ptr< Geometry > croppedGeometry;
00257             if ( ! geometry->crop( cropPoly.get(), croppedGeometry ) )
00258                 continue;
00259 
00260             // set up a default color:
00261             osg::Vec4 c = color;
00262             unsigned int a = (unsigned int)(127+(c.a()*255)/2); // scale alpha up
00263             agg::rgba8 fgColor( (unsigned int)(c.r()*255), (unsigned int)(c.g()*255), (unsigned int)(c.b()*255), a );
00264 
00265             GeometryIterator gi( croppedGeometry.get() );
00266             while( gi.hasMore() )
00267             {
00268                 c = color;
00269                 Geometry* g = gi.next();
00270             
00271                 const LineSymbol* line = feature->style().isSet() ? 
00272                     feature->style()->getSymbol<LineSymbol>() : masterLine;
00273 
00274                 const PolygonSymbol* poly =
00275                     feature->style().isSet() ? feature->style()->getSymbol<PolygonSymbol>() : masterPoly;
00276 
00277                 if (g->getType() == Geometry::TYPE_RING || g->getType() == Geometry::TYPE_LINESTRING)
00278                 {
00279                     if ( line )
00280                         c = line->stroke()->color();
00281                     else if ( poly )
00282                         c = poly->fill()->color();
00283                 }
00284 
00285                 else if ( g->getType() == Geometry::TYPE_POLYGON )
00286                 {
00287                     if ( poly )
00288                         c = poly->fill()->color();
00289                     else if ( line )
00290                         c = line->stroke()->color();
00291                 }
00292 
00293                 a = 127+(c.a()*255)/2; // scale alpha up
00294                 fgColor = agg::rgba8( (unsigned int)(c.r()*255), (unsigned int)(c.g()*255), (unsigned int)(c.b()*255), a );
00295 
00296                 ras.filling_rule( agg::fill_even_odd );
00297                 for( Geometry::iterator p = g->begin(); p != g->end(); p++ )
00298                 {
00299                     const osg::Vec3d& p0 = *p;
00300                     double x0 = xf*(p0.x()-xmin);
00301                     double y0 = yf*(p0.y()-ymin);
00302 
00303                     //const osg::Vec3d& p1 = p+1 != g->end()? *(p+1) : g->front();
00304                     //double x1 = xf*(p1.x()-xmin);
00305                     //double y1 = yf*(p1.y()-ymin);
00306 
00307                     if ( p == g->begin() )
00308                         ras.move_to_d( x0, y0 );
00309                     else
00310                         ras.line_to_d( x0, y0 );
00311                 }
00312             }
00313             ras.render(ren, fgColor);
00314             ras.reset();
00315         }
00316 
00317         bd->_pass++;
00318         return true;            
00319     }
00320 
00321     //override
00322     bool postProcess( osg::Image* image, osg::Referenced* data )
00323     {
00324                 //convert from ABGR to RGBA
00325                 unsigned char* pixel = image->data();
00326                 for(int i=0; i<image->s()*image->t()*4; i+=4, pixel+=4)
00327                 {
00328                         std::swap( pixel[0], pixel[3] );
00329                         std::swap( pixel[1], pixel[2] );
00330                 }
00331         return true;
00332     }
00333 
00334     virtual std::string getExtension()  const 
00335     {
00336         return "png";
00337     }
00338 
00339 private:
00340     const AGGLiteOptions _options;
00341     std::string _configPath;
00342 };
00343 
00344 // Reads tiles from a TileCache disk cache.
00345 class AGGLiteRasterizerTileSourceDriver : public TileSourceDriver
00346 {
00347     public:
00348         AGGLiteRasterizerTileSourceDriver() {}
00349 
00350         virtual const char* className()
00351         {
00352             return "AGG-Lite feature rasterizer";
00353         }
00354         
00355         virtual bool acceptsExtension(const std::string& extension) const
00356         {
00357             return osgDB::equalCaseInsensitive( extension, "osgearth_agglite" );
00358         }
00359 
00360         virtual ReadResult readObject(const std::string& file_name, const Options* options) const
00361         {
00362             std::string ext = osgDB::getFileExtension( file_name );
00363             if ( !acceptsExtension( ext ) )
00364             {
00365                 return ReadResult::FILE_NOT_HANDLED;
00366             }
00367 
00368             return new AGGLiteRasterizerTileSource( getTileSourceOptions(options) );
00369         }
00370 };
00371 
00372 REGISTER_OSGPLUGIN(osgearth_agglite, AGGLiteRasterizerTileSourceDriver)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines