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 #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