osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthFeatures/FeatureTileSource.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 #include <osgEarthFeatures/FeatureTileSource>
00020 #include <osgEarth/Registry>
00021 #include <osgDB/WriteFile>
00022 #include <osg/Notify>
00023 
00024 using namespace osgEarth;
00025 using namespace osgEarth::Features;
00026 using namespace osgEarth::Symbology;
00027 
00028 #define LC "[FeatureTileSource] "
00029 
00030 /*************************************************************************/
00031 
00032 FeatureTileSourceOptions::FeatureTileSourceOptions( const ConfigOptions& options ) :
00033 TileSourceOptions( options ),
00034 _geomTypeOverride( Geometry::TYPE_UNKNOWN )
00035 {
00036     fromConfig( _conf );
00037 }
00038 
00039 Config
00040 FeatureTileSourceOptions::getConfig() const
00041 {
00042     Config conf = TileSourceOptions::getConfig();
00043 
00044     conf.updateObjIfSet( "features", _featureOptions );
00045     conf.updateObjIfSet( "styles", _styles );
00046 
00047     if ( _geomTypeOverride.isSet() ) {
00048         if ( _geomTypeOverride == Geometry::TYPE_LINESTRING )
00049             conf.update( "geometry_type", "line" );
00050         else if ( _geomTypeOverride == Geometry::TYPE_POINTSET )
00051             conf.update( "geometry_type", "point" );
00052         else if ( _geomTypeOverride == Geometry::TYPE_POLYGON )
00053             conf.update( "geometry_type", "polygon" );
00054     }
00055 
00056     return conf;
00057 }
00058 
00059 void
00060 FeatureTileSourceOptions::mergeConfig( const Config& conf )
00061 {
00062     TileSourceOptions::mergeConfig( conf );
00063     fromConfig( conf );
00064 }
00065 
00066 void
00067 FeatureTileSourceOptions::fromConfig( const Config& conf )
00068 {
00069     conf.getObjIfSet( "features", _featureOptions );
00070     //if ( conf.hasChild("features") )
00071     //    _featureOptions->merge( ConfigOptions(conf.child("features")) );
00072 
00073     conf.getObjIfSet( "styles", _styles );
00074     
00075     std::string gt = conf.value( "geometry_type" );
00076     if ( gt == "line" || gt == "lines" || gt == "linestring" )
00077         _geomTypeOverride = Geometry::TYPE_LINESTRING;
00078     else if ( gt == "point" || gt == "pointset" || gt == "points" )
00079         _geomTypeOverride = Geometry::TYPE_POINTSET;
00080     else if ( gt == "polygon" || gt == "polygons" )
00081         _geomTypeOverride = Geometry::TYPE_POLYGON;
00082 }
00083 
00084 /*************************************************************************/
00085 
00086 FeatureTileSource::FeatureTileSource( const TileSourceOptions& options ) :
00087 TileSource( options ),
00088 _options( options.getConfig() ),
00089 _initialized( false )
00090 {
00091     if ( _options.featureSource().valid() )
00092     {
00093         _features = _options.featureSource().get();
00094     }
00095     else if ( _options.featureOptions().isSet() )
00096     {
00097         _features = FeatureSourceFactory::create( _options.featureOptions().value() );
00098         if ( !_features.valid() )
00099         {
00100             OE_WARN << LC << "Failed to create FeatureSource from options" << std::endl;
00101         }
00102     }
00103 }
00104 
00105 void 
00106 FeatureTileSource::initialize( const std::string& referenceURI, const Profile* overrideProfile)
00107 {
00108     if (overrideProfile)
00109     {
00110         //If we were given a profile, take it on.
00111         setProfile(overrideProfile);
00112     }
00113     else
00114     {
00115         //Assume it is global-geodetic
00116         setProfile( osgEarth::Registry::instance()->getGlobalGeodeticProfile() );
00117     }            
00118 
00119     if ( _features.valid() )
00120     {
00121         _features->initialize( referenceURI );
00122 
00123 #if 0 // removed this as it was screwing up the rasterizer (agglite plugin).. not sure there's any reason to do this anyway
00124         if (_features->getFeatureProfile())
00125         {
00126             setProfile( Profile::create(_features->getFeatureProfile()->getSRS(),
00127                                     _features->getFeatureProfile()->getExtent().xMin(), _features->getFeatureProfile()->getExtent().yMin(),
00128                                     _features->getFeatureProfile()->getExtent().xMax(), _features->getFeatureProfile()->getExtent().yMax()));
00129 
00130         }
00131 #endif
00132     }
00133     else
00134     {
00135         OE_WARN << LC << "No FeatureSource provided; nothing will be rendered (" << getName() << ")" << std::endl;
00136     }
00137 
00138     _initialized = true;
00139 }
00140 
00141 void
00142 FeatureTileSource::setFeatureSource( FeatureSource* source )
00143 {
00144     if ( !_initialized )
00145     {
00146         _features = source;
00147     }
00148     else
00149     {
00150         OE_WARN << LC << "Illegal: cannot set FeatureSource after intitialization ( " << getName() << ")" << std::endl;
00151     }
00152 }
00153 
00154 osg::Image*
00155 FeatureTileSource::createImage( const TileKey& key, ProgressCallback* progress )
00156 {
00157     if ( !_features.valid() || !_features->getFeatureProfile() )
00158         return 0L;
00159 
00160     // style data
00161     const StyleSheet* styles = _options.styles();
00162 
00163     // implementation-specific data
00164     osg::ref_ptr<osg::Referenced> buildData = createBuildData();
00165 
00166         // allocate the image.
00167         osg::ref_ptr<osg::Image> image = new osg::Image();
00168         image->allocateImage( getPixelsPerTile(), getPixelsPerTile(), 1, GL_RGBA, GL_UNSIGNED_BYTE );
00169 
00170     preProcess( image.get(), buildData.get() );
00171 
00172     // figure out if and how to style the geometry.
00173     if ( _features->hasEmbeddedStyles() )
00174     {
00175         // Each feature has its own embedded style data, so use that:
00176         osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor( Query() );
00177         while( cursor->hasMore() )
00178         {
00179             Feature* feature = cursor->nextFeature();
00180             if ( feature )
00181             {
00182                 FeatureList list;
00183                 list.push_back( feature );
00184                 renderFeaturesForStyle( 
00185                     *feature->style(), list, buildData.get(),
00186                     key.getExtent(), image.get() );
00187             }
00188         }
00189     }
00190     else if ( styles )
00191     {
00192         if ( styles->selectors().size() > 0 )
00193         {
00194             for( StyleSelectorList::const_iterator i = styles->selectors().begin(); i != styles->selectors().end(); ++i )
00195             {
00196                 const StyleSelector& sel = *i;
00197                 const Style* style = styles->getStyle( sel.getSelectedStyleName() );
00198                 queryAndRenderFeaturesForStyle( *style, sel.query().value(), buildData.get(), key.getExtent(), image.get() );
00199             }
00200         }
00201         else
00202         {
00203             const Style* style = styles->getDefaultStyle();
00204             queryAndRenderFeaturesForStyle( *style, Query(), buildData.get(), key.getExtent(), image.get() );
00205         }
00206     }
00207     else
00208     {
00209         queryAndRenderFeaturesForStyle( Style(), Query(), buildData.get(), key.getExtent(), image.get() );
00210     }
00211 
00212     // final tile processing after all styles are done
00213     postProcess( image.get(), buildData.get() );
00214 
00215         return image.release();
00216 }
00217 
00218 
00219 bool
00220 FeatureTileSource::queryAndRenderFeaturesForStyle(const Style&     style,
00221                                                   const Query&     query,
00222                                                   osg::Referenced* data,
00223                                                   const GeoExtent& imageExtent,
00224                                                   osg::Image*      out_image)
00225 {   
00226     // first we need the overall extent of the layer:
00227     const GeoExtent& featuresExtent = getFeatureSource()->getFeatureProfile()->getExtent();
00228     
00229     // convert them both to WGS84, intersect the extents, and convert back.
00230     GeoExtent featuresExtentWGS84 = featuresExtent.transform( featuresExtent.getSRS()->getGeographicSRS() );
00231     GeoExtent imageExtentWGS84 = imageExtent.transform( featuresExtent.getSRS()->getGeographicSRS() );
00232     GeoExtent queryExtentWGS84 = featuresExtentWGS84.intersectionSameSRS( imageExtentWGS84.bounds() );
00233     if ( queryExtentWGS84.isValid() )
00234     {
00235         GeoExtent queryExtent = queryExtentWGS84.transform( featuresExtent.getSRS() );
00236 
00237             // incorporate the image extent into the feature query for this style:
00238         Query localQuery = query;
00239         localQuery.bounds() = query.bounds().isSet()?
00240                     query.bounds()->unionWith( queryExtent.bounds() ) :
00241                     queryExtent.bounds();
00242 
00243         // query the feature source:
00244         osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor( localQuery );
00245 
00246         // now copy the resulting feature set into a list, converting the data
00247         // types along the way if a geometry override is in place:
00248         FeatureList cellFeatures;
00249         while( cursor->hasMore() )
00250         {
00251             Feature* feature = cursor->nextFeature();
00252             Geometry* geom = feature->getGeometry();
00253             if ( geom )
00254             {
00255                 // apply a type override if requested:
00256                 if (_options.geometryTypeOverride().isSet() &&
00257                     _options.geometryTypeOverride() != geom->getComponentType() )
00258                 {
00259                     geom = geom->cloneAs( _options.geometryTypeOverride().value() );
00260                     if ( geom )
00261                         feature->setGeometry( geom );
00262                 }
00263             }
00264             if ( geom )
00265             {
00266                 cellFeatures.push_back( feature );
00267             }
00268         }
00269 
00270         //OE_NOTICE
00271         //    << "Rendering "
00272         //    << cellFeatures.size()
00273         //    << " features in ("
00274         //    << queryExtent.toString() << ")"
00275         //    << std::endl;
00276 
00277             return renderFeaturesForStyle( style, cellFeatures, data, imageExtent, out_image );
00278     }
00279     else
00280     {
00281         return false;
00282     }
00283 }
00284 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines