osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthFeatures/GeometryCompiler.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 "GeometryCompiler"
00020 #include <osgEarthFeatures/BuildGeometryFilter>
00021 #include <osgEarthFeatures/BuildTextFilter>
00022 #include <osgEarthFeatures/AltitudeFilter>
00023 #include <osgEarthFeatures/CentroidFilter>
00024 #include <osgEarthFeatures/ExtrudeGeometryFilter>
00025 #include <osgEarthFeatures/ScatterFilter>
00026 #include <osgEarthFeatures/SubstituteModelFilter>
00027 #include <osgEarthFeatures/TransformFilter>
00028 #include <osg/MatrixTransform>
00029 #include <osg/Timer>
00030 #include <osgDB/WriteFile>
00031 
00032 #define LC "[GeometryCompiler] "
00033 
00034 using namespace osgEarth;
00035 using namespace osgEarth::Features;
00036 using namespace osgEarth::Symbology;
00037 
00038 //-----------------------------------------------------------------------
00039 
00040 namespace
00041 {
00042     osg::ref_ptr<PointSymbol>   s_defaultPointSymbol   = new PointSymbol();
00043     osg::ref_ptr<LineSymbol>    s_defaultLineSymbol    = new LineSymbol();
00044     osg::ref_ptr<PolygonSymbol> s_defaultPolygonSymbol = new PolygonSymbol();
00045 }
00046 
00047 //-----------------------------------------------------------------------
00048 
00049 GeometryCompilerOptions::GeometryCompilerOptions( const ConfigOptions& conf ) :
00050 ConfigOptions( conf ),
00051 _maxGranularity_deg( 5.0 ),
00052 _mergeGeometry( false ),
00053 _clustering( true )
00054 {
00055     fromConfig(_conf);
00056 }
00057 
00058 void
00059 GeometryCompilerOptions::fromConfig( const Config& conf )
00060 {
00061     conf.getIfSet   ( "max_granularity", _maxGranularity_deg );
00062     conf.getIfSet   ( "merge_geometry",  _mergeGeometry );
00063     conf.getIfSet   ( "clustering",      _clustering );
00064     conf.getObjIfSet( "feature_name",    _featureNameExpr );
00065     conf.getIfSet   ( "geo_interpolation", "great_circle", _geoInterp, GEOINTERP_GREAT_CIRCLE );
00066     conf.getIfSet   ( "geo_interpolation", "rhumb_line",   _geoInterp, GEOINTERP_RHUMB_LINE );
00067 }
00068 
00069 Config
00070 GeometryCompilerOptions::getConfig() const
00071 {
00072     Config conf = ConfigOptions::getConfig();
00073     conf.addIfSet   ( "max_granularity", _maxGranularity_deg );
00074     conf.addIfSet   ( "merge_geometry",  _mergeGeometry );
00075     conf.addIfSet   ( "clustering",      _clustering );
00076     conf.addObjIfSet( "feature_name",    _featureNameExpr );
00077     conf.addIfSet   ( "geo_interpolation", "great_circle", _geoInterp, GEOINTERP_GREAT_CIRCLE );
00078     conf.addIfSet   ( "geo_interpolation", "rhumb_line",   _geoInterp, GEOINTERP_RHUMB_LINE );
00079     return conf;
00080 }
00081 
00082 void
00083 GeometryCompilerOptions::mergeConfig( const Config& conf )
00084 {
00085     ConfigOptions::mergeConfig( conf );
00086     fromConfig( conf );
00087 }
00088 
00089 //-----------------------------------------------------------------------
00090 
00091 GeometryCompiler::GeometryCompiler()
00092 {
00093     //nop
00094 }
00095 
00096 GeometryCompiler::GeometryCompiler( const GeometryCompilerOptions& options ) :
00097 _options( options )
00098 {
00099     //nop
00100 }
00101 
00102 osg::Node*
00103 GeometryCompiler::compile(Feature*              feature,
00104                           const Style&          style,
00105                           const FilterContext&  context)
00106 {
00107     if ( !context.profile() ) {
00108         OE_WARN << LC << "Valid feature profile required" << std::endl;
00109         return 0L;
00110     }
00111 
00112     //if ( style.empty() ) {
00113     //    OE_WARN << LC << "Non-empty style required" << std::endl;
00114     //    return 0L;
00115     //}
00116 
00117     FeatureList workingSet;
00118     workingSet.push_back(feature);
00119     return compile(workingSet, style, context);
00120 }
00121 
00122 osg::Node*
00123 GeometryCompiler::compile(FeatureCursor*        cursor,
00124                           const Style&          style,
00125                           const FilterContext&  context)
00126 
00127 {
00128     if ( !context.profile() ) {
00129         OE_WARN << LC << "Valid feature profile required" << std::endl;
00130         return 0L;
00131     }
00132 
00133     //if ( style.empty() ) {
00134     //    OE_WARN << LC << "Non-empty style required" << std::endl;
00135     //    return 0L;
00136     //}
00137 
00138     // start by making a working copy of the feature set
00139     FeatureList workingSet;
00140     cursor->fill( workingSet );
00141 
00142     return compile(workingSet, style, context);
00143 }
00144 
00145 osg::Node*
00146 GeometryCompiler::compile(FeatureList&          workingSet,
00147                           const Style&          style,
00148                           const FilterContext&  context)
00149 {
00150 #ifdef PROFILING
00151     osg::Timer_t p_start = osg::Timer::instance()->tick();
00152     unsigned p_features = workingSet.size();
00153 #endif
00154 
00155     osg::ref_ptr<osg::Group> resultGroup = new osg::Group();
00156 
00157     // create a filter context that will track feature data through the process
00158     FilterContext sharedCX = context;
00159     if ( !sharedCX.extent().isSet() )
00160         sharedCX.extent() = sharedCX.profile()->getExtent();
00161 
00162     // only localize coordinates if the map is geocentric AND the extent is
00163     // less than 180 degrees.
00164     const MapInfo& mi = sharedCX.getSession()->getMapInfo();
00165     GeoExtent workingExtent = sharedCX.extent()->transform( sharedCX.profile()->getSRS()->getGeographicSRS() );
00166     bool localize = mi.isGeocentric() && workingExtent.width() < 180.0;
00167 
00168     // go through the Style and figure out which filters to use.
00169     const MarkerSymbol*    marker    = style.get<MarkerSymbol>();
00170     const PointSymbol*     point     = style.get<PointSymbol>();
00171     const LineSymbol*      line      = style.get<LineSymbol>();
00172     const PolygonSymbol*   polygon   = style.get<PolygonSymbol>();
00173     const ExtrusionSymbol* extrusion = style.get<ExtrusionSymbol>();
00174     const AltitudeSymbol*  altitude  = style.get<AltitudeSymbol>();
00175     const TextSymbol*      text      = style.get<TextSymbol>();
00176 
00177     // if the style was empty, use some defaults based on the geometry type of the
00178     // first feature.
00179     if ( style.empty() && workingSet.size() > 0 )
00180     {
00181         Feature* first = workingSet.begin()->get();
00182         Geometry* geom = first->getGeometry();
00183         if ( geom )
00184         {
00185             switch( geom->getComponentType() )
00186             {
00187             case Geometry::TYPE_LINESTRING:
00188             case Geometry::TYPE_RING:
00189                 line = s_defaultLineSymbol.get(); break;
00190             case Geometry::TYPE_POINTSET:
00191                 point = s_defaultPointSymbol.get(); break;
00192             case Geometry::TYPE_POLYGON:
00193                 polygon = s_defaultPolygonSymbol.get(); break;
00194             }
00195         }
00196     }
00197 
00198     if (_options.resampleMode().isSet())
00199     {
00200         ResampleFilter resample;
00201         resample.resampleMode() = *_options.resampleMode();        
00202         if (_options.resampleMaxLength().isSet())
00203         {
00204             resample.maxLength() = *_options.resampleMaxLength();
00205         }                   
00206         sharedCX = resample.push( workingSet, sharedCX );        
00207     }    
00208     
00209     bool altRequired =
00210         altitude && (
00211             altitude->clamping() != AltitudeSymbol::CLAMP_NONE ||
00212             altitude->verticalOffset().isSet() ||
00213             altitude->verticalScale().isSet() );
00214 
00215     // model substitution
00216     if ( marker )
00217     {
00218         // use a separate filter context since we'll be munging the data
00219         FilterContext markerCX = sharedCX;
00220 
00221         if ( marker->placement() == MarkerSymbol::PLACEMENT_RANDOM   ||
00222              marker->placement() == MarkerSymbol::PLACEMENT_INTERVAL )
00223         {
00224             ScatterFilter scatter;
00225             scatter.setDensity( *marker->density() );
00226             scatter.setRandom( marker->placement() == MarkerSymbol::PLACEMENT_RANDOM );
00227             scatter.setRandomSeed( *marker->randomSeed() );
00228             markerCX = scatter.push( workingSet, markerCX );
00229         }
00230         else if ( marker->placement() == MarkerSymbol::PLACEMENT_CENTROID )
00231         {
00232             CentroidFilter centroid;
00233             centroid.push( workingSet, markerCX );
00234         }
00235 
00236         if ( altRequired )
00237         {
00238             AltitudeFilter clamp;
00239             clamp.setPropertiesFromStyle( style );
00240             markerCX = clamp.push( workingSet, markerCX );
00241 
00242             // don't set this; we changed the input data.
00243             //altRequired = false;
00244         }
00245 
00246         SubstituteModelFilter sub( style );
00247         if ( marker->scale().isSet() )
00248         {
00249             //Turn on GL_NORMALIZE so lighting works properly
00250             resultGroup->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON );
00251             //sub.setModelMatrix( osg::Matrixd::scale( *marker->scale() ) );
00252         }
00253 
00254         sub.setClustering( *_options.clustering() );
00255         if ( _options.featureName().isSet() )
00256             sub.setFeatureNameExpr( *_options.featureName() );
00257 
00258         osg::Node* node = sub.push( workingSet, markerCX );
00259         if ( node )
00260         {
00261             resultGroup->addChild( node );
00262         }
00263     }
00264 
00265     // extruded geometry
00266     if ( extrusion )
00267     {
00268         if ( altRequired )
00269         {
00270             AltitudeFilter clamp;
00271             clamp.setPropertiesFromStyle( style );
00272             sharedCX = clamp.push( workingSet, sharedCX );
00273             altRequired = false;
00274         }
00275 
00276         ExtrudeGeometryFilter extrude;
00277         extrude.setStyle( style );
00278 
00279         // apply per-feature naming if requested.
00280         if ( _options.featureName().isSet() )
00281             extrude.setFeatureNameExpr( *_options.featureName() );
00282 
00283         osg::Node* node = extrude.push( workingSet, sharedCX );
00284         if ( node )
00285         {
00286             resultGroup->addChild( node );
00287         }
00288     }
00289 
00290     // simple geometry
00291     else if ( point || line || polygon )
00292     {
00293         if ( altRequired )
00294         {
00295             AltitudeFilter clamp;
00296             clamp.setPropertiesFromStyle( style );
00297             sharedCX = clamp.push( workingSet, sharedCX );
00298             altRequired = false;
00299         }
00300 
00301         BuildGeometryFilter filter( style );
00302         if ( _options.maxGranularity().isSet() )
00303             filter.maxGranularity() = *_options.maxGranularity();
00304         if ( _options.geoInterp().isSet() )
00305             filter.geoInterp() = *_options.geoInterp();
00306         if ( _options.mergeGeometry().isSet() )
00307             filter.mergeGeometry() = *_options.mergeGeometry();
00308         if ( _options.featureName().isSet() )
00309             filter.featureName() = *_options.featureName();
00310 
00311         osg::Node* node = filter.push( workingSet, sharedCX );
00312         if ( node )
00313         {
00314             resultGroup->addChild( node );
00315         }
00316     }
00317 
00318     if ( text )
00319     {
00320         if ( altRequired )
00321         {
00322             AltitudeFilter clamp;
00323             clamp.setPropertiesFromStyle( style );
00324             sharedCX = clamp.push( workingSet, sharedCX );
00325             altRequired = false;
00326         }
00327 
00328         BuildTextFilter filter( style );
00329         osg::Node* node = filter.push( workingSet, sharedCX );
00330         if ( node )
00331         {
00332             resultGroup->addChild( node );
00333         }
00334     }
00335 
00336     resultGroup->getOrCreateStateSet()->setMode( GL_BLEND, 1 );
00337 
00338     //osgDB::writeNodeFile( *(resultGroup.get()), "out.osg" );
00339 
00340 #ifdef PROFILING
00341     osg::Timer_t p_end = osg::Timer::instance()->tick();
00342     OE_INFO << LC
00343         << "features = " << p_features <<
00344         << " ,time = " << osg::Timer::instance()->delta_s(p_start, p_end) << " s." << std::endl;
00345 #endif
00346 
00347     return resultGroup.release();
00348 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines