osgEarth 2.1.1
|
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)