osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/feature_ogr/FeatureCursorOGR.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 "FeatureCursorOGR"
00020 #include <osgEarthFeatures/OgrUtils>
00021 #include <osgEarthFeatures/Feature>
00022 #include <osgEarth/Registry>
00023 #include <algorithm>
00024 
00025 #define OGR_SCOPED_LOCK GDAL_SCOPED_LOCK
00026 
00027 using namespace osgEarth;
00028 using namespace osgEarth::Features;
00029 
00030 
00031 FeatureCursorOGR::FeatureCursorOGR(OGRDataSourceH dsHandle,
00032                                    OGRLayerH layerHandle,
00033                                    const FeatureProfile* profile,
00034                                    const Symbology::Query& query,
00035                                    const FeatureFilterList& filters ) :
00036 _dsHandle( dsHandle ),
00037 _layerHandle( layerHandle ),
00038 _resultSetHandle( 0L ),
00039 _spatialFilter( 0L ),
00040 _query( query ),
00041 _chunkSize( 500 ),
00042 _nextHandleToQueue( 0L ),
00043 _profile( profile ),
00044 _filters( filters )
00045 {
00046     //_resultSetHandle = _layerHandle;
00047     {
00048         OGR_SCOPED_LOCK;
00049 
00050         std::string expr;
00051         std::string from = OGR_FD_GetName( OGR_L_GetLayerDefn( _layerHandle ));
00052         from = std::string("'") + from + std::string("'");
00053 
00054         if ( query.expression().isSet() )
00055         {
00056             // build the SQL: allow the Query to include either a full SQL statement or
00057             // just the WHERE clause.
00058             expr = query.expression().value();
00059 
00060             // if the expression is just a where clause, expand it into a complete SQL expression.
00061             std::string temp = expr;
00062             std::transform( temp.begin(), temp.end(), temp.begin(), ::tolower );
00063             //bool complete = temp.find( "select" ) == 0;
00064             if ( temp.find( "select" ) != 0 )
00065             {
00066                 std::stringstream buf;
00067                 buf << "SELECT * FROM " << from << " WHERE " << expr;
00068                 std::string bufStr;
00069                 bufStr = buf.str();
00070                 expr = bufStr;
00071             }
00072         }
00073         else
00074         {
00075             std::stringstream buf;
00076             buf << "SELECT * FROM " << from;
00077             expr = buf.str();
00078         }
00079 
00080         // if there's a spatial extent in the query, build the spatial filter:
00081         if ( query.bounds().isSet() )
00082         {
00083             OGRGeometryH ring = OGR_G_CreateGeometry( wkbLinearRing );
00084             OGR_G_AddPoint(ring, query.bounds()->xMin(), query.bounds()->yMin(), 0 );
00085             OGR_G_AddPoint(ring, query.bounds()->xMin(), query.bounds()->yMax(), 0 );
00086             OGR_G_AddPoint(ring, query.bounds()->xMax(), query.bounds()->yMax(), 0 );
00087             OGR_G_AddPoint(ring, query.bounds()->xMax(), query.bounds()->yMin(), 0 );
00088             OGR_G_AddPoint(ring, query.bounds()->xMin(), query.bounds()->yMin(), 0 );
00089 
00090             _spatialFilter = OGR_G_CreateGeometry( wkbPolygon );
00091             OGR_G_AddGeometryDirectly( _spatialFilter, ring ); 
00092             // note: "Directly" above means _spatialFilter takes ownership if ring handle
00093         }
00094 
00095 
00096         _resultSetHandle = OGR_DS_ExecuteSQL( _dsHandle, expr.c_str(), _spatialFilter, 0L );
00097 
00098         if ( _resultSetHandle )
00099         {
00100             OGR_L_ResetReading( _resultSetHandle );
00101         }
00102     }
00103 
00104     readChunk();
00105 }
00106 
00107 FeatureCursorOGR::~FeatureCursorOGR()
00108 {
00109     OGR_SCOPED_LOCK;
00110 
00111     if ( _nextHandleToQueue )
00112         OGR_F_Destroy( _nextHandleToQueue );
00113 
00114     if ( _resultSetHandle != _layerHandle )
00115         OGR_DS_ReleaseResultSet( _dsHandle, _resultSetHandle );
00116 
00117     if ( _spatialFilter )
00118         OGR_G_DestroyGeometry( _spatialFilter );
00119 
00120     if ( _dsHandle )
00121         OGRReleaseDataSource( _dsHandle );
00122 }
00123 
00124 bool
00125 FeatureCursorOGR::hasMore() const
00126 {
00127     return _resultSetHandle && ( _queue.size() > 0 || _nextHandleToQueue != 0L );
00128 }
00129 
00130 Feature*
00131 FeatureCursorOGR::nextFeature()
00132 {
00133     if ( !hasMore() )
00134         return 0L;
00135 
00136     if ( _queue.size() == 0 && _nextHandleToQueue )
00137         readChunk();
00138 
00139     // do this in order to hold a reference to the feature we return, so the caller
00140     // doesn't have to. This lets us avoid requiring the caller to use a ref_ptr when 
00141     // simply iterating over the cursor, making the cursor move conventient to use.
00142     _lastFeatureReturned = _queue.front();
00143     _queue.pop();
00144 
00145     return _lastFeatureReturned.get();
00146 }
00147 
00148 
00149 // reads a chunk of features into a memory cache; do this for performance
00150 // and to avoid needing the OGR Mutex every time
00151 void
00152 FeatureCursorOGR::readChunk()
00153 {
00154     if ( !_resultSetHandle )
00155         return;
00156     
00157     FeatureList preProcessList;
00158     
00159     OGR_SCOPED_LOCK;
00160 
00161     if ( _nextHandleToQueue )
00162     {
00163         Feature* f = OgrUtils::createFeature( _nextHandleToQueue );
00164         if ( f ) 
00165         {
00166             _queue.push( f );
00167             
00168             if ( _filters.size() > 0 )
00169                 preProcessList.push_back( f );
00170         }
00171         OGR_F_Destroy( _nextHandleToQueue );
00172         _nextHandleToQueue = 0L;
00173     }
00174 
00175     int handlesToQueue = _chunkSize - _queue.size();
00176 
00177     for( int i=0; i<handlesToQueue; i++ )
00178     {
00179         OGRFeatureH handle = OGR_L_GetNextFeature( _resultSetHandle );
00180         if ( handle )
00181         {
00182             Feature* f = OgrUtils::createFeature( handle );
00183             if ( f ) 
00184             {
00185                 _queue.push( f );
00186 
00187                 if ( _filters.size() > 0 )
00188                     preProcessList.push_back( f );
00189             }
00190             OGR_F_Destroy( handle );
00191         }
00192         else
00193             break;
00194     }
00195 
00196     // preprocess the features using the filter list:
00197     if ( preProcessList.size() > 0 )
00198     {
00199         FilterContext cx;
00200         cx.profile() = _profile.get();
00201 
00202         for( FeatureFilterList::const_iterator i = _filters.begin(); i != _filters.end(); ++i )
00203         {
00204             FeatureFilter* filter = i->get();
00205             cx = filter->push( preProcessList, cx );
00206         }
00207     }
00208 
00209     // read one more for "more" detection:
00210     _nextHandleToQueue = OGR_L_GetNextFeature( _resultSetHandle );
00211 
00212     //OE_NOTICE << "read " << _queue.size() << " features ... " << std::endl;
00213 }
00214 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines