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