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 <osgEarth/Registry> 00021 #include <osgEarth/FileUtils> 00022 #include <osgEarthFeatures/FeatureSource> 00023 #include <osgEarthFeatures/Filter> 00024 #include <osgEarthFeatures/BufferFilter> 00025 #include <osgEarthFeatures/ScaleFilter> 00026 #include "OGRFeatureOptions" 00027 #include "FeatureCursorOGR" 00028 #include <osgEarthFeatures/OgrUtils> 00029 #include <osg/Notify> 00030 #include <osgDB/FileNameUtils> 00031 #include <osgDB/FileUtils> 00032 #include <list> 00033 #include <ogr_api.h> 00034 00035 #define LC "[OGR FeatureSource] " 00036 00037 using namespace osgEarth; 00038 using namespace osgEarth::Features; 00039 using namespace osgEarth::Drivers; 00040 00041 #define OGR_SCOPED_LOCK GDAL_SCOPED_LOCK 00042 00048 class OGRFeatureSource : public FeatureSource 00049 { 00050 public: 00051 OGRFeatureSource( const OGRFeatureOptions& options ) : FeatureSource( options ), 00052 _dsHandle( 0L ), 00053 _layerHandle( 0L ), 00054 _ogrDriverHandle( 0L ), 00055 _options( options ), 00056 _featureCount(-1), 00057 _needsSync(false), 00058 _writable(false) 00059 { 00060 _geometry = 00061 _options.geometry().valid() ? _options.geometry().get() : 00062 _options.geometryConfig().isSet() ? parseGeometry( *_options.geometryConfig() ) : 00063 _options.geometryUrl().isSet() ? parseGeometryUrl( *_options.geometryUrl() ) : 00064 0L; 00065 } 00066 00068 virtual ~OGRFeatureSource() 00069 { 00070 OGR_SCOPED_LOCK; 00071 00072 if ( _layerHandle ) 00073 { 00074 if (_needsSync) 00075 { 00076 OGR_L_SyncToDisk( _layerHandle ); // for writing only 00077 const char* name = OGR_FD_GetName( OGR_L_GetLayerDefn( _layerHandle ) ); 00078 std::stringstream buf; 00079 buf << "REPACK " << name; 00080 std::string bufStr; 00081 bufStr = buf.str(); 00082 OGR_DS_ExecuteSQL( _dsHandle, bufStr.c_str(), 0L, 0L ); 00083 } 00084 _layerHandle = 0L; 00085 } 00086 00087 if ( _dsHandle ) 00088 { 00089 OGRReleaseDataSource( _dsHandle ); 00090 _dsHandle = 0L; 00091 } 00092 } 00093 00094 //override 00095 void initialize( const std::string& referenceURI ) 00096 { 00097 if ( _options.url().isSet() ) 00098 { 00099 _source = osgEarth::getFullPath( referenceURI, _options.url()->full() ); 00100 } 00101 else if ( _options.connection().isSet() ) 00102 { 00103 _source = _options.connection().value(); 00104 } 00105 } 00106 00109 const FeatureProfile* createFeatureProfile() 00110 { 00111 FeatureProfile* result = 0L; 00112 00113 // see if we have a custom profile. 00114 osg::ref_ptr<const Profile> profile; 00115 if ( _options.profile().isSet() ) 00116 { 00117 profile = Profile::create( *_options.profile() ); 00118 } 00119 00120 if ( _geometry.valid() ) 00121 { 00122 // if the user specified explicit geometry/profile, use that: 00123 GeoExtent ex; 00124 if ( profile.valid() ) 00125 { 00126 ex = profile->getExtent(); 00127 } 00128 00129 if ( !ex.isValid() ) 00130 { 00131 // default to WGS84 Lat/Long 00132 ex = osgEarth::Registry::instance()->getGlobalGeodeticProfile()->getExtent(); 00133 } 00134 result = new FeatureProfile( ex ); 00135 } 00136 00137 else if ( !_source.empty() ) 00138 { 00139 // otherwise, assume we're loading from the URL: 00140 OGR_SCOPED_LOCK; 00141 00142 // load up the driver, defaulting to shapefile if unspecified. 00143 std::string driverName = _options.ogrDriver().value(); 00144 if ( driverName.empty() ) 00145 driverName = "ESRI Shapefile"; 00146 _ogrDriverHandle = OGRGetDriverByName( driverName.c_str() ); 00147 00148 // attempt to open the dataset: 00149 int openMode = _options.openWrite().isSet() && _options.openWrite().value() ? 1 : 0; 00150 00151 _dsHandle = OGROpenShared( _source.c_str(), openMode, &_ogrDriverHandle ); 00152 if ( _dsHandle ) 00153 { 00154 if (openMode == 1) _writable = true; 00155 00156 _layerHandle = OGR_DS_GetLayer( _dsHandle, 0 ); // default to layer 0 for now 00157 if ( _layerHandle ) 00158 { 00159 GeoExtent extent; 00160 00161 // if the user provided a profile, user that: 00162 if ( profile.valid() ) 00163 { 00164 result = new FeatureProfile( profile->getExtent() ); 00165 } 00166 00167 else 00168 { 00169 // extract the SRS and Extent: 00170 OGRSpatialReferenceH srHandle = OGR_L_GetSpatialRef( _layerHandle ); 00171 if ( srHandle ) 00172 { 00173 osg::ref_ptr<SpatialReference> srs = SpatialReference::createFromHandle( srHandle, false ); 00174 if ( srs.valid() ) 00175 { 00176 // extract the full extent of the layer: 00177 OGREnvelope env; 00178 if ( OGR_L_GetExtent( _layerHandle, &env, 1 ) == OGRERR_NONE ) 00179 { 00180 GeoExtent extent( srs.get(), env.MinX, env.MinY, env.MaxX, env.MaxY ); 00181 00182 // got enough info to make the profile! 00183 result = new FeatureProfile( extent ); 00184 } 00185 } 00186 } 00187 } 00188 00189 // assuming we successfully opened the layer, build a spatial index if requested. 00190 if ( _options.buildSpatialIndex() == true ) 00191 { 00192 OE_INFO << LC << "Building spatial index for " << getName() << std::endl; 00193 std::stringstream buf; 00194 const char* name = OGR_FD_GetName( OGR_L_GetLayerDefn( _layerHandle ) ); 00195 buf << "CREATE SPATIAL INDEX ON " << name; 00196 std::string bufStr; 00197 bufStr = buf.str(); 00198 OGR_DS_ExecuteSQL( _dsHandle, bufStr.c_str(), 0L, 0L ); 00199 } 00200 00201 //Get the feature count 00202 _featureCount = OGR_L_GetFeatureCount( _layerHandle, 1 ); 00203 00204 initSchema(); 00205 00206 OGRwkbGeometryType wkbType = OGR_FD_GetGeomType( OGR_L_GetLayerDefn( _layerHandle ) ); 00207 if ( 00208 wkbType == wkbPolygon || 00209 wkbType == wkbPolygon25D ) 00210 { 00211 _geometryType = Geometry::TYPE_POLYGON; 00212 } 00213 else if ( 00214 wkbType == wkbLineString || 00215 wkbType == wkbLineString25D ) 00216 { 00217 _geometryType = Geometry::TYPE_LINESTRING; 00218 } 00219 else if ( 00220 wkbType == wkbLinearRing ) 00221 { 00222 _geometryType = Geometry::TYPE_RING; 00223 } 00224 else if ( 00225 wkbType == wkbPoint || 00226 wkbType == wkbPoint25D ) 00227 { 00228 _geometryType = Geometry::TYPE_POINTSET; 00229 } 00230 else if ( 00231 wkbType == wkbGeometryCollection || 00232 wkbType == wkbGeometryCollection25D || 00233 wkbType == wkbMultiPoint || 00234 wkbType == wkbMultiPoint25D || 00235 wkbType == wkbMultiLineString || 00236 wkbType == wkbMultiLineString25D || 00237 wkbType == wkbMultiPolygon || 00238 wkbType == wkbMultiPolygon25D ) 00239 { 00240 _geometryType = Geometry::TYPE_MULTI; 00241 } 00242 } 00243 } 00244 else 00245 { 00246 OE_INFO << LC << "failed to open dataset \"" << _source << "\"" << std::endl; 00247 } 00248 } 00249 else 00250 { 00251 OE_INFO << LC 00252 << "Feature Source: no valid source data available" << std::endl; 00253 } 00254 00255 return result; 00256 } 00257 00258 00259 //override 00260 FeatureCursor* createFeatureCursor( const Symbology::Query& query ) 00261 { 00262 if ( _geometry.valid() ) 00263 { 00264 return new GeometryFeatureCursor( 00265 _geometry.get(), 00266 getFeatureProfile(), 00267 _options.filters() ); 00268 //getFilters() ); 00269 } 00270 else 00271 { 00272 OGR_SCOPED_LOCK; 00273 00274 // Each cursor requires its own DS handle so that multi-threaded access will work. 00275 // The cursor impl will dispose of the new DS handle. 00276 00277 OGRDataSourceH dsHandle = OGROpenShared( _source.c_str(), 0, &_ogrDriverHandle ); 00278 if ( dsHandle ) 00279 { 00280 OGRLayerH layerHandle = OGR_DS_GetLayer( dsHandle, 0 ); 00281 00282 return new FeatureCursorOGR( 00283 dsHandle, 00284 layerHandle, 00285 getFeatureProfile(), 00286 query, 00287 _options.filters() ); 00288 } 00289 else 00290 { 00291 return 0L; 00292 } 00293 } 00294 } 00295 00296 virtual bool deleteFeature(FeatureID fid) 00297 { 00298 if (_writable && _layerHandle) 00299 { 00300 if (OGR_L_DeleteFeature( _layerHandle, fid ) == OGRERR_NONE) 00301 { 00302 _needsSync = true; 00303 return true; 00304 } 00305 } 00306 return false; 00307 } 00308 00309 virtual int getFeatureCount() const 00310 { 00311 return _featureCount; 00312 } 00313 00314 virtual Feature* getFeature( FeatureID fid ) 00315 { 00316 Feature* result = NULL; 00317 OGRFeatureH handle = OGR_L_GetFeature( _layerHandle, fid); 00318 if (handle) 00319 { 00320 result = OgrUtils::createFeature( handle ); 00321 OGR_F_Destroy( handle ); 00322 } 00323 return result; 00324 } 00325 00326 virtual bool isWritable() const 00327 { 00328 return _writable; 00329 } 00330 00331 const FeatureSchema& getSchema() const 00332 { 00333 return _schema; 00334 } 00335 00336 virtual bool insertFeature(Feature* feature) 00337 { 00338 OGR_SCOPED_LOCK; 00339 OGRFeatureH feature_handle = OGR_F_Create( OGR_L_GetLayerDefn( _layerHandle ) ); 00340 if ( feature_handle ) 00341 { 00342 const AttributeTable& attrs = feature->getAttrs(); 00343 00344 // assign the attributes: 00345 int num_fields = OGR_F_GetFieldCount( feature_handle ); 00346 for( int i=0; i<num_fields; i++ ) 00347 { 00348 OGRFieldDefnH field_handle_ref = OGR_F_GetFieldDefnRef( feature_handle, i ); 00349 std::string name = OGR_Fld_GetNameRef( field_handle_ref ); 00350 int field_index = OGR_F_GetFieldIndex( feature_handle, name.c_str() ); 00351 00352 AttributeTable::const_iterator a = attrs.find( toLower(name) ); 00353 if ( a != attrs.end() ) 00354 { 00355 switch( OGR_Fld_GetType(field_handle_ref) ) 00356 { 00357 case OFTInteger: 00358 OGR_F_SetFieldInteger( feature_handle, field_index, a->second.getInt(0) ); 00359 break; 00360 case OFTReal: 00361 OGR_F_SetFieldDouble( feature_handle, field_index, a->second.getDouble(0.0) ); 00362 break; 00363 case OFTString: 00364 OGR_F_SetFieldString( feature_handle, field_index, a->second.getString().c_str() ); 00365 break; 00366 } 00367 } 00368 } 00369 00370 // std::string value = feature->getAttr( name ); 00371 // if (!value.empty()) 00372 // { 00373 // switch( OGR_Fld_GetType( field_handle_ref ) ) 00374 // { 00375 // case OFTInteger: 00376 // OGR_F_SetFieldInteger( feature_handle, field_index, as<int>(value, 0) ); 00377 // break; 00378 // case OFTReal: 00379 // OGR_F_SetFieldDouble( feature_handle, field_index, as<double>(value, 0.0) ); 00380 // break; 00381 // case OFTString: 00382 // OGR_F_SetFieldString( feature_handle, field_index, value.c_str() ); 00383 // break; 00384 // } 00385 // } 00386 //} 00387 00388 // assign the geometry: 00389 OGRFeatureDefnH def = ::OGR_L_GetLayerDefn( _layerHandle ); 00390 00391 OGRwkbGeometryType reported_type = OGR_FD_GetGeomType( def ); 00392 00393 OGRGeometryH ogr_geometry = OgrUtils::createOgrGeometry( feature->getGeometry(), reported_type ); 00394 if ( OGR_F_SetGeometryDirectly( feature_handle, ogr_geometry ) != OGRERR_NONE ) 00395 { 00396 OE_WARN << LC << "OGR_F_SetGeometryDirectly failed!" << std::endl; 00397 } 00398 00399 if ( OGR_L_CreateFeature( _layerHandle, feature_handle ) != OGRERR_NONE ) 00400 { 00401 //TODO: handle error better 00402 OE_WARN << LC << "OGR_L_CreateFeature failed!" << std::endl; 00403 OGR_F_Destroy( feature_handle ); 00404 return false; 00405 } 00406 00407 // clean up the feature 00408 OGR_F_Destroy( feature_handle ); 00409 } 00410 else 00411 { 00412 //TODO: handle error better 00413 OE_WARN << LC << "OGR_F_Create failed." << std::endl; 00414 return false; 00415 } 00416 00417 return true; 00418 } 00419 00420 virtual osgEarth::Symbology::Geometry::Type getGeometryType() const 00421 { 00422 return _geometryType; 00423 } 00424 00425 protected: 00426 00427 // parses an explicit WKT geometry string into a Geometry. 00428 Symbology::Geometry* parseGeometry( const Config& geomConf ) 00429 { 00430 return OgrUtils::createGeometryFromWKT( geomConf.value() ); 00431 } 00432 00433 // read the WKT geometry from a URL, then parse into a Geometry. 00434 Symbology::Geometry* parseGeometryUrl( const std::string& geomUrl ) 00435 { 00436 std::string wkt; 00437 if ( HTTPClient::readString( geomUrl, wkt ) == HTTPClient::RESULT_OK ) 00438 { 00439 Config conf( "geometry", wkt ); 00440 return parseGeometry( conf ); 00441 } 00442 return 0L; 00443 } 00444 00445 void initSchema() 00446 { 00447 OGRFeatureDefnH layerDef = OGR_L_GetLayerDefn( _layerHandle ); 00448 for (int i = 0; i < OGR_FD_GetFieldCount( layerDef ); i++) 00449 { 00450 OGRFieldDefnH fieldDef = OGR_FD_GetFieldDefn( layerDef, i ); 00451 std::string name; 00452 name = std::string( OGR_Fld_GetNameRef( fieldDef ) ); 00453 OGRFieldType ogrType = OGR_Fld_GetType( fieldDef ); 00454 _schema[ name ] = OgrUtils::getAttributeType( ogrType ); 00455 } 00456 } 00457 00458 00459 00460 00461 00462 private: 00463 std::string _source; 00464 OGRDataSourceH _dsHandle; 00465 OGRLayerH _layerHandle; 00466 OGRSFDriverH _ogrDriverHandle; 00467 osg::ref_ptr<Symbology::Geometry> _geometry; // explicit geometry. 00468 const OGRFeatureOptions _options; 00469 int _featureCount; 00470 bool _needsSync; 00471 bool _writable; 00472 FeatureSchema _schema; 00473 Geometry::Type _geometryType; 00474 }; 00475 00476 00477 class OGRFeatureSourceFactory : public FeatureSourceDriver 00478 { 00479 public: 00480 OGRFeatureSourceFactory() 00481 { 00482 supportsExtension( "osgearth_feature_ogr", "OGR feature driver for osgEarth" ); 00483 } 00484 00485 virtual const char* className() 00486 { 00487 return "OGR Feature Reader"; 00488 } 00489 00490 virtual ReadResult readObject(const std::string& file_name, const Options* options) const 00491 { 00492 if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name ))) 00493 return ReadResult::FILE_NOT_HANDLED; 00494 00495 return ReadResult( new OGRFeatureSource( getFeatureSourceOptions(options) ) ); 00496 } 00497 }; 00498 00499 REGISTER_OSGPLUGIN(osgearth_feature_ogr, OGRFeatureSourceFactory) 00500