1313 * *
1414 ***************************************************************************/
1515
16+ #include < math.h> // M_PI
17+
1618#include " qgswfsconstants.h"
1719#include " qgswfsshareddata.h"
1820#include " qgswfsutils.h"
3436
3537#include < QCryptographicHash>
3638
39+
3740QgsWFSSharedData::QgsWFSSharedData ( const QString& uri )
3841 : mURI( uri )
3942 , mSourceCRS( 0 )
@@ -48,6 +51,7 @@ QgsWFSSharedData::QgsWFSSharedData( const QString& uri )
4851 , mFeatureCountExact( false )
4952 , mGetFeatureHitsIssued( false )
5053 , mTotalFeaturesAttemptedToBeCached( 0 )
54+ , mTryFetchingOneFeature( false )
5155{
5256 // Needed because used by a signal
5357 qRegisterMetaType< QVector<QgsWFSFeatureGmlIdPair> >( " QVector<QgsWFSFeatureGmlIdPair>" );
@@ -514,6 +518,7 @@ int QgsWFSSharedData::registerToCache( QgsWFSFeatureIterator* iterator, QgsRecta
514518 delete mDownloader ;
515519 mMutex .lock ();
516520 mDownloadFinished = false ;
521+ mComputedExtent = QgsRectangle ();
517522 mDownloader = new QgsWFSThreadedFeatureDownloader ( this );
518523 QEventLoop loop;
519524 connect ( mDownloader , SIGNAL ( ready () ), &loop, SLOT ( quit () ) );
@@ -826,6 +831,7 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
826831 existingGmlIds = getExistingCachedGmlIds ( featureList );
827832 QVector<QgsWFSFeatureGmlIdPair> updatedFeatureList;
828833
834+ QgsRectangle localComputedExtent ( mComputedExtent );
829835 Q_FOREACH ( QgsWFSFeatureGmlIdPair featPair, featureList )
830836 {
831837 const QgsFeature& gmlFeature = featPair.first ;
@@ -874,8 +880,13 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
874880
875881 cachedFeature.setAttribute ( hexwkbGeomIdx, QVariant ( QString ( array.toHex ().data () ) ) );
876882
877- QgsGeometry* polyBoudingBox = QgsGeometry::fromRect ( geometry->boundingBox () );
878- cachedFeature.setGeometry ( polyBoudingBox );
883+ QgsRectangle bBox ( geometry->boundingBox () );
884+ if ( localComputedExtent.isNull () )
885+ localComputedExtent = bBox;
886+ else
887+ localComputedExtent.combineExtentWith ( &bBox );
888+ QgsGeometry* polyBoundingBox = QgsGeometry::fromRect ( bBox );
889+ cachedFeature.setGeometry ( polyBoundingBox );
879890 }
880891 else
881892 {
@@ -936,15 +947,30 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
936947 if ( !mFeatureCountExact )
937948 mFeatureCount += featureListToCache.size ();
938949 mTotalFeaturesAttemptedToBeCached += featureListToCache.size ();
950+ if ( !localComputedExtent.isNull () && mComputedExtent .isNull () && !mTryFetchingOneFeature &&
951+ !localComputedExtent.intersects ( mCapabilityExtent ) )
952+ {
953+ QgsMessageLog::logMessage ( tr ( " Layer extent reported by the server is not correct. "
954+ " You may need to zoom again on layer while features are being downloaded" ), tr ( " WFS" ) );
955+ }
956+ mComputedExtent = localComputedExtent;
939957 }
940958 }
941959
942960 featureList = updatedFeatureList;
943961
962+ emit extentUpdated ();
963+
944964 QgsDebugMsg ( QString ( " end %1" ).arg ( featureList.size () ) );
945965
946966}
947967
968+ QgsRectangle QgsWFSSharedData::computedExtent ()
969+ {
970+ QMutexLocker locker ( &mMutex );
971+ return mComputedExtent ;
972+ }
973+
948974void QgsWFSSharedData::pushError ( const QString& errorMsg )
949975{
950976 QgsMessageLog::logMessage ( errorMsg, tr ( " WFS" ) );
@@ -970,6 +996,36 @@ void QgsWFSSharedData::endOfDownload( bool success, int featureCount,
970996 mDownloadFinished = true ;
971997 if ( success && !mRect .isEmpty () )
972998 {
999+ // In the case we requested an extent that includes the extent reported by GetCapabilities response,
1000+ // that we have no filter and we got no features, then it is not unlikely that the capabilities
1001+ // might be wrong. In which case, query one feature so that we got a beginning of extent from
1002+ // which the user will be able to zoom out. This is far from being ideal...
1003+ if ( featureCount == 0 && mRect .contains ( mCapabilityExtent ) && mWFSFilter .isEmpty () &&
1004+ mCaps .supportsHits && !mGeometryAttribute .isEmpty () && !mTryFetchingOneFeature )
1005+ {
1006+ QgsDebugMsg ( " Capability extent is probably wrong. Starting a new request with one feature limit to get at least one feature" );
1007+ mTryFetchingOneFeature = true ;
1008+ QgsWFSSingleFeatureRequest request ( this );
1009+ mComputedExtent = request.getExtent ();
1010+ if ( !mComputedExtent .isNull () )
1011+ {
1012+ // Grow the extent by ~ 50 km (completely arbitrary number if you wonder!)
1013+ // so that it is sufficiently zoomed out
1014+ if ( mSourceCRS .mapUnits () == QGis::Meters )
1015+ mComputedExtent .grow ( 50 . * 1000 . );
1016+ else if ( mSourceCRS .mapUnits () == QGis::Degrees )
1017+ mComputedExtent .grow ( 50 . / 110 );
1018+ QgsMessageLog::logMessage ( tr ( " Layer extent reported by the server is not correct. You may need to zoom on layer and then zoom out to see all fetchures" ), tr ( " WFS" ) );
1019+ }
1020+ mMutex .unlock ();
1021+ if ( !mComputedExtent .isNull () )
1022+ {
1023+ emit extentUpdated ();
1024+ }
1025+ mMutex .lock ();
1026+ return ;
1027+ }
1028+
9731029 // Arbitrary threshold to avoid the cache of BBOX to grow out of control.
9741030 // Note: we could be smarter and keep some BBOXes, but the saturation is
9751031 // unlikely to happen in practice, so just clear everything.
@@ -1099,6 +1155,41 @@ int QgsWFSSharedData::getFeatureCount( bool issueRequestIfNeeded )
10991155 return mFeatureCount ;
11001156}
11011157
1158+ QgsGmlStreamingParser* QgsWFSSharedData::createParser ()
1159+ {
1160+ QgsGmlStreamingParser::AxisOrientationLogic axisOrientationLogic ( QgsGmlStreamingParser::Honour_EPSG_if_urn );
1161+ if ( mURI .ignoreAxisOrientation () )
1162+ {
1163+ axisOrientationLogic = QgsGmlStreamingParser::Ignore_EPSG;
1164+ }
1165+
1166+ if ( mLayerPropertiesList .size () )
1167+ {
1168+ QList< QgsGmlStreamingParser::LayerProperties > layerPropertiesList;
1169+ Q_FOREACH ( QgsOgcUtils::LayerProperties layerProperties, mLayerPropertiesList )
1170+ {
1171+ QgsGmlStreamingParser::LayerProperties layerPropertiesOut;
1172+ layerPropertiesOut.mName = layerProperties.mName ;
1173+ layerPropertiesOut.mGeometryAttribute = layerProperties.mGeometryAttribute ;
1174+ layerPropertiesList << layerPropertiesOut;
1175+ }
1176+
1177+ return new QgsGmlStreamingParser ( layerPropertiesList,
1178+ mFields ,
1179+ mMapFieldNameToSrcLayerNameFieldName ,
1180+ axisOrientationLogic,
1181+ mURI .invertAxisOrientation () );
1182+ }
1183+ else
1184+ {
1185+ return new QgsGmlStreamingParser ( mURI .typeName (),
1186+ mGeometryAttribute ,
1187+ mFields ,
1188+ axisOrientationLogic,
1189+ mURI .invertAxisOrientation () );
1190+ }
1191+ }
1192+
11021193
11031194// -------------------------
11041195
@@ -1165,3 +1256,68 @@ QString QgsWFSFeatureHitsRequest::errorMessageWithReason( const QString& reason
11651256 return tr ( " Download of feature count failed: %1" ).arg ( reason );
11661257}
11671258
1259+
1260+ // -------------------------
1261+
1262+
1263+ QgsWFSSingleFeatureRequest::QgsWFSSingleFeatureRequest ( QgsWFSSharedData* shared )
1264+ : QgsWFSRequest( shared->mURI .uri() ), mShared( shared )
1265+ {
1266+ }
1267+
1268+ QgsWFSSingleFeatureRequest::~QgsWFSSingleFeatureRequest ()
1269+ {
1270+ }
1271+
1272+ QgsRectangle QgsWFSSingleFeatureRequest::getExtent ()
1273+ {
1274+ QUrl getFeatureUrl ( mUri .baseURL () );
1275+ getFeatureUrl.addQueryItem ( " REQUEST" , " GetFeature" );
1276+ getFeatureUrl.addQueryItem ( " VERSION" , mShared ->mWFSVersion );
1277+ if ( mShared ->mWFSVersion .startsWith ( " 2.0" ) )
1278+ getFeatureUrl.addQueryItem ( " TYPENAMES" , mUri .typeName () );
1279+ else
1280+ getFeatureUrl.addQueryItem ( " TYPENAME" , mUri .typeName () );
1281+ if ( mShared ->mWFSVersion .startsWith ( " 2.0" ) )
1282+ getFeatureUrl.addQueryItem ( " COUNT" , QString::number ( 1 ) );
1283+ else
1284+ getFeatureUrl.addQueryItem ( " MAXFEATURES" , QString::number ( 1 ) );
1285+
1286+ if ( !sendGET ( getFeatureUrl, true ) )
1287+ return -1 ;
1288+
1289+ const QByteArray& buffer = response ();
1290+
1291+ QgsDebugMsg ( " parsing QgsWFSSingleFeatureRequest: " + buffer );
1292+
1293+ // parse XML
1294+ QgsGmlStreamingParser* parser = mShared ->createParser ();
1295+ QString gmlProcessErrorMsg;
1296+ QgsRectangle extent;
1297+ if ( parser->processData ( buffer, true , gmlProcessErrorMsg ) )
1298+ {
1299+ QVector<QgsGmlStreamingParser::QgsGmlFeaturePtrGmlIdPair> featurePtrList =
1300+ parser->getAndStealReadyFeatures ();
1301+ QVector<QgsWFSFeatureGmlIdPair> featureList;
1302+ for ( int i = 0 ;i < featurePtrList.size ();i++ )
1303+ {
1304+ QgsGmlStreamingParser::QgsGmlFeaturePtrGmlIdPair& featPair = featurePtrList[i];
1305+ QgsFeature f ( *( featPair.first ) );
1306+ const QgsGeometry* geometry = f.constGeometry ();
1307+ if ( geometry )
1308+ {
1309+ extent = geometry->boundingBox ();
1310+ }
1311+ delete featPair.first ;
1312+ }
1313+ }
1314+ delete parser;
1315+ return extent;
1316+ }
1317+
1318+ QString QgsWFSSingleFeatureRequest::errorMessageWithReason ( const QString& reason )
1319+ {
1320+ return tr ( " Download of feature failed: %1" ).arg ( reason );
1321+ }
1322+
1323+
0 commit comments