osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthSymbology/Style.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 <osgEarthSymbology/Style>
00020 #include <osgEarthSymbology/CssUtils>
00021 #include <osgEarthSymbology/SLD>
00022 #include <osgEarth/HTTPClient>
00023 #include <algorithm>
00024 
00025 using namespace osgEarth;
00026 using namespace osgEarth::Symbology;
00027 
00028 //------------------------------------------------------------------------
00029 
00030 #undef  LC
00031 #define LC "[Style] "
00032 
00033 Style::Style( const std::string& name ) :
00034 _name( name )
00035 {
00036     //NOP
00037 }
00038 
00039 Style::Style(const Style& rhs) :
00040 _name    ( rhs._name ),
00041 _symbols ( rhs._symbols ),
00042 _origType( rhs._origType ),
00043 _origData( rhs._origData ),
00044 _uri     ( rhs._uri )
00045 {
00046     //nop
00047 }
00048 
00049 void Style::addSymbol(Symbol* symbol)
00050 {
00051     _symbols.push_back(symbol);
00052 }
00053 
00054 bool Style::removeSymbol(Symbol* symbol)
00055 {
00056         SymbolList::iterator it = find(_symbols.begin(), _symbols.end(), symbol);
00057         if (it == _symbols.end())
00058                 return false;
00059                 
00060         _symbols.erase(it);
00061         
00062         return true;
00063 }
00064 
00065 Style::Style( const Config& conf )
00066 {
00067     mergeConfig( conf );
00068 }
00069 
00070 Style
00071 Style::combineWith( const Style& rhs ) const
00072 {
00073     // start by deep-cloning this style.
00074     Config conf = getConfig( false );
00075     Style newStyle( conf );
00076 
00077     // next, merge in the symbology from the other style.
00078     newStyle.mergeConfig( rhs.getConfig(false) );
00079 
00080     if ( !this->empty() && !rhs.empty() )
00081         newStyle.setName( _name + ":" + rhs.getName() );
00082     else if ( !this->empty() && rhs.empty() )
00083         newStyle.setName( _name );
00084     else if ( this->empty() && !rhs.empty() )
00085         newStyle.setName( rhs.getName() );
00086     else
00087         newStyle.setName( _name );
00088 
00089     return newStyle;
00090 }
00091 
00092 void
00093 Style::mergeConfig( const Config& conf )
00094 {
00095     if ( _name.empty() )
00096         _name = conf.value( "name" );
00097 
00098     // if there's no explicit name, use the KEY as the name.
00099     if ( _name.empty() )
00100         _name = conf.key();
00101 
00102     conf.getIfSet( "url", _uri ); // named "url" for back compat
00103 
00104     _origType = conf.value( "type" );
00105 
00106     if ( conf.value( "type" ) == "text/css" )
00107     {
00108         _origData = conf.value();
00109     }
00110     else
00111     {
00112         Config symbolConf = conf.child( "symbols" );
00113         if ( !symbolConf.empty() )
00114         {
00115             for( ConfigSet::const_iterator i = symbolConf.children().begin(); i != symbolConf.children().end(); ++i )
00116             {
00117                 const Config& c = *i;
00118 
00119                 if ( c.key() == "text" )
00120                 {
00121                     getOrCreateSymbol<TextSymbol>()->mergeConfig( c );
00122                 }
00123                 else if ( c.key() == "point" )
00124                 {
00125                     getOrCreateSymbol<PointSymbol>()->mergeConfig( c );
00126                 }
00127                 else if ( c.key() == "line" )
00128                 {
00129                     getOrCreateSymbol<LineSymbol>()->mergeConfig( c );
00130                 }
00131                 else if ( c.key() == "polygon" )
00132                 {
00133                     getOrCreateSymbol<PolygonSymbol>()->mergeConfig( c );
00134                 }
00135                 else if ( c.key() == "extrusion" )
00136                 {
00137                     getOrCreateSymbol<ExtrusionSymbol>()->mergeConfig( c );
00138                 }
00139                 else if ( c.key() == "altitude" )
00140                 {
00141                     getOrCreateSymbol<AltitudeSymbol>()->mergeConfig( c );
00142                 }
00143                 else if ( c.key() == "marker" )
00144                 {
00145                     getOrCreateSymbol<MarkerSymbol>()->mergeConfig( c );
00146                 }
00147             }
00148         }
00149     }
00150 }
00151 
00152 Config
00153 Style::getConfig( bool keepOrigType ) const
00154 {
00155     Config conf( "style" );
00156     conf.attr("name") = _name;
00157 
00158     conf.addIfSet( "url", _uri );
00159     
00160     if ( _origType == "text/css" && keepOrigType )
00161     {
00162         conf.attr("type") = _origType;
00163         conf.value() = _origData;            
00164     }
00165     else
00166     {
00167         Config symbolsConf( "symbols" );
00168         for( SymbolList::const_iterator i = _symbols.begin(); i != _symbols.end(); ++i )
00169         {
00170             symbolsConf.addChild( i->get()->getConfig() );
00171         }
00172         conf.addChild( symbolsConf );
00173     }
00174 
00175     return conf;
00176 }
00177 
00178 //------------------------------------------------------------------------
00179 
00180 #undef  LC
00181 #define LC "[StyleSelector] "
00182 
00183 StyleSelector::StyleSelector( const Config& conf )
00184 {
00185     mergeConfig( conf );
00186 }
00187 
00188 std::string
00189 StyleSelector::getSelectedStyleName() const 
00190 {
00191     return _styleName.isSet() ? *_styleName : _name;
00192 }
00193 
00194 void
00195 StyleSelector::mergeConfig( const Config& conf )
00196 {
00197     _name = conf.value( "name" );
00198     conf.getIfSet( "style", _styleName ); // backwards compatibility
00199     conf.getIfSet( "class", _styleName );
00200     conf.getObjIfSet( "query", _query );
00201 }
00202 
00203 Config
00204 StyleSelector::getConfig() const
00205 {
00206     Config conf( "selector" );
00207     conf.add( "name", _name );
00208     conf.addIfSet( "class", _styleName );
00209     conf.addObjIfSet( "query", _query );
00210     return conf;
00211 }
00212 
00213 //------------------------------------------------------------------------
00214 
00215 #undef  LC
00216 #define LC "[StyleSheet] "
00217 
00218 StyleSheet::StyleSheet( const Config& conf )
00219 {
00220     mergeConfig( conf );
00221 }
00222 
00223 void
00224 StyleSheet::addStyle( const Style& style )
00225 {
00226     _styles[ style.getName() ] = style;
00227 }
00228 
00229 void
00230 StyleSheet::removeStyle( const std::string& name )
00231 {
00232     _styles.erase( name );
00233 }
00234 
00235 Style*
00236 StyleSheet::getStyle( const std::string& name, bool fallBackOnDefault )
00237 {
00238     StyleMap::iterator i = _styles.find( name );
00239     if ( i != _styles.end() ) {
00240         return &i->second;
00241     }
00242     else if ( name.length() > 1 && name.at(0) == '#' ) {
00243         std::string nameWithoutHash = name.substr( 1 );
00244         return getStyle( nameWithoutHash, fallBackOnDefault );
00245     }
00246     else if ( fallBackOnDefault ) {
00247         return getDefaultStyle();
00248     }
00249     else {
00250         return 0L;
00251     }
00252 }
00253 
00254 const Style*
00255 StyleSheet::getStyle( const std::string& name, bool fallBackOnDefault ) const
00256 {
00257     StyleMap::const_iterator i = _styles.find( name );
00258     if ( i != _styles.end() ) {
00259         return &i->second;
00260     }
00261     else if ( name.length() > 1 && name.at(0) == '#' ) {
00262         std::string nameWithoutHash = name.substr( 1 );
00263         return getStyle( nameWithoutHash, fallBackOnDefault );
00264     }
00265     else if ( fallBackOnDefault ) {
00266         return getDefaultStyle();
00267     }
00268     else {
00269         return 0L;
00270     }
00271 }
00272 
00273 Style*
00274 StyleSheet::getDefaultStyle()
00275 {
00276     if ( _styles.find( "default" ) != _styles.end() ) {
00277         return &_styles.find( "default" )->second;
00278     }
00279     else if ( _styles.find( "" ) != _styles.end() ) {
00280         return &_styles.find( "" )->second;
00281     }
00282     if ( _styles.size() > 0 ) {
00283         return &_styles.begin()->second;
00284     }
00285     else {
00286         // insert the empty style and return it.
00287         _styles["default"] = _emptyStyle;
00288         return &_styles.begin()->second;
00289     }
00290 }
00291 
00292 const Style*
00293 StyleSheet::getDefaultStyle() const
00294 {
00295     if ( _styles.size() == 1 ) {
00296         return &_styles.begin()->second;
00297     }
00298     else if ( _styles.find( "default" ) != _styles.end() ) {
00299         return &_styles.find( "default" )->second;
00300     }
00301     else if ( _styles.find( "" ) != _styles.end() ) {
00302         return &_styles.find( "" )->second;
00303     }
00304     else {
00305         return &_emptyStyle;
00306     }
00307 }
00308 
00309 void
00310 StyleSheet::addResourceLibrary( const std::string& name, ResourceLibrary* lib )
00311 {
00312     _libraries[name] = lib;
00313 }
00314 
00315 ResourceLibrary*
00316 StyleSheet::getResourceLibrary( const std::string& name ) const
00317 {
00318     ResourceLibraryMap::const_iterator i = _libraries.find( name );
00319     return i != _libraries.end() ? i->second.get() : 0L;
00320 }
00321 
00322 Config
00323 StyleSheet::getConfig() const
00324 {
00325     Config conf;
00326     for( StyleSelectorList::const_iterator i = _selectors.begin(); i != _selectors.end(); ++i )
00327     {
00328         conf.add( "selector", i->getConfig() );
00329     }
00330     for( StyleMap::const_iterator i = _styles.begin(); i != _styles.end(); ++i )
00331     {
00332         conf.add( "style", i->second.getConfig() );
00333     }
00334     return conf;
00335 }
00336 
00337 void
00338 StyleSheet::mergeConfig( const Config& conf )
00339 {
00340     _uriContext = conf.uriContext();
00341 
00342     // read in any resource library references
00343     ConfigSet libraries = conf.children( "library" );
00344     for( ConfigSet::iterator i = libraries.begin(); i != libraries.end(); ++i )
00345     {
00346         std::string name = i->value("name");
00347         if ( name.empty() ) {
00348             OE_WARN << LC << "Resource library missing required 'name' attribute" << std::endl;
00349             continue;
00350         }
00351 
00352         URI uri( i->value("url"), i->uriContext() );
00353         if ( uri.empty() ) {
00354             OE_WARN << LC << "Resource library missing required 'url' element" << std::endl;
00355             continue;
00356         }
00357 
00358         osg::ref_ptr<ResourceLibrary> reslib = ResourceLibrary::create( uri );
00359         if ( !reslib.valid() ) {
00360             OE_WARN << LC << "Resource library creation failed" << std::endl;
00361             continue;
00362         }
00363 
00364         addResourceLibrary( name, reslib.get() );
00365     }
00366 
00367     // read any style class definitions. either "class" or "selector" is allowed
00368     ConfigSet selectors = conf.children( "selector" );
00369     if ( selectors.empty() ) selectors = conf.children( "class" );
00370     for( ConfigSet::iterator i = selectors.begin(); i != selectors.end(); ++i )
00371     {
00372         _selectors.push_back( StyleSelector( *i ) );
00373     }
00374 
00375     // read in the actual styles
00376     ConfigSet styles = conf.children( "style" );
00377     for( ConfigSet::iterator i = styles.begin(); i != styles.end(); ++i )
00378     {
00379         const Config& styleConf = *i;
00380 
00381         if ( styleConf.value("type") == "text/css" )
00382         {
00383             // read the inline data:
00384             std::string cssString = styleConf.value();
00385 
00386             // if there's a URL, read the CSS from the URL:
00387             if ( styleConf.hasValue("url") )
00388             {
00389                 URI uri( styleConf.value("url"), styleConf.uriContext() );
00390                 HTTPClient::readString( uri.full(), cssString );
00391             }
00392 
00393             // a CSS style definition can actually contain multiple styles. Read them
00394             // and create one style for each in the catalog.
00395             std::stringstream buf( cssString );
00396             Config css = CssUtils::readConfig( buf );
00397             css.setURIContext( styleConf.uriContext( ) );
00398             
00399             const ConfigSet children = css.children();
00400             for(ConfigSet::const_iterator j = children.begin(); j != children.end(); ++j )
00401             {
00402                 Style style( styleConf );
00403                 
00404                 if ( SLDReader::readStyleFromCSSParams( *j, style ) )
00405                     _styles[ j->key() ] = style;
00406             }            
00407         }
00408         else
00409         {
00410             Style style( styleConf );
00411             _styles[ style.getName() ] = style;
00412         }
00413     }
00414 }
00415 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines