Skip to content
Permalink
Browse files
wfs provider: copy geometry and attributes only if necessary
  • Loading branch information
mhugent committed Jan 21, 2013
1 parent bde20b4 commit dda51c62b5415e70aa3bad37cfa71f86781904fd
@@ -40,7 +40,7 @@ QgsWFSFeatureIterator::QgsWFSFeatureIterator( QgsWFSProvider* provider, const Qg

QgsWFSFeatureIterator::~QgsWFSFeatureIterator()
{

close();
}

bool QgsWFSFeatureIterator::nextFeature( QgsFeature& f )
@@ -61,7 +61,17 @@ bool QgsWFSFeatureIterator::nextFeature( QgsFeature& f )
return false;
}
QgsFeature* fet = it.value();
mProvider->copyFeature( fet, f, !( mRequest.flags() & QgsFeatureRequest::NoGeometry ), mRequest.subsetOfAttributes() );

QgsAttributeList attributes;
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
attributes = mRequest.subsetOfAttributes();
}
else
{
attributes = mProvider->attributeIndexes();
}
mProvider->copyFeature( fet, f, !( mRequest.flags() & QgsFeatureRequest::NoGeometry ), attributes );
++mFeatureIterator;
return true;
}
@@ -159,21 +159,28 @@ void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetch

//copy the geometry
QgsGeometry* geometry = f->geometry();
if ( geometry )
if ( geometry && fetchGeometry )
{
unsigned char *geom = geometry->asWkb();
int geomSize = geometry->wkbSize();
unsigned char* copiedGeom = new unsigned char[geomSize];
memcpy( copiedGeom, geom, geomSize );
feature.setGeometryAndOwnership( copiedGeom, geomSize );
}
else
{
feature.setGeometry( 0 );
}

//and the attributes
const QgsAttributes& attributes = f->attributes();
feature.setAttributes( attributes );

int i = 0;
for ( QgsAttributeList::const_iterator it = fetchAttributes.begin(); it != fetchAttributes.end(); ++it )
{
feature.setAttribute( *it, attributes[*it] );
feature.setAttribute( i, attributes[*it] );
++i;
}

//id and valid
@@ -351,96 +358,6 @@ QgsFeatureIterator QgsWFSProvider::getFeatures( const QgsFeatureRequest& request
return QgsFeatureIterator( new QgsWFSFeatureIterator( this, request ) );
}

void QgsWFSProvider::select( QgsAttributeList fetchAttributes,
QgsRectangle rect,
bool fetchGeometry,
bool useIntersect )
{

if ( geometryType() == QGis::WKBNoGeometry )
{
fetchGeometry = false;
}

mUseIntersect = useIntersect;
mAttributesToFetch = fetchAttributes;
mFetchGeom = fetchGeometry;

if ( rect.isEmpty() )
{ //select all features
mSpatialFilter = mExtent;
mSelectedFeatures = mFeatures.keys();
}
else
{ //select features intersecting caller's extent
QString dsURI = dataSourceUri();
//first time through, initialize GetRenderedOnly args
//ctor cannot initialize because layer object not available then
if ( ! mInitGro )
{ //did user check "Cache Features" in WFS layer source selection?
if ( dsURI.contains( "BBOX" ) )
{ //no: initialize incremental getFeature
if ( initGetRenderedOnly( rect ) )
{
mGetRenderedOnly = true;
}
else
{ //initialization failed;
QgsDebugMsg( QString( "GetRenderedOnly initialization failed; incorrect operation may occur\n%1" )
.arg( dataSourceUri() ) );
QMessageBox( QMessageBox::Warning, "Non-Cached layer initialization failed!",
QString( "Incorrect operation may occur:\n%1" ).arg( dataSourceUri() ) );
}
}
mInitGro = true;
}

if ( mGetRenderedOnly )
{ //"Cache Features" was not selected for this layer
//has rendered extent expanded beyond last-retrieved WFS extent?
//NB: "intersect" instead of "contains" tolerates rounding errors;
// avoids unnecessary second fetch on zoom-in/zoom-out sequences
QgsRectangle olap( rect );
olap = olap.intersect( &mGetExtent );
if ( doubleNear( rect.width(), olap.width() ) && doubleNear( rect.height(), olap.height() ) )
{ //difference between canvas and layer extents is within rounding error: do not re-fetch
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: no fetch required" ).arg( mLayer->name() ) );
}
else
{ //combined old and new extents might speed up local panning & zooming
mGetExtent.combineExtentWith( &rect );
//but see if the combination is useless or too big
double pArea = mGetExtent.width() * mGetExtent.height();
double cArea = rect.width() * rect.height();
if ( olap.isEmpty() || pArea > ( cArea * 4.0 ) )
{ //new canvas extent does not overlap or combining old and new extents would
//fetch > 4 times the area to be rendered; get only what will be rendered
mGetExtent = rect;
}
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: fetching extent %2" )
.arg( mLayer->name(), mGetExtent.asWktCoordinates() ) );
dsURI = dsURI.replace( QRegExp( "BBOX=[^&]*" ),
QString( "BBOX=%1,%2,%3,%4" )
.arg( mGetExtent.xMinimum(), 0, 'f' )
.arg( mGetExtent.yMinimum(), 0, 'f' )
.arg( mGetExtent.xMaximum(), 0, 'f' )
.arg( mGetExtent.yMaximum(), 0, 'f' ) );
//TODO: BBOX may not be combined with FILTER. WFS spec v. 1.1.0, sec. 14.7.3 ff.
// if a FILTER is present, the BBOX must be merged into it, capabilities permitting.
// Else one criterion must be abandoned and the user warned. [WBC 111221]
setDataSourceUri( dsURI );
reloadData();
mLayer->updateExtents();
}
}

mSpatialFilter = rect;
mSelectedFeatures = mSpatialIndex->intersects( mSpatialFilter );
}

mFeatureIterator = mSelectedFeatures.begin();
}

int QgsWFSProvider::getFeature( const QString& uri )
{
if ( mRequestEncoding == QgsWFSProvider::GET )
@@ -49,18 +49,6 @@ class QgsWFSProvider: public QgsVectorDataProvider

QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() );

/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual void select( QgsAttributeList fetchAttributes = QgsAttributeList(),
QgsRectangle rect = QgsRectangle(),
bool fetchGeometry = true,
bool useIntersect = false );

/**
* Gets the feature at the given feature ID.
* @param featureId of the feature to be returned

0 comments on commit dda51c6

Please sign in to comment.