13
13
* *
14
14
***************************************************************************/
15
15
16
+ #include < math.h> // M_PI
17
+
16
18
#include " qgswfsconstants.h"
17
19
#include " qgswfsshareddata.h"
18
20
#include " qgswfsutils.h"
34
36
35
37
#include < QCryptographicHash>
36
38
39
+
37
40
QgsWFSSharedData::QgsWFSSharedData ( const QString& uri )
38
41
: mURI( uri )
39
42
, mSourceCRS( 0 )
@@ -48,6 +51,7 @@ QgsWFSSharedData::QgsWFSSharedData( const QString& uri )
48
51
, mFeatureCountExact( false )
49
52
, mGetFeatureHitsIssued( false )
50
53
, mTotalFeaturesAttemptedToBeCached( 0 )
54
+ , mTryFetchingOneFeature( false )
51
55
{
52
56
// Needed because used by a signal
53
57
qRegisterMetaType< QVector<QgsWFSFeatureGmlIdPair> >( " QVector<QgsWFSFeatureGmlIdPair>" );
@@ -514,6 +518,7 @@ int QgsWFSSharedData::registerToCache( QgsWFSFeatureIterator* iterator, QgsRecta
514
518
delete mDownloader ;
515
519
mMutex .lock ();
516
520
mDownloadFinished = false ;
521
+ mComputedExtent = QgsRectangle ();
517
522
mDownloader = new QgsWFSThreadedFeatureDownloader ( this );
518
523
QEventLoop loop;
519
524
connect ( mDownloader , SIGNAL ( ready () ), &loop, SLOT ( quit () ) );
@@ -826,6 +831,7 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
826
831
existingGmlIds = getExistingCachedGmlIds ( featureList );
827
832
QVector<QgsWFSFeatureGmlIdPair> updatedFeatureList;
828
833
834
+ QgsRectangle localComputedExtent ( mComputedExtent );
829
835
Q_FOREACH ( QgsWFSFeatureGmlIdPair featPair, featureList )
830
836
{
831
837
const QgsFeature& gmlFeature = featPair.first ;
@@ -874,8 +880,13 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
874
880
875
881
cachedFeature.setAttribute ( hexwkbGeomIdx, QVariant ( QString ( array.toHex ().data () ) ) );
876
882
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 );
879
890
}
880
891
else
881
892
{
@@ -936,15 +947,30 @@ void QgsWFSSharedData::serializeFeatures( QVector<QgsWFSFeatureGmlIdPair>& featu
936
947
if ( !mFeatureCountExact )
937
948
mFeatureCount += featureListToCache.size ();
938
949
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;
939
957
}
940
958
}
941
959
942
960
featureList = updatedFeatureList;
943
961
962
+ emit extentUpdated ();
963
+
944
964
QgsDebugMsg ( QString ( " end %1" ).arg ( featureList.size () ) );
945
965
946
966
}
947
967
968
+ QgsRectangle QgsWFSSharedData::computedExtent ()
969
+ {
970
+ QMutexLocker locker ( &mMutex );
971
+ return mComputedExtent ;
972
+ }
973
+
948
974
void QgsWFSSharedData::pushError ( const QString& errorMsg )
949
975
{
950
976
QgsMessageLog::logMessage ( errorMsg, tr ( " WFS" ) );
@@ -970,6 +996,36 @@ void QgsWFSSharedData::endOfDownload( bool success, int featureCount,
970
996
mDownloadFinished = true ;
971
997
if ( success && !mRect .isEmpty () )
972
998
{
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
+
973
1029
// Arbitrary threshold to avoid the cache of BBOX to grow out of control.
974
1030
// Note: we could be smarter and keep some BBOXes, but the saturation is
975
1031
// unlikely to happen in practice, so just clear everything.
@@ -1099,6 +1155,41 @@ int QgsWFSSharedData::getFeatureCount( bool issueRequestIfNeeded )
1099
1155
return mFeatureCount ;
1100
1156
}
1101
1157
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
+
1102
1193
1103
1194
// -------------------------
1104
1195
@@ -1165,3 +1256,68 @@ QString QgsWFSFeatureHitsRequest::errorMessageWithReason( const QString& reason
1165
1256
return tr ( " Download of feature count failed: %1" ).arg ( reason );
1166
1257
}
1167
1258
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